MCP Client & Server

Types and functions for the Model Context Protocol — connecting to MCP servers and building MCP servers in Julia.

Client Types

UniLM.MCPTransportType
MCPTransport

Abstract type for MCP transport implementations. Subtypes must implement:

  • _transport_connect!(t) — establish connection
  • _transport_send!(t, msg::String)::String — send JSON-RPC message, return response
  • _transport_notify!(t, msg::String) — send notification (no response expected)
  • _transport_disconnect!(t) — close connection
  • _transport_isconnected(t)::Bool — check if connected
source
UniLM.StdioTransportType
StdioTransport <: MCPTransport

Stdio transport: launches a subprocess and communicates via stdin/stdout. Messages are newline-delimited JSON-RPC 2.0.

source
UniLM.HTTPTransportType
HTTPTransport <: MCPTransport

Streamable HTTP transport: communicates via POST requests to an MCP endpoint. Handles Mcp-Session-Id header for session management.

source
UniLM.MCPErrorType
MCPError <: Exception

Error from MCP protocol operations. Contains the JSON-RPC error code, message, and optional data from the server.

source

Client Functions

Lifecycle

UniLM.mcp_connectFunction
mcp_connect(command::Cmd; client_name="UniLM.jl", protocol_version="2025-11-25") -> MCPSession

Connect to an MCP server via stdio transport (subprocess).

Example

session = mcp_connect(`npx -y @modelcontextprotocol/server-filesystem /tmp`)
tools = mcp_tools(session)
# ... use tools with tool_loop! ...
mcp_disconnect!(session)
source
mcp_connect(url::String; headers=[], kwargs...) -> MCPSession

Connect to an MCP server via HTTP transport.

Example

session = mcp_connect("https://mcp.example.com/mcp";
    headers=["Authorization" => "Bearer token"])
source
mcp_connect(transport::MCPTransport; client_name="UniLM.jl", protocol_version="2025-11-25") -> MCPSession

Connect to an MCP server via the given transport. Performs initialization handshake and populates tool cache.

source
mcp_connect(f::Function, args...; kwargs...)

Do-block form: automatically disconnects after the block executes.

Example

mcp_connect(`npx server`) do session
    tools = mcp_tools(session)
    chat = Chat(tools=map(t -> t.tool, tools))
    push!(chat, Message(Val(:user), "List files"))
    tool_loop!(chat; tools)
end
source

Discovery

UniLM.list_tools!Function
list_tools!(session::MCPSession) -> Vector{MCPToolInfo}

Fetch the tool list from the MCP server. Handles pagination via cursor. Stores result in session.tools.

source
UniLM.list_resources!Function
list_resources!(session::MCPSession) -> Vector{MCPResourceInfo}

Fetch the resource list from the MCP server. Handles pagination.

source
UniLM.list_prompts!Function
list_prompts!(session::MCPSession) -> Vector{MCPPromptInfo}

Fetch the prompt list from the MCP server. Handles pagination.

source

Operations

UniLM.call_toolFunction
call_tool(session::MCPSession, name::String, arguments::Dict{String,Any}) -> String

Call a tool on the MCP server and return the result as a string. Concatenates text content parts; non-text content is JSON-encoded.

source
UniLM.read_resourceFunction
read_resource(session::MCPSession, uri::String) -> String

Read a resource from the MCP server.

source
UniLM.get_promptFunction
get_prompt(session::MCPSession, name::String, arguments::Dict{String,Any}=Dict()) -> Vector{Dict{String,Any}}

Get a rendered prompt from the MCP server. Returns the messages array.

source
UniLM.pingFunction
ping(session::MCPSession)

Send a ping to the MCP server. Throws on error.

source

Tool Bridge

UniLM.mcp_toolsFunction
mcp_tools(session::MCPSession) -> Vector{CallableTool{GPTTool}}

Convert all tools from an MCP session into CallableTool{GPTTool} instances that work directly with tool_loop! (Chat Completions API).

Each tool's callable invokes call_tool(session, name, args) under the hood.

Example

session = mcp_connect(`npx server`)
tools = mcp_tools(session)
chat = Chat(model="gpt-5.2", tools=map(t -> t.tool, tools))
push!(chat, Message(Val(:user), "Do something"))
result = tool_loop!(chat; tools)
source
UniLM.mcp_tools_respondFunction
mcp_tools_respond(session::MCPSession) -> Vector{CallableTool{FunctionTool}}

Convert all tools from an MCP session into CallableTool{FunctionTool} instances that work directly with tool_loop (Responses API).

Example

session = mcp_connect("https://mcp.example.com/mcp")
tools = mcp_tools_respond(session)
result = tool_loop("Do something"; tools=tools)
source

Server Types

UniLM.MCPServerType
MCPServer(name, version; description=nothing)

An MCP server that can host tools, resources, and prompts.

Register primitives via register_tool!, register_resource!, register_prompt!, or the @mcp_tool, @mcp_resource, @mcp_prompt macros.

Start serving via serve.

Example

server = MCPServer("my-server", "1.0.0")
register_tool!(server, "add", "Add two numbers",
    Dict("type"=>"object", "properties"=>Dict("a"=>Dict("type"=>"number"),"b"=>Dict("type"=>"number")), "required"=>["a","b"]),
    args -> string(args["a"] + args["b"]))
serve(server)  # stdio by default
source
UniLM.MCPServerToolType
MCPServerTool <: MCPServerPrimitive

