moonbit_mcp

A MoonBit SDK for the Model Context Protocol (MCP). Build MCP servers and clients in MoonBit.

mcp
model-context-protocol
llm
agent
sdk
moon add 123123213weqw/moonbit_mcp@0.1.0
Download zip
Version
0.1.0
License
MIT
Last updated
24 days ago
Downloads
2
README

#MoonBit MCP SDK

CI MoonBit License

A MoonBit SDK for the Model Context Protocol (MCP).

Build MCP servers and clients in MoonBit — connect to Claude, Cursor, and any MCP-compatible AI agent.

#30-Second Quick Start

#Install

moon add 123123213weqw/moonbit_mcp

#Minimal Echo Server

import {
"123123213weqw/moonbit_mcp" @mcp,
}

///|
fn main {
let server = @mcp.McpServer::new("echo-server", "1.0.0")
server.tool(
"echo",
@mcp.JsonSchema::object() |> @mcp.JsonSchema::string("message"),
fn(args) {
let msg = @mcp.ContentBlock::as_text(
@mcp.ContentBlock::TextContent("echo: " + args.stringify(), None)
).or_else(fn() { "no args" })
@mcp.CallToolResult::text(msg)
},
)
// In a real server, you'd drive server.process_message(raw) from a transport.
}

#What This Provides

LayerModules
ProtocolJSON-RPC 2.0 parsing/encoding, MCP message types (Request/Response/Notification)
TypesContentBlock (text/image/audio/resource), Tool, Resource, Prompt, LogMessage
ServerLow-level Server (handler registry + dispatch) + high-level McpServer builder
SchemaJSON Schema builder for tool input/output schemas
Transporttrait Transport abstraction + InMemoryTransport (tests) + BufferedTransport

#Architecture

┌─────────────────────────────────┐ │ McpServer (high-level builder) │ │ .tool() / .resource() / ... │ └──────────────┬──────────────────┘ │ registers handlers ┌──────────────▼──────────────────┐ │ Server (low-level dispatcher) │ │ initialize / tools/list / call │ │ + capability negotiation │ └──────────────┬──────────────────┘ │ uses ┌──────────────▼──────────────────┐ │ JSON-RPC 2.0 parse_message() │ │ + message_to_string() │ └──────────────┬──────────────────┘ │ drives any ┌──────────────▼──────────────────┐ │ trait Transport │ │ InMemoryTransport | Buffered │ └─────────────────────────────────┘

#Relationship to moon_proto

  • moon_proto: static .proto schema validation + protobuf wire codec
  • moonbit_mcp: dynamic AI Agent tool protocol (JSON-RPC over stdio/HTTP)

Zero overlap. The two can coexist: parse .proto with moon_proto, expose as MCP resources with moonbit_mcp.

#Development

moon fmt --check # format check moon check --deny-warn # type check (warnings as errors) moon test --deny-warn # run tests moon test --target all # wasm / wasm-gc / js / native moon info # regenerate public interface snapshot

#Test Results

  • moon test --target all: 21/21 passed on all 4 targets
  • moon check --deny-warn: 0 warnings, 0 errors

#License

MIT

#
MessageHandler

type MessageHandler = (String) -> Unit

The callback invoked when a complete JSON-RPC message line arrives.

#
MethodHandler

type MethodHandler = (Json, ServerContext) -> Result[Json, McpError]

A handler function for a specific MCP method on a server.

Receives the raw JSON params (or Null) and returns either a result Json or an [McpError].

#
ToolCallback

type ToolCallback = (Json) -> CallToolResult

Tool handler callback type: receives the arguments JSON and returns a result.

#
Transport

pub trait Transport {
fn send(Self, String) -> Unit
}

Transport abstraction: how JSON-RPC messages enter and leave a server/client.

The trait only requires [send]. [start] and [close] are provided as default no-ops so transports that do not need them (e.g. in-memory) incur no boilerplate.

#
Audience

pub(all) enum Audience {
AudienceUser
AudienceAssistant
} derive(Eq,
Debug
)

Audience for a content block annotation.

#
BufferedTransport

pub(all) struct BufferedTransport {
sent : Array[String]
closed : Bool
}

A buffered transport that collects sent messages in an array (useful for testing).

#
BufferedTransport::close

fn BufferedTransport::close(self : BufferedTransport) -> Unit

#
BufferedTransport::messages

fn BufferedTransport::messages(self : BufferedTransport) -> Array[String]

