docs(mcp): retire bridge implementation plan

This commit is contained in:
Guillaume ARM 2026-06-10 23:41:29 +02:00
parent e1879a562d
commit ad869c7ecd
2 changed files with 10 additions and 270 deletions

View File

@ -1,261 +0,0 @@
# MCP Bridge Plan
Relates to [./mcp-computer-lua-plan.md](./mcp-computer-lua-plan.md)
## 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:
```text
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
```text
[ 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:
```ts
type ComputerConnection = {
computerId: number;
label: string | null;
ws: WebSocket;
connectedAt: number;
lastSeenAt: number;
};
```
## Link Protocol
All ComputerCraft link messages are JSON text frames.
### Computer Hello
Sent by the Lua program immediately after opening the WebSocket:
```json
{
"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
```json
{
"type": "hello-ok"
}
```
### Probe Request
Sent by the bridge when MCP tool `probe-computers` is called:
```json
{
"type": "request",
"id": "req-123",
"method": "ping"
}
```
### Probe Response
Sent by each Lua computer:
```json
{
"type": "response",
"id": "req-123",
"ok": true,
"result": "pong from 12 (Label: base-turtle)"
}
```
Error shape, reserved for later commands:
```json
{
"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:
```text
pong from 12 (Label: base-turtle)
pong from 13 (Label: miner-1)
timeout from 14 (Label: farm-turtle)
```
## Project Layout
```text
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`
### 2. Link Server
- 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:
```json
{
"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.

View File

@ -1,6 +1,6 @@
# MCP Computer Lua Plan # MCP Computer Lua Plan
Relates to [./mcp-bridge-plan.md](./mcp-bridge-plan.md) Depends on the implemented host bridge in `tools/mcp-bridge/`.
## Goal ## Goal
@ -17,20 +17,21 @@ pong from <computerId> (Label: <computerLabel>)
- Lua program path: `programs/mcp-computer.lua`. - Lua program path: `programs/mcp-computer.lua`.
- Package: `trapos-sandbox`. - Package: `trapos-sandbox`.
- The program connects outbound to the bridge's ComputerCraft link port. - The program connects outbound to the bridge's ComputerCraft link port.
- The bridge link default is `ws://<host>:3001`. - The implemented bridge link default is `ws://<host>:3001` (`CC_LINK_PORT`, default `3001`).
- The host-side MCP tool is named `probe-computers` and broadcasts to every connected computer. - The host-side MCP tool is named `probe-computers` and broadcasts to every connected computer.
- No link auth for the first version. - No link auth for the first version.
- Keep the first Lua implementation as a program, not an autostart server, until the bridge loop is proven. - Keep the first Lua implementation as a program, not an autostart server, until the bridge loop is proven.
- The implemented bridge accepts WebSocket connections on any path, so a bare `ws://<host>:3001` URL is sufficient.
## Background ## Background
CC:Tweaked cannot listen on real HTTP/TCP ports with standard APIs. It can connect outward using `http.websocket`. This program is therefore the in-game half of the bridge: CC:Tweaked cannot listen on real HTTP/TCP ports with standard APIs. It can connect outward using `http.websocket`. This program is therefore the in-game half of the bridge:
```text ```text
[ CC computer ] --outbound WebSocket--> [ tools/mcp-bridge link port :3001 ] [ CC computer ] --outbound WebSocket--> [ tools/mcp-bridge link listener :3001 ]
``` ```
The Lua program is effectively an agent. It identifies itself to the bridge, waits for JSON request frames, executes supported methods, and sends JSON response frames. The Lua program is effectively an agent. It identifies itself to the bridge, waits for JSON request frames, executes supported methods, and sends JSON response frames. The host bridge is already implemented and exposes MCP over plain HTTP JSON-RPC on `MCP_PORT` while this Lua program only speaks the ComputerCraft WebSocket link protocol.
## User Interface ## User Interface
@ -79,7 +80,7 @@ Sent immediately after opening the websocket:
Lua fields: Lua fields:
- `computerId`: `os.getComputerID()`. - `computerId`: `os.getComputerID()`.
- `computerLabel`: `os.getComputerLabel()`, or `nil` encoded as JSON null/omitted depending on `textutils.serializeJSON` behavior. - `computerLabel`: `os.getComputerLabel()`, or `nil` encoded as JSON null/omitted depending on `textutils.serializeJSON` behavior. The bridge treats missing, empty, or non-string labels as `null`.
### Hello OK ### Hello OK
@ -91,7 +92,7 @@ Expected from bridge:
} }
``` ```
The first version may continue even if `hello-ok` is not received immediately, but implementation should prefer waiting briefly so connection problems are obvious. The bridge sends `hello-ok` immediately after a valid `hello`. The Lua program should wait briefly for this frame so connection or protocol problems are obvious, then proceed only after receiving it.
### Probe Request ### Probe Request
@ -166,13 +167,13 @@ Implement a local function:
local function formatPong() local function formatPong()
local label = os.getComputerLabel(); local label = os.getComputerLabel();
if not label or label == '' then if not label or label == '' then
label = 'nil'; label = 'null';
end end
return 'pong from ' .. tostring(os.getComputerID()) .. ' (Label: ' .. tostring(label) .. ')'; return 'pong from ' .. tostring(os.getComputerID()) .. ' (Label: ' .. tostring(label) .. ')';
end end
``` ```
Keep the output exactly aligned with the bridge plan. Keep the output aligned with the implemented bridge's `formatComputer` fallback (`null` for missing labels) and the MCP tool's expected successful pong lines.
### 5. Packaging ### 5. Packaging
@ -207,7 +208,7 @@ just trapos-exec 'shell.run("/programs/mcp-computer.lua", "--help")'
just trapos-exec 'shell.run("/programs/mcp-computer.lua", "--version")' just trapos-exec 'shell.run("/programs/mcp-computer.lua", "--version")'
``` ```
For an end-to-end probe, run the TS bridge on localhost and use CraftOS-PC with HTTP local access enabled if the harness permits it. If localhost access is blocked by CC:Tweaked config, document the limitation and rely on an in-game/manual validation for the WebSocket connection. For an end-to-end probe, run the TS bridge on localhost and use CraftOS-PC with HTTP local access enabled if the harness permits it. The bridge already includes integration-test Lua clients under `tools/mcp-bridge/test-integration/lua/` that can be used as protocol references. If localhost access is blocked by CC:Tweaked config, document the limitation and rely on an in-game/manual validation for the WebSocket connection.
### Required Repo Checks ### Required Repo Checks