- Description: The framework for building
MCPservers and clients in Common Lisp. - Licence: Unlicense
- Author: Alexander Artemenko svetlyak.40wt@gmail.com
- Homepage: https://40ants.com/mcp/
- Bug tracker: https://github.com/40ants/mcp/issues
- Source control: GIT
- Depends on: alexandria, bordeaux-threads, cl-ppcre, clack, clack-sse, jsonrpc, lack, lack-request, lack-response, local-time, log4cl, log4cl-extras, openrpc-client, openrpc-server, sento, serapeum, sse-server, trivial-gray-streams, uuid, yason
A comprehensive framework for building Model Context Protocol (MCP) servers in Common Lisp. This library provides a complete implementation of the MCP specification with an easy-to-use API for creating servers that can interact with AI assistants like Claude Desktop.
Active development is ongoing and the interface is likely to change.
- ✅
STDIOTransport: Native support forSTDIO-based communication - ✅ Streamable
HTTPTransport: Allowing to create remotely hostedMCPservers - ✅ Tools System: Register and execute custom tools with
JSONSchema validation - ✅ Built on Open
RPC: Leverages the robust 40ants OpenRPC library - ✅
CLOS-based: Object-oriented design with proper encapsulation - ✅ Easy Integration: Simple
APIfor adding functionality - ✅ Error Handling: Comprehensive error management with proper
JSON-RPCerror codes - ✅ Interactive Editing:
MCPtools can be edited and updated on the fly, usingREPLdriven approach
- 🔄 Full
MCPSpecification Support: Complete implementation ofMCPprotocol version 2025-06-18 - 🔄 Resources System: Serve dynamic and static resources via
URI - 🔄 Prompts System: Provide prompt templates with argument interpolation
- 🔄
MCPClient Protocol: Implement client-side protocol for connecting toMCPservers
You can install this library from Quicklisp, but you want to receive updates quickly, then install it from Ultralisp.org:
(ql-dist:install-dist "http://dist.ultralisp.org/"
:prompt nil)
(ql:quickload :40ants-mcp)
Here's a quick example of how to create an MCP server with custom tools:
(defpackage #:my-mcp-server
(:use #:cl)
(:import-from #:40ants-mcp/content/text
#:text-content)
(:import-from #:openrpc-server))
(in-package #:my-mcp-server)
;; Define your API
(openrpc-server:define-api (my-tools :title "My Custom Tools"))
;; Define a tool that adds two numbers
(40ants-mcp/tools:define-tool (my-tools add) (a b)
(:summary "Adds two numbers and returns the result.")
(:param a integer "First number to add.")
(:param b integer "Second number to add.")
(:result (soft-list-of text-content))
(list (make-instance 'text-content
:text (format nil "The sum of ~A and ~A is: ~A"
a b (+ a b)))))
;; Start the server
(40ants-mcp/server/definition:start-server my-tools)
For production use, you can create a Roswell script. Create a file my-mcp.ros:
#!/bin/sh
#|-*- mode:lisp -*-|#
#|
exec ros -Q -- $0 \"$@\"
|#
(ql:quickload '(:40ants-mcp :alexandria) :silent t)
;; Your package and tool definitions here...
(defun main (&rest argv)
(declare (ignore argv))
(40ants-mcp/server/definition:start-server my-tools))
Build and run the script:
# Build the script
ros build my-mcp.ros
# Run the server
./my-mcp
# With remote debugging support
SLYNK_PORT=4005 ./my-mcp
Each tool you define should return a list of content items. The most common content type is text-content, but you can also return other types defined in the MCP specification.
For more examples, check the examples/ directory in the source code.
package 40ants-mcp/content/base
class 40ants-mcp/content/base:content ()
Readers
reader 40ants-mcp/content/base:content-type (content) (:TYPE = "unknown")
package 40ants-mcp/content/text
class 40ants-mcp/content/text:text-content (content)
Readers
reader 40ants-mcp/content/text:content-text (text-content) (:text)
package 40ants-mcp/http-transport
class 40ants-mcp/http-transport:http-transport ()
HTTP transport implementation for MCP (Model Context Protocol) communication.
This class handles JSON-RPC message exchange via HTTP POST requests.
Readers
reader 40ants-mcp/http-transport:transport-lack-app (http-transport) ()
Lack application instance
reader 40ants-mcp/http-transport:transport-message-handler (http-transport) ()
Function to handle incoming messages
reader 40ants-mcp/http-transport:transport-port (http-transport) (:port = 8080)
Port number to listen on.
reader 40ants-mcp/http-transport:transport-running-p (http-transport) (= t)
Flag indicating if transport is active
reader 40ants-mcp/http-transport:transport-server (http-transport) ()
Clack server instance
Accessors
accessor 40ants-mcp/http-transport:transport-lack-app (http-transport) ()
Lack application instance
accessor 40ants-mcp/http-transport:transport-message-handler (http-transport) ()
Function to handle incoming messages
accessor 40ants-mcp/http-transport:transport-running-p (http-transport) (= t)
Flag indicating if transport is active
accessor 40ants-mcp/http-transport:transport-server (http-transport) ()
Clack server instance
package 40ants-mcp/server/definition
class 40ants-mcp/server/definition:mcp-server (api)
Readers
reader 40ants-mcp/server/definition:server-tools-collections (mcp-server) (collections = nil)
function 40ants-mcp/server/definition:start-server tools-collections &key (transport :stdio) (port 8080)
Start the MCP server with specified transport.
TRANSPORT can be :stdio or :http.
PORT is only used when transport is :http.
package 40ants-mcp/server/errors
condition 40ants-mcp/server/errors:tool-error ()
You should signal this error in case if the tool can't accomplish it's job.
Readers
reader 40ants-mcp/server/errors:tool-error-content (tool-error) (:content)
package 40ants-mcp/stdio-transport
class 40ants-mcp/stdio-transport:stdio-transport ()
STDIO transport implementation for MCP (Model Context Protocol) communication.
This class handles JSON-RPC message exchange via standard input/output streams.
It is designed to work with the MCP protocol specification for AI model communication.
Readers
reader 40ants-mcp/stdio-transport:transport-input (stdio-transport) (:input-stream = *standard-input*)
Input stream for reading JSON-RPC messages. Defaults to standard-input.
reader 40ants-mcp/stdio-transport:transport-output (stdio-transport) (:output-stream = *standard-output*)
Output stream for writing JSON-RPC responses. Defaults to standard-output.
reader 40ants-mcp/stdio-transport:transport-running-p (stdio-transport) (= t)
Flag indicating if transport is active and processing messages.
Accessors
accessor 40ants-mcp/stdio-transport:transport-input (stdio-transport) (:input-stream = *standard-input*)
Input stream for reading JSON-RPC messages. Defaults to standard-input.
accessor 40ants-mcp/stdio-transport:transport-output (stdio-transport) (:output-stream = *standard-output*)
Output stream for writing JSON-RPC responses. Defaults to standard-output.
accessor 40ants-mcp/stdio-transport:transport-running-p (stdio-transport) (= t)
Flag indicating if transport is active and processing messages.
generic-function 40ants-mcp/transport/base:receive-message transport
Receive a JSON-RPC message, returns a message or NIL.
generic-function 40ants-mcp/transport/base:send-message transport message
Send a JSON-RPC message, returns no values.
package 40ants-mcp/tools
macro 40ants-mcp/tools:define-tool name args &body body
package 40ants-mcp/transport/base
generic-function 40ants-mcp/transport/base:receive-message transport
Receive a JSON-RPC message, returns a message or NIL.
generic-function 40ants-mcp/transport/base:send-message transport message
Send a JSON-RPC message, returns no values.
generic-function 40ants-mcp/transport/base:start-loop transport message-handler
Starts message processing using given transport.
generic-function 40ants-mcp/transport/base:stop-loop transport
Stops message processing using given transport.