Messages collected so far (in send order).

#
BufferedTransport::new

#
CallToolResult

pub(all) struct CallToolResult {
content : Array[ContentBlock]
structured_content : Json?
is_error : Bool
} derive(Eq,
Debug
)

Result of calling a tool.

#
CallToolResult::error

fn CallToolResult::error(text : String) -> CallToolResult

Construct an error result (business error — the tool ran but failed).

#
CallToolResult::text

fn CallToolResult::text(text : String) -> CallToolResult

Construct a successful text result.

#
CallToolResult::to_json

fn CallToolResult::to_json(self : CallToolResult) -> Json

Encode [CallToolResult] to JSON.

#
ContentAnnotations

pub(all) struct ContentAnnotations {
audience : Array[Audience]
priority : Double?
last_modified : String?
} derive(Eq,
Debug
)

Annotations providing hints about a content block's role.

#
ContentBlock

pub(all) enum ContentBlock {
TextContent(String, ContentAnnotations?)
ImageContent(String, String, ContentAnnotations?)
AudioContent(String, String, ContentAnnotations?)
ResourceLink(String, String, String?, String?, String?, ContentAnnotations?)
EmbeddedResource(ResourceContents, ContentAnnotations?)
} derive(Eq,
Debug
)

A content block — the universal payload type shared by tools, resources, and prompts.

#
ContentBlock::as_text

fn ContentBlock::as_text(self : ContentBlock) -> String?

Extract the text from a [ContentBlock] if it is a text block.

#
ContentBlock::to_json

fn ContentBlock::to_json(self : ContentBlock) -> Json

Encode a [ContentBlock] to JSON.

#
GetPromptResult

pub(all) struct GetPromptResult {
description : String?
messages : Array[PromptMessage]
} derive(Eq,
Debug
)

Result of getting a prompt.

#
GetPromptResult::to_json

fn GetPromptResult::to_json(self : GetPromptResult) -> Json

Encode [GetPromptResult] to JSON.

#
Implementation

pub(all) struct Implementation {
name : String
title : String?
version : String
} derive(Eq,
Debug
)

Name and version of a client or server implementation.

#
Implementation::to_json

fn Implementation::to_json(self : Implementation) -> Json

Encode [Implementation] to JSON.

#
InMemoryTransport

pub(all) struct InMemoryTransport {
handler : (String) -> Unit?
closed : Bool
peer : InMemoryTransport?
}

An in-memory transport pair for tests and same-process use.

Create a linked pair with [InMemoryTransport::pair]; messages sent on one end are delivered to the handler of the other.

#
InMemoryTransport::close

fn InMemoryTransport::close(self : InMemoryTransport) -> Unit

Close the transport (subsequent sends are dropped).

#
InMemoryTransport::on_message

fn InMemoryTransport::on_message(self : InMemoryTransport, h : (String) -> Unit) -> Unit

Set the message handler for this transport.

#
InMemoryTransport::pair

Create a linked pair of in-memory transports. Messages sent on one are delivered to the other's handler.

#
JsonSchema

pub(all) struct JsonSchema {
typ : SchemaType
description : String?
properties : Map[String, SchemaProperty]
required : Array[String]
} derive(Eq,
Debug
)

A builder for constructing a JSON Schema (the subset used by MCP tools).

#
JsonSchema::boolean

fn JsonSchema::boolean(self : JsonSchema, name : String) -> JsonSchema

Add a required boolean property.

#
JsonSchema::describe

fn JsonSchema::describe(self : JsonSchema, desc : String) -> JsonSchema

Set a human-readable description for the schema.

#
JsonSchema::integer

fn JsonSchema::integer(self : JsonSchema, name : String) -> JsonSchema

Add a required integer property.

#
JsonSchema::number

fn JsonSchema::number(self : JsonSchema, name : String) -> JsonSchema

Add a required number property.

#
JsonSchema::object

fn JsonSchema::object() -> JsonSchema

Create a new object schema (the root of every tool input/output schema).

#
JsonSchema::optional_string

fn JsonSchema::optional_string(self : JsonSchema, name : String) -> JsonSchema

Add an optional string property (not added to required).

#
JsonSchema::string

fn JsonSchema::string(self : JsonSchema, name : String) -> JsonSchema

Add a required string property to an object schema.

#
JsonSchema::string_desc

fn JsonSchema::string_desc(self : JsonSchema, name : String, desc : String) -> JsonSchema

Add a required string property with a description.

#
JsonSchema::to_json

