- Description: The framework for building
MCP
servers 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.
- âś…
STDIO
Transport: Native support forSTDIO
-based communication - âś… Streamable
HTTP
Transport: Allowing to create remotely hostedMCP
servers - âś… Tools System: Register and execute custom tools with
JSON
Schema validation - âś… Built on Open
RPC
: Leverages the robust 40ants OpenRPC library - âś…
CLOS
-based: Object-oriented design with proper encapsulation - âś… Easy Integration: Simple
API
for adding functionality - âś… Error Handling: Comprehensive error management with proper
JSON-RPC
error codes - âś… Interactive Editing:
MCP
tools can be edited and updated on the fly, usingREPL
driven approach
- 🔄 Full
MCP
Specification Support: Complete implementation ofMCP
protocol version 2025-06-18 - 🔄 Resources System: Serve dynamic and static resources via
URI
- 🔄 Prompts System: Provide prompt templates with argument interpolation
- 🔄
MCP
Client Protocol: Implement client-side protocol for connecting toMCP
servers
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 th
8000
e 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:transpo
57A7
rt-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.