A tool registered on an MCP server. The handler receives Dict{String,Any} arguments and returns any value (converted to text content by the server).

Fields

  • name::String: Unique tool name
  • description::Union{String,Nothing}: Human-readable description
  • input_schema::Dict{String,Any}: JSON Schema for the input parameters
  • handler::Function: (args::Dict{String,Any}) -> Any
source
UniLM.MCPServerResourceType
MCPServerResource <: MCPServerPrimitive

A static resource registered on an MCP server.

Fields

  • uri::String: Resource URI
  • name::String: Human-readable name
  • description::Union{String,Nothing}: Description
  • mime_type::String: MIME type (default "text/plain")
  • handler::Function: () -> Union{String, Vector{UInt8}}
source
UniLM.MCPServerResourceTemplateType
MCPServerResourceTemplate <: MCPServerPrimitive

A URI-templated resource. Template variables like {path} are extracted and passed to the handler.

Fields

  • uri_template::String: URI template (e.g., "file://{path}")
  • name::String: Human-readable name
  • description::Union{String,Nothing}: Description
  • mime_type::String: MIME type
  • handler::Function: (params::Dict{String,String}) -> Union{String, Vector{UInt8}}
  • _pattern::Regex: Compiled regex from template
  • _param_names::Vector{String}: Extracted parameter names
source
UniLM.MCPServerPromptType
MCPServerPrompt <: MCPServerPrimitive

A prompt template registered on an MCP server.

Fields

  • name::String: Unique prompt name
  • description::Union{String,Nothing}: Description
  • arguments::Vector{Dict{String,Any}}: Argument definitions
  • handler::Function: (args::Dict{String,Any}) -> Vector{Dict{String,Any}}
source

Server Functions

Registration

UniLM.register_tool!Function
register_tool!(server, name, description, input_schema, handler)

Register a tool on the MCP server with an explicit JSON Schema.

source
register_tool!(server, name, description, handler)

Register a tool with schema auto-inferred from the handler's type signature.

source
register_tool!(server, ct::CallableTool{GPTTool})

Register a CallableTool{GPTTool} on the MCP server, bridging from UniLM's Chat Completions tool type.

source
register_tool!(server, ct::CallableTool{FunctionTool})

Register a CallableTool{FunctionTool} on the MCP server, bridging from UniLM's Responses API tool type.

source
UniLM.register_resource!Function
register_resource!(server, uri, name, handler; mime_type="text/plain", description=nothing)

Register a static resource on the MCP server.

source
UniLM.register_resource_template!Function
register_resource_template!(server, uri_template, name, handler; mime_type="text/plain", description=nothing)

Register a URI-templated resource on the MCP server.

source
UniLM.register_prompt!Function
register_prompt!(server, name, handler; description=nothing, arguments=Dict{String,Any}[])

Register a prompt template on the MCP server.

source

Serving

UniLM.serveFunction
serve(server::MCPServer; transport=:stdio, kwargs...)

Start the MCP server using the specified transport.

Transports

  • :stdio (default): Read from stdin, write to stdout. For Claude Desktop/CLI integration.
  • :http: HTTP server. Accepts host (default "127.0.0.1") and port (default 8080).

Examples

serve(server)                            # stdio (default)
serve(server; transport=:http, port=3000)  # HTTP on port 3000
source

Macros

UniLM.@mcp_toolMacro
@mcp_tool server function name(args...)::ReturnType body end

Register a tool on server with auto-generated JSON Schema from the function signature.

Example

server = MCPServer("calc", "1.0.0")
@mcp_tool server function add(a::Float64, b::Float64)::String
    string(a + b)
end
source
UniLM.@mcp_resourceMacro
@mcp_resource server uri_or_template function(args...) body end

Register a resource or resource template on server. If the URI contains {...} placeholders, it is registered as a template.

Examples

@mcp_resource server "config://app" function()
    read("config.toml", String)
end

@mcp_resource server "file://{path}" function(path::String)
    read(path, String)
end
source
UniLM.@mcp_promptMacro
@mcp_prompt server name function(args...) body end

Register a prompt on server. The handler should return a Vector of message Dicts.

Example

@mcp_prompt server "review" function(code::String)
    [Dict("role" => "user", "content" => Dict("type" => "text", "text" => "Review: $code"))]
end
source

Example

using UniLM
using JSON

# Construct client info types
info = MCPToolInfo(Dict{String,Any}(
    "name" => "read_file",
    "description" => "Read a file from disk",
    "inputSchema" => Dict{String,Any}(
        "type" => "object",
        "properties" => Dict{String,Any}(
            "path" => Dict{String,Any}("type" => "string")
        )
    )
))
println("Tool: ", info.name, " — ", info.description)
Tool: read_file — Read a file from disk
# Build and populate a server
server = MCPServer("demo", "1.0.0")
register_tool!(server, "add", "Add two numbers",
    Dict{String,Any}(
        "type" => "object",
        "properties" => Dict{String,Any}(
            "a" => Dict{String,Any}("type" => "number"),
            "b" => Dict{String,Any}("type" => "number")
        ),
        "required" => ["a", "b"]
    ),
    args -> string(args["a"] + args["b"]))
println("Server: ", server.name, " v", server.version)
println("Tools: ", collect(keys(server.tools)))
Server: demo v1.0.0
Tools: ["add"]