Common Lisp SDK for Model Context Protocol (MCP) and Agent-to-Agent Protocol (A2A).
Clone the repository and add it to your ASDF registry:
(pushnew #p"/path/to/mcp-lisp/" asdf:*central-registry*)
(ql:quickload :mcp-lisp)Create an MCP server with tools, prompts, and resources:
(defpackage #:my-server
(:use #:cl #:mcp-lisp))
(in-package #:my-server)
;; Define a tool
(define-tool echo ((message string "The message to echo" :required t))
"Echoes the input message back."
(format nil "Echo: ~a" message))
;; Define a prompt
(define-prompt summarize ((text string "Text to summarize" :required t))
"Generate a summarization prompt."
(list (make-ht "role" "user"
"content" (make-ht "type" "text"
"text" (format nil "Summarize: ~a" text)))))
;; Define a resource
(define-resource "config://info"
(:name "Server Info" :mime-type "application/json")
"Returns server information."
(encode-json (make-ht "name" "my-server" "version" "1.0.0")))
;; Start server (stdio transport for Claude Code - blocking)
(run-server :name "my-server" :version "1.0.0" :transport :mcp-stdio)Run as an MCP server:
sbcl --script my-server.lisp:mcp-stdio- Newline-delimited JSON over stdio (for Claude Code, blocking):sse- Server-Sent Events over HTTP (non-blocking)
For interactive development, use :sse transport which runs in a background thread:
;; Start server in background
(defvar *server* (make-server :name "my-server" :version "1.0.0"))
(server-start *server* :transport :sse :port 8080)
;; ... develop, test ...
;; Stop when done
(server-stop *server*)Connect to an MCP server programmatically:
(in-package #:mcp-lisp)
;; Using with-client macro (recommended)
(with-client (c "sbcl" "--script" "echo-server.lisp")
(format t "Server: ~a~%" (gethash "name" (client-server-info c)))
;; List available tools
(dolist (tool (list-tools c))
(format t "Tool: ~a~%" (gethash "name" tool)))
;; Call a tool
(let ((result (call-tool c "echo" :message "Hello!")))
(format t "Result: ~a~%" (gethash "text" (elt result 0)))))
;; Manual lifecycle management
(let ((client (make-client "sbcl" "--script" "server.lisp")))
(client-connect client)
(client-initialize client)
;; ... use client ...
(client-shutdown client))A2A enables peer-to-peer agent communication with tasks and skills.
(define-agent-card
:name "my-agent"
:description "An example agent"
:url "http://localhost:8080"
:version "1.0.0")(define-skill analyze
((code string "Code to analyze" :required t))
"Analyzes code for issues."
;; Skill implementation
(analyze-code code));; Create a task
(let ((task (create-task)))
(add-task-message task (make-message "user"
(list (make-text-part "Analyze this code"))))
(update-task-status task "completed"))
;; A2A Client
(let ((client (make-a2a-client "http://agent-url/.well-known/agent.json")))
(fetch-agent-card client)
(send-message client task-id message))(start-a2a-server :port 8080)
;; Server exposes /.well-known/agent.json and handles A2A requests
(stop-a2a-server)See the examples/ directory:
echo-server.lisp- MCP server with tools, prompts, resourcesecho-server-sse.lisp- SSE transport variantclient-example.lisp- MCP client usage
Run the echo server:
sbcl --script examples/echo-server.lispmake testOr directly:
sbcl --non-interactive \
--eval '(ql:quickload :mcp-lisp/tests :silent t)' \
--eval '(mcp-lisp/tests:run-tests)'Dual-licensed under MIT OR Apache-2.0.