API Reference

Primary Interface

ModelContextProtocol.mcp_serverFunction
mcp_server(; name::String, version::String="1.0.0",
         tools::Union{Vector{MCPTool},MCPTool,Nothing}=nothing,
         resources::Union{Vector{MCPResource},MCPResource,Nothing}=nothing,
         prompts::Union{Vector{MCPPrompt},MCPPrompt,Nothing}=nothing,
         description::String="",
         instructions::String="",
         capabilities::Vector{Capability}=default_capabilities(),
         auto_register_dir::Union{String,Nothing}=nothing,
         title::Union{String,Nothing}=nothing,
         icons::Union{Vector{MCPIcon},Nothing}=nothing) -> Server

Primary entry point for creating and configuring a Model Context Protocol (MCP) server.

Arguments

  • name::String: Unique identifier for the server instance
  • version::String: Your server implementation version (defaults to "1.0.0") - YOUR server's version, not the MCP protocol version
  • tools: Tools to expose to the model
  • resources: Resources available to the model
  • resource_templates: Parameterized resource families (RFC 6570 {var} URI templates with a provider; advertised via resources/templates/list)
  • prompts: Predefined prompts for the model
  • description::String: Optional server description
  • instructions::String: Optional natural-language guidance for LLM clients on using this server (returned by legacy initialize and modern server/discover)
  • capabilities::Vector{Capability}: Server capability configuration
  • auto_register_dir: Directory to auto-register components from
  • title::Union{String,Nothing}: Optional human-friendly display name for the server
  • icons::Union{Vector{MCPIcon},Nothing}: Optional icons for the server
  • mrtr_state_key::Union{Vector{UInt8},Nothing}: Optional MRTR requestState signing key (≥32 bytes) shared across replicas so retries survive re-routing; defaults to a random per-server key (single-instance safe). Tokens also carry a format version: replicas on different package versions that change it reject each other's tokens ("unsupported version"), so a rolling upgrade across such a change should drain in-flight MRTR exchanges (bounded by the 600s state TTL)

Returns

  • Server: A configured server instance ready to handle MCP client connections

Example

server = mcp_server(
    name = "my-server",
    version = "1.0.0",  # Your server version
    title = "My MCP Server",
    description = "Demo server with time tool",
    tools = MCPTool(
        name = "get_time",
        description = "Get current time",
        parameters = [],
        handler = args -> Dates.format(now(), "HH:MM:SS")
    )
)
start!(server)
source

Server Operations

ModelContextProtocol.start!Function
start!(server::Server; transport::Union{Transport,Nothing}=nothing) -> Nothing

Start the MCP server, setting up logging and entering the main server loop.

Arguments

  • server::Server: The server instance to start
  • transport::Union{Transport,Nothing}: Optional transport to use. If not provided, uses StdioTransport

Returns

  • Nothing: The function returns after the server stops

Throws

  • ServerError: If the server is already running
source
ModelContextProtocol.stop!Function
stop!(server::Server) -> Nothing

Stop a running MCP server: the server loop observes active == false on its next iteration and exits with the transport still open, so shutdown can deliver each subscriptions/listen stream's graceful closing result before the transport closes.

On HTTP this takes effect within the loop's bounded read wait. On stdio the loop blocks in readline, so stop! only takes effect when the next message — or EOF — arrives; the normal stdio lifecycle ends via stdin EOF, which runs the same graceful-closure path.

Arguments

  • server::Server: The server instance to stop

Returns

  • Nothing: The function returns after setting the server to inactive

Throws

  • ServerError: If the server is not currently running
source
ModelContextProtocol.register!Function
register!(server::Server, component::Union{Tool,Resource,MCPPrompt}) -> Server

Register a tool, resource, or prompt with the MCP server.

Arguments

  • server::Server: The server to register the component with
  • component: The component to register (can be a tool, resource, or prompt)

Returns

  • Server: The server instance for method chaining
source

Component Types

Tools

ModelContextProtocol.MCPToolType
MCPTool(; name::String, description::String, parameters::Vector{ToolParameter}=ToolParameter[],
      input_schema::Union{Nothing,AbstractDict}=nothing, handler::Function,
      return_type::Type=Vector{Content}) <: Tool

Implement a tool that can be invoked by clients in the MCP protocol.

