MCP Client & Server
Types and functions for the Model Context Protocol — connecting to MCP servers and building MCP servers in Julia.
Client Types
UniLM.MCPSession — Type
MCPSessionA live connection to an MCP server. Manages lifecycle, transport, and cached tool/resource/prompt lists.
Create via mcp_connect. Disconnect via mcp_disconnect!.
UniLM.MCPToolInfo — Type
MCPToolInfoA tool definition received from an MCP server via tools/list. Convert to CallableTool via mcp_tools or mcp_tools_respond.
UniLM.MCPResourceInfo — Type
MCPResourceInfoA resource definition received from an MCP server via resources/list.
UniLM.MCPPromptInfo — Type
MCPPromptInfoA prompt definition received from an MCP server via prompts/list.
UniLM.MCPServerCapabilities — Type
MCPServerCapabilitiesCapabilities declared by an MCP server during initialization.
UniLM.MCPTransport — Type
MCPTransportAbstract 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
UniLM.StdioTransport — Type
StdioTransport <: MCPTransportStdio transport: launches a subprocess and communicates via stdin/stdout. Messages are newline-delimited JSON-RPC 2.0.
UniLM.HTTPTransport — Type
HTTPTransport <: MCPTransportStreamable HTTP transport: communicates via POST requests to an MCP endpoint. Handles Mcp-Session-Id header for session management.
UniLM.MCPError — Type
MCPError <: ExceptionError from MCP protocol operations. Contains the JSON-RPC error code, message, and optional data from the server.
Client Functions
Lifecycle
UniLM.mcp_connect — Function
mcp_connect(command::Cmd; client_name="UniLM.jl", protocol_version="2025-11-25") -> MCPSessionConnect 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)mcp_connect(url::String; headers=[], kwargs...) -> MCPSessionConnect to an MCP server via HTTP transport.
Example
session = mcp_connect("https://mcp.example.com/mcp";
headers=["Authorization" => "Bearer token"])mcp_connect(transport::MCPTransport; client_name="UniLM.jl", protocol_version="2025-11-25") -> MCPSessionConnect to an MCP server via the given transport. Performs initialization handshake and populates tool cache.
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)
endUniLM.mcp_disconnect! — Function
mcp_disconnect!(session::MCPSession)Gracefully disconnect from the MCP server.
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.
UniLM.list_resources! — Function
list_resources!(session::MCPSession) -> Vector{MCPResourceInfo}Fetch the resource list from the MCP server. Handles pagination.
UniLM.list_prompts! — Function
list_prompts!(session::MCPSession) -> Vector{MCPPromptInfo}Fetch the prompt list from the MCP server. Handles pagination.
Operations
UniLM.call_tool — Function
call_tool(session::MCPSession, name::String, arguments::Dict{String,Any}) -> StringCall a tool on the MCP server and return the result as a string. Concatenates text content parts; non-text content is JSON-encoded.
UniLM.read_resource — Function
read_resource(session::MCPSession, uri::String) -> StringRead a resource from the MCP server.
UniLM.get_prompt — Function
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.
UniLM.ping — Function
ping(session::MCPSession)Send a ping to the MCP server. Throws on error.
Tool Bridge
UniLM.mcp_tools — Function
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)UniLM.mcp_tools_respond — Function
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)Server Types
UniLM.MCPServer — Type
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 defaultUniLM.MCPServerPrimitive — Type
MCPServerPrimitiveAbstract supertype for MCP server-side primitives (tools, resources, prompts).
UniLM.MCPServerTool — Type
MCPServerTool <: MCPServerPrimitiveA 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 namedescription::Union{String,Nothing}: Human-readable descriptioninput_schema::Dict{String,Any}: JSON Schema for the input parametershandler::Function:(args::Dict{String,Any}) -> Any
UniLM.MCPServerResource — Type
MCPServerResource <: MCPServerPrimitiveA static resource registered on an MCP server.
Fields
uri::String: Resource URIname::String: Human-readable namedescription::Union{String,Nothing}: Descriptionmime_type::String: MIME type (default"text/plain")handler::Function:() -> Union{String, Vector{UInt8}}
UniLM.MCPServerResourceTemplate — Type
MCPServerResourceTemplate <: MCPServerPrimitiveA 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 namedescription::Union{String,Nothing}: Descriptionmime_type::String: MIME typehandler::Function:(params::Dict{String,String}) -> Union{String, Vector{UInt8}}_pattern::Regex: Compiled regex from template_param_names::Vector{String}: Extracted parameter names
UniLM.MCPServerPrompt — Type
MCPServerPrompt <: MCPServerPrimitiveA prompt template registered on an MCP server.
Fields
name::String: Unique prompt namedescription::Union{String,Nothing}: Descriptionarguments::Vector{Dict{String,Any}}: Argument definitionshandler::Function:(args::Dict{String,Any}) -> Vector{Dict{String,Any}}
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.
register_tool!(server, name, description, handler)Register a tool with schema auto-inferred from the handler's type signature.
register_tool!(server, ct::CallableTool{GPTTool})Register a CallableTool{GPTTool} on the MCP server, bridging from UniLM's Chat Completions tool type.
register_tool!(server, ct::CallableTool{FunctionTool})Register a CallableTool{FunctionTool} on the MCP server, bridging from UniLM's Responses API tool type.
UniLM.register_resource! — Function
register_resource!(server, uri, name, handler; mime_type="text/plain", description=nothing)Register a static resource on the MCP server.
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.
UniLM.register_prompt! — Function
register_prompt!(server, name, handler; description=nothing, arguments=Dict{String,Any}[])Register a prompt template on the MCP server.
Serving
UniLM.serve — Function
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. Acceptshost(default"127.0.0.1") andport(default8080).
Examples
serve(server) # stdio (default)
serve(server; transport=:http, port=3000) # HTTP on port 3000Macros
UniLM.@mcp_tool — Macro
@mcp_tool server function name(args...)::ReturnType body endRegister 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)
endUniLM.@mcp_resource — Macro
@mcp_resource server uri_or_template function(args...) body endRegister 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)
endUniLM.@mcp_prompt — Macro
@mcp_prompt server name function(args...) body endRegister 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"))]
endExample
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"]