///|
/// MCP protocol version implemented by this SDK.
///
/// Single source of truth for the `MCP-Protocol-Version` header and the
/// `_meta.io.modelcontextprotocol/protocolVersion` field. Per the 2026-07-28
/// revision, every request carries its own version; there is no handshake.
pub const ProtocolVersion : String = "2026-07-28"
///|
pub(all) struct ServerInfo {
name : String
title : String?
version : String
description : String?
} derive(Debug, Eq)
///|
pub(all) struct ServerCapabilities {
experimental : Map[String, Json]?
logging : Map[String, Json]?
completions : Map[String, Json]?
tools : ToolCapabilities?
resources : ResourceCapabilities?
prompts : PromptCapabilities?
extra_fields : Map[String, Json]
/// Optional protocol extensions, per 2026-07-28 versioning: a map of
/// extension identifiers (following `_meta` key naming rules) to
/// per-extension settings objects.
extensions : Map[String, Json]?
} derive(Debug, Eq)
///|
pub(all) struct ToolCapabilities {
list_changed : Bool?
extra_fields : Map[String, Json]
} derive(Debug, Eq)
///|
pub(all) struct ResourceCapabilities {
subscribe : Bool?
list_changed : Bool?
extra_fields : Map[String, Json]
} derive(Debug, Eq)
///|
pub(all) struct PromptCapabilities {
list_changed : Bool?
extra_fields : Map[String, Json]
} derive(Debug, Eq)
///|
/// Request ID supporting exact JSON integers and strings. Int is a convenience
/// constructor; Number retains arbitrary-size wire integers.
pub(all) enum RequestId {
Int(Int32)
Number(JsonInteger)
Str(String)
} derive(Debug)
///|
/// Convert RequestId to its JSON string representation
pub fn RequestId::to_json_string(self : RequestId) -> String {
match self {
Int(n) => n.to_string()
Number(n) => n.to_json_string()
// Delegate string quoting to the Json serializer so every JSON escape
// (\b, \f, other control chars < 0x20) is emitted correctly; a
// hand-rolled escape list could produce invalid JSON text.
Str(s) => Json::string(s).stringify()
}
}
///|
pub fn RequestId::to_json(self : RequestId) -> Json {
match self {
Int(value) => Json::number(value.to_double())
Number(value) => value.to_json()
Str(value) => Json::string(value)
}
}
///|
pub fn RequestId::from_json(value : Json) -> RequestId raise MCPError {
match value {
String(value) => Str(value)
Number(_, ..) => Number(JsonInteger::from_json(value))
_ => raise InvalidRequest("Request id must be a string or JSON integer")
}
}
///|
/// Type-tagged canonical identity for routing, duplicate checks and cancellation.
pub fn RequestId::key(self : RequestId) -> String {
match self {
Int(value) => "n:" + JsonInteger::from_int(value).key()
Number(value) => "n:" + value.key()
Str(value) => "s:" + value
}
}
///|
pub impl Eq for RequestId with fn equal(self, other) {
self.key() == other.key()
}
///|
pub(all) struct JsonRpcRequest {
jsonrpc : String
id : RequestId
method_name : String
params : Json
} derive(Debug, Eq)
///|
pub(all) struct PromptArgument {
name : String
title : String?
description : String?
required : Bool?
extensions : Map[String, Json]
} derive(Debug, Eq)
///|
pub(all) struct PromptMessage {
role : String
content : ContentBlock
extensions : Map[String, Json]
} derive(Debug, Eq)
///|
pub(all) struct GetPromptResult {
description : String?
messages : Array[PromptMessage]
metadata : ResultMetadata
} derive(Debug, Eq)
///|
pub fn JsonRpcRequest::from_json(
json : Json,
) -> Result[JsonRpcRequest, MCPError] {
if json is Object(obj) {
let jsonrpc = match obj.get("jsonrpc") {
Some(String("2.0")) => "2.0"
_ => return Err(InvalidRequest("Missing or invalid 'jsonrpc' field"))
}
let id = match obj.get("id") {
Some(value) =>
RequestId::from_json(value) catch {
error => return Err(error)
}
None => return Err(InvalidRequest("Missing 'id' field"))
}
let method_name = match obj.get("method") {
Some(String(m)) => m
_ => return Err(InvalidRequest("Missing or invalid 'method' field"))
}
let params = obj.get("params").unwrap_or(null)
Ok({ jsonrpc, id, method_name, params, })
} else {
Err(InvalidRequest("Request must be a JSON object"))
}
}
///|
/// MRTR (Multi Round-Trip Requests) — 2026-07-28 spec basic/patterns/mrtr.
///
/// When a server needs client input (sampling/elicitation/roots) to finish a
/// request, it returns an `InputRequiredResult` whose `inputRequests` lists
/// what it needs and `requestState` carries server-side continuation state.
/// The client fulfills the inputs and retries the original request with
/// `inputResponses` + the echoed `requestState`.
///|
/// The three server→client input request methods. Servers MUST NOT send an
/// input request the client did not declare support for in its capabilities.
pub(all) enum InputRequestKind {
ElicitationCreate
SamplingCreateMessage
RootsList
} derive(Eq, Debug)
///|
/// One entry in an `inputRequests` map: a server-assigned key plus the
/// request method and params the client must fulfill.
pub(all) struct InputRequestEntry {
method_name : InputRequestKind
params : Json
} derive(Eq, Debug)
///|
/// Convert an `InputRequestKind` to its JSON-RPC method string.
pub fn InputRequestKind::to_method(self : InputRequestKind) -> String {
match self {
ElicitationCreate => "elicitation/create"
SamplingCreateMessage => "sampling/createMessage"
RootsList => "roots/list"
}
}
///|
/// Which kind of change notification a subscription filter should match.
/// Used internally by the server to route notifications to the right streams.
pub(all) enum SubscriptionNotificationKind {
ToolsListChanged
PromptsListChanged
ResourcesListChanged
/// A specific subscribed resource changed; matched against the
/// subscription's `resourceSubscriptions` URI list.
ResourceUpdated(uri~ : String)
} derive(Eq, Debug)
///|
/// Explicit trait method promotion for current MoonBit toolchains.
pub extend ServerInfo with @moonbitlang/core/debug.Debug::{to_repr}
///|
pub extend ServerInfo with Eq::{not_equal, equal}
///|
pub extend ServerCapabilities with @moonbitlang/core/debug.Debug::{to_repr}
///|
pub extend ServerCapabilities with Eq::{not_equal, equal}
///|
pub extend ToolCapabilities with @moonbitlang/core/debug.Debug::{to_repr}
///|
pub extend ToolCapabilities with Eq::{not_equal, equal}
///|
pub extend ResourceCapabilities with @moonbitlang/core/debug.Debug::{to_repr}
///|
pub extend ResourceCapabilities with Eq::{not_equal, equal}
///|
pub extend PromptCapabilities with @moonbitlang/core/debug.Debug::{to_repr}
///|
pub extend PromptCapabilities with Eq::{not_equal, equal}
///|
pub extend ToolDefinition with @moonbitlang/core/debug.Debug::{to_repr}
///|
pub extend ToolDefinition with Eq::{not_equal, equal}
///|
pub extend RequestId with Eq::{not_equal, equal}
///|
pub extend RequestId with @moonbitlang/core/debug.Debug::{to_repr}
///|
pub extend JsonRpcRequest with @moonbitlang/core/debug.Debug::{to_repr}
///|
pub extend JsonRpcRequest with Eq::{not_equal, equal}
///|
pub extend PromptArgument with @moonbitlang/core/debug.Debug::{to_repr}
///|
pub extend PromptArgument with Eq::{not_equal, equal}
///|
pub extend PromptMessage with @moonbitlang/core/debug.Debug::{to_repr}
///|
pub extend PromptMessage with Eq::{not_equal, equal}
///|
pub extend GetPromptResult with @moonbitlang/core/debug.Debug::{to_repr}
///|
pub extend GetPromptResult with Eq::{not_equal, equal}
///|
pub extend InputRequestKind with Eq::{not_equal, equal}
///|
pub extend InputRequestKind with @moonbitlang/core/debug.Debug::{to_repr}
///|
pub extend InputRequestEntry with Eq::{not_equal, equal}
///|
pub extend InputRequestEntry with @moonbitlang/core/debug.Debug::{to_repr}
///|
pub extend SubscriptionNotificationKind with Eq::{not_equal, equal}
///|
pub extend SubscriptionNotificationKind with @moonbitlang/core/debug.Debug::{
to_repr,
}