Mcparen is a small Common Lisp client for the Model Context Protocol. Its core loads on SBCL and Clozure CL on Unix-like systems and implements MCP 2025-11-25 and 2025-06-18 over standard I/O and Streamable HTTP. It requests the newer revision and accepts the older revision when selected during protocol negotiation.
The library handles:
- JSON-RPC lifecycle
- concurrent requests
- typed errors
- timeouts and cancellation
- cursor pagination
- tool calls, resources, and prompts
- HTTP sessions
- bounded process cleanup
List pagination is bounded before pages are accumulated. One list operation may
read at most 1,000 pages and retain at most 10,000 items, 16 MiB of conservative
encoded item and cursor data, and 100,000 item and cursor tree nodes. Session
restarts begin a fresh accumulation and are limited to eight attempts. These
reloadable bounds are exported with the *mcp-pagination- prefix.
(ql:quickload :mcparen)Create a lazy Streamable HTTP client:
(defparameter *client*
(mcparen:make-mcp-client
(mcparen:make-mcp-streamable-http-transport
"https://example.test/mcp"
:headers-function
(lambda ()
(let ((token (uiop:getenv "EXAMPLE_MCP_TOKEN")))
(and token
(list (cons "Authorization"
(format nil "Bearer ~A" token)))))))
:name "example-client"
:version "1.0.0"))
(unwind-protect
(progn
(mcparen:mcp-client-connect *client*)
(dolist (tool (mcparen:mcp-client-list-tools *client*))
(format t "~A: ~A~%"
(mcparen:mcp-tool-name tool)
(mcparen:mcp-tool-description tool))))
(mcparen:mcp-client-close *client*))Create a standard I/O client:
(mcparen:make-mcp-client
(mcparen:make-mcp-stdio-transport
"/absolute/path/to/server"
:arguments '("--stdio")
:directory #P"/workspace/"))Credential providers run at request or process-launch time. Callers can retain environment-variable names instead of secret values in long-lived objects.
Streamable HTTP transports also accept :exchange-scope-function. This function
receives and synchronously invokes a zero-argument thunk around each complete
HTTP exchange, from late header resolution through response parsing and
dispatch. It can establish application-owned dynamic state for normal requests,
SSE resumptions, idle listener cycles, and session deletion.
Both transport constructors accept :maximum-message-characters. The default
is 16 MiB. Mcparen rejects larger standard I/O messages, HTTP JSON bodies, SSE
lines, and aggregate SSE event data before retaining an unbounded document.
Outbound documents are checked against the same transport-specific limit before
encoding.
Public raw MCP values use these exact Common Lisp representations:
- JSON objects are hash tables with
equalkeys - JSON arrays are vectors
- JSON strings and numbers are Common Lisp strings and numbers
- JSON
true,false, andnullare returned byjson-true-value,json-false-value, andjson-null-value
json-object constructs an object from alternating string keys and values.
These representations are also used by tool schemas, raw tool metadata, tool
arguments, structured results, resources, and prompts.
mcp-client-connect performs initialize followed by
notifications/initialized. Public operations reconnect a deliberately closed
client when it is used again. mcp-client-close terminates owned resources.
mcp-client-detach only closes inherited descriptors and is suitable for a
forked image that must not signal a parent-owned server.
On supported POSIX systems, a standard I/O server must enter a process group led by its direct child process. Shutdown closes stdin, then uses bounded TERM and KILL phases.
./script/checkPart of the Lambda Symbolics library shelf.