1. Conduid
  2. Other
  3. Cl MCP
MCP server · Other

Cl MCP

Unclaimed MIT other
40Fair

Scored 4 days ago · breakdown

About Cl MCP

Cl MCP is an MCP server published by cl-ai-project in the Other category.

The repository has 88 stars and 18 forks, with the last commit 4 days ago. Recent commit activity is the strongest signal that reported issues will get attention.

Install

From source
git clone https://github.com/cl-ai-project/cl-mcp

This server has no ConduID identity, so agent calls to it are not receipted. Pin the version you install and review the source before granting it credentials.

Ask AI

✦

Ask AI about Cl MCP

Powered by Claude · Grounded in docs

I know everything about Cl MCP. Ask me about installation, configuration, usage, or troubleshooting.

Security checks

Static checks derived from the repository 3 days ago. Heuristics on the source, not an audit.

  • ✓README presentThe repository ships documentation.
  • ✓License declaredUsable under a stated license.
  • ✓Tests presentA test suite exists in the repository.
  • ✓Dependencies pinnedA lockfile pins dependency versions.

2 checks have not been run yet.

Releases

v3.1.0v3.1.0 — Loads That Fail as ASDF Does, Warnings With Places, and the Project's Own Code · 17 Oct 2026Highlights `load-system` now fails where `asdf:load-system` fails. A file that compiles with a full `WARNING` is refused, and every warning is reported as a record with its file, line and enclosing definition. `run-tests` and…
v3.0.2v3.0.2 — Clearer run-tests Results and Root Guidance · 27 Sep 2026Highlights Three fixes found by dogfooding v3.0.1 on a real project (PR #200). Each one had cl-mcp answer truthfully but in a way an agent could not act on. Fixes The root-not-set error keeps its advice After a reconnect, the first file…
v3.0.1v3.0.1 — Prove Suites Counted, clear_fasls on Subsystems, and a Shutdown Race · 27 Sep 2026Highlights A patch release: two long-standing issues that could tell an agent something false, and a worker-pool race that made the `specs` CI job fail now and then. Fixes `run-tests` counts prove suites, and the ASDF fallback never claims…
v3.0.0v3.0.0 — Per-Session Project Roots, CLOS Introspection, cl-spec Tools, and a Hardened Worker Pool · 27 Sep 2026Highlights cl-mcp v3.0.0 lands 49 PRs across 513 commits since v2.3.1. The tool surface grows from 22 to 27: `clos-describe`, plus four `spec-*` tools in a new optional tool group that is off by default. It is a major release…
v2.3.1v2.3.1 — Two Reporting Bugs Found by Dogfooding v2.3.0 · 31 Jul 2026v2.3.1 — Two Reporting Bugs Found by Dogfooding v2.3.0 A patch release. Both fixes came from a dogfooding session run immediately after v2.3.0 shipped: two throwaway projects were built with cl-mcp's own tools, and these are the defects…

README

cl-mcp

CI Lint

A Model Context Protocol (MCP) server for Common Lisp, providing JSON-RPC 2.0 over stdio, TCP, and HTTP (Streamable HTTP). It enables AI agents to interact with Common Lisp environments through structured tools for REPL evaluation, system loading, file operations, code introspection, and structure-aware editing.

Features

  • REPL evaluation with object inspection — evaluate forms, drill down into complex results (CLOS instances, hash-tables, etc.), and capture structured error context with stack frames and local variables
  • Sandboxed file operations — read/write/list files restricted to the project root and ASDF system source directories, preventing accidental access outside the project
  • Structure-aware Lisp editing — replace, insert, and patch top-level forms using Eclector CST parsing with automatic parinfer repair, preserving formatting and comments
  • Code intelligence — symbol lookup and description; callers with their exact call sites and the tests that exercise them; CLOS class hierarchies, slots and generic-function methods; macroexpansion of a form straight from its file; Lisp-aware search and file viewing with collapsed signatures; CLHS lookup
  • Structured test runner — run Rove, FiveAM and prove tests with pass/fail counts, failure details, and source locations
  • Worker pool isolation — eval-dependent tools run in isolated child SBCL processes with automatic crash recovery, circuit breaker, and per-session affinity; an optional init hook can start your app inside the worker
  • Three transports — stdio, TCP (multi-client), and Streamable HTTP (for Claude Code)
  • Project scaffolding — generate a throwaway package-inferred project with Rove or FiveAM tests
  • Optional contract checking — the cl-spec tool group (off by default) lists, reads and checks cl-spec contracts; see Optional tool groups

Tools at a glance

Category Tool Purpose Runs in
Project & files fs-set-project-root Set this session's project root parent (the worker follows)
fs-get-project-info Show the root and working directory parent
fs-read-file / fs-write-file / fs-list-directory Text I/O inside the allowed roots parent
project-scaffold Generate a new project skeleton parent
Lisp source lisp-read-file Collapsed or pattern-expanded view of a file parent
lisp-edit-form / lisp-patch-form Replace, insert or delete a top-level form; scoped text patch parent
lisp-check-parens Diagnose unbalanced delimiters and suggest the fix parent
clgrep-search Lisp-aware grep that reports the enclosing form; no loading needed parent
lisp-macroexpand Expand a macro call from a file or a code string parent locates, worker expands
REPL repl-eval Evaluate forms, with backtraces and locals on error worker
inspect-object Drill into a result object worker
load-system Load or reload an ASDF system worker
run-tests Run Rove/FiveAM/prove tests with structured results worker
Introspection code-find / code-describe Definition location; signature and documentation worker
code-find-references Callers, call sites and affected tests worker (xref) + parent (source scan)
clos-describe Classes, slots and generic-function methods worker, verified against source by the parent
Reference clhs-lookup Common Lisp HyperSpec parent
Pool pool-status / pool-kill-worker Diagnose or replace the session's worker parent
cl-spec (opt-in) spec-list / spec-symbol / spec-describe / spec-check List, read and check contracts worker

For every tool's input/output schema, see docs/tools.md.

Requirements

  • SBCL 2.x (developed with SBCL 2.5.x)
  • Quicklisp (optional; pure ASDF also works)
  • Dependencies (via ASDF/Quicklisp): runtime — alexandria, cl-ppcre, yason, usocket, bordeaux-threads, eclector, hunchentoot, named-readtables; tests — rove; optional — fiveam (for running FiveAM suites), clhs (loaded on-demand by clhs-lookup tool), swank (only for MCP_WORKER_SWANK), cl-spec (only for the cl-spec tool group).

Quick Start

Install

# Install from Roswell
ros install cl-ai-project/cl-mcp

# or fetch from GitHub
cd ~/common-lisp
git clone https://github.com/cl-ai-project/cl-mcp.git

Load and run from an existing REPL:

(asdf:load-system :cl-mcp)  ; or (ql:quickload :cl-mcp) if using Quicklisp

;; Start the HTTP server on port 3000 (the default)
(cl-mcp:start-http-server :port 3000)

;; Or start the TCP transport on port 12345, accepting clients until stopped
(cl-mcp:ensure-tcp-server-thread :port 12345)

Or run a minimal stdio loop (one JSON-RPC line per request):

# With Roswell
ros run -s cl-mcp -e "(cl-mcp:run :transport :stdio)"

# With a plain sbcl command
sbcl --eval '(require :asdf)' \
     --eval '(asdf:load-system :cl-mcp)' \
     --eval '(cl-mcp:run :transport :stdio)'

Project root: File operations require a project root to be set. The root belongs to the session that sets it, with fs-set-project-root or with initialize's rootPath/rootUri: several agents can share one server and work on different projects, and none of them moves another's root. MCP_PROJECT_ROOT, when set, is the default for a session that sets none. If it is not set, a session's first file access returns an error prompting it to call fs-set-project-root; AI agents handle this by setting it to their working directory. A session's own root lasts as long as the session, so a reconnect -- a new HTTP session or TCP connection -- starts from MCP_PROJECT_ROOT when it is set, and otherwise without a root, and has to set its own again.

System Prompts

The prompts/ directory contains system prompts that teach AI agents how to use cl-mcp tools effectively:

  • repl-driven-development.md — Tool selection guide, REPL-driven workflow (explore → experiment → persist → verify), editing patterns, and troubleshooting recipes
  • common-lisp-expert.md — Production-quality Common Lisp coding standards, CLOS/conditions/restarts conventions, and TDD with Rove
  • cl-spec-driven-development.md — Contract-driven workflow for the optional cl-spec tool group: finding and writing Function Specs and Properties, baselines, seed replay, and reading spec-check verdicts. Supplements the two prompts above rather than replacing them

cl-mcp also sends a short summary of the first, and of the third when the cl-spec group is enabled, as its MCP server instructions (see Server instructions), so a client that honours them gets the essentials without any setup. Reference the full prompts from your project's CLAUDE.md (or equivalent) when you want the complete guide, or when your client ignores server instructions:

# CLAUDE.md
@prompts/repl-driven-development.md
@prompts/common-lisp-expert.md

If you enable the cl-spec tool group (see Optional tool groups), add the third prompt as well. Leave it out otherwise: without the group, the tools it describes are not in the agent's tool list.

@prompts/cl-spec-driven-development.md

Claude Code

HTTP transport (recommended)

Start the HTTP server from your REPL and keep using it alongside Claude Code:

(asdf:load-system :cl-mcp)  ; or (ql:quickload :cl-mcp)

;; Start HTTP server on port 3000 (default)
(cl-mcp:start-http-server :port 3000)

;; Server is now running at http://127.0.0.1:3000/mcp
;; You can continue using your REPL normally
(+ 1 2)  ; => 3

;; Stop the server when done
(cl-mcp:stop-http-server)

Register it with Claude Code:

claude mcp add --transport http cl-mcp http://127.0.0.1:3000/mcp

or write the entry yourself, in the project's .mcp.json (or ~/.claude.json for all projects):

{
  "mcpServers": {
    "cl-mcp": {
      "type": "http",
      "url": "http://127.0.0.1:3000/mcp"
    }
  }
}

start-http-server also takes :token :generate (or a token string) to require an Authorization: Bearer <token> header on every request; the generated token is printed to *error-output*.

This approach lets both you and Claude Code share the same Lisp runtime. You can inspect state from SLIME/Sly while Claude Code works through MCP.

Stdio transport

For a simpler setup where Claude Code manages the server process directly:

{
  "mcpServers": {
    "cl-mcp": {
      "type": "stdio",
      "command": "ros",
      "args": ["run", "-s", "cl-mcp", "-e", "(cl-mcp:run)"],
      "env": {
        "MCP_ENABLE_TOOL_GROUPS": "cl-spec"
      }
    }
  }
}

The env entry is optional; it turns on the cl-spec tool group (see Optional tool groups). Any variable from Environment Variables can be passed the same way.

Stdio is easy to configure but the Lisp process is owned by Claude Code, making manual intervention from SLIME or another REPL difficult.

Codex

Configure in ~/.codex/config.toml.

Stdio transport

The simplest setup — Codex spawns and manages the server process:

[mcp_servers.cl-mcp]
command = "ros"
args = ["run", "-s", "cl-mcp", "-e", "(cl-mcp:run)"]

As with Claude Code's stdio mode, the Lisp process is owned by Codex and not easily accessible from SLIME or another REPL.

TCP transport with stdio bridge

Start a TCP server from your REPL, then point Codex at it via the bundled Python bridge that translates stdio ↔ TCP:

;; In your REPL: keep accepting clients, so Codex can reconnect after a restart
(asdf:load-system :cl-mcp)
(cl-mcp:ensure-tcp-server-thread :port 12345)
[mcp_servers.cl-mcp]
command = "python3"
# Codex starts the bridge from your project, not from the cl-mcp checkout,
# so give the script's absolute path.
args = ["/path/to/cl-mcp/scripts/stdio_tcp_bridge.py", "--host", "127.0.0.1", "--port", "12345"]

--host and --port default to 127.0.0.1 and 12345; the bridge also reads LISP_MCP_HOST and LISP_MCP_PORT. (cl-mcp:start-tcp-server-thread serves a single client and then stops unless given :accept-once nil.)

This gives you the same shared-REPL workflow as Claude Code's HTTP mode — you keep your SLIME/Sly session while Codex works through the bridge.

Worker Pool Isolation

Eval-dependent tools (repl-eval, load-system, run-tests, code-*, clos-describe, lisp-macroexpand, inspect-object, and the optional spec-* tools) run in isolated child SBCL processes. Each session gets a dedicated worker with automatic crash recovery and circuit breaker protection. File-system and editing tools run inline in the parent process, each request under its own session's project root.

With the worker pool enabled, a worker crash loses all worker-local Lisp state (loaded systems, definitions, packages, and REPL state). Any in-flight call that observes the crash fails. The pool normally attempts recovery; if it supplies a replacement, that worker starts with fresh Lisp state. The circuit breaker can halt automatic recovery after repeated crashes. In diagnostic logs, worker.crashed can initially report exit_status=running after TCP EOF; that is a provisional snapshot. Use the later worker.reaped event for the final process exit status.

For a pooled SBCL worker request, a condition that no existing handler resolves and that reaches the debugger path is observed and aborted as that request's structured failure. This preserves the worker for later requests, but it does not roll back side effects made before the failure. A process exit such as SB-EXT:EXIT remains a real worker crash and follows normal EOF/reaper recovery.

Disable the worker pool with MCP_NO_WORKER_POOL=1 or the :worker-pool keyword:

(cl-mcp:run :transport :stdio :worker-pool nil)

Environment Variables

Variable Purpose Default
MCP_PROJECT_ROOT Default project root for sessions that set none of their own (not set: each session sets its own)
MCP_LOG_LEVEL Log level: debug, info, warn (or warning), error; an unrecognized value is ignored debug
MCP_LOG_FILE Also log to a file, named <stem>-<timestamp>-<pid>.<ext> beside the given path; workers do not inherit it (stderr only)
MCP_NO_WORKER_POOL Any non-empty value (even 0) disables worker pool isolation (not set = pool enabled)
MCP_ENABLE_TOOL_GROUPS Optional tool groups to enable, separated by commas or spaces, case-insensitive (cl-spec); read when the system loads. The :tool-groups argument of run, start-http-server, serve-tcp, start-tcp-server-thread and ensure-tcp-server-thread overrides it (empty: all groups off)
MCP_WORKER_SWANK Any non-empty value makes each worker (ql:quickload :swank) and start a Swank server on a free port, reported in the worker.swank.started log event (needs Quicklisp in the worker; without it the worker runs without Swank) (off)
CL_MCP_WORKER_POOL_WARMUP Number of standby workers to maintain (non-negative integer) 1
CL_MCP_MAX_POOL_SIZE Maximum total workers, bound + standby (positive integer) 16
MCP_WORKER_INIT_SYSTEM ASDF system to load in the elected owner worker at bind (master gate for the init hook) (unset = off)
MCP_WORKER_INIT_ENTRY PKG:SYMBOL nullary thunk run after the load (preferred activation) (none)
MCP_WORKER_INIT_EVAL Lisp form run via repl-eval as an escape hatch (none)
MCP_WORKER_INIT_PACKAGE Package used to read/eval MCP_WORKER_INIT_EVAL CL-USER
MCP_WORKER_INIT_MAX_FAILURES Soft init failures before init auto-retry latches off 1
MCP_WORKER_INIT_MODE singleton (one owner binds a fixed port). v1 supports singleton only singleton

Tuning warmup for cold-start handshakes

The worker pool warms its standbys asynchronously once cl-mcp:run returns control to the MCP transport, so the stdio handshake is not blocked on subprocess launches. If you still see your MCP client report Failed to connect on a cold FASL cache — for example the first cl-mcp invocation after a system upgrade — set CL_MCP_WORKER_POOL_WARMUP=0 to skip pre-spawning entirely. Workers are then created on demand the first time a session needs one, trading first-eval latency for the smallest possible startup footprint. Once your client establishes the session you can ignore the warmup; the pool will grow as sessions arrive.

Running an app inside a worker (init hook)

Set MCP_WORKER_INIT_SYSTEM (and optionally MCP_WORKER_INIT_ENTRY) to have the pool run a startup routine inside the single worker elected as the "runtime owner" when a session binds it. This lets an app (e.g. a web server) run in the same process that serves repl-eval/load-system, so hot-reload lands in the app's process, while the parent keeps the persistent /mcp endpoint. pool-kill-worker restarts the runtime without dropping /mcp.

  • The init runs on a background thread under a worker-global ASDF load lock, so it never races a load-system RPC.
  • MCP_WORKER_INIT_SYSTEM is loaded the way the load-system tool loads: a file that compiles with a full WARNING is refused, as asdf:load-system refuses it, and the init fails. ql:quickload muffles such warnings, so an app that has only ever been quickloaded can meet this the first time its files are compiled here; load-system on it names the warning and its place.
  • Init failures never trip the crash circuit breaker; a failed init leaves a plain, usable REPL worker. Check pool-status (init_owner_session, init_disabled, init_failures) to see runtime state.
  • Requires the pool enabled (do not set MCP_NO_WORKER_POOL=1); cl-mcp warns at startup if the init vars are set while the pool is disabled.
  • The init form must be bind-robust and idempotent, and should pass :address "127.0.0.1" for a localhost-only dev server. Do not embed secrets in MCP_WORKER_INIT_EVAL.
  • Reloading code with load-system :force t while the app is serving live requests can race in-flight request threads (class/method redefinition); reload between requests or quiesce the app's acceptor first.

Example (recurya): add a nullary recurya/dev:start-dev-runtime! thunk that starts the DB and web server, then set MCP_WORKER_INIT_SYSTEM=recurya/dev and MCP_WORKER_INIT_ENTRY=recurya/dev:start-dev-runtime!.

Known v1 limitations:

  • Single dev runtime / single session. singleton mode is designed for one developer session driving one fixed-port app. Ownership is bound to the owner session and never migrates to a different live session, so hot-reload stays in the app's process. A narrow multi-session race remains (if the owner's worker crashes during the same window that a second session binds), so two concurrent sessions against one init runtime is not supported in v1; a future per-worker/ephemeral-port mode is planned for that.
  • Reset is not instantaneous. pool-kill-worker re-arms the runtime, but the app is re-initialized lazily on the session's next tool call (not eagerly), so the app is briefly down after a reset until the next MCP request. The parent /mcp endpoint stays up throughout.
  • Soft-failure retry is worker-scoped. MCP_WORKER_INIT_MAX_FAILURES counts init failures across a session's worker (re)binds (e.g. successive hard-crash recoveries). A soft init failure (the app reports an error but the worker stays alive) keeps the runtime owned by that session (no migration) but is not auto-retried on the same worker — recover it with pool-kill-worker.

