cc-libs/.plans/mcp-bridge-plan.md

6.9 KiB

MCP Bridge Plan

Goal

Build a small TypeScript bridge that lets MCP clients call tools backed by live ComputerCraft computers.

The first MCP tool is probe-computers. It broadcasts a probe request to every linked computer and returns one line per response:

pong from <computerId> (Label: <computerLabel>)

Decisions

  • Host-side implementation lives in tools/mcp-bridge/.
  • MCP clients connect on MCP_PORT, default 3000.
  • ComputerCraft computers connect on CC_LINK_PORT, default 3001.
  • The MCP port and ComputerCraft link port are separate listeners.
  • No auth is required for the first bridge implementation.
  • probe-computers takes no arguments and probes every currently linked computer.
  • The bridge owns real HTTP/MCP transport. ComputerCraft computers connect outbound over WebSocket.

Background

CC:Tweaked computers cannot bind a real TCP/HTTP port with the standard APIs. They can make outbound HTTP/WebSocket connections. Therefore the host bridge exposes real MCP over HTTP and maintains outbound WebSocket links from computers.

The current MCP TypeScript SDK situation is split:

  • @modelcontextprotocol/sdk v1 is stable and commonly used by existing examples.
  • Newer docs describe split packages such as @modelcontextprotocol/server and @modelcontextprotocol/node, but the upstream README says that branch is v2/pre-alpha as of this research.

Prefer stable v1 for the first implementation unless opencode compatibility requires the newer packages. Re-check package docs immediately before implementation.

Architecture

[ opencode / MCP client ] --HTTP MCP--> [ tools/mcp-bridge ] --WebSocket--> [ CC computer(s) ]
                                  :3000                     :3001

The bridge has two independent surfaces:

  • MCP listener: streamable HTTP MCP endpoint for agents.
  • Link listener: WebSocket endpoint for ComputerCraft computers.

The bridge keeps an in-memory registry of connected computers:

type ComputerConnection = {
  computerId: number;
  label: string | null;
  ws: WebSocket;
  connectedAt: number;
  lastSeenAt: number;
};

All ComputerCraft link messages are JSON text frames.

Computer Hello

Sent by the Lua program immediately after opening the WebSocket:

{
  "type": "hello",
  "computerId": 12,
  "computerLabel": "base-turtle"
}

Bridge behavior:

  • Validate computerId is a number.
  • Treat missing/empty computerLabel as null.
  • Register or replace the existing connection for that computerId.
  • Reply with hello-ok.

Hello OK

{
  "type": "hello-ok"
}

Probe Request

Sent by the bridge when MCP tool probe-computers is called:

{
  "type": "request",
  "id": "req-123",
  "method": "ping"
}

Probe Response

Sent by each Lua computer:

{
  "type": "response",
  "id": "req-123",
  "ok": true,
  "result": "pong from 12 (Label: base-turtle)"
}

Error shape, reserved for later commands:

{
  "type": "response",
  "id": "req-123",
  "ok": false,
  "error": "unknown method"
}

MCP Tool Behavior

Tool name: probe-computers.

Input schema: no arguments.

Behavior:

  1. Snapshot the current connected computer registry.
  2. If none are connected, return No computers connected..
  3. Generate one request id per computer, or one shared batch id with per-computer tracking.
  4. Send a ping request to every linked computer.
  5. Wait for responses until either all answer or the probe timeout expires.
  6. Return text with one line per successful response.
  7. Include timeout lines for computers that did not answer.

Suggested timeout: CC_PROBE_TIMEOUT_MS, default 2000.

Example output:

pong from 12 (Label: base-turtle)
pong from 13 (Label: miner-1)
timeout from 14 (Label: farm-turtle)

Project Layout

tools/mcp-bridge/
  package.json
  package-lock.json
  tsconfig.json
  src/
    index.ts
    link-server.ts
    mcp-server.ts
    protocol.ts
  test/
    protocol.test.ts
    probe-computers.test.ts

Keep the first implementation minimal. Collapse files if the code is clearer in fewer modules.

Implementation Sections

1. Tooling Setup

  • Create tools/mcp-bridge/package.json.
  • Use TypeScript with strict checks.
  • Use Node's built-in test runner if practical, or Vitest if SDK/test ergonomics require it.
  • Add scripts:
    • npm run build
    • npm test
    • npm run dev
    • npm start
  • Start WebSocket server on CC_LINK_PORT.
  • Accept JSON text frames only.
  • Register computers after valid hello.
  • Remove computers on close/error.
  • Track pending request resolvers by request id.
  • Ensure malformed frames do not crash the process.

3. MCP Server

  • Start MCP HTTP transport on MCP_PORT.
  • Register tool probe-computers.
  • Implement tool response as MCP text content.
  • Keep ordinary /health endpoint available on the MCP listener if the selected transport/framework allows it without fighting the SDK.

/health response should be normal HTTP, not MCP:

{
  "ok": true,
  "computers": 2
}

4. Configuration

Environment variables:

  • MCP_HOST, default 127.0.0.1.
  • MCP_PORT, default 3000.
  • CC_LINK_HOST, default 0.0.0.0.
  • CC_LINK_PORT, default 3001.
  • CC_PROBE_TIMEOUT_MS, default 2000.

5. Verification

Unit tests:

  • Protocol validation accepts valid hello and rejects invalid frames.
  • probe-computers returns No computers connected. when registry is empty.
  • probe-computers aggregates multiple successful responses.
  • probe-computers reports timeout for a connected computer that does not answer.

Integration tests:

  • Start bridge on ephemeral ports.
  • Connect fake WebSocket computer clients.
  • Call the probe path through the MCP handler, or through a thin internal function if the SDK transport is hard to drive in tests.

Manual/agent checks:

  • npm run build from tools/mcp-bridge.
  • npm test from tools/mcp-bridge.
  • Use opencode headless mode only for critical MCP compatibility checks after the bridge can run locally.

Open Questions To Re-check During Implementation

  • Exact HTTP MCP transport API for the chosen stable SDK version.
  • Whether opencode expects streamable HTTP only, SSE compatibility, or can use stdio. This bridge should prioritize HTTP because the requirement is an MCP port.
  • Whether tool names with hyphens are accepted cleanly by the MCP clients we care about. If not, challenge probe-computers and use probe_computers.

Out Of Scope For First Pass

  • Authentication and authorization.
  • Persistent computer registry.
  • Commands other than ping/probe-computers.
  • Multi-bridge clustering.
  • TLS termination. Put the bridge behind a reverse proxy if needed later.

Deliverables

  • tools/mcp-bridge/ TypeScript project.
  • MCP HTTP listener on port 3000 by default.
  • Computer WebSocket link listener on port 3001 by default.
  • MCP tool probe-computers returning live ComputerCraft pong lines.
  • Tests for protocol parsing and probe aggregation.