Skip to content

Latest commit

 

History

24 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Mcparen

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.

Use

(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.

JSON values

Public raw MCP values use these exact Common Lisp representations:

  • JSON objects are hash tables with equal keys
  • JSON arrays are vectors
  • JSON strings and numbers are Common Lisp strings and numbers
  • JSON true, false, and null are returned by json-true-value, json-false-value, and json-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.

Lifecycle

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.

Managed connections

Load mcparen/managed for shared restartable connections and discovery snapshots. Construct mcp-managed-server instances with :name, :required-p and either :client or :client-factory. A factory receives the server and a notification callback; pass that callback to the transport constructor.

(asdf:load-system :mcparen/managed)
(defparameter *servers*
  (make-instance 'mcparen:mcp-connection-manager
                 :maximum-schema-bytes (* 1024 1024)
                 :runtimes
                 (list (make-instance
                        'mcparen:mcp-managed-server :name "example"
                        :client-factory
                        (lambda (server notification-handler)
                          (declare (ignore server))
                          (mcparen:make-mcp-client
                           (mcparen:make-mcp-streamable-http-transport
                            "https://example.test/mcp"
                            :notification-handler notification-handler)))))))
(unwind-protect
     (progn
       (mcparen:mcp-manager-start *servers*)
       (mcparen:mcp-manager-snapshot *servers*))
  (mcparen:mcp-manager-close *servers*))

Use mcp-manager-build with zero-argument server factories for cleanup across factory and partial-startup failures. A server has one lifecycle owner; share that manager among application consumers. Required servers receive aggregate schema budget first, preserving presentation order. Optional failures are isolated, and failed discovery is cached until a refresh is requested.

Use mcp-manager-refresh for explicit rediscovery, or mcp-server-runtime-connect at use boundaries. Notifications and transparent reconnections invalidate discovery. Read detached mcp-discovery-snapshot values through mcp-server-runtime-snapshot or mcp-manager-snapshot; each contains state, capabilities, generation, revision, tools and a diagnostic. Use mcp-manager-collect to aggregate resources or prompts, supplying a client list function and optionally an item identity function. Results and failures are separate, server-qualified lists; duplicate identities within a server are rejected when an identity function is supplied. Use mcp-server-runtime-call for scoped client operations. Consume or project secret-bearing results inside its callback before returning to the caller.

Specialize the mcp-managed- protocol for credential scopes, diagnostic redaction, metadata projection and provider-specific schema validation. mcp-managed-credential-key returns a non-secret identity of the exact active credential snapshot and an optional resolution condition; enable persistent identity checks with mcp-managed-credential-check-p. Specialize mcp-managed-call-with-local-cleanup when local fallback needs application bindings without fresh credential resolution. Before callback entry, errors and nonlocal scope exits still trigger exactly one local teardown attempt. Use mcp-server-runtime-cancel to interrupt in-flight requests before closing. Close and detach leave connections restartable. Manager teardown is serialized against discovery.

The lock order is manager, server, then notification revision. Scope and projection methods run synchronously. Within those methods, inspect the given server rather than reentering manager operations.

Tests

./script/check

Part of the Lambda Symbolics library shelf.

About

MCP client library for Common Lisp

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages