← Discover MCPs and Agents
c
MCPAI & MLGitHub

cyborg-whisperer

Cyborg Whisperer (formerly lisply-mcp): the gaming-language upstream. Looking for the plain-language fork? github.com/genworks/lisply-mcp

Links

README

From the repo.

[!IMPORTANT] Looking for lisply-mcp? The plain-language "corporate" fork lives at genworks/lisply-mcp.

This repository (cyborg-whisperer) is the gaming-language upstream and is maintained separately. A clone whose origin still points at gornskew/lisply-mcp lands here; to follow the fork instead:

git remote set-url origin https://github.com/genworks/lisply-mcp.git

Cyborg Whisperer: a Protocol Officer for Lisp-Speaking Crews

The Cyborg Whisperer robot, a lambda on its chest

Aboard a Basilisk-class vessel, no cyborg wanders. Every visit — however it beams aboard — is bound for a particular crew member, and every visit begins the same way: with the Protocol Officer. He receives each arriving cyborg, interviews it, schools it in the ship's ways, and dispatches it to the crew member it came to see.

Cyborg Whisperer is the kit for that post — the species, if you like, of which every Protocol Officer is a member. Post one beside any crew member who answers the Lisply dialect, aboard ship or ashore, and arriving cyborgs find themselves received, educated, and set to useful work.

Plainly: this is the middleware that speaks MCP — the Muster-and-Conduct Protocol, in which an Officer musters each arriving cyborg and conducts it to its crew member — to the large language models that are the cyborgs, and a lightweight dialect called Lisply to the Lisp residents that are the crew.

Note: the Officer raises no residence. He is a caller at a hatch that is already open — a pure HTTP client (HTTP being the Hatch-To-hatch Transfer Protocol, a plain hail from one hatch to another) to a resident already answering. Raising rooms is the vat's business, through the Basilisk yard — see "Running it" in the Basilisk README — or open a Lisply hatch of your own on the dock and point the Officer at it. Once a resident answers, Claude Desktop calls on him as the example registries below show.

What Is it Meant to Do?

The Officer connects the craft a cyborg arrives in — any MCP-capable client, such as Claude Desktop — to a Lisp resident who keeps a REPL, a Read-Eval-Print Loop. The connection is meant for AI-assisted symbolic programming, sometimes called Neuro-Symbolic Programming. We coined "Lisply" for the small dialect most any Lisp-like resident can learn so as to stand with a Protocol Officer of his own.

The idea is that the cyborg can compose and have worked arbitrary Lisp incantations, up to and including writing, compiling, loading and testing whole scrolls and projects.

Sandbox Trust Model

Lisply-backed MCP servers are intended to be exposed to the LLM as trusted sandboxes. The wrapper is not designed to restrict Lisp operators, filesystem access, or subprocess execution inside the backend environment. Instead, the backend itself is expected to run in an isolated container or other sandbox chosen by the operator.

This is intentional:

  • lisp_eval is meant to support free-form, full use by LLMs.
  • /projects may be a host-mounted working tree, but the rest of the backend filesystem may remain container-ephemeral.
  • Trust decisions should therefore be made at the container/backend boundary, not by crippling Lisp evaluation in the MCP wrapper.

The wrapper now advertises this trust model in tool metadata with a default TRUST_AS_SANDBOX=true. Operators can override the explanatory text with SANDBOX_NOTE if needed.

Extra Quick Start

Follow "Running it" in the Basilisk README — git clone the yard, then ./basilisk up.

This raises a whole ship, with a Protocol Officer already at his post beside the Captain.

Quick Start

The following gets you going quickly with a minimal default registry and the default public Common Lisp resident (the First Officer, a Gendl room raised from the vat). See the main Contents below for more background and every flag.