fn JsonSchema::to_json(self : JsonSchema) -> Json

Encode a [JsonSchema] to a JSON value.

#
LogLevel

pub(all) enum LogLevel {
LevelDebug
LevelInfo
LevelNotice
LevelWarning
LevelError
LevelCritical
LevelAlert
LevelEmergency
} derive(Eq,
Debug
)

Log severity level (RFC 5424 syslog ordering, low to high).

#
LogLevel::to_string

fn LogLevel::to_string(self : LogLevel) -> String

Convert a [LogLevel] to its JSON string representation.

#
LogMessage

pub(all) struct LogMessage {
level : LogLevel
logger : String?
data : Json
} derive(Eq,
Debug
)

A log message notification sent from server to client.

#
LogMessage::to_json

fn LogMessage::to_json(self : LogMessage) -> Json

Encode a [LogMessage] to a JSON notification params object.

#
McpError

pub(all) enum McpError {
RpcError(Int, String)
ParseError(String)
TransportError(String)
ProtocolError(String)
UnknownMethod(String)
UnknownTarget(String)
InvalidArguments(String)
} derive(Eq,
Debug
)

Error type returned by all MCP SDK operations that can fail.

#
McpError::to_code

fn McpError::to_code(self : McpError) -> Int

Convert an [McpError] to a JSON-RPC error code.

#
McpError::to_message

fn McpError::to_message(self : McpError) -> String

Human-readable message for an [McpError].

#
McpServer

pub(all) struct McpServer {
server : Server
tools : Array[Tool]
tool_callbacks : Map[String, (Json) -> CallToolResult]
}

High-level MCP server builder with ergonomic tool/resource/prompt registration.

#
McpServer::inner

fn McpServer::inner(self : McpServer) -> Server

Access the underlying low-level server.

#
McpServer::new

fn McpServer::new(name : String, version : String) -> McpServer

Create a new high-level server builder.

#
McpServer::process_message

fn McpServer::process_message(self : McpServer, raw : String) -> String?

Process an incoming message (delegate to the inner server).

#
McpServer::tool

fn McpServer::tool(self : McpServer, name : String, schema : JsonSchema, cb : (Json) -> CallToolResult) -> McpServer

Register a tool with its input schema and callback.

#
McpServer::tool_desc

fn McpServer::tool_desc(self : McpServer, name : String, desc : String, schema : JsonSchema, cb : (Json) -> CallToolResult) -> McpServer

Register a tool with description.

#
Paginated

pub(all) struct Paginated[T] {
items : Array[T]
next_cursor : String?
} derive(Eq,
Debug
)

A paginated result carrying an optional cursor for the next page.

#
Paginated::new

fn[T] Paginated::new(items : Array[T]) -> Paginated[T]

Construct a paginated result with no next cursor.

#
Paginated::with_cursor

fn[T] Paginated::with_cursor(items : Array[T], cursor : String) -> Paginated[T]

Construct a paginated result with a next cursor.

#
Prompt

pub(all) struct Prompt {
name : String
title : String?
description : String?
arguments : Array[PromptArgument]
} derive(Eq,
Debug
)

A prompt definition registered on an MCP server.

#
Prompt::arg

fn Prompt::arg(self : Prompt, name : String, required : Bool) -> Prompt

Add an argument to a prompt.

#
Prompt::new

fn Prompt::new(name : String) -> Prompt

Create a new prompt with the given name.

#
Prompt::to_json

fn Prompt::to_json(self : Prompt) -> Json

Encode a [Prompt] to JSON.

#
PromptArgument

pub(all) struct PromptArgument {
name : String
description : String?
required : Bool
} derive(Eq,
Debug
)

A named argument accepted by a prompt.

#
PromptMessage

pub(all) struct PromptMessage {
role : PromptRole
content : ContentBlock
} derive(Eq,
Debug
)

A single message in a prompt result.

#
PromptRole

pub(all) enum PromptRole {
RoleUser
RoleAssistant
} derive(Eq,
Debug
)

Role of a prompt message sender.

#
ReadResourceResult

pub(all) struct ReadResourceResult {
contents : Array[ResourceContents]
} derive(Eq,
Debug
)

Result of reading a resource.

#
ReadResourceResult::text

fn ReadResourceResult::text(uri : String, text : String) -> ReadResourceResult

Construct a read result from a single text resource.

#
ReadResourceResult::to_json

Encode [ReadResourceResult] to JSON.

