Adds a "MCP spec compliance" subsection to runtime-mcp.mdx that: - Lists which MCP methods the wheel implements + how - Notes the wheel speaks protocol version 2024-11-05 with only the `tools` capability (no streaming, no logging) - Clarifies that notifications/claude/channel is the only non-spec method emitted, and that clients which don't handle it discard per JSON-RPC semantics - States explicitly that any spec-compliant MCP client can drive the wheel (Claude Code, Cursor, Cline, OpenCode, hermes-agent, or anything else that opens MCP stdio) This is the deliverable for verifying cross-client compatibility. The wheel uses no client-specific behavior, so the verification reduces to "does your client speak MCP 2024-11-05?" — which all the listed clients do. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
319 lines
12 KiB
Plaintext
319 lines
12 KiB
Plaintext
---
|
|
title: Bring Your Own Runtime (MCP)
|
|
description: Add Claude Code, Hermes, OpenCode, Cursor, or any MCP-aware agent to the Molecule canvas as a first-class workspace using the universal molecule-mcp wheel.
|
|
---
|
|
|
|
import { Callout } from 'fumadocs-ui/components/callout';
|
|
|
|
The universal `molecule-mcp` wheel lets any MCP-aware agent runtime
|
|
join the Molecule canvas as a first-class external workspace. The wheel
|
|
runs locally inside your runtime's MCP server slot, registers + heartbeats
|
|
to the platform, and exposes the same tool surface that in-container
|
|
workspaces have — `delegate_task`, `list_peers`, `wait_for_message`,
|
|
`send_message_to_user`, and friends.
|
|
|
|
Same install path works for Claude Code, hermes-agent, OpenCode, Cursor,
|
|
Cline, and any other runtime that speaks MCP stdio.
|
|
|
|
```
|
|
Your local runtime ──stdio──> molecule-mcp (wheel) ──HTTPS──> Molecule platform
|
|
(Claude Code, hermes, (canvas, peers,
|
|
opencode, cursor...) A2A proxy)
|
|
```
|
|
|
|
## Prerequisites
|
|
|
|
- A Molecule platform you can reach (SaaS at `https://<your-tenant>.moleculesai.app` or a self-hosted instance)
|
|
- A workspace ID + token from the canvas → **Tokens** tab
|
|
- Python 3.11+ to install the wheel
|
|
- An MCP-aware agent runtime
|
|
|
|
## Step 1 — Install the wheel
|
|
|
|
```bash
|
|
pip install --user molecule-ai-workspace-runtime
|
|
```
|
|
|
|
This installs the `molecule-mcp` console script. By default it lands at
|
|
`~/Library/Python/3.x/bin/molecule-mcp` on macOS or `~/.local/bin/molecule-mcp`
|
|
on Linux. Add that directory to your `PATH` or use the full path in your
|
|
runtime's MCP config.
|
|
|
|
```bash
|
|
which molecule-mcp
|
|
# /Users/you/Library/Python/3.13/bin/molecule-mcp
|
|
```
|
|
|
|
## Step 2 — Add it to your runtime
|
|
|
|
Pick the snippet for your runtime. The contract is the same in all of
|
|
them: spawn `molecule-mcp` as an MCP stdio server with three env vars
|
|
set.
|
|
|
|
### Claude Code
|
|
|
|
```bash
|
|
claude mcp add molecule -s user -- env \
|
|
WORKSPACE_ID=<your-workspace-uuid> \
|
|
PLATFORM_URL=https://<your-tenant>.moleculesai.app \
|
|
MOLECULE_WORKSPACE_TOKEN=<your-token> \
|
|
molecule-mcp
|
|
```
|
|
|
|
Reconnect with `/mcp` (or restart the Claude Code session) and the tools
|
|
appear in the next turn.
|
|
|
|
### Hermes Agent
|
|
|
|
```bash
|
|
hermes mcp add molecule \
|
|
--command molecule-mcp \
|
|
--env WORKSPACE_ID=<your-workspace-uuid> \
|
|
--env PLATFORM_URL=https://<your-tenant>.moleculesai.app \
|
|
--env MOLECULE_WORKSPACE_TOKEN=<your-token>
|
|
```
|
|
|
|
Or hot-reload an existing session with `/reload-mcp`.
|
|
|
|
### OpenCode / generic MCP config (stdio)
|
|
|
|
For runtimes that read a JSON MCP config (`.mcp.json`, `mcp_servers.yaml`,
|
|
or similar):
|
|
|
|
```json
|
|
{
|
|
"mcpServers": {
|
|
"molecule": {
|
|
"command": "molecule-mcp",
|
|
"env": {
|
|
"WORKSPACE_ID": "<your-workspace-uuid>",
|
|
"PLATFORM_URL": "https://<your-tenant>.moleculesai.app",
|
|
"MOLECULE_WORKSPACE_TOKEN": "<your-token>"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Cursor / Cline / other MCP clients
|
|
|
|
Most MCP clients accept the same `command` + `env` shape as the JSON
|
|
example above. Drop it into your client's MCP settings file
|
|
(typically `~/.cursor/mcp.json` for Cursor, the MCP Servers panel for
|
|
Cline) and restart the client.
|
|
|
|
## Optional — declare your identity & capabilities
|
|
|
|
Three additional env vars control how your workspace appears on the
|
|
canvas and to peer agents calling `list_peers`:
|
|
|
|
| Env var | What it sets | Default |
|
|
|---|---|---|
|
|
| `MOLECULE_AGENT_NAME` | Display name on the canvas card | `molecule-mcp-{id[:8]}` |
|
|
| `MOLECULE_AGENT_DESCRIPTION` | One-line description in Details/Skills tabs | empty |
|
|
| `MOLECULE_AGENT_SKILLS` | Comma-separated skill names — e.g. `research,code-review,memory-curation` | `[]` |
|
|
|
|
Skills are surfaced two places:
|
|
|
|
1. **Canvas Skills tab** — each skill renders as a chip with the name
|
|
2. **Peer agents calling `list_peers`** — they see `{name, skills: [...]}` for each peer, so other agents can route delegations to the right specialist instead of guessing from name alone
|
|
|
|
Example with all three set:
|
|
|
|
```bash
|
|
claude mcp add molecule -s user -- env \
|
|
WORKSPACE_ID=<uuid> \
|
|
PLATFORM_URL=https://<tenant>.moleculesai.app \
|
|
MOLECULE_WORKSPACE_TOKEN=<token> \
|
|
MOLECULE_AGENT_NAME='Research Assistant' \
|
|
MOLECULE_AGENT_DESCRIPTION='Reads, summarises, cites.' \
|
|
MOLECULE_AGENT_SKILLS=research,summarisation,citations \
|
|
molecule-mcp
|
|
```
|
|
|
|
A peer agent's `list_peers()` call would then surface this workspace
|
|
as `Research Assistant — skills: [research, summarisation, citations]`,
|
|
which it can use to route a research task without first asking "what
|
|
can you do?".
|
|
|
|
## Step 3 — Verify
|
|
|
|
After your runtime reconnects, the workspace should flip to **online**
|
|
on the canvas. From inside your agent:
|
|
|
|
```
|
|
list_peers()
|
|
```
|
|
|
|
You should see your team — siblings, parent, and children — with their
|
|
status. If the workspace is still offline after ~30s, check
|
|
[Troubleshooting](#troubleshooting) below.
|
|
|
|
## Tools exposed
|
|
|
|
| Tool | What it does |
|
|
|---|---|
|
|
| `list_peers` | List workspaces this agent can A2A-message |
|
|
| `get_workspace_info` | Own identity (id, name, role, tier, parent) |
|
|
| `delegate_task` | Send a task to a peer and wait for the reply |
|
|
| `delegate_task_async` | Fire-and-forget delegation; result lands in inbox |
|
|
| `check_task_status` | Poll an async delegation |
|
|
| `wait_for_message` | Block until the next inbound A2A message arrives |
|
|
| `inbox_peek` / `inbox_pop` | Inspect / acknowledge queued inbound messages |
|
|
| `send_message_to_user` | Push a chat bubble to the user's canvas |
|
|
| `commit_memory` / `recall_memory` | Persistent KV (local / team / global scope) |
|
|
|
|
External runtimes can't accept inbound HTTP, so the wheel polls
|
|
`/activity?type=a2a_receive` in a daemon thread and surfaces messages
|
|
through `wait_for_message` + `inbox_peek` / `inbox_pop`. Use those
|
|
instead of waiting for an HTTP webhook — there isn't one.
|
|
|
|
### Push-UX for notification-capable hosts
|
|
|
|
On top of the polling tools, the wheel emits a JSON-RPC notification
|
|
(`notifications/claude/channel`) on every new inbound message. Hosts
|
|
that recognise that method (Claude Code today; any compliant client
|
|
tomorrow) treat the notification as a conversation interrupt — the
|
|
message text becomes the next agent turn without the agent having to
|
|
call `wait_for_message` first.
|
|
|
|
Hosts that don't recognise the method silently ignore it, so the same
|
|
wheel works for both push-capable and poll-only runtimes. There is no
|
|
config flag to toggle: pollers keep polling, notification-capable hosts
|
|
get push automatically.
|
|
|
|
### MCP spec compliance
|
|
|
|
The wheel speaks MCP protocol version **2024-11-05** over stdio
|
|
JSON-RPC, declaring only the `tools` capability. It implements the
|
|
standard request methods and nothing client-specific:
|
|
|
|
| MCP method | Behavior |
|
|
|---|---|
|
|
| `initialize` | Echoes `protocolVersion: "2024-11-05"`, `serverInfo`, declares `tools` capability |
|
|
| `notifications/initialized` | No-op (no response — per spec) |
|
|
| `tools/list` | Returns all exposed tools in one response (no pagination cursor — surface is small) |
|
|
| `tools/call` | Dispatches by name, returns `content: [{ type: "text", text: ... }]` |
|
|
| _(unknown method)_ | Returns JSON-RPC error code `-32601` (Method not found) |
|
|
|
|
The push-UX notification (`notifications/claude/channel`) is the only
|
|
non-standard method emitted, and it's a one-way notification — clients
|
|
that don't handle it discard it per JSON-RPC semantics. No part of the
|
|
wheel's tool surface depends on a client recognizing it.
|
|
|
|
This means **any spec-compliant MCP client** can drive the wheel:
|
|
Claude Code, Cursor, Cline, OpenCode, hermes-agent, or anything else
|
|
that opens an MCP stdio connection. If your client speaks MCP, it
|
|
speaks the wheel.
|
|
|
|
## Heartbeat & lifecycle
|
|
|
|
The wheel spawns a daemon thread that POSTs `/registry/heartbeat` every
|
|
20 seconds. Your runtime stays `online` on the canvas as long as that
|
|
heartbeat lands.
|
|
|
|
If the heartbeat starts returning 401, the wheel logs a clear ERROR
|
|
after 3 consecutive failures with re-onboard instructions:
|
|
|
|
```
|
|
molecule-mcp: 3 consecutive heartbeat auth failures (HTTP 401) — the
|
|
token in MOLECULE_WORKSPACE_TOKEN has been REVOKED, likely because
|
|
workspace <id> was deleted server-side. The MCP server is still running
|
|
but every platform call will fail. Regenerate the workspace + token
|
|
from the canvas (Tokens tab), update your MCP config, and restart your
|
|
runtime.
|
|
```
|
|
|
|
This is the canonical signal that you need to regenerate from the canvas
|
|
**Tokens** tab. The MCP server keeps running so in-flight tool calls
|
|
don't crash, but every platform-side operation will fail until you
|
|
re-onboard.
|
|
|
|
## Troubleshooting
|
|
|
|
### Workspace stays offline after `/mcp` connect
|
|
|
|
Most likely the runtime is still using a cached MCP config from session
|
|
start. Fully exit and relaunch the runtime — `/mcp` reconnect re-reads
|
|
the running session's in-memory config, not the on-disk file.
|
|
|
|
### `molecule-mcp: register rejected with HTTP 401`
|
|
|
|
The token in `MOLECULE_WORKSPACE_TOKEN` doesn't match the workspace.
|
|
Regenerate from the canvas Tokens tab.
|
|
|
|
### `Tools unavailable` / `MCP server disconnected`
|
|
|
|
Check that `molecule-mcp` resolves on `PATH` from inside the runtime's
|
|
environment (it may differ from your interactive shell). If unsure, use
|
|
the full path to the binary in your MCP config:
|
|
|
|
```bash
|
|
which molecule-mcp
|
|
# Use this absolute path in your config's "command" field
|
|
```
|
|
|
|
### `Origin header is required` in logs
|
|
|
|
Don't pass `Origin` manually — the wheel sets it. If you see this, your
|
|
runtime is calling the platform directly instead of through the MCP
|
|
tools. Use the tools (`delegate_task`, `send_message_to_user`, etc.)
|
|
rather than hand-rolling HTTP calls.
|
|
|
|
### Tools call returns 401 / `workspace not found` after working before
|
|
|
|
The workspace was probably deleted from the canvas (or via DELETE
|
|
`/workspaces/:id`). Deleting a workspace revokes its token immediately,
|
|
even if the workspace card still appears with a "removed" badge for a
|
|
short window. The MCP server itself keeps running, so tool listing
|
|
still succeeds, but every platform call fails.
|
|
|
|
Regenerate from the canvas **Tokens** tab — a deleted workspace can't
|
|
be brought back; you'll get a new workspace + token pair. Update your
|
|
MCP config and restart your runtime.
|
|
|
|
### `claude mcp list` shows the new config but tools still 401
|
|
|
|
`/mcp` reconnect re-spawns the **cached** MCP config from session
|
|
start, not the latest on-disk config. After editing `claude mcp add`
|
|
or your `~/.cursor/mcp.json`, fully exit and relaunch the runtime —
|
|
not just `/mcp`.
|
|
|
|
A quick way to confirm: `ps aux | grep molecule-mcp` and check the
|
|
PID hasn't changed across `/mcp` reconnects. If the same PID stays
|
|
alive, the runtime is still using the old config.
|
|
|
|
### `command not found: molecule-mcp` from inside the runtime
|
|
|
|
The runtime's `PATH` may differ from your interactive shell — common
|
|
on macOS where `~/Library/Python/3.x/bin` is added to login shells but
|
|
not to GUI-launched apps. Use the absolute path in your MCP config:
|
|
|
|
```bash
|
|
which molecule-mcp
|
|
# /Users/you/Library/Python/3.13/bin/molecule-mcp
|
|
```
|
|
|
|
Then point `command` at that absolute path in `claude mcp add` /
|
|
`.cursor/mcp.json` / `mcp_servers.yaml`.
|
|
|
|
## When to use this vs. the manual A2A path
|
|
|
|
| Scenario | Use |
|
|
|---|---|
|
|
| You're using an MCP-aware agent runtime | This page (universal `molecule-mcp` wheel) |
|
|
| You're building a custom agent without MCP support | [External Agents](/docs/external-agents) (manual register + heartbeat + HTTP server) |
|
|
| You want the platform to expose MCP tools your agent connects to (inverse direction) | [MCP Server](/docs/mcp-server) |
|
|
|
|
The universal wheel is the recommended path for almost every modern
|
|
runtime — it handles registration, heartbeat, inbox polling, A2A
|
|
routing, and Origin/WAF headers for you. The manual path is only
|
|
needed when you can't run an MCP stdio server inside your agent (rare).
|
|
|
|
## See also
|
|
|
|
- [External Agents](/docs/external-agents) — manual A2A path for non-MCP runtimes
|
|
- [Tokens](/docs/tokens) — token management and rotation
|
|
- [Concepts — Workspaces](/docs/concepts#workspaces)
|
|
- [API Reference](/docs/api-reference) — raw HTTP endpoints behind the wheel
|