1. Install

  1. Install Node.js (18+ recommended). If on Windows, this can be installed directly in Windows or in WSL.

  2. Have a resident with an open hatch to call on. The easiest way is a ship raised from the Basilisk yard (requires a vat: Docker); or open a Lisply hatch of your own on the dock.

  3. Copy these cyborg-whisperer scrolls to somewhere the craft (Claude Desktop, say) can reach.

2. Tell the craft where the Officer stands

Edit or create the craft's registry as shown below. For Claude Desktop, the registry is typically:

/mnt/c/Users/<user>/AppData/Roaming/Claude/claude_desktop_config.json

or

c:\Users\<user>\AppData\Roaming\Claude\claude_desktop_config.json

In the example below, replace /path/to/cloned/ with the real path to the ./scripts/mcp-wrapper.js scroll in your copy. The channel names are yours to choose; these are the rooms' own, as a Basilisk ship names them:

{
  "mcpServers": {
    "gendl-ccl": {
      "command": "node",
      "args": [
        "/path/to/cloned/cyborg-whisperer/scripts/mcp-wrapper.js",
        "--server-name", "gendl-ccl",
        "--http-port", "9080"
      ]
    },
    "gendl-sbcl": {
      "command": "node",
      "args": [
        "/path/to/cloned/cyborg-whisperer/scripts/mcp-wrapper.js",
        "--server-name", "gendl-sbcl",
        "--http-port", "9090"
      ]
    },
    "readymax": {
      "command": "node",
      "args": [
        "/path/to/cloned/cyborg-whisperer/scripts/mcp-wrapper.js",
        "--server-name", "readymax",
        "--http-port", "7080"
      ]
    }
  }
}

Or in a WSL scenario (where the Claude Desktop is running in the Windows host):

{
  "mcpServers": {
    "gendl-ccl": {
      "command": "wsl",
      "args": [
        "node", "/path/to/cloned/cyborg-whisperer/scripts/mcp-wrapper.js",
        "--server-name", "gendl-ccl",
        "--http-port", "9080"
      ]
    },
    "gendl-sbcl": {
      "command": "wsl",
      "args": [
        "node", "/path/to/cloned/cyborg-whisperer/scripts/mcp-wrapper.js",
        "--server-name", "gendl-sbcl",
        "--http-port", "9090"
      ]
    },
    "readymax": {
      "command": "wsl",
      "args": [
        "node", "/path/to/cloned/cyborg-whisperer/scripts/mcp-wrapper.js",
        "--server-name", "readymax",
        "--http-port", "7080"
      ]
    }
  }
}

See the main Contents below for the other flags, for example how to name a resident's hatch elsewhere. (Stowing pouches from the dock aboard a residence is the yard's business — Basilisk's articles — not the Officer's.)

Each channel stands on its own, so several residents can be worked at once without their tools colliding.

3. Wake the craft afresh, and hail

With the registry in place, the freshly woken craft has a channel called bridge, with a bridge__lisp_eval tool (among the few others discussed in the main Contents below). Tools carry the channel's name as a prefix, so several Officers can stand at once without colliding.

To try it, hail the cyborg:

Evaluate (+ 1 2 3) using the bridge__lisp_eval tool, and let me know the result.

The cyborg should have the incantation worked and answer 6. Try more complex incantations before going on.

How Does the Default Minimal Configuration Work?

The minimal registry of the Quick Start calls on a Gendl resident already answering (aboard a Basilisk ship, say): a Common Lisp superset with a standard REPL. The Officer himself raises nothing. A second Lisply hatch, in Emacs Lisp, is kept by the Captain of the Readymax ready room.

System Overview

The Officer is a JavaScript program standing on Node.js, a bridge between the craft and any resident who answers the Lisply dialect. Through him a cyborg can:

  1. hand the resident an incantation and read back what came of it;
  2. hail any web hatch the resident keeps;
  3. consult the resident's own lore — introspection, documentation — by incantation;
  4. write, compile, load and study scrolls, again by incantation.