#
RequestId

pub(all) enum RequestId {
IdInt(Int)
IdString(String)
} derive(Eq,
Debug
)

A JSON-RPC request id. Per MCP spec, id must be string or integer, never null.

#
Resource

pub(all) struct Resource {
uri : String
name : String
title : String?
description : String?
mime_type : String?
} derive(Eq,
Debug
)

A resource exposed by an MCP server.

#
Resource::new

fn Resource::new(uri : String, name : String) -> Resource

Create a new resource with a URI and display name.

#
Resource::to_json

fn Resource::to_json(self : Resource) -> Json

Encode a [Resource] to JSON.

#
ResourceContents

pub(all) enum ResourceContents {
TextResourceContents(String, String?, String)
BlobResourceContents(String, String?, String)
} derive(Eq,
Debug
)

Contents of a resource — either text or base64 blob.

#
ResourceContents::to_json

fn ResourceContents::to_json(self : ResourceContents) -> Json

Encode [ResourceContents] to JSON.

#
ResourceTemplate

pub(all) struct ResourceTemplate {
uri_template : String
name : String
title : String?
description : String?
mime_type : String?
} derive(Eq,
Debug
)

A parameterized resource template (URI Template RFC 6570).

#
RpcErrorObject

pub(all) struct RpcErrorObject {
code : Int
message : String
data : Json?
} derive(Eq,
Debug
)

JSON-RPC error object.

#
RpcMessage

pub(all) enum RpcMessage {
MsgRequest(RpcRequest)
MsgResponse(RpcResponse)
MsgNotification(RpcNotification)
} derive(Eq,
Debug
)

Sum type for any inbound JSON-RPC message.

#
RpcNotification

pub(all) struct RpcNotification {
method_name : String
params : Json?
} derive(Eq,
Debug
)

A JSON-RPC notification (no id, no response expected).

#
RpcNotification::method_str

fn RpcNotification::method_str(self : RpcNotification) -> String

The method string of a notification.

#
RpcNotification::to_json

fn RpcNotification::to_json(self : RpcNotification) -> Json

Encode an [RpcNotification] to a JSON object.

#
RpcRequest

pub(all) struct RpcRequest {
id : RequestId
method_name : String
params : Json?
} derive(Eq,
Debug
)

A JSON-RPC request.

#
RpcRequest::method_str

fn RpcRequest::method_str(self : RpcRequest) -> String

The method string of a request.

#
RpcRequest::to_json

fn RpcRequest::to_json(self : RpcRequest) -> Json

Encode an [RpcRequest] to a JSON object.

#
RpcResponse

pub(all) enum RpcResponse {
RpcResult(RequestId, Json)
RpcErrorResp(RequestId, RpcErrorObject)
} derive(Eq,
Debug
)

A JSON-RPC response (result or error, mutually exclusive).

#
RpcResponse::to_json

fn RpcResponse::to_json(self : RpcResponse) -> Json

Encode an [RpcResponse] to a JSON object.

#
SchemaProperty

pub(all) struct SchemaProperty {
typ : SchemaType
description : String?
} derive(Eq,
Debug
)

A property definition inside an object schema.

#
SchemaType

pub(all) enum SchemaType {
SchemaObject
SchemaString
SchemaNumber
SchemaInteger
SchemaBoolean
SchemaArray
} derive(Eq,
Debug
)

JSON Schema types supported by MCP tool input/output schemas.

#
Server

pub(all) struct Server {
server_info : Implementation
capabilities : ServerCapabilities
handlers : Map[String, (Json, ServerContext) -> Result[Json, McpError]]
initialized : Bool
}

The low-level MCP server: dispatches JSON-RPC messages to registered handlers and manages the initialize handshake.

#
Server::handle_method

fn Server::handle_method(self : Server, m : String, h : (Json, ServerContext) -> Result[Json, McpError]) -> Server

Register a handler for a specific MCP method.

#
Server::new

fn Server::new(name : String, version : String) -> Server

Create a new server with the given name/version and default (empty) capabilities.

#
Server::process_message

fn Server::process_message(self : Server, raw : String) -> String?

Process a single incoming JSON-RPC message string and return the response string (if any — notifications produce no response).

#
Server::with_tools

fn Server::with_tools(self : Server) -> Server

Enable tools capability with list-changed notifications.

#
ServerCapabilities

pub(all) struct ServerCapabilities {
tools_list_changed : Bool
resources_subscribe : Bool
resources_list_changed : Bool
prompts_list_changed : Bool
logging : Bool
} derive(Eq,
Debug
)