Fields

  • name::String: Unique identifier for the tool
  • description::String: Human-readable description of the tool's purpose
  • parameters::Vector{ToolParameter}: Simple parameters (ignored if input_schema is provided)
  • input_schema::Union{Nothing,AbstractDict}: Raw JSON Schema for complex parameter types
  • handler::Function: Function that implements the tool's functionality
  • return_type::Type: Expected return type of the handler (defaults to Vector{Content})
  • annotations::Union{Nothing,Dict{String,Any}}: Optional tool annotations (behavioral hints for clients), e.g. Dict("readOnlyHint" => true, "destructiveHint" => false, "idempotentHint" => true, "openWorldHint" => false). Emitted verbatim intools/list`.
  • output_schema::Union{Nothing,AbstractDict}: Optional JSON Schema for the tool's structured result, emitted as outputSchema in tools/list. Pair it with a CallToolResult(structured_content=…) so clients can validate the structured output.
  • _meta::Union{Nothing,Dict{String,Any}}: Optional metadata for protocol extensions, emitted verbatim in tools/list when set
  • task_support::Symbol: Task-augmented execution support (MCP 2025-11-25, experimental): :forbidden (default — calls run synchronously), :optional (client may run the call as a task), or :required (client must run the call as a task). Emitted as execution.taskSupport in tools/list for clients that negotiated 2025-11-25.
  • required_scopes::Vector{String}: OAuth scopes the caller must hold to invoke this tool. Enforced at tools/call dispatch when the request carries an authenticated principal (HTTP auth active): every listed scope must be present on ctx.authenticated_user.scopes or the call is refused with an insufficient-scope error. Empty (default) means no per-tool requirement. When auth is not configured (no authenticated user) the check is skipped — the server performs no authorization. Not emitted in tools/list (it is server-side policy, not part of the tool's schema).

Parameter Definition

Tools can define parameters in two ways:

  1. Simple parameters using parameters::Vector{ToolParameter}: Good for flat schemas with basic types (string, number, boolean).

  2. Complex schemas using input_schema::AbstractDict: Supports arrays, enums, nested objects, and any valid JSON Schema. When provided, input_schema takes precedence over parameters.

Handler Return Types

The tool handler can return various types which are automatically converted:

  • An instance of the specified Content type (TextContent, ImageContent, etc.)
  • A Vector{<:Content} for multiple content items (can mix TextContent, ImageContent, etc.)
  • A Dict (automatically converted to JSON and wrapped in TextContent)
  • A String (automatically wrapped in TextContent)
  • A Tuple{Vector{UInt8}, String} (automatically wrapped in ImageContent)
  • A CallToolResult object for full control over the response (including error handling)

When returntype is Vector{Content} (default), single Content items are automatically wrapped in a vector. Note: When returning CallToolResult directly, the returntype field is ignored.

source
ModelContextProtocol.ToolParameterType
ToolParameter(; name::String, description::String, type::String, required::Bool=false,
              default::Any=nothing, header::Union{String,Nothing}=nothing)

Define a parameter for an MCP tool.

Fields

  • name::String: The parameter name (used as the key in the params dictionary)
  • description::String: Human-readable description of the parameter
  • type::String: Type of the parameter as specified in the MCP schema (e.g., "string", "number", "boolean")
  • required::Bool: Whether the parameter is required for tool invocation
  • default::Any: Default value for the parameter if not provided (nothing means no default)
  • header::Union{String,Nothing}: Optional SEP-2243 header-mirroring suffix, emitted as x-mcp-header in the generated schema: modern HTTP clients mirror the argument as an Mcp-Param-<header> request header (for routing), which the server validates against the body
source
ModelContextProtocol.MCPIconType
MCPIcon(; src::String, mimeType=nothing, sizes=nothing, theme=nothing)

Icon metadata for tools, resources, prompts, and server info (MCP 2025-11-25).

Fields

  • src::String: URI pointing to the icon (http/https URL or data: URI)
  • mimeType::Union{String,Nothing}: MIME type override (e.g., "image/png", "image/svg+xml")
  • sizes::Union{Vector{String},Nothing}: Size hints (e.g., ["48x48", "any"])
  • theme::Union{String,Nothing}: Which background the icon is designed for ("light" or "dark")
source

Resources

ModelContextProtocol.MCPResourceType
MCPResource <: Resource

Implement a resource that clients can access in the MCP protocol. Resources represent data that can be read by models and tools.

Fields

  • uri::URI: Unique identifier for the resource
  • name::String: Human-readable name for the resource
  • description::String: Detailed description of the resource
  • mime_type::String: MIME type of the resource data
  • data_provider::Function: Zero-argument function returning the resource data for resources/read. Return a TextResourceContents/BlobResourceContents (or a vector of them) for full control — BlobResourceContents is how binary resources are served (base64 blob on the wire). A String is used as the text verbatim; any other value is JSON-encoded into a text contents entry with the resource's mime_type.
  • annotations::AbstractDict{String,Any}: Additional metadata for the resource
source
ModelContextProtocol.ResourceTemplateType
ResourceTemplate(; name::String, uri_template::String,
               mime_type::Union{String,Nothing}=nothing, description::String="",
               title::Union{String,Nothing}=nothing,
               icons::Union{Vector{MCPIcon},Nothing}=nothing,
               data_provider::Union{Function,Nothing}=nothing,
               _meta::Union{Nothing,Dict{String,Any}}=nothing)

Define a parameterized family of resources: an RFC 6570 URI template (level-1 {var} placeholders, advertised via resources/templates/list) plus a provider that serves any resources/read whose URI matches the template.

Fields

  • name::String: Name of the resource template
  • uri_template::String: URI template with {var} placeholders; each placeholder matches one path segment (no /)
  • mime_type::Union{String,Nothing}: MIME type shared by all matching resources
  • description::String: Human-readable description of the template
  • title::Union{String,Nothing}: Optional human-friendly display name
  • icons::Union{Vector{MCPIcon},Nothing}: Optional icons for UI display
  • data_provider::Union{Function,Nothing}: Called for a matching resources/read as provider(uri::String) — or opt into provider(uri::String, vars::Dict{String,String}) to receive the extracted template variables. Return values follow the same contract as MCPResource providers (ResourceContents/vector, String verbatim, JSON fallback). Templates without a provider are advertised but not readable.
  • _meta::Union{Nothing,Dict{String,Any}}: Optional metadata for protocol extensions, emitted verbatim in resources/templates/list when set
  • completions::Union{Nothing,Dict{String,Any}}: Optional completion/complete sources per template variable name: a Vector{String} (served filtered by prefix against the partial value) or a function value -> values / (value, context_args) -> values returning the suggestions
source

Prompts

ModelContextProtocol.MCPPromptType
MCPPrompt(; name::String, description::String="",
        arguments::Vector{PromptArgument}=PromptArgument[],
        messages::Vector{PromptMessage}=PromptMessage[],
        title::Union{String,Nothing}=nothing,
        icons::Union{Vector{MCPIcon},Nothing}=nothing,
        completions::Union{Nothing,Dict{String,Any}}=nothing)

Implement a prompt or prompt template as defined in the MCP schema. Prompts can include variables that are replaced with arguments when retrieved.

Fields

  • name::String: Unique identifier for the prompt
  • description::String: Human-readable description of the prompt's purpose
  • arguments::Vector{PromptArgument}: Arguments that this prompt accepts
  • messages::Vector{PromptMessage}: The sequence of messages in the prompt
  • title::Union{String,Nothing}: Optional human-friendly display name
  • icons::Union{Vector{MCPIcon},Nothing}: Optional icons for UI display
  • _meta::Union{Nothing,Dict{String,Any}}: Optional metadata for protocol extensions, emitted verbatim in prompts/list when set
  • completions::Union{Nothing,Dict{String,Any}}: Optional completion/complete sources per argument name: a Vector{String} (served filtered by prefix against the partial value) or a function value -> values / (value, context_args) -> values returning the suggestions
source
ModelContextProtocol.PromptArgumentType
PromptArgument(; name::String, description::String="", required::Bool=false,
              title::Union{String,Nothing}=nothing)

Define an argument that a prompt template can accept.

Fields

  • name::String: The argument name (used in template placeholders)
  • description::String: Human-readable description of the argument
  • required::Bool: Whether the argument is required when using the prompt
  • title::Union{String,Nothing}: Optional human-friendly display name
source
ModelContextProtocol.PromptMessageType
PromptMessage(; content::Union{TextContent, ImageContent, AudioContent, ResourceLink, EmbeddedResource}, role::Role=user)

Represent a single message in a prompt template.

Fields

  • content::Union{TextContent, ImageContent, AudioContent, ResourceLink, EmbeddedResource}: The content of the message
  • role::Role: Whether this message is from the user or assistant (defaults to user)
source

Content Types

Abstract Types

ModelContextProtocol.ContentType
Content

Abstract base type for all content formats in the MCP protocol. Content can be exchanged between clients and servers in various formats.

source

Concrete Content Types

ModelContextProtocol.TextContentType
TextContent(; type::String="text", text::String, 
            annotations::Union{Nothing,Dict{String,Any}}=nothing,
            _meta::Union{Nothing,Dict{String,Any}}=nothing) <: Content

Text-based content for messages and tool responses.

Fields

  • type::String: Content type identifier (always "text")
  • text::String: The actual text content
  • annotations::Union{Nothing,Dict{String,Any}}: Optional annotations for the client
  • _meta::Union{Nothing,Dict{String,Any}}: Optional metadata for protocol extensions
source
ModelContextProtocol.ImageContentType
ImageContent(; type::String="image", data::Vector{UInt8}, mime_type::String,
             annotations::Union{Nothing,Dict{String,Any}}=nothing,
             _meta::Union{Nothing,Dict{String,Any}}=nothing) <: Content

Image content for messages and tool responses.

Fields

  • type::String: Content type identifier (always "image")
  • data::Vector{UInt8}: Raw image data (automatically base64-encoded when serialized)
  • mime_type::String: MIME type of the image (e.g., "image/png")
  • annotations::Union{Nothing,Dict{String,Any}}: Optional annotations for the client
  • _meta::Union{Nothing,Dict{String,Any}}: Optional metadata for protocol extensions
source
ModelContextProtocol.AudioContentType
AudioContent(; type::String="audio", data::Vector{UInt8}, mime_type::String,
             annotations::Union{Nothing,Dict{String,Any}}=nothing,
             _meta::Union{Nothing,Dict{String,Any}}=nothing) <: Content

Audio content for messages and tool responses (protocol 2025-03-26+).

Fields

  • type::String: Content type identifier (always "audio")
  • data::Vector{UInt8}: Raw audio data (automatically base64-encoded when serialized)
  • mime_type::String: MIME type of the audio (e.g., "audio/wav"), serialized as mimeType
  • annotations::Union{Nothing,Dict{String,Any}}: Optional annotations for the client
  • _meta::Union{Nothing,Dict{String,Any}}: Optional metadata for protocol extensions
source
ModelContextProtocol.EmbeddedResourceType
EmbeddedResource(; type::String="resource", resource::Dict{String,Any},
                 annotations::Union{Nothing,Dict{String,Any}}=nothing,
                 _meta::Union{Nothing,Dict{String,Any}}=nothing) <: Content

Embedded resource content for inline resource data.

Fields

  • type::String: Content type identifier (always "resource")
  • resource::Dict{String,Any}: The embedded resource data
  • annotations::Union{Nothing,Dict{String,Any}}: Optional annotations for the client
  • _meta::Union{Nothing,Dict{String,Any}}: Optional metadata for protocol extensions
source
ModelContextProtocol.ResourceLinkType
ResourceLink(; type::String="resource_link", uri::String, name::String,
             description::Union{String,Nothing}=nothing,
             mime_type::Union{String,Nothing}=nothing,
             title::Union{String,Nothing}=nothing,
             annotations::Union{Nothing,Dict{String,Any}}=nothing,
             _meta::Union{Nothing,Dict{String,Any}}=nothing) <: Content

Link to a resource a tool result can reference without embedding it (protocol 2025-06-18). Serialized per the MCP spec as {"type": "resource_link", "uri": ..., "name": ..., ...}.

Fields

  • type::String: Content type identifier (always "resource_link")
  • uri::String: URI of the linked resource
  • name::String: Name of the resource
  • description::Union{String,Nothing}: Optional description of the resource
  • mime_type::Union{String,Nothing}: Optional MIME type, serialized as mimeType
  • size::Union{Int,Nothing}: Optional resource size in bytes
  • title::Union{String,Nothing}: Optional human-readable title
  • annotations::Union{Nothing,Dict{String,Any}}: Optional annotations for the client
  • _meta::Union{Nothing,Dict{String,Any}}: Optional metadata for protocol extensions
source

Resource Content Types

ModelContextProtocol.TextResourceContentsType
TextResourceContents(; uri::URI, mime_type::String="text/plain", text::String) <: ResourceContents

Text content for resources in the MCP protocol.

Fields

  • uri::URI: Resource identifier
  • mime_type::String: MIME type of the text content
  • text::String: The actual text content
source
ModelContextProtocol.BlobResourceContentsType
BlobResourceContents(; uri::URI, mime_type::String="application/octet-stream", 
                    blob::Vector{UInt8}) <: ResourceContents

Binary content for resources.

Fields

  • uri::URI: Resource identifier
  • mime_type::String: MIME type of the binary content
  • blob::Vector{UInt8}: Raw binary data (automatically base64-encoded when serialized)
source

Tool Results

ModelContextProtocol.CallToolResultType
CallToolResult(; content::Vector{Dict{String,Any}}, is_error::Bool=false,
               structured_content=nothing) <: ResponseResult

Result returned from a tool invocation.

Fields

  • content::Vector{Dict{String,Any}}: Content produced by the tool
  • is_error::Bool: Whether the tool execution resulted in an error
  • structured_content::Union{Nothing,AbstractDict}: Optional structured result (a JSON object per the MCP spec), serialized as structuredContent and omitted when nothing. Pair it with the tool's output_schema so clients can validate and consume it programmatically. Per the spec, a tool returning structured content SHOULD also include a human-readable serialization (e.g. the JSON as text) in content for clients that don't consume structured output.
  • _meta::Union{Nothing,AbstractDict}: Optional result metadata for protocol extensions, serialized as _meta and omitted when nothing
source

Transport Configuration

ModelContextProtocol.TransportType
Transport

Abstract base type for all MCP transport implementations. Defines the interface for reading and writing messages between client and server.

source
ModelContextProtocol.StdioTransportType
StdioTransport(; input::IO=stdin, output::IO=stdout)

Transport implementation using standard input/output streams. This is the default transport for local MCP server processes.

Fields

  • input::IO: Input stream for reading messages (default: stdin)
  • output::IO: Output stream for writing messages (default: stdout)
  • connected::Bool: Connection status (always true for stdio)
  • write_lock::ReentrantLock: Serializes output writes (responses and notifications share stdout, and background task executions may write concurrently with the loop)
source
ModelContextProtocol.HttpTransportType
HttpTransport(; host::String="127.0.0.1", port::Int=8080, endpoint::String="/",
              allowed_origins::Vector{String}=String[], allowed_hosts::Vector{String}=String[])

Transport implementation following the MCP Streamable HTTP specification (2025-06-18). Supports Server-Sent Events (SSE) for streaming and session management. A request's response is a single JSON object, or — when request-scoped notifications (progress, log messages) are emitted during handling — an SSE stream scoped to that request.

When bound to a loopback host without bearer auth, requests whose Host or Origin header is neither local nor allowlisted are rejected with 403 (DNS-rebinding protection); a deployment behind a reverse proxy adds its public hostname to allowed_hosts (or enables auth, which disables the guard).

Fields

  • host::String: Host address to bind to (default: "127.0.0.1")
  • port::Int: Port number to listen on (default: 8080)
  • endpoint::String: HTTP endpoint path (default: "/")
  • server::Union{HTTP.Server,Nothing}: HTTP server instance
  • connected::Bool: Connection status
  • server_task::Union{Task,Nothing}: Server task handle
  • active_streams::Dict{String,HTTP.Stream}: Active streaming connections
  • request_queue::Channel{QueuedHttpRequest}: Queue for incoming requests (id, body, auth user)
  • response_channels::Dict{String,Channel{Tuple{Symbol,String}}}: Per-request response routes carrying (:notification, json) entries followed by one (:response, json)
  • allowed_origins::Vector{String}: Origins accepted by the DNS-rebinding guard (exact match)
  • allowed_hosts::Vector{String}: Extra Host-header hostnames accepted by the DNS-rebinding guard
source
ModelContextProtocol.connectFunction
connect(transport::Transport) -> Nothing

Establish the transport connection. Default implementation does nothing (for transports that are always connected).

Arguments

  • transport::Transport: The transport instance to connect

Returns

  • Nothing

Throws

  • TransportError: If connection cannot be established
source
connect(transport::HttpTransport) -> Nothing

Start the HTTP server and begin listening for connections.

Arguments

  • transport::HttpTransport: The transport instance

Returns

  • Nothing

Throws

  • TransportError: If the server cannot be started
source

Server Type

ModelContextProtocol.ServerType
Server(config::ServerConfig; transport::Union{Transport,Nothing}=nothing)

Represent a running MCP server instance that manages resources, tools, and prompts.

Fields

  • config::ServerConfig: Server configuration settings
  • transport::Union{Transport,Nothing}: Transport implementation for client-server communication
  • resources::Vector{Resource}: Available resources
  • tools::Vector{Tool}: Available tools
  • prompts::Vector{MCPPrompt}: Available prompts
  • resource_templates::Vector{ResourceTemplate}: Available resource templates
  • subscriptions::DefaultDict{String,Vector{Subscription}}: Resource subscription registry
  • progress_trackers::Dict{Union{String,Int},Progress}: Progress tracking for operations
  • tasks::TaskStore: Registry of server-side tasks (MCP Tasks, experimental)
  • listen_subscriptions::SubscriptionRegistry: Active modern-era subscriptions/listen streams
  • active::Bool: Whether the server is currently active
  • task_notification_queue::Union{Channel{Any},Nothing}: notifications/tasks dispatch FIFO (set by install_task_notifications!, closed by stop!)
  • tool_header_paths::Dict{String,Vector{Tuple{Vector{String},String}}}: per-tool SEP-2243 mirror tables — derived from the normalized schema by validate_tool_headers and persisted by register!, read by the handle_modern_request preflight

Constructor

  • Server(config::ServerConfig; transport=nothing): Creates a new server with the specified configuration
source

Resource Subscriptions

ModelContextProtocol.subscribe!Function
subscribe!(server::Server, uri::String, callback::Function) -> Server

Subscribe to updates for a specific resource identified by URI.

The callback is an in-process observer: notify_resource_updated invokes it as callback(uri) whenever that URI is announced as changed. It runs on the announcing task, its errors are logged and swallowed, and it sends nothing to clients on its own (client delivery is notify_resource_updated's job).

Arguments

  • server::Server: The server instance
  • uri::String: The resource URI to subscribe to
  • callback::Function: Called as callback(uri::String) on each announced update

Returns

  • Server: The server instance for method chaining
source
ModelContextProtocol.unsubscribe!Function
unsubscribe!(server::Server, uri::String, callback::Function) -> Server

Remove a subscription for a specific resource URI and callback function.

Arguments

  • server::Server: The server instance
  • uri::String: The resource URI to unsubscribe from
  • callback::Function: The callback function to remove

Returns

  • Server: The server instance for method chaining
source
ModelContextProtocol.notify_list_changedFunction
notify_list_changed(server::Server, kind::Symbol) -> Int

Announce that a list of server components changed, delivering notifications/{kind}/list_changed to every subscriptions/listen stream that subscribed to it and to the connected legacy session (when the corresponding listChanged capability is declared). Call this after mutating server.tools, server.prompts, or server.resources at runtime.

Only streams open at the time of the change are notified (there is no backlog).

Arguments

  • server::Server: The server whose lists changed
  • kind::Symbol: One of :tools, :prompts, :resources

Returns

  • Int: How many delivery targets a transport handoff was attempted for — subscriptions/listen streams plus the legacy session. Counts attempted handoffs, not enqueue or client receipt (a disconnected HTTP peer, or a full notification queue, drops silently).
source
ModelContextProtocol.notify_resource_updatedFunction
notify_resource_updated(server::Server, uri::AbstractString) -> Int

Announce that a resource's contents changed, delivering notifications/resources/updated to every subscriptions/listen stream that subscribed to that URI and to the connected legacy session when it subscribed via resources/subscribe. In-process callbacks registered with subscribe! for the URI are also invoked (with the URI as their only argument); callback errors are logged and do not affect client delivery or the returned count.

Arguments

  • server::Server: The server holding the resource
  • uri::AbstractString: The resource URI that changed

Returns

  • Int: How many delivery targets a transport handoff was attempted for — subscriptions/listen streams plus the legacy session. Counts attempted handoffs, not enqueue or client receipt (a disconnected HTTP peer, or a full notification queue, drops silently).
source

Handler Context Helpers

ModelContextProtocol.send_progressFunction
send_progress(ctx::RequestContext, progress::Real;
              total::Union{Real,Nothing}=nothing,
              message::Union{String,Nothing}=nothing) -> Bool

Emit an MCP notifications/progress for the current request. A tool handler that accepts the RequestContext (its second argument) can call this during a long operation to report progress.

Returns false (a no-op) when the client did not supply a progressToken, no transport is connected, or the call is a detachable modern-era task call (tasks extension: notifications/progress is not supported on tasks, and the spawned handler has no request stream to route them to), so it is always safe to call. Send an increasing progress; include total for a determinate bar and message for a status line.

source
ModelContextProtocol.task_cancelledFunction
task_cancelled(ctx) -> Bool

Check whether the current task-augmented execution has been cancelled by the client (via tasks/cancel). Long-running, context-aware tool handlers can poll this to stop work early; the discarded result is never delivered (cancelled tasks stay cancelled). Always false for ordinary (non-task) calls, so it is safe to call unconditionally.

handler = (args, ctx) -> begin
    for chunk in work_chunks
        task_cancelled(ctx) && return TextContent(text = "aborted")
        process(chunk)
    end
    TextContent(text = "done")
end
source

Multi Round-Trip Requests (MRTR)

ModelContextProtocol.InputRequiredType
InputRequired(requests::AbstractDict; state=nothing)

The value a handler returns when it needs client input to finish (MRTR, 2026-07-28): the request is answered with an InputRequiredResult carrying these input requests, and the client retries with responses under the same keys. On the retry the handler runs AGAIN from the top — read the responses with input_responses(ctx) and any carried-over state with input_state(ctx).

Only meaningful on modern-era tools/call (legacy sessions have no wire shape for it and get an error). If a needed response is still missing on the retry, return another InputRequired — the spec says re-issue, not error.

A valid requestState can be replayed within its TTL (one-time semantics would require server-side shared state, which the stateless design avoids), so handlers should stay idempotent across retries.

Fields

  • requests::LittleDict{String,InputRequest}: server-assigned unique keys → input requests
  • state::Any: JSON-serializable handler state to carry to the retry, delivered inside the integrity-protected requestState (do NOT put secrets here: it is signed, not encrypted)
source
ModelContextProtocol.elicit_requestFunction
elicit_request(message::String; requested_schema=nothing) -> InputRequest

Build a form-mode elicitation input request (elicitation/create): ask the user a question, constraining the answer with a requested schema. The schema is REQUIRED on the wire (ElicitRequestFormParams.requestedSchema, an object schema with properties), so when none is given a minimal empty-object schema is synthesized — a schema-validating client would reject the request otherwise.

Arguments

  • message::String: The message to present to the user
  • requested_schema: JSON schema (Dict) for the expected response content; must be an object schema. Defaults to {"type": "object", "properties": {}}

Returns

  • InputRequest: The request for an InputRequired return
source
ModelContextProtocol.sampling_requestFunction
sampling_request(params::AbstractDict) -> InputRequest

Build a sampling input request (sampling/createMessage): ask the client's LLM for a completion. params is the CreateMessageRequest params object (e.g. messages, maxTokens).

Arguments

  • params::AbstractDict: The sampling/createMessage params

Returns

  • InputRequest: The request for an InputRequired return
source
ModelContextProtocol.roots_requestFunction
roots_request() -> InputRequest

Build a roots input request (roots/list): ask the client for its filesystem roots.

Returns

  • InputRequest: The request for an InputRequired return
source
ModelContextProtocol.input_responsesFunction
input_responses(ctx) -> Dict{String,Any}

The client's inputResponses from an MRTR retry (2026-07-28), keyed like the inputRequests the server issued. Empty on a first (non-retry) request — a handler asks for input by returning InputRequired when the response it needs is absent.

Arguments

  • ctx: The request context passed to a ctx-aware handler

Returns

  • Dict{String,Any}: The responses (empty when none)
source
ModelContextProtocol.input_stateFunction
input_state(ctx) -> Any

The handler state carried through the verified requestState of an MRTR retry (whatever the handler put in InputRequired(...; state=...)), or nothing on a first request.

Arguments

  • ctx: The request context passed to a ctx-aware handler

Returns

  • The carried state, or nothing
source

Tasks Extension

ModelContextProtocol.task_detachFunction
task_detach(ctx; ttl_ms=nothing, status_message=nothing) -> Bool

Hand the current tool call off to background task execution (MCP Tasks extension, SEP-2663). Callable from a ctx-aware tool handler: when the request is modern-era, the tool is task-capable (task_support :optional or :required), and the client declared the io.modelcontextprotocol/tasks extension, this durably creates the task and immediately delivers the CreateTaskResult (resultType:"task") as the call's response — the handler keeps running in the background, and its eventual return value (or thrown error) becomes the task's terminal state, observable via tasks/get.

Returns false — and the handler simply continues as an ordinary synchronous call — when any precondition is absent (legacy-era request, extension not declared, tool not task-capable). Idempotent: a second call returns true without creating another task.

Arguments

  • ctx: The request context passed to a ctx-aware handler
  • ttl_ms::Union{Int,Nothing}: Requested retention duration (clamped to the store's maximum); nothing for the server default
  • status_message::Union{String,Nothing}: Optional initial statusMessage

Returns

  • Bool: true when the call is (now) task-detached
source
ModelContextProtocol.task_await_inputFunction
task_await_input(ctx, request::InputRequest) -> Any
task_await_input(ctx, requests::AbstractVector{InputRequest}) -> Vector{Any}

Ask the client for input MID-TASK and block the handler until it answers (tasks extension, SEP-2663). Callable from a handler that has already detached via task_detach: the request(s) are registered under server-minted keys (unique over the task's lifetime), the task's status flips to input_required, and tasks/get surfaces the outstanding requests in inputRequests. The client answers with tasks/update inputResponses; each response value is returned to the waiting handler (the vector form returns responses in request order, and only once ALL of them have arrived — a partial tasks/update is accepted, the task simply stays input_required until the rest arrive). Once nothing is pending the status returns to working.

Build requests with elicit_request, sampling_request, or roots_request — the same constructors the MRTR flow uses. A server MUST NOT send input requests the creating request's client capabilities did not declare, so an undeclared capability throws (failing the task).

Throws TaskCancelledException when the task goes terminal while (or before) waiting. An unanswered request blocks until the client answers or cancels, or until the task's ttl elapses — a per-wait deadline timer fails an expired task still parked on client input and unwinds its waiters, so abandoned tasks cannot pin handler state forever. To distinguish expiry from a client cancel, check task_cancelled(ctx)true only for the latter.

The registered requests are frozen: each request's params are normalized into an owned plain-JSON snapshot at registration, so a key's content can never change across polls (the spec's key-stability rule) and the capability check binds to exactly what will be surfaced. Params must therefore be plain JSON data — nested dicts/vectors/tuples/sets of strings, numbers, booleans, and nothing (what elicit_request and friends naturally produce); anything else is rejected with an ArgumentError.

Before detachment there is no inputRequests surface: a handler that needs input to DECIDE (e.g. whether to proceed at all) returns InputRequired for the MRTR round on the original request instead.

Arguments

  • ctx: The request context passed to a ctx-aware handler
  • request/requests: The input request(s) to surface to the client

Returns

  • The client's response value (single form), or a Vector{Any} of response values in request order (vector form)
source
ModelContextProtocol.TaskCancelledExceptionType
TaskCancelledException()

Thrown by task_await_input when the task reaches a terminal state while the handler is waiting (or had already reached one when it asked) — cancelled by the client via tasks/cancel, or failed by the server because its ttl elapsed while parked on client input. Handlers that need to distinguish the two can check task_cancelled(ctx), which is true only for a client cancellation. Catch it for cleanup; otherwise it unwinds the handler, whose discarded outcome never overwrites the terminal status.

source

Protocol Version Negotiation

ModelContextProtocol.SUPPORTED_PROTOCOL_VERSIONSConstant

All LEGACY (initialize-handshake) MCP protocol versions supported by this implementation, newest first. These are the versions initialize negotiates; modern-era versions (per-request _meta, no handshake) live in MODERN_PROTOCOL_VERSIONS.

source
ModelContextProtocol.FEATURE_VERSIONSConstant

Minimum protocol version required for each feature.

Features are identified by Symbol keys. The value is the minimum protocol version that introduced the feature. Use supports(version, feature) to check availability.

Features

  • :tasks - Experimental task tracking (SEP-1686)
  • :sse_priming_events - SSE priming for stream resumability (SEP-1699)
  • :icon_metadata - Icon metadata for tools/resources/prompts (SEP-973)
  • :tool_calling_in_sampling - Tool calling in sampling requests (SEP-1577)
  • :oauth_openid_connect - OpenID Connect discovery for OAuth (PR #797)
  • :oauth_incremental_scope - Incremental scope consent (SEP-835)
  • :url_elicitation - URL mode elicitation requests (SEP-1036)
  • :streamable_http - Streamable HTTP transport
  • :resource_links - ResourceLink content type
source
ModelContextProtocol.negotiate_versionFunction
negotiate_version(client_version::Union{AbstractString, Nothing}) -> String

Negotiate the protocol version with a client per the MCP specification.

If the client requests a version we support, return that version. Otherwise, return our latest version and let the client decide whether it can proceed.

Arguments

  • client_version::Union{AbstractString, Nothing}: Protocol version requested by the client, or nothing

Returns

  • String: The negotiated protocol version
source
ModelContextProtocol.supportsFunction
supports(version::AbstractString, feature::Symbol) -> Bool

Check whether a protocol version supports a specific feature.

Arguments

  • version::AbstractString: The negotiated protocol version
  • feature::Symbol: Feature identifier (see FEATURE_VERSIONS for available features)

Returns

  • Bool: true if the version supports the feature

Example

if supports(negotiated_version, :tasks)
    # Include task tracking in response
end
source
ModelContextProtocol.is_supported_versionFunction
is_supported_version(version::AbstractString) -> Bool

Check whether a protocol version is in our supported versions list.

Arguments

  • version::AbstractString: Protocol version string to check

Returns

  • Bool: true if we support this version
source

Authentication (OAuth Resource Server)

Configuration and Middleware

ModelContextProtocol.OAuthConfigType
OAuthConfig(; issuer::String, audience::String,
             required_scopes::Vector{String}=String[],
             jwks_uri::Union{String,Nothing}=nothing,
             introspection_endpoint::Union{String,Nothing}=nothing)

Configure OAuth 2.0 token validation for an MCP server.

Fields

  • issuer::String: Expected token issuer (iss claim)
  • audience::String: Expected audience (aud claim) - typically your server's URL
  • required_scopes::Vector{String}: Scopes required to access the server
  • jwks_uri::Union{String,Nothing}: URL to fetch JSON Web Key Set for JWT validation
  • introspection_endpoint::Union{String,Nothing}: Token introspection endpoint URL
source
ModelContextProtocol.AuthMiddlewareType
AuthMiddleware(; config::OAuthConfig,
                validator::TokenValidator,
                allowlist::Union{Set{String},Nothing}=nothing,
                case_insensitive_allowlist::Bool=true,
                enabled::Bool=true)

Middleware for authenticating HTTP requests to an MCP server.

Fields

  • config::OAuthConfig: OAuth configuration
  • validator::TokenValidator: Token validation strategy
  • allowlist::Union{Set{String},Nothing}: Optional set of allowed usernames/subjects
  • case_insensitive_allowlist::Bool: When true (default), allowlist username matching is case-insensitive (identity providers vary/normalize case — e.g. Keycloak lowercases GitHub logins); the opaque OAuth subject is always matched exactly. Set false for exact username matching.
  • enabled::Bool: Whether authentication is enabled (for development/testing)
source
ModelContextProtocol.AuthenticatedUserType
AuthenticatedUser(; subject::String, provider::String,
                  username::Union{String,Nothing}=nothing,
                  scopes::Vector{String}=String[],
                  claims::Dict{String,Any}=Dict{String,Any}())

Represent an authenticated user after successful token validation.

Fields

  • subject::String: Unique user identifier (sub claim from token)
  • provider::String: Authentication provider name (e.g., "github", "google")
  • username::Union{String,Nothing}: Human-readable username if available
  • scopes::Vector{String}: Granted OAuth scopes
  • claims::Dict{String,Any}: Raw claims from the token
source
ModelContextProtocol.create_auth_middlewareFunction
create_auth_middleware(config::OAuthConfig;
                      validator::TokenValidator,
                      allowlist::Union{Set{String},Nothing}=nothing,
                      enabled::Bool=true) -> AuthMiddleware

Create an authentication middleware for the HTTP transport.

Arguments

  • config::OAuthConfig: OAuth configuration
  • validator::TokenValidator: Token validation strategy (REQUIRED — no default, so an unsafe validator is never selected implicitly. Note JWTValidator does not verify signatures; prefer IntrospectionValidator or GitHubOAuthValidator for tokens from external issuers.)
  • allowlist::Union{Set{String},Nothing}: Optional allowlist of usernames/subjects
  • enabled::Bool: Whether auth is enabled (default: true)

Example

auth = create_auth_middleware(
    OAuthConfig(
        issuer = "https://github.com",
        audience = "my-mcp-server"
    ),
    validator = IntrospectionValidator(client_id = "id", client_secret = "secret"),
    allowlist = Set(["user1", "user2"])
)
source
ModelContextProtocol.create_simple_authFunction
create_simple_auth(tokens::Dict{String,String};
                  allowlist::Union{Set{String},Nothing}=nothing) -> AuthMiddleware

Create a simple API key-based authentication middleware.

Arguments

  • tokens::Dict{String,String}: Map of API keys to usernames
  • allowlist::Union{Set{String},Nothing}: Optional additional allowlist

Example

auth = create_simple_auth(Dict(
    "sk-abc123" => "user1",
    "sk-def456" => "user2"
))
source
ModelContextProtocol.disable_authFunction
disable_auth() -> AuthMiddleware

Create a disabled auth middleware (for development/testing). All requests will be allowed with an anonymous user.

source
ModelContextProtocol.is_auth_enabledFunction
is_auth_enabled(transport::HttpTransport) -> Bool

Return whether OAuth Resource Server token validation is enabled on this transport.

Arguments

  • transport::HttpTransport: The transport instance

Returns

  • Bool: true if an enabled AuthMiddleware is configured
source

Token Validators

ModelContextProtocol.SimpleTokenValidatorType
SimpleTokenValidator(; tokens::Dict{String,AuthenticatedUser})

Simple token validator using a static mapping of tokens to users. Useful for API keys and development/testing.

Development use

Lookups are plain dictionary comparisons (not constant-time) and tokens are held in memory in plaintext. Intended for development and trusted static API keys, not as a general-purpose production token store.

Fields

  • tokens::Dict{String,AuthenticatedUser}: Map of valid tokens to user info
source
ModelContextProtocol.JWTValidatorType
JWTValidator(; insecure_skip_signature_verification::Bool, clock_skew_seconds::Int=60)

JWT validator that checks claims (iss, aud, exp, nbf, scope) but does not verify the token's cryptographic signature.

No signature verification — explicit opt-in required

This validator decodes and validates JWT claims but does not verify the token's cryptographic signature, so any caller can forge the issuer, audience, and scopes. It therefore refuses to construct unless you pass insecure_skip_signature_verification = true.

For tokens from an authorization server, use JWKSValidator (signature verification via JWKS — the recommended path) or IntrospectionValidator (RFC 7662). Choose JWTValidator only when this server sits behind a gateway that has already verified the signature.

Fields

  • jwks_cache::Dict{String,Any}: Unused (retained for struct-layout compatibility)
  • clock_skew_seconds::Int: Allowed clock skew for exp/nbf validation
source
ModelContextProtocol.JWKSValidatorType
JWKSValidator(jwks_uri::String; allowed_algs=["RS256", "RS384", "RS512"],
              clock_skew_seconds=60, refresh_interval_seconds=300,
              allow_insecure_http=false)
JWKSValidator(keyset::JWTs.JWKSet; ...)

JWT validator with cryptographic signature verification against a JSON Web Key Set (RFC 7517), plus the same claims validation as JWTValidator (iss, aud, exp, nbf, scopes — all fail-closed). This is the recommended validator for JWTs from external authorization servers (Keycloak, Auth0, GitHub Apps, etc.).

Keys are fetched lazily: construction never touches the network, so a server can start while its authorization server is down (requests fail closed until keys load). An unknown kid triggers a JWKS re-fetch (key rotation) at most once per refresh_interval_seconds — rate-limited so attacker-supplied kid values cannot hammer the JWKS endpoint. Fetches use bounded HTTP timeouts and a response size cap (MAX_JWKS_BYTES), and never hold the validator lock during network I/O.

file:// URIs are supported for local key sets. An http:// URL is rejected at construction unless allow_insecure_http=true (a plaintext JWKS lets an on-path attacker swap in their own signing key — use only for localhost/testing). The second constructor accepts a pre-built JWTs.JWKSet (e.g. static keys) directly; with no URL it never refreshes.

Algorithm allowlist

Tokens whose header alg is not in allowed_algs are rejected before any cryptography runs (this also rejects alg=none). The default allows the RSA family only; do not add HMAC algorithms (HS*) for keys published in a public JWKS document.

Fields

  • keyset::JWTs.JWKSet: Key set (url-backed or static) holding keys by kid
  • allowed_algs::Vector{String}: Permitted JWT signature algorithms
  • clock_skew_seconds::Int: Allowed clock skew for exp/nbf validation
  • refresh_interval_seconds::Float64: Minimum seconds between JWKS fetch attempts (>= 0)
source
ModelContextProtocol.IntrospectionValidatorType
IntrospectionValidator(; client_id=nothing, client_secret=nothing)

Token validator using OAuth 2.0 Token Introspection (RFC 7662). Used for opaque tokens that cannot be validated locally.

Fields

  • client_id::Union{String,Nothing}: Client ID for introspection auth
  • client_secret::Union{String,Nothing}: Client secret for introspection auth
source
ModelContextProtocol.GitHubOAuthValidatorType
GitHubOAuthValidator(; cache_ttl_seconds::Int=300)

Token validator for GitHub OAuth access tokens. Validates tokens by calling GitHub's /user API endpoint.

Fields

  • cache_ttl_seconds::Int: How long to cache user info (default: 5 minutes)
  • user_cache::Dict{String,Tuple{AuthenticatedUser,DateTime}}: Cache of validated tokens
  • cache_lock::ReentrantLock: Lock for thread-safe cache access
source
ModelContextProtocol.create_github_authFunction
create_github_auth(; allowed_users::Union{Vector{String},Set{String}}=String[],
                    required_org::Union{String,Nothing}=nothing,
                    cache_ttl_seconds::Int=300) -> AuthMiddleware

Create an authentication middleware configured for GitHub OAuth.

Arguments

  • allowed_users: List of GitHub usernames allowed to access the server
  • required_org: Optionally require membership in a GitHub organization
  • cache_ttl_seconds: How long to cache validated tokens (default: 5 minutes)

Returns

AuthMiddleware configured for GitHub OAuth validation.

Example

# Allow specific users
auth = create_github_auth(
    allowed_users = ["user1", "user2", "user3"]
)

# Require organization membership
auth = create_github_auth(
    required_org = "JuliaSMLM"
)

# Both user allowlist and org requirement
auth = create_github_auth(
    allowed_users = ["user1", "user2"],
    required_org = "LidkeLab"
)
source

Protected Resource Metadata (RFC 9728)

ModelContextProtocol.ProtectedResourceMetadataType
ProtectedResourceMetadata(; resource::String,
                           authorization_servers::Vector{String},
                           scopes_supported::Vector{String}=String[],
                           bearer_methods_supported::Vector{String}=["header"])

MCP Protected Resource Metadata per RFC 9728. Served at .well-known/oauth-protected-resource.

Fields

  • resource::String: The protected resource identifier (your server URL)
  • authorization_servers::Vector{String}: URLs of authorization servers that can issue tokens
  • scopes_supported::Vector{String}: OAuth scopes the resource understands
  • bearer_methods_supported::Vector{String}: How tokens can be sent (header, body, query)
source
ModelContextProtocol.create_protected_resource_metadataFunction
create_protected_resource_metadata(resource_url::String,
                                   authorization_servers::Vector{String};
                                   scopes::Vector{String}=String[]) -> ProtectedResourceMetadata

Create Protected Resource Metadata for the MCP server.

Arguments

  • resource_url::String: The URL of your MCP server (the protected resource)
  • authorization_servers::Vector{String}: URLs of OAuth authorization servers
  • scopes::Vector{String}: OAuth scopes the server understands

Example

metadata = create_protected_resource_metadata(
    "https://mcp.example.com",
    ["https://github.com/login/oauth"],
    scopes = ["read:user", "repo"]
)
source
ModelContextProtocol.create_github_resource_metadataFunction
create_github_resource_metadata(resource_url::String;
                               scopes::Vector{String}=["read:user"]) -> ProtectedResourceMetadata

Create Protected Resource Metadata configured for GitHub OAuth.

Arguments

  • resource_url::String: Your MCP server URL
  • scopes::Vector{String}: GitHub OAuth scopes to request (default: ["read:user"])

Example

metadata = create_github_resource_metadata(
    "https://mcp.lidkelab.org",
    scopes = ["read:user", "read:org"]
)
source

Request Authentication

ModelContextProtocol.authenticate_requestFunction
authenticate_request(middleware::AuthMiddleware, authorization_header::Union{String,Nothing}) -> AuthResult

Authenticate an HTTP request using the auth middleware.

Arguments

  • middleware::AuthMiddleware: The authentication middleware
  • authorization_header::Union{String,Nothing}: The Authorization header value

Returns

AuthResult indicating success with user info, or failure with error details.

source
ModelContextProtocol.validate_tokenFunction
validate_token(validator::TokenValidator, token::AbstractString, config::OAuthConfig) -> AuthResult

Validate an OAuth token using the specified validator.

Arguments

  • validator::TokenValidator: The validation strategy to use
  • token::AbstractString: The token to validate
  • config::OAuthConfig: OAuth configuration with expected issuer, audience, etc.

Returns

  • AuthResult: Success with user info, or failure with error details
source
ModelContextProtocol.extract_bearer_tokenFunction
extract_bearer_token(authorization_header::String) -> Union{String,Nothing}

Extract Bearer token from Authorization header.

Arguments

  • authorization_header::String: The Authorization header value

Returns

The token if present and valid format, nothing otherwise.

source

Utility Functions

ModelContextProtocol.content2dictFunction
content2dict(content::Content) -> Dict{String,Any}

Convert a Content object to its dictionary representation for JSON serialization.

Arguments

  • content::Content: The content object to convert

Returns

  • Dict{String,Any}: Dictionary representation of the content

Examples

text_content = TextContent(text="Hello", type="text")
dict = content2dict(text_content)
# Returns: Dict("type" => "text", "text" => "Hello", "annotations" => Dict())
source

Transport Options

ModelContextProtocol.jl supports multiple transport mechanisms:

STDIO Transport (Default)

server = mcp_server(name = "my-server")
start!(server)  # Uses StdioTransport by default

HTTP Transport

server = mcp_server(name = "my-http-server")
transport = HttpTransport(; port = 3000)
connect(transport)   # binds the port and starts the listener
start!(server; transport = transport)

# With custom configuration
transport = HttpTransport(;
    host = "127.0.0.1",  # Important for Windows
    port = 8080,         # Default port
    endpoint = "/"       # Default endpoint
)
connect(transport)
start!(server; transport = transport)

Note: HTTP transport currently supports HTTP only, not HTTPS. For production use:

  • Use mcp-remote with --allow-http flag for secure connections
  • Or deploy behind a reverse proxy (nginx, Apache) for TLS termination

Internal API

The following internal types and functions are documented for developers working on the package itself.

Protocol Types

ModelContextProtocol.CallToolParamsType
CallToolParams(; name::String, arguments::Union{Dict{String,Any},Nothing}=nothing) <: RequestParams

Parameters for invoking a specific tool on an MCP server.

Fields

  • name::String: Name of the tool to call
  • arguments::Union{Dict{String,Any},Nothing}: Optional arguments to pass to the tool
  • task::Union{Dict{String,Any},Nothing}: When present, the caller requests task-augmented execution (MCP Tasks, experimental); may carry a requested "ttl" in milliseconds
source
ModelContextProtocol.ClientCapabilitiesType
ClientCapabilities(; experimental::Union{Dict{String,Dict{String,Any}},Nothing}=nothing,
                roots::Union{Dict{String,Bool},Nothing}=nothing,
                sampling::Union{Dict{String,Any},Nothing}=nothing)

Capabilities reported by an MCP client during initialization.

Fields

  • experimental::Union{Dict{String,Dict{String,Any}},Nothing}: Experimental features supported
  • roots::Union{Dict{String,Bool},Nothing}: Root directories client has access to
  • sampling::Union{Dict{String,Any},Nothing}: Sampling capabilities for model generation
source
ModelContextProtocol.CompleteParamsType
CompleteParams(; ref::CompletionReference, argument::CompletionArgument,
               context::Union{Dict{String,Any},Nothing}=nothing) <: RequestParams

Parameters for a completion/complete request.

Fields

  • ref::CompletionReference: The prompt or resource template being completed
  • argument::CompletionArgument: The argument name and partial value
  • context::Union{Dict{String,Any},Nothing}: Optional context; its arguments entry carries already-resolved argument values
source
ModelContextProtocol.CompletionArgumentType
CompletionArgument(; name::String, value::String)

Name the argument being completed and the partial value typed so far.

Fields

  • name::String: The argument (or template variable) name
  • value::String: The partial value to complete
source
ModelContextProtocol.CompletionReferenceType
CompletionReference(; type::String, name::Union{String,Nothing}=nothing,
                    uri::Union{String,Nothing}=nothing)

Identify what a completion/complete request targets: a prompt (type of ref/prompt with name) or a resource template (type of ref/resource with uri naming the URI template).

Fields

  • type::String: "ref/prompt" or "ref/resource"
  • name::Union{String,Nothing}: The prompt name (for ref/prompt)
  • uri::Union{String,Nothing}: The URI template (for ref/resource)
source
ModelContextProtocol.ErrorInfoType
ErrorInfo(; code::Int, message::String, data::Union{Dict{String,Any},Nothing}=nothing)

Error information structure for JSON-RPC error responses.

Fields

  • code::Int: Numeric error code (predefined in ErrorCodes module)
  • message::String: Human-readable error description
  • data::Union{Dict{String,Any},Nothing}: Optional additional error details
source
ModelContextProtocol.GetPromptParamsType
GetPromptParams(; name::String, arguments::Union{Dict{String,String},Nothing}=nothing) <: RequestParams

Parameters for requesting a specific prompt from an MCP server.

Fields

  • name::String: Name of the prompt to retrieve
  • arguments::Union{Dict{String,String},Nothing}: Optional arguments to apply to the prompt template
source
ModelContextProtocol.GetPromptResultType
GetPromptResult(; description::String, messages::Vector{PromptMessage}) <: ResponseResult

Result returned from a get prompt request.

Fields

  • description::String: Description of the prompt
  • messages::Vector{PromptMessage}: The prompt messages with template variables replaced
source
ModelContextProtocol.ImplementationType
Implementation(; name::String="default-client", version::String="1.0.0",
               title::Union{String,Nothing}=nothing,
               description::Union{String,Nothing}=nothing)

Information about a client or server implementation of the MCP protocol.

Fields

  • name::String: Name of the implementation
  • version::String: Version string of the implementation
  • title::Union{String,Nothing}: Optional human-readable display name
  • description::Union{String,Nothing}: Optional human-readable description (MCP 2025-11-25)
source
ModelContextProtocol.InitializeParamsType
InitializeParams(; capabilities::ClientCapabilities=ClientCapabilities(),
               clientInfo::Implementation=Implementation(),
               protocolVersion::Union{String,Nothing}=nothing) <: RequestParams

Parameters for MCP protocol initialization requests.

Fields

  • capabilities::ClientCapabilities: Client capabilities being reported
  • clientInfo::Implementation: Information about the client implementation
  • protocolVersion::Union{String,Nothing}: Version of the MCP protocol requested by the client. The server negotiates against SUPPORTED_PROTOCOL_VERSIONS (latest: LATEST_PROTOCOL_VERSION); see negotiate_version.
source
ModelContextProtocol.InitializeResultType
InitializeResult(; serverInfo::Dict{String,Any}, capabilities::Dict{String,Any},
               protocolVersion::String, instructions::String="") <: ResponseResult

Result returned in response to MCP protocol initialization.

Fields

  • serverInfo::Dict{String,Any}: Information about the server implementation
  • capabilities::Dict{String,Any}: Server capabilities being reported
  • protocolVersion::String: Version of the MCP protocol being used
  • instructions::String: Optional usage instructions for clients
source
ModelContextProtocol.JSONRPCErrorType
JSONRPCError(; id::Union{RequestId,Nothing}, error::ErrorInfo) <: Response

JSON-RPC error response message returned when requests fail.

Fields

  • id::Union{RequestId,Nothing}: Identifier matching the request this is responding to, or null
  • error::ErrorInfo: Information about the error that occurred
source
ModelContextProtocol.JSONRPCNotificationType
JSONRPCNotification(; method::String, 
                   params::Union{RequestParams,Dict{String,Any}}) <: Notification

JSON-RPC notification message that does not expect a response.

Fields

  • method::String: Name of the notification method
  • params::Union{RequestParams,Dict{String,Any}}: Parameters for the notification
source
ModelContextProtocol.JSONRPCRequestType
JSONRPCRequest(; id::RequestId, method::String, 
             params::Union{RequestParams, Nothing}, 
             meta::RequestMeta=RequestMeta()) <: Request

JSON-RPC request message used to invoke methods on the server.

Fields

  • id::RequestId: Unique identifier for the request
  • method::String: Name of the method to invoke
  • params::Union{RequestParams, Nothing}: Parameters for the method
  • meta::RequestMeta: Additional metadata for the request
source
ModelContextProtocol.JSONRPCResponseType
JSONRPCResponse(; id::RequestId, result::Union{ResponseResult,AbstractDict{String,Any}}) <: Response

JSON-RPC response message returned for successful requests.

Fields

  • id::RequestId: Identifier matching the request this is responding to
  • result::Union{ResponseResult,AbstractDict{String,Any}}: Results of the method execution
source
ModelContextProtocol.ListPromptsParamsType
ListPromptsParams(; cursor::Union{String,Nothing}=nothing) <: RequestParams

Parameters for requesting a list of available prompts from an MCP server.

Fields

  • cursor::Union{String,Nothing}: Optional pagination cursor for long prompt lists
source
ModelContextProtocol.ListPromptsResultType
ListPromptsResult(; prompts::Vector{Dict{String,Any}}, 
                nextCursor::Union{String,Nothing}=nothing) <: ResponseResult

Result returned from a list prompts request.

Fields

  • prompts::Vector{Dict{String,Any}}: List of available prompts with their metadata
  • nextCursor::Union{String,Nothing}: Optional pagination cursor for fetching more prompts
source
ModelContextProtocol.ListResourceTemplatesParamsType
ListResourceTemplatesParams(; cursor::Union{String,Nothing}=nothing) <: RequestParams

Parameters for a resources/templates/list request.

Fields

  • cursor::Union{String,Nothing}: Optional pagination cursor for long template lists
source
ModelContextProtocol.ListResourcesParamsType
ListResourcesParams(; cursor::Union{String,Nothing}=nothing) <: RequestParams

Parameters for requesting a list of available resources from an MCP server.

Fields

  • cursor::Union{String,Nothing}: Optional pagination cursor for long resource lists
source
ModelContextProtocol.ListResourcesResultType
ListResourcesResult(; resources::Vector{Dict{String,Any}}, 
                  nextCursor::Union{String,Nothing}=nothing) <: ResponseResult

Result returned from a list resources request.

Fields

  • resources::Vector{Dict{String,Any}}: List of available resources with their metadata
  • nextCursor::Union{String,Nothing}: Optional pagination cursor for fetching more resources
source
ModelContextProtocol.ListTasksParamsType
ListTasksParams(; cursor::Union{String,Nothing}=nothing) <: RequestParams

Parameters for a paginated tasks/list request.

Fields

  • cursor::Union{String,Nothing}: Opaque pagination cursor from a previous response
source
ModelContextProtocol.ListToolsParamsType
ListToolsParams(; cursor::Union{String,Nothing}=nothing) <: RequestParams

Parameters for requesting a list of available tools from an MCP server.

Fields

  • cursor::Union{String,Nothing}: Optional pagination cursor for long tool lists
source
ModelContextProtocol.ListToolsResultType
ListToolsResult(; tools::Vector{Dict{String,Any}}, 
              nextCursor::Union{String,Nothing}=nothing) <: ResponseResult

Result returned from a list tools request.

Fields

  • tools::Vector{Dict{String,Any}}: List of available tools with their metadata
  • nextCursor::Union{String,Nothing}: Optional pagination cursor for fetching more tools
source
ModelContextProtocol.ProgressParamsType
ProgressParams(; progress_token::ProgressToken, progress::Float64,
             total::Union{Float64,Nothing}=nothing) <: RequestParams

Parameters for progress notifications during long-running operations.

Fields

  • progress_token::ProgressToken: Token identifying the operation being reported on
  • progress::Float64: Current progress value
  • total::Union{Float64,Nothing}: Optional total expected value
source
ModelContextProtocol.ReadResourceResultType
ReadResourceResult(; contents::Vector{Dict{String,Any}}) <: ResponseResult

Result returned from a read resource request.

Fields

  • contents::Vector{Dict{String,Any}}: The contents of the requested resource
source
ModelContextProtocol.RequestMetaType
RequestMeta(; progress_token::Union{ProgressToken,Nothing}=nothing,
            protocol_version::Union{String,Nothing}=nothing,
            client_capabilities::Union{Dict{String,Any},Nothing}=nothing,
            client_info::Union{Dict{String,Any},Nothing}=nothing)

Metadata for MCP protocol requests: progress tracking, plus the modern-era (2026-07-28+) per-request protocol fields carried in _meta under io.modelcontextprotocol/* keys. A non-nothing protocol_version marks the request as modern-era (stateless, no initialize handshake) and routes it through handle_modern_request.

Fields

  • progress_token::Union{ProgressToken,Nothing}: Optional token for tracking request progress
  • protocol_version::Union{String,Nothing}: io.modelcontextprotocol/protocolVersion (required on every modern-era request; absent on legacy requests). Only string values are honored — a non-string value is treated as absent.
  • client_capabilities::Any: io.modelcontextprotocol/clientCapabilities (required on every modern-era request), kept as the raw parsed JSON object — no re-encoding copy is made
  • client_info::Any: io.modelcontextprotocol/clientInfo (optional), kept as the raw parsed JSON object
  • log_level::Union{String,Nothing}: io.modelcontextprotocol/logLevel (optional) — the client's per-request opt-in to notifications/message delivery. Only string values are stored; validation against the recognized levels happens in handle_modern_request
  • has_log_level::Bool: Whether the logLevel key was present at all. Presence is tracked separately from the typed value so a present-but-invalid level is REJECTED (-32602 per the spec), never silently treated as absent
source
ModelContextProtocol.SetLevelParamsType
SetLevelParams(; level::String) <: RequestParams

Parameters for logging/setLevel requests.

Fields

  • level::String: Minimum log level the client wants to receive (one of the MCP/RFC-5424 levels: "debug", "info", "notice", "warning", "error", "critical", "alert", "emergency")
source
ModelContextProtocol.SubscribeParamsType
SubscribeParams(; uri::String) <: RequestParams

Parameters for resources/subscribe requests.

Fields

  • uri::String: URI of the resource the client wants update notifications for
source
ModelContextProtocol.SubscriptionsListenParamsType
SubscriptionsListenParams(; notifications::Union{Nothing,Dict{String,Any}}=nothing) <: RequestParams

Parameters for subscriptions/listen requests (modern era).

Fields

  • notifications::Union{Nothing,Dict{String,Any}}: The notification-type filter — toolsListChanged/promptsListChanged/resourcesListChanged booleans and a resourceSubscriptions array of resource URIs. Required: an absent or malformed filter is rejected with -32602 by the handler (see parse_subscription_filter); nothing here only represents the not-yet-validated wire state.
source
ModelContextProtocol.TaskResultParamsType
TaskResultParams(; taskId::String) <: RequestParams

Parameters for a tasks/result payload retrieval. The response blocks until the task reaches a terminal status and then matches the original request's result type.

Fields

  • taskId::String: The task identifier to retrieve results for
source
ModelContextProtocol.UnsubscribeParamsType
UnsubscribeParams(; uri::String) <: RequestParams

Parameters for resources/unsubscribe requests.

Fields

  • uri::String: URI of the resource to stop receiving update notifications for
source
ModelContextProtocol.UpdateTaskParamsType
UpdateTaskParams(; taskId::String, inputResponses::Dict{String,Any}) <: RequestParams

Parameters for a tasks/update request (tasks extension, SEP-2663): the client's responses to outstanding inputRequests surfaced by tasks/get on an input_required task. Both fields are required — a request missing either fails typed parsing and is rejected with -32602.

Fields

  • taskId::String: The task identifier to update
  • inputResponses::Dict{String,Any}: Responses keyed to match the server-issued inputRequests keys
source
ModelContextProtocol.get_params_typeMethod
get_params_type(method::String) -> Union{Type,Nothing}

Get the appropriate parameter type for a given JSON-RPC method name.

Arguments

  • method::String: The JSON-RPC method name

Returns

  • Union{Type,Nothing}: The Julia type to use for parsing parameters, or nothing if no specific type is defined
source
ModelContextProtocol.get_result_typeMethod
get_result_type(id::RequestId) -> Union{Type{<:ResponseResult},Nothing}

Get the expected result type for a response based on the request ID.

Arguments

  • id::RequestId: The request ID to look up

Returns

  • Union{Type{<:ResponseResult},Nothing}: The expected response result type, or nothing if not known

Note: This is a placeholder that needs to be implemented with request tracking.

source
ModelContextProtocol.parse_error_responseMethod
parse_error_response(raw::JSON3.Object) -> Response

Parse a JSON-RPC error response object into a typed Response struct.

Arguments

  • raw::JSON3.Object: The parsed JSON object representing an error response

Returns

  • Response: A JSONRPCError with properly typed error information
source
ModelContextProtocol.parse_messageMethod
parse_message(json::String) -> MCPMessage

Parse a JSON-RPC message string into the appropriate typed message object.

Arguments

  • json::String: The raw JSON-RPC message string

Returns

  • MCPMessage: A typed MCPMessage subtype (JSONRPCRequest, JSONRPCResponse, JSONRPCNotification, or JSONRPCError)
source
ModelContextProtocol.parse_notificationMethod
parse_notification(raw::JSON3.Object) -> Notification

Parse a JSON-RPC notification object into a typed Notification struct.

Arguments

  • raw::JSON3.Object: The parsed JSON object representing a notification

Returns

  • Notification: A JSONRPCNotification with properly typed parameters if possible
source
ModelContextProtocol.parse_requestMethod
parse_request(raw::JSON3.Object) -> Request

Parse a JSON-RPC request object into a typed Request struct.

Arguments

  • raw::JSON3.Object: The parsed JSON object representing a request

Returns

  • Request: A JSONRPCRequest with properly typed parameters based on the method
source
ModelContextProtocol.parse_success_responseMethod
parse_success_response(raw::JSON3.Object) -> Response

Parse a successful JSON-RPC response object into a typed Response struct.

Arguments

  • raw::JSON3.Object: The parsed JSON object representing a successful response

Returns

  • Response: A JSONRPCResponse with properly typed result if possible, or JSONRPCError if parsing fails
source
ModelContextProtocol.serialize_messageMethod
serialize_message(msg::MCPMessage) -> String

Serialize an MCP message object into a JSON-RPC compliant string.

Arguments

  • msg::MCPMessage: The message object to serialize (Request, Response, Notification, or Error)

Returns

  • String: A JSON string representation of the message following the JSON-RPC 2.0 specification
source
ModelContextProtocol.HandlerResultType
HandlerResult(; response::Union{Response,Nothing}=nothing,
            error::Union{ErrorInfo,Nothing}=nothing)

Represent the result of handling a request.

Fields

  • response::Union{Response,Nothing}: The response to send (if successful)
  • error::Union{ErrorInfo,Nothing}: Error information (if request failed)
  • deferred::Bool: When true, neither field is set and the response will be delivered out-of-loop via deliver_response (used by the blocking tasks/result)

A HandlerResult must contain either a response, an error, or be deferred.

source
ModelContextProtocol.RequestContextType
RequestContext(; server::Server, state::ServerState=ServerState(),
               request_id::Union{RequestId,Nothing}=nothing,
               progress_token::Union{ProgressToken,Nothing}=nothing)

Store the current request context for MCP protocol handlers.

Fields

  • server::Server: The MCP server instance handling the request
  • state::ServerState: The persistent server state, carrying the negotiated protocol version for feature gating (see supports)
  • request_id::Union{RequestId,Nothing}: The ID of the current request (if any)
  • progress_token::Union{ProgressToken,Nothing}: Optional token for progress reporting
source
ModelContextProtocol._json_integer_valueMethod
_json_integer_value(s::AbstractString) -> Union{BigInt,Nothing}

Evaluate a JSON-number token EXACTLY, returning its value when it denotes an integer: "42", "42.0", "4.2e1", and "-0.0" all evaluate (to 42, 42, 42, and 0), while non-numbers, non-integral values, and tokens with unreasonably large exponents (a "1e999999" mirror must not allocate a gigadigit BigInt) return nothing. Never goes through Float64, so distinct integers beyond 2^53 stay distinct.

source
ModelContextProtocol.completion_valuesMethod
completion_values(sources, arg_name::String, value::String,
                  context_args::Union{Nothing,Dict{String,String}}) -> Vector{String}

Resolve the suggestion list for one completion request from a component's completions sources: a Vector source is served filtered by prefix against the partial value; a Function source is called as f(value) — or f(value, context_args) when applicable, where context_args is the request context's validated arguments map (already-resolved argument values) or nothing. Missing sources (or a component without any) resolve to no suggestions. Source misconfiguration — a non-Vector/non-Function source, a non-string element, or a function returning a lone string or non-strings — throws ArgumentError (surfaced by the handler as an internal error naming the cause) rather than silently coercing.

Arguments

  • sources: The component's completions field (a Dict or nothing)
  • arg_name::String: The argument (or template variable) being completed
  • value::String: The partial value typed so far
  • context_args: The request context's validated arguments, or nothing

Returns

  • Vector{String}: The full (uncapped) suggestion list
source
ModelContextProtocol.convert_to_content_typeMethod
convert_to_content_type(result::Any) -> Any

Apply the documented convenience conversions for tool handler return values: a Dict becomes JSON wrapped in TextContent, a String becomes TextContent, and a Tuple{Vector{UInt8},String} becomes ImageContent.

These conversions are independent of the tool's declared return_type (the caller validates the converted result against return_type afterwards), so the documented behavior holds for the default return_type = Vector{Content} too.

Arguments

  • result::Any: The raw value returned by a tool handler

Returns

  • Any: A Content object for the convenience cases above; otherwise result unchanged
source
ModelContextProtocol.execute_tool_callMethod
execute_tool_call(tool::MCPTool, args::AbstractDict, ctx::RequestContext)
    -> Union{CallToolResult,ErrorInfo}

Run a tool handler and normalize its return value to a CallToolResult (applying the documented convenience conversions and return_type validation), an InputRequired (passed through verbatim for the MRTR layer to convert), or an ErrorInfo when execution throws. Shared by the synchronous tools/call path and background task-augmented executions.

source
ModelContextProtocol.handle_call_toolMethod
handle_call_tool(ctx::RequestContext, params::CallToolParams) -> HandlerResult

Handle requests to call a specific tool with the provided parameters.

Arguments

  • ctx::RequestContext: The current request context
  • params::CallToolParams: Parameters containing the tool name and arguments

Returns

  • HandlerResult: Contains either the tool execution results or an error if the tool is not found or execution fails
source
ModelContextProtocol.handle_cancel_taskMethod
handle_cancel_task(ctx::RequestContext, params::CancelTaskParams) -> HandlerResult

Handle a tasks/cancel: transition a non-terminal task to "cancelled" (waking any blocked tasks/result requests) and return the task state. Cancelling a task already in a terminal status is rejected with -32602 per spec.

source
ModelContextProtocol.handle_completeMethod
handle_complete(ctx::RequestContext, params::CompleteParams) -> HandlerResult

Handle a completion/complete request: suggest values for a prompt argument (ref/prompt, resolved by prompt name) or a resource-template variable (ref/resource, resolved by URI template). Suggestions come from the matched component's completions sources (see completion_values); the response caps values at the spec's 100, reporting the full count as total and hasMore accordingly. An unknown ref type, prompt name, or template URI is -32602, as is a context.arguments that is not an object of strings (the schema's shape).

source
ModelContextProtocol.handle_get_taskMethod
handle_get_task(ctx::RequestContext, params::GetTaskParams) -> HandlerResult

Handle a tasks/get poll: return the task's current state, flattened into the result per the spec (GetTaskResult = Result & Task).

source
ModelContextProtocol.handle_initializeMethod
handle_initialize(ctx::RequestContext, params::InitializeParams) -> HandlerResult

Handle MCP protocol initialization requests by setting up the server and returning capabilities.

Arguments

  • ctx::RequestContext: The current request context
  • params::InitializeParams: The initialization parameters from the client

Returns

  • HandlerResult: Contains the server's capabilities and configuration
source
ModelContextProtocol.handle_list_promptsMethod
handle_list_prompts(ctx::RequestContext, params::ListPromptsParams) -> HandlerResult

Handle requests to list available prompts on the MCP server.

Arguments

  • ctx::RequestContext: The current request context
  • params::ListPromptsParams: Parameters for the list request (including optional cursor)

Returns

  • HandlerResult: Contains information about all available prompts
source
ModelContextProtocol.handle_list_resource_templatesMethod
handle_list_resource_templates(ctx::RequestContext, params::ListResourceTemplatesParams)
    -> HandlerResult

Handle a resources/templates/list request: advertise the server's resource templates in the spec wire shape (resourceTemplates entries with uriTemplate, name, and optional description/mimeType/title/icons/_meta).

source
ModelContextProtocol.handle_list_resourcesMethod
handle_list_resources(ctx::RequestContext, params::ListResourcesParams) -> HandlerResult

Handle requests to list all available resources on the MCP server.

Arguments

  • ctx::RequestContext: The current request context
  • params::ListResourcesParams: Parameters for the list request (including optional cursor)

Returns

  • HandlerResult: Contains information about all registered resources
source
ModelContextProtocol.handle_list_tasksMethod
handle_list_tasks(ctx::RequestContext, params::ListTasksParams) -> HandlerResult

Handle a paginated tasks/list, restricted to the requestor's authorization context. Not offered (-32601) when the server cannot identify requestors (HTTP without auth).

source
ModelContextProtocol.handle_list_toolsMethod
handle_list_tools(ctx::RequestContext, params::ListToolsParams) -> HandlerResult

Handle requests to list all available tools on the MCP server.

Arguments

  • ctx::RequestContext: The current request context
  • params::ListToolsParams: Parameters for the list request (including optional cursor)

Returns

  • HandlerResult: Contains information about all registered tools
source
ModelContextProtocol.handle_notificationMethod
handle_notification(ctx::RequestContext, notification::JSONRPCNotification) -> Nothing

Process notification messages from clients that don't require responses.

Arguments

  • ctx::RequestContext: The current request context
  • notification::JSONRPCNotification: The notification to process

Returns

  • Nothing: Notifications don't generate responses
source
ModelContextProtocol.handle_pingMethod
handle_ping(ctx::RequestContext, params::Nothing) -> HandlerResult

Handle MCP protocol ping requests.

Arguments

  • ctx::RequestContext: The current request context
  • params::Nothing: The ping parameters does not contain any data

Returns

  • HandlerResult: Ping returns an empty response payload
source
ModelContextProtocol.handle_read_resourceMethod
handle_read_resource(ctx::RequestContext, params::ReadResourceParams) -> HandlerResult

Handle requests to read content from a specific resource by URI.

Arguments

  • ctx::RequestContext: The current request context
  • params::ReadResourceParams: Parameters containing the URI of the resource to read

Returns

  • HandlerResult: Contains either the resource contents or an error if the resource is not found or cannot be read
source
ModelContextProtocol.handle_requestMethod
handle_request(server::Server, state::ServerState, request::Request) -> Response

Process an MCP protocol request and route it to the appropriate handler based on the request method.

Arguments

  • server::Server: The MCP server instance handling the request
  • state::ServerState: The persistent server state, threaded into the request context (carries the negotiated protocol version)
  • request::Request: The parsed JSON-RPC request to process

Behavior

This function creates a request context, then dispatches the request to the appropriate handler based on the request method. Supported methods include:

  • initialize: Server initialization
  • resources/list: List available resources
  • resources/read: Read a specific resource
  • tools/list: List available tools
  • tools/call: Invoke a specific tool
  • prompts/list: List available prompts
  • prompts/get: Get a specific prompt

If an unknown method is received, a METHODNOTFOUND error is returned. Any exceptions thrown during processing are caught and converted to INTERNAL_ERROR responses.

Returns

  • Response: Either a successful response or an error response depending on the handler result
source
ModelContextProtocol.handle_set_levelMethod
handle_set_level(ctx::RequestContext, params::SetLevelParams) -> HandlerResult

Handle logging/setLevel requests by adjusting the installed MCPLogger's minimum level.

Accepts the MCP/RFC-5424 levels (MCP_LOG_LEVELS) and maps them to Julia LogLevels. Setting "debug" also enables the per-request lifecycle log lines emitted by handle_request. When the global logger is not an MCPLogger the request still succeeds (the preference simply has nothing to apply to).

Arguments

  • ctx::RequestContext: The current request context
  • params::SetLevelParams: The requested minimum level

Returns

  • HandlerResult: Empty result on success; INVALID_PARAMS error for unknown levels
source
ModelContextProtocol.handle_subscribe_resourceMethod
handle_subscribe_resource(ctx::RequestContext, params::SubscribeParams) -> HandlerResult

Handle resources/subscribe requests by recording the URI in the session's wire-subscription set. Returns an empty result per spec. Idempotent: repeat subscriptions to the same URI are accepted.

Arguments

  • ctx::RequestContext: The current request context
  • params::SubscribeParams: Parameters containing the resource URI

Returns

  • HandlerResult: An empty result acknowledging the subscription
source
ModelContextProtocol.handle_task_resultMethod
handle_task_result(ctx::RequestContext, params::TaskResultParams) -> HandlerResult

Handle a tasks/result retrieval. For a terminal task, respond immediately with the underlying call's result or error. For a non-terminal task the spec requires blocking until terminal — the response route is detached from the (serial) server loop and a waiter task delivers the response when the task finishes, so the loop stays free to process tasks/get polls and the tasks/cancel that may be what unblocks this very request.

source
ModelContextProtocol.handle_unsubscribe_resourceMethod
handle_unsubscribe_resource(ctx::RequestContext, params::UnsubscribeParams) -> HandlerResult

Handle resources/unsubscribe requests by removing the URI from the session's wire-subscription set. Returns an empty result per spec. Idempotent: unsubscribing a URI that was never subscribed is accepted.

Arguments

  • ctx::RequestContext: The current request context
  • params::UnsubscribeParams: Parameters containing the resource URI

Returns

  • HandlerResult: An empty result acknowledging the unsubscription
source
ModelContextProtocol.match_uri_templateMethod
match_uri_template(template::String, uri::String) -> Union{Nothing,Dict{String,String}}

Match uri against an RFC 6570 level-1 URI template. Each {var} placeholder matches one path segment (one or more characters excluding /). Returns the extracted variables on a full match, nothing otherwise.

Deliberate subset of RFC 6570: variable names are [A-Za-z0-9_]+ (no dotted or pct-encoded names); adjacent placeholders with no literal between them ({a}{b}) are ambiguous and never match; a repeated variable name must capture the same value in every position.

source
ModelContextProtocol.normalize_read_contentsMethod
normalize_read_contents(data, fallback_uri::String, fallback_mime::String)
    -> Vector{LittleDict{String,Any}}

Normalize a resource provider's return value into spec resources/read contents entries: TextResourceContents/BlobResourceContents (or a vector of them) serialize directly — the only path that can produce binary blob contents; a String becomes the text verbatim; anything else (including custom ResourceContents subtypes) is JSON-encoded into a text entry carrying fallback_uri/fallback_mime.

source
ModelContextProtocol.notify_task_statusMethod
notify_task_status(server::Server, record::TaskRecord) -> Nothing

Send an optional notifications/tasks/status with the task's full wire state. Best-effort: failures are logged at debug level and never propagate (requestors must not rely on these notifications per spec).

source
ModelContextProtocol.param_header_violationMethod
param_header_violation(annotated::Vector{Tuple{Vector{String},String}},
                       arguments, headers::Dict{String,Any})
    -> Union{String,Nothing}

Validate a modern-era HTTP tools/call's Mcp-Param-* headers against its body (SEP-2243 custom-header mirroring), driven by the tool's MIRROR TABLE — the (property path, suffix) pairs validate_tool_headers derived from the NORMALIZED schema at registration, so enforcement matches advertisement exactly. For every annotated path PRESENT in the request's arguments with a non-null value, the mirrored header must exist, must not be duplicated or unsafe, must decode (a =?base64?...?= sentinel is validated STRICTLY; anything else is a literal), and must match the body value — strings compare exactly, booleans through true/false, integers exactly through the full JSON number grammar, and non-integral numbers numerically.

Skipped per spec: absent paths (nothing to mirror), explicit JSON null values (clients omit the header for null, servers must not expect it), headers whose path is not in the body, and Mcp-Param-* headers matching no annotation (forward compatibility). Returns the violation description, or nothing.

source
ModelContextProtocol.request_protocol_versionMethod
request_protocol_version(ctx::RequestContext) -> Union{String,Nothing}

The protocol version in effect for THIS request: the per-request version carried in a modern-era request's _meta when present, otherwise the session version negotiated by initialize (legacy era). nothing before any negotiation.

source
ModelContextProtocol.serialize_resource_contentsMethod
serialize_resource_contents(resource::ResourceContents) -> LittleDict{String,Any}

Serialize resource contents to the spec wire shape: {uri, text, mimeType} for TextResourceContents, {uri, blob, mimeType} (base64) for BlobResourceContents.

Arguments

  • resource::ResourceContents: The resource contents to serialize

Returns

  • LittleDict{String,Any}: The serialized resource contents entry
source
ModelContextProtocol.spawn_task_execution!Method
spawn_task_execution!(ctx::RequestContext, tool::MCPTool, args::AbstractDict,
                      record::TaskRecord) -> Nothing

Run a tool call in a background Julia task, recording the outcome into record and emitting a notifications/tasks/status on the terminal transition. The execution context carries the original request's progress token (valid for the task lifetime per spec) and the task record (for task_cancelled(ctx)). If the task was cancelled while running, the outcome is discarded.

source
ModelContextProtocol.task_principalMethod
task_principal(ctx::RequestContext) -> Union{String,Nothing}

The authorization principal tasks are bound to: the authenticated subject when HTTP auth is enabled, otherwise nothing (single-user transports like stdio).

source
ModelContextProtocol.task_terminal_responseMethod
task_terminal_response(request_id, record::TaskRecord) -> Response

Build the tasks/result response for a terminal task: exactly what the underlying request would have returned — its CallToolResult (with the related-task _meta added) or its JSON-RPC error. A task cancelled before completion has no underlying result, so it answers with an error. Caller must hold the store lock.

source
ModelContextProtocol.tasks_list_offeredMethod
tasks_list_offered(server::Server) -> Bool

Whether tasks/list is offered: requires a TaskCapability with list=true, and is withheld on an HTTP transport without authentication (the server cannot identify requestors there, so listing would expose task metadata across clients).

source
ModelContextProtocol.tasks_supportedMethod
tasks_supported(ctx::RequestContext) -> Bool

Whether the tasks capability is in effect for THIS session: the server is configured with a TaskCapability AND the client negotiated a protocol version with task support (2025-11-25+). When false, task metadata on requests is ignored (per spec) and the tasks/* methods do not exist.

source
ModelContextProtocol.validate_tool_headersMethod
validate_tool_headers(tool::MCPTool) -> Vector{Tuple{Vector{String},String}}

Reject invalid SEP-2243 x-mcp-header annotations at registration and return the tool's MIRROR TABLE — the (property path, header suffix) pairs runtime enforcement uses. Rules: every annotation value must be a string, every suffix a nonempty HTTP token (it becomes part of the Mcp-Param-* header NAME), suffixes case-insensitively unique within the tool (header names are case-insensitive, so "Route" and "route" would collapse onto one mirrored header), the annotated property must declare an annotatable type (string, integer, or boolean — the spec excludes number, objects, and arrays), and annotations are only valid on statically reachable properties (never under array items, composition branches, or definitions). Advertising an invalid annotation would force conforming clients to discard the tool — better to refuse it server-side with a clear error. Throws ArgumentError on violation.

The table is derived from the NORMALIZED schema — the same JSON tree tools/list advertises — so validation, advertisement, and enforcement can never diverge (a NamedTuple-shaped raw schema serializes to ordinary JSON objects and is honored exactly as advertised).

source
ModelContextProtocol.with_related_task_metaMethod
with_related_task_meta(result::CallToolResult, task_id::String) -> CallToolResult

Return a copy of result whose _meta carries the spec-required io.modelcontextprotocol/related-task association for tasks/result responses.

source
ModelContextProtocol.MODERN_PROTOCOL_VERSIONSConstant

Modern-era (stateless, per-request _meta) MCP protocol versions supported by this implementation, newest first. A request carrying io.modelcontextprotocol/protocolVersion in _meta is served statelessly under one of these versions; initialize selects legacy semantics from SUPPORTED_PROTOCOL_VERSIONS. Both eras are served concurrently (dual-era server, per the 2026-07-28 spec's backward-compatibility model).

source
ModelContextProtocol.MODERN_METHODSConstant

Methods served in the modern era, each gated on the capability that provides it (nothing = always available). Methods REMOVED from the modern era — ping, logging/setLevel, resources/subscribe/unsubscribe (replaced by subscriptions/listen), and the legacy core tasks methods tasks/result and tasks/list — return METHODNOTFOUND on modern requests even though the legacy era serves them. tasks/get, tasks/update, and tasks/cancel belong to the io.modelcontextprotocol/tasks EXTENSION (SEP-2663): always dispatchable, but gated in-handler on the request's declared extension capability (-32021 for non-declaring clients, per the extension's error rules — not -32601). A method whose capability the server does not declare is equally METHODNOTFOUND: the advertised capability set and the callable surface must agree.

source
ModelContextProtocol.dispatch_modernMethod
dispatch_modern(ctx::RequestContext, request::Request) -> HandlerResult

Route a validated modern-era request to its handler. Shared feature handlers (tools, resources, prompts) are reused from the legacy era; server/discover is modern-only. Requests whose typed params failed to parse get -32602 rather than an internal error.

Arguments

  • ctx::RequestContext: The request context (carries the per-request protocol version)
  • request::Request: The parsed request

Returns

  • HandlerResult: The handler's result
source
ModelContextProtocol.handle_discoverMethod
handle_discover(ctx::RequestContext) -> HandlerResult

Handle server/discover (a server MUST in the modern era): advertise the protocol versions this server supports across both eras, its modern capability surface, and optional instructions, with the CacheableResult fields (ttlMs, cacheScope) the spec requires on discovery results. resultType and serverInfo are attached by the modern envelope.

Capabilities carry only what the modern era actually serves: the features present, their listChanged/subscribe flags (delivered via subscriptions/listen), logging when declared (per-request logLevel opt-in — a MUST for servers that emit notifications/message), and no legacy-only tasks — and never the legacy builder's embedded resource listings, which would leak resource metadata into shared caches and do not match the modern ServerCapabilities shape.

Arguments

  • ctx::RequestContext: The current request context

Returns

  • HandlerResult: The discovery result
source
ModelContextProtocol.handle_modern_requestMethod
handle_modern_request(server::Server, state::ServerState, request::Request;
                      authenticated_user=nothing) -> Union{Response,Nothing}

Serve a modern-era (2026-07-28+) request statelessly: validate the per-request _meta protocol fields, dispatch to the shared feature handlers, and apply the modern result envelope plus the CacheableResult fields where required. The handler context gets a FRESH ServerState — modern requests are self-contained, and a ctx-aware tool handler must not be able to mutate the legacy session's state.

Validation, in order (per the spec):

  • missing protocolVersion (only reachable for server/discover, which routes modern unconditionally) → -32602 Invalid params
  • unsupported protocolVersionUnsupportedProtocolVersionError (-32022) with data.supported/data.requested
  • missing clientCapabilities → -32602 Invalid params (a required _meta field)
  • present but unrecognized logLevel → -32602 Invalid params (the spec's SHOULD; presence-aware — a mistyped value is rejected, never treated as absent)
  • method not on the modern surface (or its capability undeclared) → -32601

notifications/message follows the per-request opt-in: a request that set a valid io.modelcontextprotocol/logLevel (and passed all validation) gets records at or above that level on its own response stream, provided the server declares the logging capability; every other modern request gets none — the suppression flag the loop armed stays set through the iteration, covering the loop's own post-dispatch lifecycle records too. subscriptions/listen never honors the opt-in: its response stream IS the subscription stream, and the spec forbids notifications/message there.

Arguments

  • server::Server: The MCP server instance
  • state::ServerState: The legacy session state (NOT given to handlers; see above)
  • request::Request: The parsed request (with meta.protocol_version set)
  • authenticated_user: Per-request identity from HTTP auth, else nothing

Returns

  • Union{Response,Nothing}: The response to send
source
ModelContextProtocol.modern_cache_scopeMethod
modern_cache_scope(server::Server) -> String

The cacheScope for this server's cacheable results: "private" when bearer auth is enabled (responses are served inside an authorization context and MUST NOT be shared across contexts by intermediaries), "public" otherwise.

Arguments

  • server::Server: The server instance

Returns

  • String: "public" or "private"
source
ModelContextProtocol.modern_input_required_responseMethod
modern_input_required_response(server::Server, ir::InputRequired, id,
                               method::String, client_capabilities,
                               params_digest, principal::String) -> Response

Build the modern-era response for a handler's InputRequired (MRTR): the -32021 MissingRequiredClientCapability error when the request did not declare a capability the input requests need, otherwise the enveloped InputRequiredResult (resultType input_required + inputRequests + a minted requestState). Shared by the in-loop serve path and off-loop detachable tool calls (tasks extension), so both build byte-identical responses.

Arguments

  • server::Server: The MCP server instance
  • ir::InputRequired: The handler's input-required value
  • id: The request id to respond with
  • method::String: The request method (bound into the requestState)
  • client_capabilities: The request's declared _meta client capabilities
  • params_digest: The request's canonical params digest
  • principal::String: The MRTR principal (see mrtr_principal)

Returns

  • Response: The error or enveloped result response
source
ModelContextProtocol.modern_invalid_paramsMethod
modern_invalid_params(ctx::RequestContext, method::String) -> HandlerResult

Build the -32602 Invalid params result for a modern request whose typed parameters are missing or malformed.

source
ModelContextProtocol.modern_method_availableMethod
modern_method_available(server::Server, method::String) -> Bool

Whether method exists on this server's modern surface: it must be a modern-era method AND its providing capability must be declared — the advertised capability set and the callable surface must agree.

Arguments

  • server::Server: The server instance
  • method::String: The request method

Returns

  • Bool: true when the method is callable in the modern era
source
ModelContextProtocol.modern_result_envelopeMethod
modern_result_envelope(response::JSONRPCResponse, server::Server) -> JSONRPCResponse

Apply the modern-era result envelope: every result MUST carry resultType ("complete" unless the handler set one) and SHOULD identify the server via io.modelcontextprotocol/serverInfo in the result's _meta (merged into any handler-provided _meta).

The known handler result types are re-shaped WITHOUT a JSON round-trip, so values travel by reference — no numeric precision loss (Int64 above 2^53 survives) and no extra copies of base64 payloads. Only unknown result types fall back to an untyped JSON3 round-trip (which preserves Int64, unlike a Dict{String,Any}-typed read).

Arguments

  • response::JSONRPCResponse: The handler's response
  • server::Server: The server (for serverInfo)

Returns

  • JSONRPCResponse: A response whose result carries the modern envelope fields
source
ModelContextProtocol.modernize_error_codeMethod
modernize_error_code(code::Int) -> Int

Map legacy-range error codes to their modern-era replacements. The 2026-07-28 allocation policy grandfathers -32000..-32019 for legacy responses but modern responses must use spec codes: not-found conditions for resources (-32000), tools (-32001), URIs (-32002, reserved — MUST NOT be emitted), and prompts (-32003) are all -32602 Invalid params in the modern era.

Arguments

  • code::Int: A legacy-era error code

Returns

  • Int: The code to emit on a modern-era response
source
ModelContextProtocol.serve_modernMethod
serve_modern(server::Server, request::Request, version::String, mrtr_state,
             authenticated_user) -> Union{Response,Nothing}

Dispatch a fully validated modern-era request and build its response (envelope, CacheableResult fields, MRTR inputrequired handling). Split out of `handlemodern_request` so the per-request log opt-in can re-scope the logger around the whole serve path.

Arguments

  • server::Server: The MCP server instance
  • request::Request: The validated request
  • version::String: The request's protocol version
  • mrtr_state: The verified MRTR state payload, or nothing
  • authenticated_user: Per-request identity from HTTP auth, else nothing

Returns

  • Union{Response,Nothing}: The response to send (nothing when deferred)
source
ModelContextProtocol.InputRequestType
InputRequest(method::String, params)

One entry of an InputRequiredResult's inputRequests map: a request the client should fulfill and answer in its retry's inputResponses. Only the three spec-blessed request types are valid — construct via elicit_request, sampling_request, or roots_request.

Fields

  • method::String: The request method (elicitation/create, sampling/createMessage, roots/list)
  • params::Any: The request's params (a Dict, or nothing for none)
source
ModelContextProtocol.canonical_json_digestMethod
canonical_json_digest(x) -> String

SHA-256 hex digest of the canonical (sorted-key) JSON serialization of x. Used to bind an issued requestState to the exact original params it may resume.

Arguments

  • x: Any parsed JSON value

Returns

  • String: The hex digest
source
ModelContextProtocol.canonicalize_jsonMethod
canonicalize_json(x) -> Any

Rebuild a JSON value with all object keys sorted (recursively), producing a serialization-stable structure for digesting. Non-container values pass through.

Arguments

  • x: Any parsed JSON value

Returns

  • The canonical structure
source
ModelContextProtocol.capability_satisfiedMethod
capability_satisfied(client_capabilities, r::InputRequest) -> Bool

Whether this request's declared _meta client capabilities cover input request r. Declaration means the capability VALUE is an object (a null or scalar value declares nothing — including MODE values: {"elicitation": {"form": null}} declares no form support), and subfeatures are honored:

  • form-mode elicitation: form declared with an object value covers it, and ONLY the bare empty elicitation object implies it — any other declared mode set (url, or modes from a future revision) excludes form
  • tool-enabled sampling (params.tools OR params.toolChoice present): requires sampling.tools declared as an object, not just sampling

Arguments

  • client_capabilities: The request's declared client capabilities (any JSON value)
  • r::InputRequest: The input request to check

Returns

  • Bool: true when r may be sent to this client
source
ModelContextProtocol.input_required_envelopeMethod
input_required_envelope(server::Server, ir::InputRequired, method::String,
                        params_digest, principal::String) -> LittleDict{String,Any}

Build the InputRequiredResult wire shape for a handler's InputRequired value: resultType: "input_required", the inputRequests map (each entry {method, params?}), and a freshly minted requestState bound to this method, principal, and params digest. Capability checking is the caller's job (undeclared_capability_requirements) — it must reject with -32021 BEFORE building this envelope.

Arguments

  • server::Server: The server
  • ir::InputRequired: The handler's value
  • method::String: The request method (bound into the state token)
  • params_digest: The request's canonical params digest
  • principal::String: The requesting principal

Returns

  • LittleDict{String,Any}: The result object
source
ModelContextProtocol.issue_request_stateMethod
issue_request_state(server::Server, method::String, params_digest,
                    principal::String, handler_state) -> String

Mint an integrity-protected requestState token: an HMAC-SHA256-signed payload embedding issue time + TTL, the principal, the ORIGINATING METHOD, the canonical digest of the original request params, and the handler's carried state. Signed with the per-server key, so a token survives neither tampering nor (with the default ephemeral key) a server restart. Binding the method prevents cross-method state confusion: tools/call and prompts/get params can be structurally identical, and a token issued for one must not resume the other.

Arguments

  • server::Server: The server (holds the signing key)
  • method::String: The request method the state was issued for
  • params_digest: The request's canonical params digest (from RequestMeta)
  • principal::String: The requesting principal (mrtr_principal)
  • handler_state: The handler's JSON-serializable state (may be nothing)

Returns

  • String: The token (base64(payload).base64(mac))
source
ModelContextProtocol.mrtr_principalMethod
mrtr_principal(user::Union{AuthenticatedUser,Nothing}) -> String

The principal string bound into a requestState: the canonical provider-qualified identity (see principal_identity), or "" when the request is unauthenticated. A state issued to one principal must not be redeemable by another — including a DIFFERENT provider's token that happens to carry the same subject.

Arguments

  • user::Union{AuthenticatedUser,Nothing}: The request's authenticated user

Returns

  • String: The principal
source
ModelContextProtocol.principal_identityMethod
principal_identity(user::AuthenticatedUser) -> String

The canonical, collision-free identity string for an authenticated principal: the JSON array [provider, subject]. Two identity providers can issue the same sub, so the subject alone must never identify a principal; JSON encoding (not delimiter concatenation) makes the pair unambiguous — ("a", "b\x1fc") and ("a\x1fb", "c") cannot collide. username is display-oriented and mutable, so it never participates.

source
ModelContextProtocol.undeclared_capability_requirementsMethod
undeclared_capability_requirements(ir::InputRequired, client_capabilities)
    -> LittleDict{String,Any}

The requiredCapabilities object for the capabilities ir's input requests need but this request did not declare — a ClientCapabilities-shaped object precise to the subfeature: {"elicitation": {"form": {}}} for a form elicitation, {"sampling": {}} for plain sampling, {"sampling": {"tools": {}}} for tool-enabled sampling. A server MUST NOT send inputRequests the client did not declare support for: a non-empty return means the request must be rejected with -32021 carrying this object as error.data.requiredCapabilities.

Arguments

  • ir::InputRequired: The handler's input-required value
  • client_capabilities: The request's declared client capabilities (any JSON value)

Returns

  • LittleDict{String,Any}: The missing requirements (empty when all declared)
source
ModelContextProtocol.verify_request_stateMethod
verify_request_state(server::Server, token::AbstractString, method::String,
                     params_digest, principal::String) -> Tuple{Bool,Any}

Verify a retry's requestState BEFORE any handler runs: signature (constant-time), TTL, principal, originating method, and original-params digest must all hold — the token is attacker-controlled input. Returns (true, handler_state) on success or (false, reason) on any failure.

Arguments

  • server::Server: The server (holds the signing key)
  • token::AbstractString: The offered requestState
  • method::String: THIS request's method (must equal the issuing method)
  • params_digest: THIS request's canonical params digest (must equal the original's)
  • principal::String: THIS request's principal

Returns

  • Tuple{Bool,Any}: (ok, handler_state_or_reason)
source
ModelContextProtocol.call_tool_result_wireMethod
call_tool_result_wire(result::CallToolResult) -> LittleDict{String,Any}

Serialize a CallToolResult to the plain result object inlined on a completed task (tasks/get result field): content/isError plus structuredContent and _meta when present. No resultType (it is a nested result, not a response envelope) and no legacy related-task _meta (the taskId is already at the response root, and SEP-2663 forbids the redundant key).

source
ModelContextProtocol.ensure_task_notifications!Method
ensure_task_notifications!(server::Server) -> Nothing

(Re)install the notifications/tasks dispatch pipeline when it is absent or its queue has been closed — stop! and the server-loop shutdown both close the queue (ending the dispatcher so it cannot pin the server past its lifetime), so a server started again needs a fresh queue and dispatcher. A live pipeline is left untouched.

source
ModelContextProtocol.ext_task_authorizedMethod
ext_task_authorized(ctx::RequestContext, record::TaskRecord) -> Bool

Re-authorize a task-related request against the task's recorded requirements (SEP-2663: authorization checks on EVERY task request, not only at creation): when the request is authenticated, the current token must carry every scope the originating tool required. A failure is reported as task-not-found by the caller, indistinguishable from an unknown id.

source
ModelContextProtocol.ext_task_principalMethod
ext_task_principal(ctx::RequestContext) -> Union{String,Nothing}

The authorization principal extension tasks are bound to. Unlike the legacy task_principal (subject only), this binds provider AND subject via the canonical collision-free principal_identity — two identity providers can issue the same sub, and a token from the wrong provider must not resolve another caller's task. nothing when auth is not enabled (single-user transports). Shares its encoding with the MRTR requestState principal, so the composition flow (MRTR round, then task creation) is bound to one identity end-to-end.

source
ModelContextProtocol.ext_task_wireMethod
ext_task_wire(record::TaskRecord; detailed::Bool=false) -> LittleDict{String,Any}

Serialize a task record to the SEP-2663 wire shape: taskId, status, optional statusMessage, createdAt/lastUpdatedAt (ISO 8601 UTC), ttlMs (always present; null = unlimited), and pollIntervalMs — integer milliseconds, and never the legacy ttl/pollInterval keys. With detailed=true the status-specific DetailedTask payload is inlined: result for "completed", error for "failed", inputRequests for "input_required". Caller must hold the store lock.

source
ModelContextProtocol.handle_ext_cancel_taskMethod
handle_ext_cancel_task(ctx::RequestContext, params::CancelTaskParams) -> HandlerResult

Handle a modern-era tasks/cancel (tasks extension): signal cancellation intent and acknowledge with an empty result. Cancellation is cooperative and eventually consistent — a running handler observes it via task_cancelled(ctx), and the ack is idempotent: cancelling an already-terminal task acks identically (-32602 is reserved for unknown taskIds, a deliberate delta from the legacy era's terminal-cancel rejection). Gated on the extension declaration (-32021).

source
ModelContextProtocol.handle_ext_get_taskMethod
handle_ext_get_task(ctx::RequestContext, params::GetTaskParams) -> HandlerResult

Handle a modern-era tasks/get poll (tasks extension): return the DetailedTask for the task's current status, with the terminal result/error inlined. Gated on the extension declaration (-32021); an unknown, expired, cross-principal, or legacy-era taskId is -32602.

source
ModelContextProtocol.handle_ext_update_taskMethod
handle_ext_update_task(ctx::RequestContext, params::UpdateTaskParams) -> HandlerResult

Handle a modern-era tasks/update (tasks extension): deliver the client's inputResponses to the task's outstanding input requests, acknowledging with an empty result. Responses keyed to requests that are not currently outstanding — never issued, already answered, or superseded — are ignored per spec, and a partial set (a strict subset of the outstanding keys) is accepted: answered keys are removed and the task stays input_required until the rest arrive; once nothing is pending the status returns to working. The ack is eventually consistent — delivery happens before the ack here, but the resumed handler runs concurrently, so the observable status is whatever tasks/get sees next. Gated on the extension declaration (-32021); an unknown taskId is -32602.

source
ModelContextProtocol.install_task_notifications!Method
install_task_notifications!(server::Server) -> Nothing

Wire the tasks extension's notifications/tasks status updates: install the store's status-change hook so every extension-era transition (parking on input, resuming, completing, failing, cancelling, expiring) pushes the task's complete DetailedTask — identical to what tasks/get would return at that moment — to the subscriptions/listen streams that subscribed to the task's id.

The hook runs under the store lock (which the wire snapshot requires) but does NO transport I/O there: it enqueues the snapshot — plus the task's transition-time principal and required_scopes, re-checked per stream at delivery — onto a bounded FIFO consumed by a single dispatcher task, which broadcasts OUTSIDE the store lock. A stalled client can therefore never wedge the task store (a synchronous stdio write under the lock would block every tasks/* request once the client's pipe fills), the single consumer preserves transition order, and a full queue load-sheds (best-effort pushes; polling stays authoritative). Installed by mcp_server; stop! closes the queue, ending the dispatcher.

source
ModelContextProtocol.safe_error_messageMethod
safe_error_message(prefix::String, e) -> String

Format an exception for an error message WITHOUT trusting its show/showerror methods: an exception whose display itself throws must not escape the error path it is being reported on (it would defeat every catch that interpolates $(e) and, on the task-worker path, leave a delivered task non-terminal forever). Falls back to the exception's type name, then to a static string.

source
ModelContextProtocol.spawn_detachable_tool_call!Method
spawn_detachable_tool_call!(ctx::RequestContext, tool::MCPTool,
                            args::AbstractDict,
                            tool_scopes::Vector{String}) -> HandlerResult

Run a task-capable modern-era tools/call off the serial server loop: capture the request's response route, spawn the handler on a background Julia task, and defer. tool_scopes is the caller's snapshot of the tool's required_scopes — the exact set this request was authorized against, recorded onto a minted task for per-request re-authorization. The handler decides the response shape by what it does first:

  • returns without detaching → ordinary synchronous result (the immediate-result shortcut), delivered on the captured route
  • returns InputRequired without detaching → the MRTR round (capability check, input_required envelope) — this is what lets MRTR exchanges resolve BEFORE task creation, per the SEP-2663 composition rule
  • calls task_detach(ctx) → the CreateTaskResult was already delivered; the eventual outcome is recorded into the task (a CallToolResult completes it, a thrown error fails it with the JSON-RPC error inlined)

The worker guarantees exactly one outcome on every path: any throw between the handler's return and the response delivery — including one raised by a diagnostic logger — lands in a last-resort catch that answers -32603 (or fails the already-created task).

source
ModelContextProtocol.tasks_extension_declaredMethod
tasks_extension_declared(client_capabilities) -> Bool

Whether this request declared the io.modelcontextprotocol/tasks extension in its _meta clientCapabilities. Declaration means the extension key is present under extensions with an OBJECT value (the spec's "an empty object indicates support"; a null or scalar value declares nothing, matching the MRTR capability rules).

source
ModelContextProtocol.tasks_extension_required_errorMethod
tasks_extension_required_error() -> ErrorInfo

The -32021 MissingRequiredClientCapability error for task-surface requests from a client that did not declare the tasks extension, carrying the spec's requiredCapabilities object naming the extension.

source
ModelContextProtocol.broadcast_subscription_notificationMethod
broadcast_subscription_notification(server::Server, method::String;
                                    params::AbstractDict=LittleDict{String,Any}(),
                                    uri::Union{String,Nothing}=nothing,
                                    task_id::Union{String,Nothing}=nothing) -> Int

Deliver a notification to every subscriptions/listen stream that opted into it, tagged with each stream's own subscription id. Every record — not just the filter matches — is swept for liveness (route_alive), so a disconnected client whose filter never matches anything still gets pruned. Returns the number of streams the notification reached.

Delivery happens while holding the registry lock (every delivery path enqueues without blocking), so a broadcast cannot interleave with a stream's registration or graceful closure; see the SubscriptionRegistry docstring for the lock ordering.

Arguments

  • server::Server: The server whose subscriptions to notify
  • method::String: The notification method
  • params::AbstractDict: Additional notification params
  • uri::Union{String,Nothing}: For notifications/resources/updated, the resource URI
  • task_id::Union{String,Nothing}: For notifications/tasks, the task id
  • authorize: Optional per-stream predicate record::SubscriptionRecord -> Bool checked after the filter match — used by notifications/tasks to re-authorize each delivery against the stream's stored principal/scopes WITHOUT taking the task-store lock here (the ordering store → registry must never reverse)

Returns

  • Int: How many streams received the notification
source
ModelContextProtocol.cancel_subscription!Method
cancel_subscription!(server::Server, request_id) -> Bool

Cancel an active subscriptions/listen stream by its originating request id — the notifications/cancelled path, which is how a stdio client (which cannot close a response stream) ends a subscription. The record is removed so no further messages carry its id; per JSON-RPC cancellation semantics no response is sent.

Only ROUTELESS records (stream transports like stdio, where the single shared channel means the cancellation can only come from the stream's own client) are cancellable this way. A route-bound (HTTP) stream is cancelled by closing the response stream itself — an in-band cancellation message must never be honored for it, because on HTTP the notification can arrive on ANY connection: honoring it would let one client end another client's stream by guessing its id.

Arguments

  • server::Server: The server holding the subscription
  • request_id: The listen request's JSON-RPC id (from the notification's requestId)

Returns

  • Bool: true when an active subscription was cancelled
source
ModelContextProtocol.close_subscriptions!Method
close_subscriptions!(server::Server) -> Nothing

End all subscriptions/listen streams gracefully: each open stream receives the JSON-RPC response to its originating listen request (an empty complete result tagged with its subscription id and carrying serverInfo like every other modern result), which is how a client distinguishes an orderly server shutdown from an abrupt transport drop. Called during server shutdown.

The closing results are delivered while holding the registry lock, so a concurrent broadcast can never write on a stream AFTER its graceful result: the broadcast either completes first or finds an empty registry.

Arguments

  • server::Server: The server whose subscriptions to close

Returns

  • Nothing
source
ModelContextProtocol.handle_subscriptions_listenMethod
handle_subscriptions_listen(ctx::RequestContext, params::SubscriptionsListenParams) -> HandlerResult

Open a subscriptions/listen stream: validate the filter (a malformed one is rejected with -32602, not silently emptied), send notifications/subscriptions/acknowledged as the stream's FIRST message (carrying the honored subset of the requested filter), register the subscription, and defer the request's response — the stream stays open until the client closes it, cancels it (notifications/cancelled on stdio), or the server shuts down (close_subscriptions!).

Ack-then-register happens under the registry lock, so a concurrent broadcast can neither enqueue a change notification ahead of the acknowledgment nor observe a half-registered stream — and a stream whose ack cannot be delivered is never registered at all.

Notification types the server cannot deliver are omitted from the acknowledged filter rather than silently accepted, so a client can tell what it will actually receive.

Arguments

  • ctx::RequestContext: The current request context
  • params::SubscriptionsListenParams: The request's notification filter

Returns

  • HandlerResult: A deferred result (the response, if any, arrives at closure)
source
ModelContextProtocol.legacy_session_notificationMethod
legacy_session_notification(state::ServerState, transport, method::String;
                            params::AbstractDict = LittleDict{String,Any}()) -> Bool

Deliver a plain JSON-RPC notification to the connected legacy session, if there is one. The caller passes the session state and transport it already fetched (one snapshot per announcement — a concurrent restart cannot authorize against one session and deliver through another). The session must have completed a real initialize handshake: initialized alone is not proof (a bare notifications/initialized sets it), so a negotiated protocol_version is required too — a server that only ever served modern requests is never armed for legacy delivery.

Delivery is transport-polymorphic via send_notification — stdout on stdio, the standalone GET SSE stream on Streamable HTTP. The ambient request route is explicitly bypassed for the send: when an announcement happens inside a request handler (legacy or modern), the legacy notification must go out-of-band to the legacy session's own stream, never onto the calling request's response channel (which on a modern request would leak it to a different — possibly differently authenticated — client).

Arguments

  • state::ServerState: The legacy session state snapshot
  • transport: The transport snapshot (Transport or nothing)
  • method::String: The notification method
  • params::AbstractDict: The notification's params

Returns

  • Bool: true when the transport handoff was attempted without error — NOT proof of enqueue or client receipt (a disconnected HTTP transport, or one whose notification queue is at its soft cap, drops silently); false when there is no handshaken legacy session, no transport, or the send threw
source
ModelContextProtocol.list_changed_declaredMethod
list_changed_declared(server::Server, kind::Symbol) -> Bool

Report whether the server declares the listChanged capability for kind — the gate for sending notifications/{kind}/list_changed to the legacy session (modern subscriptions/listen streams are gated per-stream at ack time instead, via the honored filter subset).

Arguments

  • server::Server: The server whose declared capabilities to check
  • kind::Symbol: One of :tools, :prompts, :resources

Returns

  • Bool: Whether the matching capability declares list_changed = true
source
ModelContextProtocol.subscription_notificationMethod
subscription_notification(method::String, params::AbstractDict, sub_id) -> String

Serialize a notification for delivery on a subscriptions/listen stream, tagging it with the subscription id the spec requires on every stream message.

Arguments

  • method::String: The notification method
  • params::AbstractDict: The notification's params (the _meta tag is added here)
  • sub_id: The subscription id (the listen request's JSON-RPC id)

Returns

  • String: The serialized JSON-RPC notification
source

Core Implementation

ModelContextProtocol.process_messageMethod
process_message(server::Server, state::ServerState, message::String) -> Union{String,Nothing}

Process an incoming JSON-RPC message and generate an appropriate response.

Arguments

  • server::Server: The MCP server instance
  • state::ServerState: Current server state
  • message::String: Raw JSON-RPC message to process

Returns

  • Union{String,Nothing}: A serialized response string or nothing for notifications
source
ModelContextProtocol.run_server_loopMethod
run_server_loop(server::Server, state::ServerState) -> Nothing

Execute the main server loop that reads JSON-RPC messages from the transport and writes responses back. Implements optimized CPU usage by blocking on input rather than active polling.

Arguments

  • server::Server: The MCP server instance with configured transport
  • state::ServerState: The server state object to track running status

Returns

  • Nothing: The function runs until interrupted or state.running becomes false
source
ModelContextProtocol.CapabilityResponseType
CapabilityResponse(; 
    listChanged::Bool=false, 
    subscribe::Union{Bool,Nothing}=nothing, 
    tools::Union{Dict{String,Any},Nothing}=nothing, 
    resources::Union{Vector{Dict{String,Any}},Nothing}=nothing)

Define response structure for capabilities including tool and resource listings.

Fields

  • listChanged::Bool: Whether listings can change during server lifetime.
  • subscribe::Union{Bool,Nothing}: Whether subscriptions are supported.
  • tools::Union{Dict{String,Any},Nothing}: Tool definitions by name.
  • resources::Union{Vector{Dict{String,Any}},Nothing}: Available resource listings.
source
ModelContextProtocol.CompletionCapabilityType
CompletionCapability()

Advertise argument-completion support (completion/complete): contextual value suggestions for prompt arguments and resource-template variables, declared as the completions capability. Sources are configured per component via the completions field on MCPPrompt / ResourceTemplate; components without sources serve empty suggestion lists.

source
ModelContextProtocol.LoggingCapabilityType
LoggingCapability(; levels::Vector{String}=["info", "warn", "error"])

Configure logging-related capabilities for an MCP server.

Fields

  • levels::Vector{String}: Supported logging levels.
source
ModelContextProtocol.PromptCapabilityType
PromptCapability(; list_changed::Bool=false)

Configure prompt-related capabilities for an MCP server.

Fields

  • list_changed::Bool: Whether server supports notifications when prompt listings change.
source
ModelContextProtocol.ResourceCapabilityType
ResourceCapability(; list_changed::Bool=false, subscribe::Bool=false)

Configure resource-related capabilities for an MCP server.

Fields

  • list_changed::Bool: Whether server supports notifications when resource listings change.
  • subscribe::Bool: Whether server supports subscriptions to resource updates.
source
ModelContextProtocol.TaskCapabilityType
TaskCapability(; list::Bool=true, cancel::Bool=true)

Configure MCP Tasks support (SEP-1686, experimental): task-augmented tools/call plus the tasks/get, tasks/result, and optionally tasks/list/tasks/cancel operations. Only advertised to clients that negotiated protocol 2025-11-25 or later.

Fields

  • list::Bool: Whether tasks/list is offered. Note: on an HTTP transport without authentication the server cannot identify requestors, so list is withheld from the advertised capability regardless of this setting (per the spec's security guidance).
  • cancel::Bool: Whether tasks/cancel is offered.
source
ModelContextProtocol.ToolCapabilityType
ToolCapability(; list_changed::Bool=false)

Configure tool-related capabilities for an MCP server.

Fields

  • list_changed::Bool: Whether server supports notifications when tool listings change.
source
ModelContextProtocol.capabilities_to_protocolMethod
capabilities_to_protocol(capabilities::Vector{Capability}, server::Server) -> Dict{String,Any}

Convert server capabilities to the initialization response format required by the MCP protocol.

Arguments

  • capabilities::Vector{Capability}: List of server capabilities.
  • server::Server: The server containing tools and resources.

Returns

  • Dict{String,Any}: Protocol-formatted capabilities dictionary including available tools and resources.
source
ModelContextProtocol.create_init_responseMethod
create_init_response(server::Server, protocol_version::String) -> InitializeResult

Create the initialization response for an MCP server.

Arguments

  • server::Server: The server to create the response for.
  • protocol_version::String: MCP protocol version string.

Returns

  • InitializeResult: Initialization response including server capabilities and info.
source
ModelContextProtocol.merge_capabilitiesMethod
merge_capabilities(base::Vector{Capability}, override::Vector{Capability}) -> Vector{Capability}

Merge two sets of capabilities, with the override set taking precedence.

Arguments

  • base::Vector{Capability}: Base set of capabilities.
  • override::Vector{Capability}: Override capabilities that take precedence.

Returns

  • Vector{Capability}: Merged set of capabilities.
source
ModelContextProtocol.to_protocol_formatMethod
to_protocol_format(cap::Capability) -> Dict{String,Any}

Convert an MCP capability to the JSON format expected by the MCP protocol.

Arguments

  • cap::Capability: The capability to convert.

Returns

  • Dict{String,Any}: Protocol-formatted capability dictionary.
source
ModelContextProtocol.auto_register!Method
auto_register!(server::Server, dir::AbstractString) -> Server

Automatically register MCP components found in the specified directory structure.

Arguments

  • server::Server: The server to register components with
  • dir::AbstractString: Root directory containing component subdirectories

Directory Structure

  • dir/tools/: Contains tool definition files
  • dir/resources/: Contains resource definition files
  • dir/prompts/: Contains prompt definition files

Each subdirectory is optional. Files should be .jl files containing component definitions.

Component File Format

Component files must have the tool/resource/prompt as the last expression in the file. The return value of include() is used to obtain the component.

Example:

# tools/my_tool.jl
julia_version_tool = MCPTool(
    name = "julia_version",
    description = "Get Julia version",
    handler = params -> Dict("version" => string(VERSION))
)  # ← This must be the last expression

Returns

  • Server: The updated server instance for method chaining
source
ModelContextProtocol.default_capabilitiesMethod
default_capabilities() -> Vector{Capability}

Create the default set of server capabilities for an MCP server.

Returns

  • Vector{Capability}: Default capabilities including resources, tools, and prompts
source
ModelContextProtocol.normalize_pathMethod
normalize_path(path::String) -> String

Convert paths to absolute form, resolving relative paths against the project root.

Arguments

  • path::String: The path to normalize

Returns

  • String: Absolute, normalized path with all symbolic links resolved
source
ModelContextProtocol.scan_mcp_componentsMethod
scan_mcp_components(dir::String) -> Dict{Symbol,Vector}

Scan a directory recursively for MCP component definitions (tools, resources, prompts).

Arguments

  • dir::String: Directory path to scan for component definitions

Returns

  • Dict{Symbol,Vector}: Dictionary of found components grouped by type
source
ModelContextProtocol.CapabilityType
Capability

Abstract base type for all MCP protocol capabilities. Capabilities represent protocol features that servers can support. Concrete implementations define configuration for specific feature sets.

source
ModelContextProtocol.MCPMessageType
MCPMessage

Abstract base type for all message types in the MCP protocol. Serves as the root type for requests, responses, and notifications.

source
ModelContextProtocol.NotificationType
Notification <: MCPMessage

Abstract base type for one-way notifications in the MCP protocol. Notification messages don't expect a corresponding response.

source
ModelContextProtocol.ProgressType
Progress(; token::Union{String,Int}, current::Float64, 
        total::Union{Float64,Nothing}=nothing, message::Union{String,Nothing}=nothing)

Track progress of long-running operations in the MCP protocol.

Fields

  • token::Union{String,Int}: Unique identifier for the progress tracker
  • current::Float64: Current progress value
  • total::Union{Float64,Nothing}: Optional total expected value
  • message::Union{String,Nothing}: Optional status message
source
ModelContextProtocol.RequestType
Request <: MCPMessage

Abstract base type for client-to-server requests in the MCP protocol. Request messages expect a corresponding response from the server.

source
ModelContextProtocol.RequestParamsType
RequestParams

Abstract base type for all parameter structures in MCP protocol requests. Concrete subtypes define parameters for specific request methods.

source
ModelContextProtocol.ResponseType
Response <: MCPMessage

Abstract base type for server-to-client responses in the MCP protocol. Response messages are sent from the server in reply to client requests.

source
ModelContextProtocol.ResponseResultType
ResponseResult

Abstract base type for all result structures in MCP protocol responses. Concrete subtypes define result formats for specific response methods.

source
ModelContextProtocol.RoleType
Role

Enum representing roles in the MCP protocol.

Values

  • user: Content or messages from the user
  • assistant: Content or messages from the assistant
source
ModelContextProtocol.ServerConfigType
ServerConfig(; name::String, version::String="1.0.0",
           description::String="", capabilities::Vector{Capability}=Capability[],
           instructions::String="",
           title::Union{String,Nothing}=nothing,
           icons::Union{Vector{MCPIcon},Nothing}=nothing)

Define configuration settings for an MCP server instance.

Fields

  • name::String: The server name shown to clients
  • version::String: Server implementation version (e.g., "1.0.0", "2.3.1") - YOUR server's version, not the protocol version
  • description::String: Human-readable server description
  • capabilities::Vector{Capability}: Protocol capabilities supported by the server
  • instructions::String: Usage instructions for clients
  • title::Union{String,Nothing}: Optional human-friendly display name
  • icons::Union{Vector{MCPIcon},Nothing}: Optional icons for UI display
source
ModelContextProtocol.ServerErrorType
ServerError(message::String) <: Exception

Exception type for MCP server-specific errors.

Fields

  • message::String: The error message describing what went wrong
source
ModelContextProtocol.ServerStateType
ServerState()

Track the internal state of an MCP server during operation.

Fields

  • initialized::Bool: Whether the server has been initialized by a client
  • running::Bool: Whether the server main loop is active
  • last_request_id::Int: Last used request ID for server-initiated requests
  • pending_requests::Dict{RequestId,String}: Map of request IDs to method names
  • protocol_version::Union{String,Nothing}: MCP protocol version negotiated during initialization (see negotiate_version), or nothing before the client initializes. Server-global, not data-raced: all handler execution is serialized through run_server_loop. As with session_id, the transport is single-session, so a repeat initialize overwrites this ("last initialize wins")
  • wire_subscriptions::Set{String}: Resource URIs the client subscribed to via resources/subscribe
source
ModelContextProtocol.SubscriptionType
Subscription(; uri::String, callback::Function, created_at::DateTime=now())

Define a subscription to resource updates in the MCP protocol.

Fields

  • uri::String: The URI of the subscribed resource
  • callback::Function: Function to call when the resource is updated
  • created_at::DateTime: When the subscription was created
source
Base.convertMethod
convert(::Type{URI}, s::String) -> URI

Convert a string to a URI object.

Arguments

  • s::String: The string to convert

Returns

  • URI: The resulting URI object
source
ModelContextProtocol.PendingTaskInputType
PendingTaskInput(method::String, params, channel::Channel{Any})

One outstanding mid-task input request on an extension-era task (SEP-2663): the request the client sees under the task's inputRequests (as {method, params?} on tasks/get), paired with the channel the blocked task_await_input waiter takes the client's tasks/update response from. The channel is buffered (size 1) and receives exactly one value — the key is removed from the pending map in the same critical section that delivers, so a key can never be answered twice.

Fields

  • method::String: The input request's method (e.g. elicitation/create)
  • params::Any: The input request's params (a Dict, or nothing for none)
  • channel::Channel{Any}: Delivery channel to the blocked handler; closed (never fed) when the task is cancelled, unwinding the waiter
source
ModelContextProtocol.TaskDetachStateType
TaskDetachState(transport, route)

Per-call state for a detachable modern-era tools/call (tasks extension, SEP-2663). Created when the call is spawned off-loop with its response route captured; task_detach(ctx) uses it to mint the task and deliver the CreateTaskResult, and the spawn wrapper uses it to learn whether the handler detached. All access is under lock.

Fields

  • lock::ReentrantLock: Guards record/closed against the detach/finish race
  • transport::Any: The serving transport at spawn time
  • route::Any: The captured response route (see capture_response_route)
  • required_scopes::Vector{String}: The tool's required_scopes, recorded onto the minted task for per-request re-authorization of the extension surface
  • record::Union{TaskRecord,Nothing}: The minted task, published the moment it is durably created — BEFORE any fallible wire building or delivery, so a failure in between can never orphan a hidden non-terminal record
  • closed::Bool: Set when the handler has returned — a late task_detach (e.g. from a stray child task) must fail rather than deliver a second response
  • create_delivered::Bool: Set once the CreateTaskResult delivery was attempted; while false, the request is still owed a response (the spawn wrapper answers -32603 if the handoff died between task creation and delivery)
source
ModelContextProtocol.TaskRecordType
TaskRecord

Mutable record of one server-side task (a task-augmented request execution).

Fields

  • task_id::String: Receiver-generated unique identifier (cryptographically random)
  • status::String: One of "working", "input_required", "completed", "failed", "cancelled"
  • status_message::Union{String,Nothing}: Optional human-readable status detail
  • created_at::DateTime: UTC creation timestamp
  • last_updated_at::DateTime: UTC timestamp of the last status change
  • ttl_ms::Union{Int,Nothing}: Actual retention duration from creation; nothing = unlimited
  • poll_interval_ms::Union{Int,Nothing}: Suggested client polling interval
  • principal::Union{String,Nothing}: Authorization binding (authenticated subject), nothing when unauthenticated
  • method::String: The originating request method (e.g. "tools/call")
  • era::Symbol: :legacy for SEP-1686 experimental tasks (2025-11-25 sessions), :ext for the modern-era io.modelcontextprotocol/tasks extension (SEP-2663). The eras are wire-incompatible and never serve each other's records
  • required_scopes::Vector{String}: The originating tool's required_scopes, re-checked on every extension-era task request (SEP-2663 requires authorization on each task-related request — a later token for the same subject but without the tool's scopes must not read the result). Empty when the tool declares none
  • result::Union{CallToolResult,Nothing}: Final result when the underlying call succeeded (or failed via isError)
  • error::Union{ErrorInfo,Nothing}: Final JSON-RPC error when the underlying call errored
  • done::Base.Event: Set exactly once when the task reaches a terminal status
  • cancel_requested::Threads.Atomic{Bool}: Set once tasks/cancel is accepted; atomic so handlers can poll it lock-free from worker threads via task_cancelled(ctx)
  • pending_inputs::LittleDict{String,PendingTaskInput}: Outstanding mid-task input requests keyed by server-minted id (extension era only; insertion-ordered, so inputRequests serializes in issue order). Non-empty exactly while the task is input_required
  • input_key_counter::Int: Monotone counter minting pending_inputs keys — a key is never reused over the task's lifetime, even after its request is answered (SEP-2663 key-uniqueness rule)

All mutation goes through the owning TaskStore under its lock.

source
ModelContextProtocol.TaskStoreType
TaskStore(; default_ttl_ms=TASK_DEFAULT_TTL_MS, max_ttl_ms=TASK_MAX_TTL_MS,
          poll_interval_ms=TASK_POLL_INTERVAL_MS, page_size=TASKS_PAGE_SIZE)

Thread-safe registry of server-side tasks.

Fields

  • lock::ReentrantLock: Guards all record access and mutation
  • tasks::Dict{String,TaskRecord}: Records by task id
  • default_ttl_ms::Int: ttl applied when the requestor does not ask for one
  • max_ttl_ms::Int: Upper bound applied to requested ttls
  • poll_interval_ms::Int: Suggested polling interval included in task responses
  • page_size::Int: Page size for tasks/list cursor pagination
  • on_status_change::Base.RefValue{Any}: Optional hook record -> Nothing fired after every status transition, while the store lock is held (see _fire_status_change); installed for the tasks extension's notifications/tasks. nothing disables it
  • notification_seq::Threads.Atomic{Int}: Monotone sequence stamped on every enqueued status notification. Atomic on purpose: it is written at transition sites (under the store lock) but read for registration thresholds under the unrelated registry lock — a plain Ref would be a data race on a threaded runtime. Subscriptions record the counter at registration and receive only later-stamped events, so a queued-but-undrained backlog never replays older states to a freshly registered stream
source
ModelContextProtocol._fire_status_changeMethod
_fire_status_change(store::TaskStore, record::TaskRecord) -> Nothing

Fire the store's status-change hook for a record whose status just changed. Called at every transition site WHILE the store lock is held — the hook builds the task's wire snapshot (which requires the lock) and ENQUEUES it (no transport I/O happens under the store lock; a dedicated dispatcher task broadcasts from the queue, see install_task_notifications!). A throwing hook is swallowed: a notification must never break the transition that triggered it.

source
ModelContextProtocol.cancel_task!Method
cancel_task!(store::TaskStore, record::TaskRecord) -> Bool

Transition a task to "cancelled". Returns false without mutating when the task is already terminal (the handler maps that to a -32602 error per spec). Sets cancel_requested so cooperative handlers can observe it via task_cancelled(ctx), and unblocks any task_await_input waiter by draining the pending input requests.

source
ModelContextProtocol.create_task!Method
create_task!(store::TaskStore, method::String;
             requested_ttl_ms=nothing, principal=nothing, era=:legacy,
             status_message=nothing) -> TaskRecord

Create a new task record in "working" status with a cryptographically random task id. The requested ttl is clamped to the store's max_ttl_ms; when absent the store's default_ttl_ms applies.

source
ModelContextProtocol.drain_pending_inputs!Method
drain_pending_inputs!(record::TaskRecord) -> Nothing

Close and clear every outstanding mid-task input request on a task entering a terminal status: a blocked task_await_input waiter observes its channel closing and unwinds (there is nothing left that could ever feed it). Caller must hold the store lock — which is also what makes close-vs-deliver atomic: tasks/update delivers under the same lock, so a channel is either fed exactly once or closed, never both.

source
ModelContextProtocol.expire_parked_input!Method
expire_parked_input!(store::TaskStore, record::TaskRecord, now_utc::DateTime) -> Bool

Fail an extension-era task whose ttl elapsed while parked in input_required: a task past its ttl that is waiting on CLIENT input is abandoned — the client the server is waiting on can no longer use the result — so it is terminalized (status failed, error inlined) and its pending inputs drained, unwinding the blocked task_await_input waiter. A no-op (returning false) for any record not in exactly that state, so the deadline timer and the store sweep can both call it and whichever runs first wins. Caller must hold the store lock.

source
ModelContextProtocol.finish_task!Method
finish_task!(store::TaskStore, record::TaskRecord,
             outcome::Union{CallToolResult,ErrorInfo}) -> Bool

Transition a task to its terminal status from a completed execution. An ErrorInfo (a JSON-RPC error) is always "failed". For a CallToolResult the eras diverge: legacy (SEP-1686) maps is_error to "failed", while the extension era (SEP-2663) requires "completed" for ANY result — "failed" is reserved for JSON-RPC errors, and a tool-level isError:true result completes with the result inlined. Returns false without mutating when the task is already terminal (e.g. cancelled while the work was still running — cancelled tasks MUST stay cancelled, so the outcome is discarded).

source
ModelContextProtocol.get_taskMethod
get_task(store::TaskStore, task_id::String,
         principal::Union{String,Nothing}; era=:legacy) -> Union{TaskRecord,Nothing}

Look up a task by id, enforcing authorization-context binding: a record is only returned when its stored principal matches the requestor's AND it belongs to the requested era (legacy sessions cannot see extension tasks and vice versa — the wire shapes are incompatible). A mismatch returns nothing (indistinguishable from "not found", so task existence is not leaked).

source
ModelContextProtocol.list_tasksMethod
list_tasks(store::TaskStore, principal::Union{String,Nothing},
           cursor::Union{String,Nothing}; era=:legacy)
    -> Tuple{Vector{TaskRecord},Union{String,Nothing}}

Return one page of the requestor's tasks (oldest first) and the next-page cursor, or nothing for the cursor when no further pages exist. Only tasks bound to the same principal AND era are visible (tasks/list exists only in the legacy era; extension records must never leak into it — the extension deliberately has no list, so one caller's task ids cannot be exposed to another). Throws ArgumentError for an invalid cursor (mapped to -32602 by the handler).

source
ModelContextProtocol.sweep_expired!Method
sweep_expired!(store::TaskStore) -> Nothing

Delete terminal task records whose ttl has elapsed, and fail expired extension-era tasks still parked in input_required (see expire_parked_input! — here as a backstop; the clock-driven per-wait deadline timer in task_await_input is what guarantees the transition without further store activity). Once failed, such a record is terminal AND expired, so the next sweep deletes it — a post-expiry poll observes either the failed record briefly (when its own sweep is the one that just terminalized it) or task-not-found, timing-dependent; neither is promised. Other non-terminal records are retained past their ttl (the spec permits but does not require deleting those, and their background work may still be running). Caller must hold store.lock.

source
ModelContextProtocol.task_is_expiredMethod
task_is_expired(record::TaskRecord, now_utc::DateTime) -> Bool

Return whether the task's ttl (counted from creation) has elapsed. Unlimited (ttl_ms === nothing) tasks never expire.

source
ModelContextProtocol.task_wireMethod
task_wire(record::TaskRecord) -> LittleDict{String,Any}

Serialize a task record to the spec wire shape: taskId, status, optional statusMessage, createdAt/lastUpdatedAt (ISO 8601 UTC), ttl (always present; null for unlimited), and optional pollInterval.

source
ModelContextProtocol.SubscriptionFilterType
SubscriptionFilter(; tools_list_changed=false, prompts_list_changed=false,
                   resources_list_changed=false, resource_uris=Set{String}(),
                   task_ids=Set{String}())

The notification types a subscriptions/listen stream opted into. A server MUST NOT send notification types the client did not explicitly request, so every delivery is checked against this filter.

Fields

  • tools_list_changed::Bool: deliver notifications/tools/list_changed
  • prompts_list_changed::Bool: deliver notifications/prompts/list_changed
  • resources_list_changed::Bool: deliver notifications/resources/list_changed
  • resource_uris::Set{String}: deliver notifications/resources/updated for these URIs (a set: membership is checked on every update broadcast)
  • task_ids::Set{String}: deliver notifications/tasks status updates for these task ids (tasks extension, SEP-2663; only ids the requestor could tasks/get are ever agreed to)
source
ModelContextProtocol.SubscriptionRecordType
SubscriptionRecord(id, filter, route, transport,
                   task_principal=nothing, task_scopes=Set{String}())

One active subscriptions/listen stream.

Fields

  • id::Union{String,Int}: the listen request's JSON-RPC id — also the io.modelcontextprotocol/subscriptionId every message on the stream carries
  • filter::SubscriptionFilter: the notification types this stream opted into
  • route::Any: the transport route handle the notifications are delivered on (nothing for stream transports like stdio, which share one channel)
  • transport::Any: the transport to deliver over (Transport; typed Any to avoid include-order coupling)
  • task_principal::Union{String,Nothing}: the listen requestor's extension-task principal, re-checked at every notifications/tasks delivery
  • task_scopes::Set{String}: the listen requestor's token scopes, re-checked against the task's required_scopes at every notifications/tasks delivery — a task whose authorization requirements changed after the listen must not keep leaking status to a stream that could no longer tasks/get it
  • task_seq::Int: the task-notification sequence at registration; only events stamped LATER are delivered to this stream, so a queued-but-undrained backlog never replays states older than the stream's own initial snapshot
source
ModelContextProtocol.SubscriptionRegistryType
SubscriptionRegistry()

Registry of active subscriptions/listen streams. Guarded by a lock: the single server loop registers streams while HTTP connection tasks and background task executions can broadcast notifications concurrently. Deliveries happen WHILE holding this lock (all delivery paths enqueue without blocking), which is what guarantees the acknowledged-first and nothing-after-the-closing-result orderings.

Lock ordering: registry.lock may be held when a delivery takes the HTTP transport's channels_lock, never the reverse — nothing takes registry.lock while holding channels_lock.

Fields

  • subs::Vector{SubscriptionRecord}: active subscriptions
  • lock::ReentrantLock: guards subs
source
ModelContextProtocol.filter_to_wireMethod
filter_to_wire(f::SubscriptionFilter) -> LittleDict{String,Any}

Serialize a filter to the wire shape used in the acknowledgment's notifications field, which reflects the subset the server agreed to honor. Types not subscribed are omitted, and the resource URIs are emitted sorted (the in-memory set has no stable order).

Arguments

  • f::SubscriptionFilter: The filter

Returns

  • LittleDict{String,Any}: The honored subset
source
ModelContextProtocol.filter_wantsFunction
filter_wants(f::SubscriptionFilter, method::String,
             uri::Union{String,Nothing}=nothing,
             task_id::Union{String,Nothing}=nothing) -> Bool

Whether a notification of method (for resource updates, of uri; for task status updates, of task_id) was opted into.

Arguments

  • f::SubscriptionFilter: The subscription's filter
  • method::String: The notification method
  • uri::Union{String,Nothing}: The resource URI for notifications/resources/updated
  • task_id::Union{String,Nothing}: The task id for notifications/tasks

Returns

  • Bool: true when the notification may be delivered on this stream
source
ModelContextProtocol.parse_subscription_filterMethod
parse_subscription_filter(notifications) -> Union{SubscriptionFilter,String}

Validate and parse the notifications filter object of a subscriptions/listen request. Returns the parsed filter, or a violation message the caller must reject with -32602: the filter must be an object, the *ListChanged flags booleans, resourceSubscriptions an array of at most MAX_RESOURCE_SUBSCRIPTIONS strings, and at least one notification type must be requested — a malformed filter must not silently establish a long-lived stream that can never deliver anything.

Unknown keys are ignored (forward compatibility), and requesting types this server cannot deliver is NOT a violation: the honored subset in the acknowledgment is how the server communicates what it will actually send (see handle_subscriptions_listen).

Arguments

  • notifications: The request's params.notifications value (any JSON value)

Returns

  • Union{SubscriptionFilter,String}: The parsed filter, or the violation
source

Transport Implementation

ModelContextProtocol.TransportErrorType
TransportError(message::String) <: Exception

Exception type for transport-specific errors.

Fields

  • message::String: The error message describing what went wrong
source
ModelContextProtocol.capture_response_routeMethod
capture_response_route(transport::Transport) -> Any

Capture a route handle for delivering the CURRENT request's response later, from outside the server loop (used by tasks/result, which must block until the task completes without blocking the loop). The returned handle is passed to deliver_response.

The default returns nothing — for stream transports like stdio, responses carry their correlation in the JSON-RPC id, so no per-request route exists. Transports that route responses per request (HTTP) override this to detach and return the current request's route so the loop can move on to the next request.

Arguments

  • transport::Transport: The transport instance

Returns

  • An opaque route handle understood by deliver_response for this transport
source
ModelContextProtocol.closeFunction
close(transport::Transport) -> Nothing

Close the transport connection and clean up resources.

Arguments

  • transport::Transport: The transport instance to close

Returns

  • Nothing
source
ModelContextProtocol.deliver_log_notificationMethod
deliver_log_notification(transport::Transport, route::Any, message::String) -> Bool

Deliver a request-scoped log notification (ModernRequestLogger) on a request's response route. Distinct from deliver_notification because the failure policy differs: a subscriptions/listen stream that cannot keep up is load-shed by CLOSING it, but a request's response channel must never be closed under log pressure — the final response still has to travel it. Implementations drop the record (returning false, which sends it to the logger's fallback stream) rather than sacrifice the channel.

The default delegates to deliver_notification (correct for stdio's shared stream, which has no per-request channel to protect).

Arguments

  • transport::Transport: The transport instance
  • route::Any: The request's captured notification route
  • message::String: The serialized JSON-RPC notification

Returns

  • Bool: true when the notification was delivered
source
ModelContextProtocol.deliver_notificationMethod
deliver_notification(transport::Transport, route::Any, message::String) -> Bool

Deliver a notification on a route captured earlier with capture_response_route, used by subscriptions/listen streams (whose request never completes, so its route carries notifications instead). Returns whether delivery succeeded — false means the client is gone and the subscription should be pruned.

The default writes to the shared stream (correct for stdio, where all messages share one channel and the io.modelcontextprotocol/subscriptionId tag demultiplexes them). Transports that route per request (HTTP) override this to push onto that request's response stream.

Arguments

  • transport::Transport: The transport instance
  • route::Any: The handle returned by capture_response_route
  • message::String: The serialized JSON-RPC notification

Returns

  • Bool: true when the notification was delivered
source
ModelContextProtocol.deliver_responseMethod
deliver_response(transport::Transport, route::Any, message::String) -> Nothing

Deliver a serialized JSON-RPC response for a request whose route was captured earlier with capture_response_route. Safe to call from a background task. The default ignores the route and writes to the shared stream (correct for stdio, where write_message is lock-serialized).

Arguments

  • transport::Transport: The transport instance
  • route::Any: The handle returned by capture_response_route
  • message::String: The serialized JSON-RPC response

Returns

  • Nothing
source
ModelContextProtocol.flushMethod
flush(transport::Transport) -> Nothing

Flush any buffered data in the transport. Default implementation does nothing.

Arguments

  • transport::Transport: The transport instance to flush

Returns

  • Nothing
source
ModelContextProtocol.is_connectedFunction
is_connected(transport::Transport) -> Bool

Check if the transport is currently connected and operational.

Arguments

  • transport::Transport: The transport instance to check

Returns

  • Bool: true if connected and ready, false otherwise
source
ModelContextProtocol.notification_routeMethod
notification_route(transport::Transport) -> Any

Return the route handle identifying the request the transport just handed to the server loop, for request-scoped notification delivery. The loop stores it in task-local storage around message processing so send_notification can route notifications emitted during synchronous handling onto that request's response stream. The default returns nothing — stdio has a single shared stream, so notifications need no routing. HTTP overrides this with the current request's ID.

Arguments

  • transport::Transport: The transport instance

Returns

  • An opaque route handle, or nothing when the transport needs no routing
source
ModelContextProtocol.pending_auth_contextMethod
pending_auth_context(transport::Transport) -> Union{Nothing,Any}

Return the authenticated user associated with the message most recently read from transport, or nothing when the transport has no per-request authentication (e.g. stdio). Transports that authenticate requests override this; the default is nothing.

source
ModelContextProtocol.pending_param_headersMethod
pending_param_headers(transport::Transport) -> Union{Nothing,Dict{String,Any}}

Return the Mcp-Param-* custom headers (SEP-2243 parameter mirroring) of the message most recently read from transport: a Dict keyed by LOWERCASED header suffix, with String values (OWS-stripped) or :invalid for duplicated/unsafe headers — or nothing when the transport carries no HTTP headers (e.g. stdio), which disables the mirroring validation entirely. HTTP overrides this; the default is nothing.

source
ModelContextProtocol.read_messageFunction
read_message(transport::Transport) -> Union{String,Nothing}

Read a single message from the transport.

Arguments

  • transport::Transport: The transport instance to read from

Returns

  • Union{String,Nothing}: The message string if available, or nothing if no message or connection closed
source
ModelContextProtocol.route_aliveMethod
route_alive(transport::Transport, route::Any) -> Bool

Whether the client behind a captured response route is still reachable — used by subscription broadcasts to sweep dead streams without writing anything to them.

The default returns true: stream transports (stdio) have no per-request route whose death is observable here, and their delivery attempt reports failure itself. HTTP overrides this to check whether the route's channel still exists and is open.

Arguments

  • transport::Transport: The transport instance
  • route::Any: The handle returned by capture_response_route

Returns

  • Bool: true when the route may still deliver
source
ModelContextProtocol.send_notificationMethod
send_notification(transport::Transport, message::String) -> Nothing

Deliver a server-to-client JSON-RPC notification over transport.

The default writes the message directly — correct for stdio, where notifications and responses share one stream. Transports that multiplex per-request responses (e.g. HTTP, where write_message routes to the calling request's response channel) override this to send notifications over a separate out-of-band channel, so a mid-request notification never corrupts that request's response.

Arguments

  • transport::Transport: The transport instance to send over
  • message::String: The serialized JSON-RPC notification

Returns

  • Nothing
source
ModelContextProtocol.set_negotiated_version!Method
set_negotiated_version!(transport::Transport, version::String) -> Nothing

Inform the transport of the protocol version negotiated during initialize, so transports that advertise a version per response (e.g. the HTTP MCP-Protocol-Version header) echo the negotiated one rather than a static default. Default is a no-op (stdio carries no version metadata).

Arguments

  • transport::Transport: The transport instance to update
  • version::String: The negotiated MCP protocol version

Returns

  • Nothing
source
ModelContextProtocol.write_messageFunction
write_message(transport::Transport, message::String) -> Nothing

Write a message to the transport.

Arguments

  • transport::Transport: The transport instance to write to
  • message::String: The message to send

Returns

  • Nothing

Throws

  • TransportError: If the message cannot be sent
source
ModelContextProtocol.closeMethod
close(transport::StdioTransport) -> Nothing

Mark the transport as closed. Does not actually close stdin/stdout.

Arguments

  • transport::StdioTransport: The stdio transport instance

Returns

  • Nothing
source
ModelContextProtocol.flushMethod
flush(transport::StdioTransport) -> Nothing

Flush the output stream.

Arguments

  • transport::StdioTransport: The stdio transport instance

Returns

  • Nothing
source
ModelContextProtocol.is_connectedMethod
is_connected(transport::StdioTransport) -> Bool

Check if the stdio transport is connected.

Arguments

  • transport::StdioTransport: The stdio transport instance

Returns

  • Bool: Connection status
source
ModelContextProtocol.read_messageMethod
read_message(transport::StdioTransport) -> Union{String,Nothing}

Read a line from the input stream.

Arguments

  • transport::StdioTransport: The stdio transport instance

Returns

  • Union{String,Nothing}: The message string, or nothing if empty or EOF
source
ModelContextProtocol.write_messageMethod
write_message(transport::StdioTransport, message::String) -> Nothing

Write a message to the output stream with a newline.

Arguments

  • transport::StdioTransport: The stdio transport instance
  • message::String: The message to write

Returns

  • Nothing

Throws

  • TransportError: If writing fails
source
ModelContextProtocol.QueuedHttpRequestType
QueuedHttpRequest(id, body, user, param_headers=nothing)

Envelope for a request on the HTTP work queue. Carries the per-request authenticated user (or nothing) and the request's Mcp-Param-* custom headers (SEP-2243 parameter mirroring; nothing for messages that carry none) from the concurrent connection handler to the single server loop, so per-request context travels with the request rather than via shared transport state.

source
ModelContextProtocol.accepts_sseMethod
accepts_sse(accept_header::AbstractString) -> Bool

Whether an Accept header admits a text/event-stream response, per media-range matching: comma-separated ranges, media types compared case-insensitively with parameters stripped, text/* and */* admitted, and q=0 a refusal. The MOST SPECIFIC matching range decides (RFC 9110 precedence): exact text/event-stream over text/* over */* — so text/event-stream;q=0, text/*;q=1 is a refusal even though a laxer range matches. A bare substring test gets all of this wrong.

Pass the COMBINED value when the request repeats the Accept field (repeated fields are equivalent to their comma-joined concatenation).

Arguments

  • accept_header::AbstractString: The request's (combined) Accept header value

Returns

  • Bool: true when the client can consume an SSE response
source
ModelContextProtocol.broadcast_to_sseMethod
broadcast_to_sse(transport::HttpTransport, message::String; event::String="message") -> Nothing

Broadcast a message immediately to all SSE streams.

Arguments

  • transport::HttpTransport: The transport instance
  • message::String: The message to broadcast
  • event::String: The event type (default: "message")

Returns

  • Nothing
source
ModelContextProtocol.capture_response_routeMethod
capture_response_route(transport::HttpTransport) -> Union{String,Nothing}

Detach the current request's response route so its response can be delivered later from a background task (see deliver_response). Clears current_request_id so the loop's subsequent write_message calls cannot route into this request's channel.

source
ModelContextProtocol.closeMethod
close(transport::HttpTransport) -> Nothing

Stop the HTTP server and close all connections.

Arguments

  • transport::HttpTransport: The transport instance

Returns

  • Nothing
source
ModelContextProtocol.collect_param_headersMethod
collect_param_headers(request) -> Dict{String,Any}

Collect the request's Mcp-Param-* custom headers (SEP-2243 parameter mirroring) into a Dict keyed by LOWERCASED header suffix. Values are OWS-stripped Strings, or :invalid when the header is duplicated or carries unsafe bytes (the same rules mcp_standard_header applies) — the preflight in handle_modern_request rejects :invalid entries with -32020. Always returns a Dict (possibly empty) for HTTP requests: an EMPTY Dict still arms the missing-header-with-body-value check, which nothing (a transport with no headers at all, e.g. stdio) disables.

source
ModelContextProtocol.decode_mcp_header_valueMethod
decode_mcp_header_value(value::AbstractString) -> Union{String,Nothing}

Decode a standard-header value per SEP-2243: a =?base64?...?= sentinel wraps a Base64-encoded UTF-8 payload (used when the raw value is not header-safe). The Base64 is validated STRICTLY — canonical alphabet, correct padding, length a multiple of four — because Julia's decoder is permissive (it ignores invalid characters and missing padding), and SEP-2243 requires such values to be rejected, not fuzzily matched. The decoded bytes must be valid UTF-8. Returns nothing when the value must cause a -32020 rejection.

Arguments

  • value::AbstractString: The header value (already whitespace-stripped)

Returns

  • Union{String,Nothing}: The decoded value, or nothing when malformed
source
ModelContextProtocol.deliver_log_notificationMethod
deliver_log_notification(transport::HttpTransport, route, message::String) -> Bool

Push a request-scoped log notification onto the request's response stream. Unlike deliver_notification, backlog pressure NEVER closes the channel — the request's final response still has to travel it, and load-shedding it away because a stalled client let log records pile up would destroy the response. Past the cap the record is simply dropped (false), sending it to the logger's fallback stream instead.

source
ModelContextProtocol.deliver_notificationMethod
deliver_notification(transport::HttpTransport, route, message::String) -> Bool

Push a notification onto the response stream of the request identified by route (captured via capture_response_route) — the delivery path for subscriptions/listen streams. Returns false when that route is gone (client disconnected), so the caller can prune the subscription.

A listen stream lives arbitrarily long, so — unlike ordinary request channels, whose buffering is bounded by the request's own lifetime — its backlog must be capped: a reader that stopped draining would otherwise accumulate every notification forever. At LISTEN_BACKLOG_CAP pending items the stream is load-shed: its channel is closed (which ends the connection handler after it drains what is already buffered) and delivery is reported failed so the caller prunes the subscription.

source
ModelContextProtocol.deliver_responseMethod
deliver_response(transport::HttpTransport, route::Union{String,Nothing}, message::String) -> Nothing

Deliver a deferred response to the request identified by route (captured earlier via capture_response_route). The HTTP connection handler is still blocked on the request's response channel, so the POST stays open until this delivers — which is exactly the blocking behavior tasks/result requires. Dropped silently when the client has disconnected (its channel is gone or closed).

source
ModelContextProtocol.end_responseMethod
end_response(transport::HttpTransport) -> Nothing

Deprecated: No longer needed as HTTP transport now sends complete responses. This method exists for backward compatibility but does nothing.

Arguments

  • transport::HttpTransport: The transport instance

Returns

  • Nothing
source
ModelContextProtocol.format_sse_eventMethod
format_sse_event(data::String; event::Union{String,Nothing}=nothing, id::Union{Int64,String,Nothing}=nothing) -> String

Format a message as a Server-Sent Event.

Arguments

  • data::String: The data to send
  • event::Union{String,Nothing}: Optional event type
  • id::Union{Int64,String,Nothing}: Optional event ID

Returns

  • String: Formatted SSE event
source
ModelContextProtocol.generate_session_idMethod
generate_session_id() -> String

Generate a cryptographically secure session ID that meets MCP requirements. Must contain only visible ASCII characters (0x21 to 0x7E).

Returns

  • String: A valid session ID
source
ModelContextProtocol.handle_requestMethod
handle_request(transport::HttpTransport, stream::HTTP.Stream)

Handle incoming HTTP requests following the Streamable HTTP specification. Returns a single JSON response per request.

Arguments

  • transport::HttpTransport: The transport instance
  • stream::HTTP.Stream: The HTTP stream

Returns

  • Nothing
source
ModelContextProtocol.handle_sse_streamMethod
handle_sse_stream(transport::HttpTransport, stream::HTTP.Stream, stream_id::String)

Handle a Server-Sent Events connection for notifications and streaming responses.

Arguments

  • transport::HttpTransport: The transport instance
  • stream::HTTP.Stream: The HTTP stream
  • stream_id::String: Unique identifier for this SSE stream

Returns

  • Nothing
source
ModelContextProtocol.is_connectedMethod
is_connected(transport::HttpTransport) -> Bool

Check if the HTTP server is running and accepting connections.

Arguments

  • transport::HttpTransport: The transport instance

Returns

  • Bool: true if connected, false otherwise
source
ModelContextProtocol.is_loopback_hostMethod
is_loopback_host(host::AbstractString) -> Bool

Determine whether a hostname refers to the local loopback: localhost (optionally with a trailing dot), any 127.0.0.0/8 IPv4 address, ::1, or an IPv4-mapped IPv6 loopback (::ffff:127.x.y.z). String-list matching is not enough here — binding or addressing via 127.0.0.2 is just as local as 127.0.0.1.

Arguments

  • host::AbstractString: Hostname, IP literal, or bracketed IPv6 literal

Returns

  • Bool: true if the host is loopback
source
ModelContextProtocol.is_valid_session_idMethod
is_valid_session_id(session_id::String) -> Bool

Validate that a session ID contains only visible ASCII characters (0x21 to 0x7E).

Arguments

  • session_id::String: The session ID to validate

Returns

  • Bool: true if valid, false otherwise
source
ModelContextProtocol.mcp_standard_headerMethod
mcp_standard_header(request, name::String) -> Union{String,Nothing,Symbol}

Fetch a SEP-2243 standard header strictly: header names are matched case-insensitively across ALL header instances; duplicates (a smuggling vector — a gateway may honor a different copy than the backend) and values containing non-visible-ASCII bytes (NUL/control/8-bit, which HTTP.jl's parser admits but intermediaries interpret divergently) are rejected. Returns the single whitespace-stripped value, nothing when absent, or :invalid when the header must cause a -32020 rejection.

Arguments

  • request: The HTTP request
  • name::String: The header name

Returns

  • Union{String,Nothing,Symbol}: Value, nothing (absent), or :invalid
source
ModelContextProtocol.modern_error_http_statusMethod
modern_error_http_status(payload::String) -> Int

Map a modern-era JSON-RPC response to its HTTP status per the 2026-07-28 transport: -32601 (method not found) → 404; the protocol validation errors — -32020 HeaderMismatch, -32021 MissingRequiredClientCapability, -32022 UnsupportedProtocolVersion — → 400; everything else (results and application-level errors) → 200.

Arguments

  • payload::String: The serialized JSON-RPC response

Returns

  • Int: The HTTP status code to use
source
ModelContextProtocol.modern_header_violationMethod
modern_header_violation(request, msg, body_version) -> Union{String,Nothing}

Validate the SEP-2243 standard request headers of a modern-era POST against its body: MCP-Protocol-Version and Mcp-Method are required on every request and must match the body's _meta protocol version and method; Mcp-Name is required on tools/call/prompts/get (mirroring params.name) and resources/read (mirroring params.uri), with the Base64 sentinel decoded before comparison. Header names are case-insensitive, duplicates and unsafe bytes are rejected (mcp_standard_header), values are compared case-sensitively after whitespace stripping. (A request whose headers claim a modern era while the body carries no modern _meta never reaches this function — the caller rejects it as a missing required field, -32602.)

Arguments

  • request: The HTTP request (for header access)
  • msg: The parsed JSON body (a JSON3.Object)
  • body_version: The body's _meta protocol version

Returns

  • Union{String,Nothing}: A violation description for a -32020 HeaderMismatch, or nothing when the headers validate
source
ModelContextProtocol.notification_routeMethod
notification_route(transport::HttpTransport) -> Union{String,Nothing}

Return the HTTP request ID of the message just read from the queue, used by the server loop as the request-scoped notification route (see the base notification_route docstring).

source
ModelContextProtocol.parse_host_headerMethod
parse_host_header(hostport::AbstractString) -> Union{String,Nothing}

Parse a Host-header style host[:port] value strictly, returning the lowercased hostname or nothing when the value is malformed (userinfo, multiple colons on a non-bracketed host, junk after a bracketed IPv6 literal, non-numeric port). Malformed values must be REJECTED by the DNS-rebinding guard, not leniently truncated into something that looks local ([::1]evil.example must not read as [::1]).

Arguments

  • hostport::AbstractString: A Host-header style value

Returns

  • Union{String,Nothing}: The lowercased hostname (brackets kept for IPv6 literals), or nothing when malformed
source
ModelContextProtocol.pending_auth_contextMethod
pending_auth_context(transport::HttpTransport) -> Union{AuthenticatedUser,Nothing}

Return the authenticated user of the message most recently read from the queue (set in read_message, consumed immediately by the single server loop). This is how the per-request identity reaches RequestContext.authenticated_user; handlers should read it from the request context, not from the transport.

source
ModelContextProtocol.pending_param_headersMethod
pending_param_headers(transport::HttpTransport) -> Union{Nothing,Dict{String,Any}}

Return the Mcp-Param-* headers of the message most recently read from the queue (set in read_message, consumed immediately by the single server loop) — the SEP-2243 parameter-mirroring context validated by the handle_modern_request preflight.

source
ModelContextProtocol.read_messageMethod
read_message(transport::HttpTransport) -> Union{String,Nothing}

Read a message from the request queue. Waits a BOUNDED interval and returns nothing when no request arrives, so the server loop regularly re-checks its run condition: stop! must be able to end the loop while the transport is still open (graceful subscriptions/listen closure delivers on the open transport, then the transport is closed) — a blocking take! would pin the loop until the next request.

Arguments

  • transport::HttpTransport: The transport instance

Returns

  • Union{String,Nothing}: The message string, or nothing when no request arrived (or the transport disconnected)
source
ModelContextProtocol.rebinding_violationMethod
rebinding_violation(host_header, origin_header, allowed_hosts, allowed_origins) -> Union{String,Nothing}

Check Host and Origin headers against DNS-rebinding attacks on a loopback-bound server (GHSA-w48q-cv73-mx4w class): a malicious website resolves its own domain to 127.0.0.1 and drives the local server from the victim's browser. A legitimate local client sends a loopback Host; the attack necessarily carries the attacker's hostname. Malformed Host values are violations (see parse_host_header). allowed_hosts applies to the Host header only; Origin is admitted by loopback hostname or an exact allowed_origins match — a proxy hostname in allowed_hosts deliberately does NOT admit browser origins on that host.

Arguments

  • host_header: The request's Host header value ("" when absent)
  • origin_header: The request's Origin header value ("" when absent)
  • allowed_hosts: Extra hostnames accepted in Host (e.g. a reverse-proxy domain)
  • allowed_origins: Full origins accepted in Origin (exact match, existing semantics)

Returns

  • Union{String,Nothing}: A human-readable violation description, or nothing if the request is acceptable
source
ModelContextProtocol.route_aliveMethod
route_alive(transport::HttpTransport, route) -> Bool

Whether a captured response route still has a live consumer: its channel is still registered and open. The connection handler unregisters and closes the channel when its client disconnects (or its stream is load-shed), so a dead route shows up here without anything being written to it.

source
ModelContextProtocol.send_notificationMethod
send_notification(transport::HttpTransport, notification::String) -> Nothing

Send a notification. A notification emitted while the server loop is synchronously handling a request (progress, log messages) is request-scoped: it is routed onto that request's response channel and delivered on the POST's SSE response stream, per Streamable HTTP. Anything else — notifications from background tasks (MCP Tasks status updates) or emitted outside request handling — goes to the standalone GET SSE notification stream.

The request route is read from the server loop's task-local storage (set in run_server_loop), so background tasks — which never inherit it — can't misroute their notifications into whatever request the loop happens to be processing.

Arguments

  • transport::HttpTransport: The transport instance
  • notification::String: The notification message to send

Returns

  • Nothing
source
ModelContextProtocol.set_negotiated_version!Method
set_negotiated_version!(transport::HttpTransport, version::String) -> Nothing

Update the version advertised in MCP-Protocol-Version response headers (and accepted in request headers) to the version negotiated during initialize, so per-request headers echo what the initialize response returned.

source
ModelContextProtocol.split_outside_quotesMethod
split_outside_quotes(s::AbstractString, delim::Char) -> Vector{String}

Split s on delim occurrences that lie OUTSIDE double-quoted strings, honoring backslash escapes inside quotes (RFC 9110 quoted-string). Header parameters may legally quote separator characters (profile="a,b"), so a naive split corrupts the ranges around them.

Arguments

  • s::AbstractString: The header text to split
  • delim::Char: The separator character

Returns

  • Vector{String}: The parts (quotes preserved verbatim)
source
ModelContextProtocol.write_messageMethod
write_message(transport::HttpTransport, message::String) -> Nothing

Write a message to the current request's response channel. The request handler will send this as the HTTP response.

Arguments

  • transport::HttpTransport: The transport instance
  • message::String: The message to send

Returns

  • Nothing
source

Authentication Implementation

ModelContextProtocol.check_allowlistMethod
check_allowlist(user::AuthenticatedUser, allowlist::Set{String};
                case_insensitive::Bool=true) -> Bool

Check whether user is in the allowlist, by username then by subject.

Username matching honors case_insensitive (default true) because identity providers vary or normalize username case (e.g. Keycloak lowercases GitHub logins). The opaque OAuth subject is ALWAYS matched exactly — case-folding a stable identifier could collide two distinct principals.

Arguments

  • user::AuthenticatedUser: The authenticated user
  • allowlist::Set{String}: Set of allowed usernames or subjects
  • case_insensitive::Bool=true: Match usernames case-insensitively

Returns

true if user is allowed.

source
ModelContextProtocol.decode_jwt_headerMethod
decode_jwt_header(token::String) -> Union{Dict{String,Any},Nothing}

Decode the JWT header (first segment) without verification. Returns nothing if the token format is invalid.

source
ModelContextProtocol.decode_jwt_payloadMethod
decode_jwt_payload(token::String) -> Union{Dict{String,Any},Nothing}

Decode JWT payload without verification (for claim inspection). Returns nothing if token format is invalid.

source
ModelContextProtocol.fetch_jwks_http_bodyMethod
fetch_jwks_http_body(url::String) -> Union{String,Nothing}

GET a JWKS over HTTP(S) with bounded connect/read timeouts, streaming the body and aborting once MAX_JWKS_BYTES is exceeded. Returns the body string on a 200, or nothing on non-200, oversize, or transport error.

source
ModelContextProtocol.fetch_jwks_keysMethod
fetch_jwks_keys(url::String) -> Union{Vector{Dict{String,Any}},Nothing}

Fetch and parse the keys array of a JWKS document from an http(s):// or file:// URL. Network fetches use bounded connect/read timeouts and reject responses larger than MAX_JWKS_BYTES (read is aborted once the cap is exceeded, so an oversized or unbounded body cannot exhaust memory). Returns nothing on any failure (fetch, oversize, parse, or missing keys field) — callers fail closed.

source
ModelContextProtocol.lookup_jwks_key!Method
lookup_jwks_key!(validator::JWKSValidator, kid::String) -> Union{JWTs.JWK,Nothing}

Look up a verification key by kid, re-fetching the JWKS on a miss (key rotation) subject to the refresh rate limit. The network fetch happens outside the validator lock; the key-set swap and re-lookup happen under it.

source
ModelContextProtocol.auth_error_responseMethod
auth_error_response(error_code::Symbol, message::String) -> Tuple{Int,String,Dict{String,String}}

Generate HTTP response for authentication errors.

Returns

  • Tuple of (status_code, body, headers)
source
ModelContextProtocol.handle_well_known_requestMethod
handle_well_known_request(metadata::ProtectedResourceMetadata) -> Tuple{Int,String,Dict{String,String}}

Handle a request to the .well-known/oauth-protected-resource endpoint.

Returns

Tuple of (status_code, body, headers).

source
ModelContextProtocol.GitHubOAuthValidatorWithOrgType
GitHubOAuthValidatorWithOrg <: TokenValidator

Wrapper validator that adds organization membership checking.

Fields

  • base_validator::GitHubOAuthValidator: The underlying GitHub token validator
  • required_org::Union{String,Nothing}: Required organization membership
source
ModelContextProtocol.fetch_github_userMethod
fetch_github_user(token::String) -> Union{Dict{String,Any},Nothing}

Fetch user information from GitHub API using an access token. Returns nothing if the token is invalid or the request fails.

source

Utilities

ModelContextProtocol.MCPLoggerType
MCPLogger(stream::IO=stderr, level::LogLevel=Info) -> MCPLogger

Create a new MCPLogger instance with specified stream and level.

Arguments

  • stream::IO=stderr: The output stream where log messages will be written
  • level::LogLevel=Info: The minimum logging level to display

Returns

  • MCPLogger: A new logger instance
source
ModelContextProtocol.MCPLoggerType
MCPLogger <: AbstractLogger

Define a custom logger for MCP server that formats messages according to protocol requirements.

Once a LEGACY session is initialized, log records are delivered to the client as MCP notifications/message notifications via the server's transport (send_notification): stdio writes them to stdout alongside responses; Streamable HTTP delivers them on the originating request's SSE response stream (or the standalone notification stream when no request is being handled). Before initialization — or if transport delivery fails — records fall back to stream as JSON lines. Modern-era (2026-07-28+) requests never deliver through these ambient gates: a request that opted in via io.modelcontextprotocol/logLevel is served under a request-scoped ModernRequestLogger wrapping this logger, and every other modern request keeps the loop-armed suppression flag, so its records reach only the fallback stream.

Fields

  • stream::IO: Fallback output stream for log messages (used before the client initializes and when transport delivery is unavailable)
  • min_level::LogLevel: Minimum logging level to display (mutable so logging/setLevel can adjust it on the installed logger)
  • message_limits::Dict{Any,Int}: Message limit settings for rate limiting
  • transport::Any: The server transport notifications are delivered over (Union{Nothing,Transport}; typed Any to avoid include-order coupling)
  • transport_active::Base.RefValue{Bool}: Gate flipped on client initialization — notifications MUST NOT be emitted to a client that has not initialized
source
ModelContextProtocol.ModernRequestLoggerType
ModernRequestLogger(inner::MCPLogger, transport, route,
                    level::Union{String,Nothing}) <: AbstractLogger

The logging scope of ONE modern-era (2026-07-28+) request. handle_modern_request installs it around the serve path with with_logger, which is what makes every guarantee task-inheritance-proof: child tasks a handler spawns inherit the logstate (unlike task-local storage), so their records land here too, subject to the same rules as the serving task's.

Semantics per SEP-2575: with a requested level, records at or above it (RFC-5424) are delivered as notifications/message on the ORIGINATING request's response stream — the route captured at construction, pushed via deliver_log_notification (which never closes the request's response channel under backlog pressure) on the serving transport — never on the standalone GET stream, a subscriptions/listen stream, or another server's transport. A level is only ever set when the arming site verified the current logger serves this server's transport; an identity-MISMATCHED MCPLogger (another server's) still gets a scope, but a wire-silent one (level = nothing), so child tasks cannot deliver through the foreign transport either. Without a level (no opt-in, no logging capability, or that mismatch), nothing is ever delivered. Delivery ends when closed is set (the final response is on its way) or the response channel is gone — late records are dropped, not diverted. Undelivered records fall back to the operator's inner.stream under inner's own min_level, so a debug opt-in below the operator's level never spams stderr.

Fields

  • inner::MCPLogger: The server's installed logger (fallback stream + operator level)
  • transport::Any: The serving server's transport
  • route::Any: The request's captured notification route
  • level::Union{String,Nothing}: The validated requested MCP level, or nothing for a wire-silent scope
  • closed::Base.RefValue{Bool}: Set once the request's response is under way
  • lk::ReentrantLock: Serializes delivery against closure — close_scope! takes it to flip closed, so a child task's in-flight delivery either completes before the final response or observes closed and drops; the check-then-deliver window is never open across teardown
source
Logging.handle_messageMethod
Logging.handle_message(logger::MCPLogger, level, message, _module, group, id, filepath, line; kwargs...) -> Nothing

Format and output log messages according to the MCP protocol format.

Arguments

  • logger::MCPLogger: The MCP logger instance
  • level: The log level of the message
  • message: The log message content
  • _module: The module where the log was generated
  • group: The log group
  • id: The log message ID
  • filepath: The source file path
  • line: The source line number
  • kwargs...: Additional contextual information to include in the log

Returns

  • Nothing: Function writes to the logger stream but doesn't return a value
source
ModelContextProtocol.close_scope!Method
close_scope!(logger::ModernRequestLogger) -> Nothing

End a request's logging scope: after this, no record is delivered on the request's response stream. Taking the delivery lock makes closure wait out any in-flight delivery, so a notification can never trail the final response.

Arguments

  • logger::ModernRequestLogger: The scope to close

Returns

  • Nothing
source
ModelContextProtocol.format_log_notificationMethod
format_log_notification(level, message, _module, filepath, line; kwargs...) -> (String, String)

Build the wire form of a log record as an MCP notifications/message.

Arguments

  • level: The Julia LogLevel of the record
  • message: The log message content
  • _module: The module where the log was generated
  • filepath: The source file path
  • line: The source line number
  • kwargs...: Additional context, stringified into the metadata

Returns

  • Tuple{String,String}: The MCP level name and the serialized JSON-RPC notification
source
ModelContextProtocol.init_loggingFunction
init_logging(level::LogLevel=Info) -> Nothing

Initialize logging for the MCP server with a custom MCP-formatted logger.

Arguments

  • level::LogLevel=Info: The minimum logging level to display

Returns

  • Nothing: Function sets the global logger but doesn't return a value
source
ModelContextProtocol.mcp_level_severityMethod
mcp_level_severity(level::String) -> Int

The RFC-5424 severity rank of an MCP log level (1 = debug, lowest … 8 = emergency, highest), for at-or-above comparisons.

Arguments

  • level::String: One of MCP_LOG_LEVELS

Returns

  • Int: The 1-based rank within MCP_LOG_LEVELS (unrecognized levels rank highest, so they never widen delivery)
source
ModelContextProtocol.mcp_level_to_juliaMethod
mcp_level_to_julia(level::String) -> LogLevel

Map an MCP/RFC-5424 log level string to the closest Julia LogLevel.

Arguments

  • level::String: One of MCP_LOG_LEVELS

Returns

  • LogLevel: Debug, Info, Warn, or Error (the four Julia standard levels)
source
StructTypes.namesMethod
StructTypes.names(::Type{CallToolResult})

Map Julia field names to their MCP wire keys: is_errorisError (the spec key — clients rely on it to detect tool errors) and structured_contentstructuredContent.

source
StructTypes.omitemptiesMethod
StructTypes.omitempties(::Type{CallToolResult}) -> Tuple{Symbol,Symbol}

Omit structured_content and _meta from the response when they are nothing, so tools that don't use them emit no structuredContent/_meta keys.

source
StructTypes.omitemptiesMethod
StructTypes.omitempties(::Type{ClientCapabilities}) -> Tuple{Symbol,Symbol,Symbol}

Specify which fields should be omitted from JSON serialization when they are empty or null.

Arguments

  • ::Type{ClientCapabilities}: The ClientCapabilities type

Returns

  • Tuple{Symbol,Symbol,Symbol}: Fields to omit when empty
source
StructTypes.omitemptiesMethod
StructTypes.omitempties(::Type{ListPromptsResult}) -> Tuple{Symbol}

Specify which fields should be omitted from JSON serialization when they are empty or null.

Arguments

  • ::Type{ListPromptsResult}: The ListPromptsResult type

Returns

  • Tuple{Symbol}: Fields to omit when empty
source