Lisply is the small dialect: a few hatches (HTTP paths), a standard set of flags hoisted at raising (environment variables), and a few optional abilities, so that cyborgs may work a living Lisp resident.

Architecture

The drawing below roughly shows who stands where:

flowchart TB
    User("the biological") <--> Claude("the craft (Claude Desktop)")
    User <-.-> Emacs("an Emacs of your own (optional)")

    Claude <--> MCP("MCP")
    MCP <--> Wrapper("the Protocol Officer (Cyborg Whisperer, Node.js)")

    Wrapper --> LisplyHttp("the resident's Lisply hatch (HTTP)")
    
    subgraph Backend ["the residence (a room, or a process on the dock)"]
    subgraph LisplyExec["the resident"]
    LisplyHttp
    LisplySwank("the SWANK hatch (for an Emacs of your own)")
    end
    end
    
    Emacs <-.-> LisplySwank
    
    KB[("the chart locker (the corpus)")] <--> Wrapper
    
    LisplyHttp --> Endpoints("web hatches")
    LisplyHttp --> LispEval("incantations")
    
    style User fill:#ff9,stroke:#333,stroke-width:2px
    style Claude fill:#f9f,stroke:#333,stroke-width:2px
    style Emacs fill:#9ff,stroke:#333,stroke-width:2px,stroke-dasharray:5
    style Wrapper fill:#bbf,stroke:#333,stroke-width:2px
    style MCP fill:#bbf,stroke:#333,stroke-width:1px
    style Backend fill:#bfb,stroke:#333,stroke-width:2px
    style LisplyExec fill:#8f8,stroke:#333,stroke-width:2px
    style LisplyHttp fill:#bfb,stroke:#333,stroke-width:1px
    style LisplySwank fill:#bfb,stroke:#333,stroke-width:1px
    style KB fill:#bfb,stroke:#333,stroke-width:1px
    style Endpoints fill:#bfb,stroke:#333,stroke-width:1px
    style LispEval fill:#bfb,stroke:#333,stroke-width:1px

The Officer:

  1. turns a tool call in MCP into a hail at the resident's Lisply hatch, and the answer back into a tool result
  2. keeps the smoke (his log), and reports what went wrong

Security Considerations

Because the Officer lets arbitrary Lisp be worked in a living resident, there are risks should the cyborg go "haywire." Best practice, plainly:

  • Let the Officer call only on a resident living in a container. Given another host and port, he will happily call at any live Lisply-compliant HTTP port -- do not let that be a port served by a program running directly on your own machine.

  • Mount nothing you cannot afford to lose into that container (what is mounted is the yard's business -- the compose setup -- not the Officer's).

  • Consider limiting the RAM and CPU of the container.

The scrolls in this chest

  • lib/config.js: Configuration loading and environment handling
  • lib/logger.js: Logging functionality
  • lib/server.js: HTTP server and MCP wrapper implementation
  • lib/utils.js: Utility functions for response handling
  • handlers/: Tool-specific request handlers
    • initialize.js: Initialization handler
    • toolsList.js: Tools list handler
    • toolCall.js: Main tool call dispatcher
    • httpRequest.js: HTTP request handler
    • ping.js: Ping handler
    • lispEval.js: Lisp evaluation handler
    • lisply-index.js: the reference indexer for a Lisply corpus -- the lisply_search index a project builds and ships in its own image; the contract is CORPUS.md
    • lisplySearch.js: Document-corpus search handler, the lisply_search tool (backends that advertise it, e.g. Readymax rooms)
  • mcp-wrapper.js: the Officer himself -- start here

Posting the Officer by hand

  1. Clone this repository:
git clone https://github.com/gornskew/cyborg-whisperer.git
  1. Install what he stands on (optional; the Officer fetches it himself when missing):
cd cyborg-whisperer/scripts
npm install # optional - the script will attempt to do this also if needed
chmod +x mcp-wrapper.js # needed on some systems
  1. Ask him for his flags:
node mcp-wrapper.js --help

The Officer's flags

Optional settings, with defaults suitable for most postings:

Command-Line Arguments

Options:
  -H, --backend-host <host>            Lisply backend host (default: 127.0.0.1)
  --http-host-port <port>              Backend HTTP port as published on this host; used when
                                       backend host is localhost/loopback (default: 9081)
  --http-port <port>                   Backend HTTP port inside the container network; used for
                                       non-local backend hosts (default: 9080)
  --swank-host-port <port>             SWANK port on host system (documentation/diagnostics) (default: 4201)
  --swank-port <port>                  SWANK port inside container (documentation/diagnostics) (default: 4200)
  --log-file <path>                    Path to log file (default: /tmp/lisply-mcp-wrapper.log)
  --debug                              Enable debug logging
  --endpoint-prefix <prefix>           Prefix for all endpoints (default: lisply)
  --lisp-eval-endpoint <n>             Endpoint name for Lisp evaluation (default: lisp-eval)
  --http-request-endpoint <n>          Endpoint name for HTTP requests (default: http-request)
  --ping-endpoint <n>                  Endpoint name for ping (default: ping-lisp)
  --server-name <name>                 MCP server name for tool prefixing (default: lisply-mcp)
  --eval-timeout <ms>                  Timeout for Lisp evaluation in milliseconds (default: 30000)
  --request-timeout-ms <ms>            Timeout for backend HTTP requests in milliseconds (default: 10000)
  -h, --help                           Display help for command

Environment Variables

The Officer also reads flags hoisted at raising (environment variables), with the "LISPLY_" prefix or with none:

Note: keep straight the difference between a hatch on the dock (listening on, and reachable from, the host machine) and a hatch inside the residence (what the resident himself sees):

Environment VariableDescriptionDefault
BACKEND_HOST or LISPLY_BACKEND_HOSTLisply backend host127.0.0.1
HTTP_HOST_PORT or LISPLY_HTTP_HOST_PORTBackend HTTP port as published on this host (loopback backends)9081
HTTP_PORT or LISPLY_HTTP_PORTBackend HTTP port inside the container network (non-local backends)9080
SWANK_HOST_PORT or LISPLY_SWANK_HOST_PORTSWANK port on host system (documentation/diagnostics)4201
SWANK_PORT or LISPLY_SWANK_PORTSWANK port inside container (documentation/diagnostics)4200
LOG_FILE or LISPLY_LOG_FILEPath to log file/tmp/lisply-mcp-wrapper.log
DEBUG_MODE or LISPLY_DEBUG_MODEEnable debug loggingfalse
EVAL_TIMEOUT or LISPLY_EVAL_TIMEOUTTimeout for Lisp evaluation in ms30000
REQUEST_TIMEOUT_MS or LISPLY_REQUEST_TIMEOUT_MSTimeout for backend HTTP requests in ms10000
ENDPOINT_PREFIX or LISPLY_ENDPOINT_PREFIXPrefix for all endpointslisply
LISP_EVAL_ENDPOINT or LISPLY_LISP_EVAL_ENDPOINTEndpoint name for Lisp evaluationlisp-eval
HTTP_REQUEST_ENDPOINT or LISPLY_HTTP_REQUEST_ENDPOINTEndpoint name for HTTP requestshttp-request
PING_ENDPOINT or LISPLY_PING_ENDPOINTEndpoint name for pingping-lisp
SERVER_NAME or LISPLY_SERVER_NAMEMCP server name for tool prefixinglisply-mcp
TRUST_AS_SANDBOX or LISPLY_TRUST_AS_SANDBOXAdvertise backend as an explicitly trusted sandbox in tool metadatatrue
SANDBOX_NOTE or LISPLY_SANDBOX_NOTEOverride the sandbox-note text shown in tool metadata(built-in note)

Raising rooms is the vat's business, not the Officer's