Security Model

cl-mcp is a trusted, localhost-only development tool. repl-eval executes arbitrary Common Lisp code in the host image, so any client with MCP access has full system privileges. Do not expose the endpoint beyond localhost. File operation restrictions (project root enforcement) are convenience guardrails to prevent accidental mistakes, not security boundaries.

Because a request that reaches it is code execution, the HTTP transport refuses what a web page could send it, as the MCP Streamable HTTP transport requires: a request whose Origin is not a loopback origin (403), a request whose Host does not name the loopback interface while the server listens only on it (403; this is what stops DNS rebinding), and a POST that is not Content-Type: application/json (415). Clients that are not browsers send no Origin and are unaffected. A server started on a non-loopback address was exposed on purpose, and its Host is not checked; its Origin still is, since a page rebound to its LAN address sends an Origin matching that Host.

Input that would drive a recursive parser off the end of a thread's stack is refused before any parser sees it. SBCL cannot always recover from an exhausted stack, and when it cannot, the whole server stops. A JSON message nested more than 1000 levels deep is a parse error (-32700). A worker's answer that deep comes back as an error instead of being read: ask for a shallower preview_max_depth or max_depth. Lisp source that would make the reader recurse more than 500 levels is refused by the tools that read it, whether it is a file, tool content or repl-eval code. That covers nested lists and also chains of prefixes such as ', #' and #+.

The HTTP transport has no authentication by default. start-http-server's :token argument (:generate or a string) makes every request other than OPTIONS carry Authorization: Bearer <token>.

Workers are child processes of the server and inherit its whole environment, API keys and other secrets included: code run through repl-eval can read them. Only the MCP_WORKER_INIT_* variables and MCP_LOG_FILE are withheld (the worker's own MCP_* control variables are set fresh). A worker listens on 127.0.0.1 and answers only the parent, which proves itself with a per-worker shared secret.

License

MIT

README fetched from the repository 3 days ago. The original is authoritative.

Questions

About Cl MCP

How do I install Cl MCP?

No package has been published for this server, so install it from source: clone the repository and follow its README.

Is Cl MCP safe to use with an AI agent?

Its trust score is 40 out of 100 (fair). It passes 4 of the 4 static security checks run so far. It has no ConduID identity yet, so agent calls to it are not receipted.

Is Cl MCP still maintained?

Yes — the latest release is v3.1.0 (17 Oct 2026), and the last commit was 4 days ago. The repository has 88 stars and 8 open issues.