Server-side capability flags (each optional; advertised in initialize response).

#
ServerCapabilities::new

Default capabilities: everything off. Use the builder methods to enable.

#
ServerCapabilities::to_json

Encode [ServerCapabilities] to the JSON capabilities object.

#
ServerContext

pub(all) struct ServerContext {
server_info : Implementation
capabilities : ServerCapabilities
initialized : Bool
}

Mutable server state passed to method handlers.

#
Tool

pub(all) struct Tool {
name : String
title : String?
description : String?
input_schema : JsonSchema
output_schema : JsonSchema?
annotations : ToolAnnotations?
} derive(Eq,
Debug
)

A tool definition registered on an MCP server.

#
Tool::describe

fn Tool::describe(self : Tool, desc : String) -> Tool

Set the tool's human-readable description.

#
Tool::new

fn Tool::new(name : String, schema : JsonSchema) -> Tool

Create a new tool with the given name and input schema.

#
Tool::to_json

fn Tool::to_json(self : Tool) -> Json

Encode a [Tool] to its JSON representation (for tools/list responses).

#
ToolAnnotations

pub(all) struct ToolAnnotations {
title : String?
read_only_hint : Bool
destructive_hint : Bool
idempotent_hint : Bool
open_world_hint : Bool
} derive(Eq,
Debug
)

Behavioral hints about a tool (all are advisory, not enforced).

#
ToolAnnotations::new

Default tool annotations.

#
content_blocks_to_json

fn content_blocks_to_json(blocks : Array[ContentBlock]) -> Json

Encode an array of content blocks to a JSON array.

#
implementation_error_start

let implementation_error_start : Int

Start of the implementation-defined error range.

#
internal_error_code

let internal_error_code : Int

JSON-RPC 2.0 standard error code: internal error.

#
invalid_params_code

let invalid_params_code : Int

JSON-RPC 2.0 standard error code: invalid params.

#
invalid_request_code

let invalid_request_code : Int

JSON-RPC 2.0 standard error code: invalid request.

#
json_rpc_version

let json_rpc_version : String

JSON-RPC 2.0 protocol version string.

#
latest_protocol_version

let latest_protocol_version : String

The latest MCP protocol version this SDK targets.

#
message_to_string

fn message_to_string(msg : RpcMessage) -> String

Serialize any [RpcMessage] to a JSON string.

#
method_cancelled

let method_cancelled : String

#
method_initialize

let method_initialize : String

MCP method name constants.

#
method_initialized

let method_initialized : String

#
method_logging_message

let method_logging_message : String

#
method_logging_set_level

let method_logging_set_level : String

#
method_not_found_code

let method_not_found_code : Int

JSON-RPC 2.0 standard error code: method not found.

#
method_ping

let method_ping : String

#
method_progress

let method_progress : String

#
method_prompts_get

let method_prompts_get : String

#
method_prompts_list

let method_prompts_list : String

#
method_prompts_list_changed

let method_prompts_list_changed : String

#
method_resources_list

let method_resources_list : String

#
method_resources_list_changed

let method_resources_list_changed : String

#
method_resources_read

let method_resources_read : String

#
method_resources_subscribe

let method_resources_subscribe : String

#
method_resources_templates_list

let method_resources_templates_list : String

#
method_resources_updated

let method_resources_updated : String

#
method_tools_call

let method_tools_call : String

#
method_tools_list

let method_tools_list : String

#
method_tools_list_changed

let method_tools_list_changed : String

#
parse_error_code

let parse_error_code : Int

JSON-RPC 2.0 standard error code: parse error.

#
parse_message

fn parse_message(raw : String) -> Result[RpcMessage, McpError]

Parse an [RpcMessage] from a raw JSON string.

#
resource_not_found_code

let resource_not_found_code : Int

Resource not found error code (de-facto standard in MCP ecosystem).

#
send_and_return

fn[T : Transport] send_and_return(t : T, msg : String) -> T

Send a message through any transport and return the transport (for chaining).

#
send_message

fn[T : Transport] send_message(t : T, msg : String) -> Unit

Send a message through any transport (generic helper for trait dispatch).

#
text_content

fn text_content(text : String) -> ContentBlock

Convenience constructor: create a text content block with no annotations.

#
tools_to_json

fn tools_to_json(tools : Array[Tool]) -> Json

Encode an array of tools for a tools/list response.