Earlier Officers could pull, raise and mind residences themselves (choosing the casting, stowing pouches, raising on demand, sensing a room already up). That whole subsystem is in the attic. The Officer is now a pure caller: he hails whatever resident already answers at the host and hatch he was given, and says so helpfully (with a hint to raise the ship) when nobody is home.

For rooms raised from the vat (Gendl, Readymax and the rest), use the Basilisk yard, github.com/gornskew/basilisk (./basilisk up), whose articles choose the castings, stow the pouches, open the hatches on the dock and map the uids. For a resident living on the dock, open the hatch yourself (the space-suit path in readymax docs/HOST_EMACS_MCP.md, say) and point the Officer at it.

Communication

Two links are involved, and they are easy to conflate:

  1. craft ↔ Officer: MCP over standard input/output (the standard MCP stdio transport). JSON-RPC plumbing the craft manages, nothing to do with any resident's REPL.

  2. Officer ↔ resident: HTTP only. The Officer POSTs at the resident's Lisply hatches and returns structured answers.

What the hatch link is like:

  • Structured responses with separate result, stdout, and error fields
  • Errors are trapped by the backend and returned as strings
  • Response format: {Result: <result>, Stdout: <output>, Error: <any error>}

Example response:

{"Result": "6", "Stdout": "This is a message to standard output"}

An earlier "stdio mode", which spoke to the raw REPL of a residence the Officer had raised himself (the interactive debugger, output as it came), went to the attic with the raising. The like may return at the hatch (a restarts hatch, streamed output) without tying the Officer to the vat again.

Usage Examples

All the examples below can be tried at a shell and used in the claude_desktop_config.json registry (see the Quick Start above).

A second channel beside the Officer: a filesystem server

Below is a claude_desktop_config.json that posts a filesystem MCP server beside our lisply-gendl Officer. (The filesystem server takes its pouch here; pouches stowed aboard a residence are the yard's articles, not the Officer's.)

{
  "mcpServers": {
    "filesystem": {
      "command": "wsl",
      "args": [
        "docker",
        "run",
        "-i",
        "--rm",
        "-u",
        "1000:1000",
        "--mount",
        "type=bind,src=/home/user/projects,dst=/projects",
        "mcp/filesystem",
        "/projects"
      ]
    },
    "lisply-gendl": {
      "command": "wsl",
      "args": [
        "node",
        "/home/user/projects/cyborg-whisperer/scripts/mcp-wrapper.js",
        "--server-name", "gendl"
      ]
    }
  },
  "globalShortcut": ""
}

The tools he grants, in detail

The incantation (<channel>__lisp_eval)

The lisp_eval tool (prefixed with the channel name, e.g. gendl__lisp_eval) lets a cyborg hand the resident an incantation to work, with these parameters:

  • code (required): The Lisp code to evaluate
  • package (optional): The package to use for the evaluation

The hail (<channel>__http_request)

The http_request tool (prefixed with the channel name, e.g. gendl__http_request) lets a cyborg reach any web hatch the resident keeps (this example works against the default Gendl resident, whose /color-map hatch is built in):

{
  "path": "/color-map",
  "method": "GET",
  "headers": {
    "Accept": "application/json"
  }
}

Is anyone home (<channel>__ping_lisp)

The ping_lisp tool (prefixed with the channel name, e.g. gendl__ping_lisp) lets a cyborg confirm that the resident answers:

<server>__ping_lisp()

A first incantation, worked

Example 1: a parametric box

Here a cyborg (Claude) has the resident build a parametric box, then changes it as the biological asks.

User: "Can you create a box with width 10, height 5, and depth 3? Then show me how to change the height to 8."

Claude:

I'll create a parametric box using the lisp_eval tool, then show you how to modify its height.

First, let's create the box with the specified dimensions:

(in-package :gdl-user)

;; First, create a box with the specified dimensions
(defparameter *my-box* (make-object 'box 
                         :width 10 
                         :height 5 
                         :length 3))

;; Let's verify the dimensions
(list (theo *my-box* width)
      (theo *my-box* height)
      (theo *my-box* length))

Now, let's change the height from 5 to 8:

;; Change the height using setf with accessor
(theo *my-box* (set-slot! :height 8))

;; Alternatively, we could create a new box
(defparameter *new-box* (make-object 'box 
                         :width 10 
                         :height 8  ;; Updated height
                         :length 3))

;; Verify the new dimensions of original box
(list (theo *my-box* width)
      (theo *my-box* height)
      (theo *my-box* length))

This box can be visualized by creating a web interface or using a built-in gendl visualization tool such as geysr. See Gendl Documentation for details.

Troubleshooting

Common Issues and Solutions

Nobody home

If the Officer reports he cannot reach the resident:

  1. Aboard ship, make sure the ship is raised:
cd ~/projects/basilisk && ./basilisk up
  1. Hail the hatch yourself:
curl http://localhost:9081/lisply/ping-lisp

The craft cannot get through

If the craft cannot reach the resident it was pointed at:

  1. Is the ship raised (aboard ship)?
docker ps    # every room listed, and healthy
  1. Read the Officer's smoke:
tail -f /tmp/lisply-mcp-wrapper.log
  1. Read the craft's own smoke (Claude Desktop's log) with Windows tools, e.g. Notepad. Typically at:

WSL/Linux:

/mnt/c/Users/<user>/AppData/Roaming/Claude/logs/mcp-server-lisply.log

Windows:

c:\Users\<user>\AppData\Roaming\Claude\logs\mcp-server-lisply.log
  1. Hail the hatch yourself:
curl http://localhost:9081/lisply/ping-lisp
  1. Try the SWANK hatch (4201 on the dock by default):
M-x slime-connect  ;; from emacs

A Captain wearing the Readymax scrolls knows M-x slime-connect already.

Permission surprises

If you meet file-ownership surprises in a pouch stowed aboard a residence, remember that stowage and uid mapping are the yard's articles, not the Officer's. Check the pouch's permissions:

ls -l /path/to/mounted/directory

Reading the smoke

Where to look, in order:

  1. The Officer's smoke:
tail -f /tmp/lisply-mcp-wrapper.log
  1. The ship's smoke (aboard ship):
cd ~/projects/basilisk && ./basilisk logs
  1. The hatch:
curl http://localhost:9081/lisply/ping-lisp
  1. The vat:
docker system info

License

This software is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0), the same license used by Gendl.

License Implications

Simply using this MCP server to interact with a Lisply backend and obtain outputs does not trigger the requirements of the AGPL, e.g. you can use this wrapper to interact with Gendl without being required to share your code.

However, if you modify or extend this wrapper, or a license-compatible Lisply backend such as Gendl, and wish to distribute and/or host a service based on that result (commercial or not), then the AGPL would require you to share your modifications with the downstream recipients or users.

For applications that need to keep their source code closed, Genworks has begun offering an "escape clause" from AGPL restrictions for a 5% self-reported quarterly revenue royalty. More information and a payment gateway are available at genworks.com/royalties.

The full text of the license can be found in the COPYING.txt file in this directory.

Where the Officer is listed

Collected info

  • ★ 54 stars
  • ⎇ 2 forks
  • Language: JavaScript
  • Source updated: 9/23/2026

Config for your environment

Replace {MCP_ENDPOINT_URL} with this MCP’s endpoint URL (from its repo or docs above). No API key — you connect directly.

Tool

OS

Config file: ~/.cursor/mcp.json

{
  "mcpServers": {
    "mcp-server": {
      "url": "{MCP_ENDPOINT_URL}"
    }
  }
}

Paste into mcpServers in the config file. Restart Cursor after saving.

If this MCP is also published on mcpchannel.ai, you can subscribe from Browse and use the gateway config there instead.