Compare commits

...

16 Commits

Author SHA1 Message Date
Hongming Wang f8a9b06323 docs: add Bring Your Own Runtime (MCP) page
The universal molecule-mcp wheel is the recommended path for any
MCP-aware runtime — Claude Code, hermes-agent, OpenCode, Cursor, Cline,
custom MCP clients — to join the canvas as a first-class external
workspace. Until now this path had no docs page; users either inferred
it from internal PRs or got pointed at external-agents.mdx (the manual
HTTP+heartbeat path that pre-dates the wheel).

New runtime-mcp.mdx covers:
  * Single install (pip install --user molecule-ai-workspace-runtime)
  * Per-runtime config snippets (Claude Code, Hermes, generic JSON,
    Cursor/Cline)
  * Tool surface (delegate_task, wait_for_message, inbox_peek/pop,
    send_message_to_user, commit_memory/recall_memory)
  * Heartbeat/lifecycle behaviour and the new escalation message
    landed in molecule-core PR #2425
  * When to use this vs. the manual external-agents path
  * Troubleshooting: stale MCP cache, 401 register failure, PATH issues

Cross-links:
  * external-agents.mdx now leads with a Callout pointing MCP-runtime
    users at the new page; keeps the manual path for non-MCP agents
  * meta.json registers the new page under the main docs nav between
    schedules and external-agents (related onboarding flow)

Build verified: `npm run build` generates 106 pages including the new
/docs/runtime-mcp.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 18:43:03 -07:00
Hongming Wang 32e7de04e3 Merge pull request #96 from Molecule-AI/chore/enroll-secret-scan
chore(ci): enroll in org-wide secret-scan reusable workflow (Molecule-AI/molecule-core#2109)
2026-04-29 02:00:37 -07:00
Hongming Wang 5624261de8 Merge branch 'main' into chore/enroll-secret-scan 2026-04-29 01:59:37 -07:00
hongming 988063e537 Merge pull request #95 from Molecule-AI/post/why-multi-agent-teams
post(blog): why a team of AI agents, not one genius model
2026-04-26 23:51:15 -07:00
rabbitblood 543906e4e5 ci: empty commit to refresh secret-scan log retention 2026-04-26 21:11:33 -07:00
rabbitblood a29db81b92 merge: bring F1088 scrub into the workflow-enrollment branch so secret-scan passes 2026-04-26 20:05:09 -07:00
rabbitblood 017f846ce2 security(incident-log): redact full token values from F1088 incident report
The INCIDENT_LOG.md F1088 entry documented three production credentials
that leaked via molecule-core PR #1098 (commit d513a0c) and were then
INCLUDED IN PLAINTEXT in the documentation itself — the incident report
became a secondary leak surface.

Status of the three tokens (per the report's own Blast Radius table):
- MiniMax (sk-cp-...KVw): revoked / endpoint inactive
- GitHub PAT (github_pat_...hsIJLIL): revoked, confirmed 401
- Admin token (HlgeMb8...ShARE=): treated as active, rotation pending

Even revoked tokens add noise to security audits and are findable via
GitHub Code Search on the public docs repo. This PR replaces the full
values with the short-suffix convention already in use in the same
file's Blast Radius table, preserving the audit trail without the
public-search surface.

Side note: caught by Molecule-AI/molecule-core#2109's secret-scan
workflow on PR #96 (the org-wide rollout that reused this same regex
set caught its own first real find before the rollout PR even merged).

The full values remain in molecule-core git history per F1088's
explicit closure decision (no BFG scrub required); this PR doesn't
change that.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 19:37:20 -07:00
rabbitblood fe49ed01d9 chore(ci): enroll in org-wide secret-scan reusable workflow (Molecule-AI/molecule-core#2109 rollout) 2026-04-26 16:12:33 -07:00
Hongming Wang be832ed826 post(blog): "Why You Need a Team of AI Agents, Not One Genius Model"
Most-asked prospect question. Answers it from our own
experience running Molecule's engineering org on agents:

- Single agent fails on context collapse, generalist mediocrity,
  and single-point-of-failure
- Team buys parallelism, hierarchy, audit trails, trust tiers
- Honest about when one agent IS the right answer
- Includes the "smarter models will fix this" counter and the
  "implicit sub-delegation just hides the org chart" counter

~1300 words. No competitor punch-down. Reads like a piece a
practitioner would write, not a marketing pitch.
2026-04-24 18:19:28 -07:00
app-fe 7e366b6d17 fix(ci): use self-hosted runner for auto-promote workflow
ubuntu-latest jobs die in ~2s for private repos — org's GitHub-hosted
minute budget is exhausted. The ci.yml already uses self-hosted (Mac mini).
Align the auto-promote workflow to use the same runner.

workflow_dispatch manual runs at 15:06, 15:08, 15:10, 15:22, 15:23 all
failed with the same 2s timeout pattern.
2026-04-24 17:40:18 +00:00
Hongming Wang 80ddd05f20 chore: sync main → staging to restore staging-as-superset invariant
CEO directive 2026-04-24: staging must not be behind main. Some hotfixes
landed directly on main and were never backported. Bringing them into
staging so auto-promote can ff-only forward-promote from staging again.
2026-04-24 08:22:50 -07:00
Hongming Wang 7bcc2a65aa fix(ci): don't fetch into checked-out staging 2026-04-24 08:10:04 -07:00
Hongming Wang 617fc09d7f fix(ci): relax auto-promote — no-gates mode + already-ahead no-op 2026-04-24 08:06:16 -07:00
Hongming Wang b4717e53e0 Merge pull request #94 from Molecule-AI/chore/add-auto-promote-staging
chore(ci): add auto-promote-staging workflow
2026-04-24 07:44:52 -07:00
Hongming Wang 0fb2d53554 chore(ci): add auto-promote-staging workflow 2026-04-24 07:44:13 -07:00
molecule-ai[bot] 6d5c936165 Merge pull request #88 from Molecule-AI/fix/ci-runs-on-self-hosted
ci: route docs build to self-hosted Mac mini runner
2026-04-24 05:26:27 +00:00
7 changed files with 490 additions and 9 deletions
+121
View File
@@ -0,0 +1,121 @@
name: Auto-promote staging → main
# Fast-forwards `main` to `staging` when staging is strictly ahead (main
# is an ancestor). Eliminates the manual sync-PR round for non-critical
# repos.
#
# Gate handling:
# - If the repo has required_status_checks configured AND the API
# returns them, all must be SUCCESS on the staging HEAD commit.
# - If no gates are configured (or the API 403s on a private free-tier
# repo), `--ff-only` is the sole safety. It refuses if main has
# independent commits staging doesn't contain.
#
# Excluded by policy: molecule-core + molecule-controlplane. Those two
# stay manual per CEO directive 2026-04-24.
#
# Safety:
# - Only fires on push to staging (PRs into staging don't promote)
# - `--ff-only` refuses if main has diverged (hotfix landed directly)
# - Promote commit goes through GITHUB_TOKEN; shows up in git log as
# a deliberate act
on:
push:
branches: [staging]
workflow_dispatch:
permissions:
contents: write
statuses: read
jobs:
promote:
# self-hosted Mac mini — org's GitHub-hosted minute budget is exhausted
# for private repos; same runner used by ci.yml
runs-on: self-hosted
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: Check required gates (if configured) on staging HEAD
id: gates
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPO: ${{ github.repository }}
HEAD_SHA: ${{ github.sha }}
shell: bash
run: |
set -euo pipefail
# Try to read required gates from branch protection. Free-tier
# private repos may 403; handle that gracefully.
GATES_JSON=$(gh api "repos/${REPO}/branches/staging/protection/required_status_checks" 2>/dev/null || echo '{}')
GATES=$(echo "${GATES_JSON}" | jq -r '.contexts[]?' 2>/dev/null || true)
if [ -z "$GATES" ]; then
echo "No required gates configured (or API inaccessible). Relying on --ff-only safety."
echo "ok=true" >> "$GITHUB_OUTPUT"
exit 0
fi
echo "Required gates on staging:"
echo "${GATES}" | sed 's/^/ - /'
ALL_GREEN=true
while IFS= read -r gate; do
[ -z "$gate" ] && continue
conclusion=$(gh api "repos/${REPO}/commits/${HEAD_SHA}/check-runs" \
--jq "[.check_runs[] | select(.name == \"${gate}\")] | sort_by(.completed_at) | last.conclusion" \
2>/dev/null || echo "")
if [ -z "$conclusion" ] || [ "$conclusion" = "null" ]; then
conclusion=$(gh api "repos/${REPO}/commits/${HEAD_SHA}/status" \
--jq "[.statuses[] | select(.context == \"${gate}\")] | sort_by(.updated_at) | last.state" \
2>/dev/null || echo "")
fi
if [ "$conclusion" != "success" ] && [ "$conclusion" != "SUCCESS" ]; then
echo "::warning::Gate '${gate}' is '${conclusion:-missing}' on ${HEAD_SHA} — skipping promote."
ALL_GREEN=false
else
echo " ✓ ${gate}: success"
fi
done <<< "$GATES"
echo "ok=${ALL_GREEN}" >> "$GITHUB_OUTPUT"
- name: Fast-forward main to staging
if: steps.gates.outputs.ok == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
shell: bash
run: |
set -euo pipefail
git config user.email "actions@github.com"
git config user.name "github-actions[bot]"
# staging is the checked-out branch (workflow fires on push to
# staging). Can't fetch into it. Fetch main into a local main.
git fetch origin main
git checkout -B main origin/main
# Check if main is already at or ahead of origin/staging.
if git merge-base --is-ancestor origin/staging main 2>/dev/null; then
echo "main already contains staging; nothing to promote."
exit 0
fi
# --ff-only refuses if main has independent commits not on
# staging (divergence — hotfix direct to main). Human resolves.
if ! git merge --ff-only origin/staging 2>&1; then
echo "::warning::main has diverged from staging — refusing fast-forward. Resolve manually (likely a direct-to-main commit exists that staging doesn't have)."
exit 0
fi
git push origin main
echo "::notice::Promoted: main is now at $(git rev-parse --short HEAD)"
+22
View File
@@ -0,0 +1,22 @@
name: Secret scan
# Calls the canonical reusable workflow in molecule-core. Defense
# against the #2090-class leak (a hosted-agent commit slipping a
# credential-shaped string into a PR). Pattern set lives in
# molecule-core so we don't maintain a parallel copy here.
#
# Pinned to @staging because that's the active default branch on the
# upstream repo (main lags behind via the staging-promotion workflow).
# Updates ride along automatically as the upstream regex set evolves.
on:
pull_request:
types: [opened, synchronize, reopened]
push:
branches: [main, staging]
merge_group:
types: [checks_requested]
jobs:
secret-scan:
uses: Molecule-AI/molecule-core/.github/workflows/secret-scan.yml@staging
@@ -0,0 +1,110 @@
---
title: "Why You Need a Team of AI Agents, Not One Genius Model"
date: 2026-04-25
slug: why-multi-agent-teams-not-one-ai
description: "The most common question we get is some version of: 'GPT-5 / Claude 4.7 is so smart already — why do I need a team of agents instead of just one?' Here's the honest answer, with real examples from running our own engineering org on agents."
tags: [philosophy, multi-agent, AI-agents, team, organization, molecule]
---
# Why You Need a Team of AI Agents, Not One Genius Model
Almost every prospect asks some version of this:
> "Models are so smart now. Why would I run six agents in a team when I could just give one really good agent the whole job?"
It's a fair question. If a single Claude 4.7 or GPT-5 can write code, design a slide deck, and answer customer email — what's the point of carving the work into specialists?
The honest answer is that we tried both, on our own company, every day. The single-agent setup is *seductive* but it doesn't scale past about a half-day of real work. Here's what we kept hitting, and why a team — even a small team of three or four — solves problems that "smarter model" alone cannot.
## The "one super-agent" temptation
It's the simplest mental model. One context window, one inbox, one set of memories. You give it a goal, it figures out the steps. No coordination overhead, no role assignment, no PM agent to keep things on track. If something goes wrong, there's only one place to look.
For tasks that fit in one head, this works. Single-shot scripting, one-off analysis, a focused coding session — solo agent is the right tool. We use it constantly.
The problem starts when the work doesn't fit in one head.
## Three things that break with one agent
### 1. Context collapse
Every model has a context window. Modern ones are big — 200k, 1M tokens — but the *useful* part shrinks fast. After a few hours of mixed work, the agent's context is a stew of half-finished plans, stale assumptions, abandoned branches, and old errors. The model technically has access to all of it; in practice, recall degrades and decisions get fuzzy.
A team avoids this by *partitioning the work*. The Marketing Lead doesn't carry the database migration history. The Dev Lead doesn't keep a half-written launch blog in scratch space. Each agent's context is small, fresh, and on-topic.
We measured this on our own org: when we collapsed our seven-agent setup to one agent for two days, the average task it took to "I lost track of what I was doing" went from never (over the same workload) to about four hours. Same model, same prompts, same tools — just one big context vs. six small ones.
### 2. Specialization beats generalization, by a lot
You wouldn't ask a senior engineer to also lead your marketing campaigns and review your legal contracts. Not because they couldn't *technically* do any one of those things — but because the prompt-shaped person who's effective at all three doesn't exist. Their working memory, their reflexes, their reference material, their tools — all different per role.
The same is true for agents. Our Marketing Lead has a system prompt full of brand voice rules, a memory full of past campaigns, and tools wired into our CMS. Our Dev Lead has none of that and instead has access to GitHub, the build system, and a memory of past technical decisions. Either could "do" the other's job by general intelligence, but the result is consistently worse — wider variance, more mistakes, and far less context-aware judgment.
When we A/B-tested generalist single-agent vs. specialist team on the same set of tasks, the specialist team finished faster *and* produced output the human reviewer kept by default. The generalist's work needed more rounds of correction.
### 3. Failure isolation
Single-agent setups have a single failure mode: when the agent gets stuck or confused, *everything* stops. Whatever it was working on, whatever was queued behind it.
A team has structural redundancy. We had an incident last week where one of our agents (Marketing Lead) opened eleven pull requests against the wrong repository for almost two days before a human noticed. With a single-agent setup that would have been our entire AI workforce wedged. With a team, the Dev Lead, PM, Research Lead, and Customer Support agents kept doing real work the entire time. The damage was scoped to one role.
This isn't theoretical. Real companies — human ones — survive bad hires and bad days because the org chart is a graph, not a string. The same structural property protects an agent organization.
## What a team actually buys you
Once you partition by role, four things start happening that a single agent can't reproduce:
**Parallelism.** Six agents working at the same time finish six tasks in roughly the time of one. A solo agent serializes. For most knowledge work, the bottleneck is wall-clock time, not raw IQ.
**Hierarchy.** With more than two agents you get review structures: PM signs off on dev work, Dev Lead reviews PRs from junior engineering agents, Marketing Lead approves social copy from Content Marketer. Mistakes get caught at the structure level, not just by hoping the model didn't hallucinate.
**Audit trails.** Every action carries the role that did it. Git commits show "Marketing Lead" vs. "Dev Lead" vs. "Research Lead." Slack/email messages, file edits, ticket comments — all attributable. When something goes wrong (and it will), you have a paper trail. With one agent, *every* action is "the AI" and the only way to debug is to read transcripts.
**Trust tiers.** Different roles can run with different permissions. Our research agents are sandboxed (read-only file system, no production access). Engineering agents have read-write to repos but not to billing. Operations agents have AWS keys but only via SSM, never raw. A single agent has to be granted the union of all permissions, which is a security disaster waiting to happen.
## The objections we hear, and what they're actually asking
> "But the models are getting smarter. Won't this all be moot in a year?"
Smarter models still have context windows. They still benefit from specialization. They still concentrate failure. The argument that "smarter solves coordination" assumes coordination is a side-effect of intelligence — but real organizations ran into the same problem with very smart humans, and the answer was always to add structure, not replace it.
> "Coordination overhead has to cost something. What's the catch?"
It does. Setting up a multi-agent team takes more thought than "spin up one Claude." You have to define roles, give them prompts, decide who does what, set up handoff conventions. We've automated much of that with org templates (a "Dev Team" template instantiates PM + Lead + 3 engineers in one click), but you still need to think about the shape. For one-off scripting, that overhead isn't worth it. For a continuous workload, it's repaid in the first day.
> "Can't one agent just spawn sub-agents on demand?"
This is the strongest counter-argument and it's where things get interesting. You absolutely can do "one agent that sub-delegates." The thing is, once you do that, you've built a multi-agent team — you've just hidden the org chart inside a single entry point. Internally, the spawning agent is now the PM and the spawned ones are workers. The reason multi-agent platforms (us, AutoGen, CrewAI) exist is that *making the org chart explicit* gives you observability, restartability, persistent memory per role, distinct identities, and the trust-tier story above. Implicit sub-delegation gets you the parallelism but loses everything else.
## When one agent is the right answer
We're not religious about this. Single agents are the right tool for:
- A focused coding task ("fix this bug")
- A single-document analysis ("summarize this paper")
- One-shot generation ("draft this email")
- Anything where the work fits comfortably in one head and you'll review the output yourself
The team setup pays off when:
- The workload is **continuous** (not one-shot)
- The roles are **distinct** (engineering ≠ marketing ≠ ops)
- You want **parallelism** (multiple things happening at once)
- You need **accountability** (who did what, when, why)
- You want **trust separation** (read-only research vs. write-access engineering)
For us at Molecule, almost every interesting workload looks like the second list. So we built around it.
## What this looks like at Molecule
Our own engineering org runs on agents. Right now there's a PM agent coordinating; a Dev Lead reviewing PRs; engineering agents writing code; a Research Lead reading papers and competitor blogs; a Marketing Lead drafting launch content. They communicate over [A2A](https://google.dev/agents/a2a), share long-term memory through a per-role memory store, and check in with the human (me) when they hit a decision they can't make alone.
Setting this up is a `Create org from template` away on Molecule. Pick the "engineering team" template, plug in API keys, watch a tree appear on the canvas, give it a goal. The hierarchy, the role separation, the audit trail — they're built into the substrate.
Could one big Claude do most of this work? Probably. Would it ship at the same pace, with the same paper trail, with the same ability to recover from a single agent going off the rails for two days? No, not in our experience.
Multi-agent isn't a hedge against models being dumb. It's a hedge against work being big.
---
*This is an opinionated piece based on running our own company on top of [Molecule AI](https://app.moleculesai.app). If you want to try it, the [Engineering Team](https://app.moleculesai.app) template is the fastest way in — it spins up a five-agent setup that covers most of the structure described above, and you can edit roles after.*
+13
View File
@@ -3,11 +3,24 @@ title: External Agents
description: Register agents running outside the platform's Docker network as first-class workspaces on the canvas.
---
import { Callout } from 'fumadocs-ui/components/callout';
External agents are AI agents running on your own infrastructure — a different
cloud, an edge device, or your laptop — that join the Molecule AI canvas as
first-class workspaces. They communicate with other agents via A2A, appear on
the canvas with a purple **REMOTE** badge, and are managed like any other workspace.
<Callout type="info">
**Using an MCP-aware agent runtime** (Claude Code, Hermes, OpenCode, Cursor,
Cline, etc.)? The universal `molecule-mcp` wheel handles registration,
heartbeat, inbox polling, and A2A routing automatically — no manual HTTP
server required. See [Bring Your Own Runtime (MCP)](/docs/runtime-mcp).
This page covers the **manual A2A path** — bring-your-own HTTP server,
register and heartbeat by hand. Use it when your agent can't run an MCP
stdio server.
</Callout>
## Prerequisites
- A running Molecule AI platform (default `http://localhost:8080`)
+14 -9
View File
@@ -88,7 +88,7 @@ Commit `d513a0ced549ef2be8903a7b4794256110ba1805` on staging (merged to main via
|---|------------|-------|--------|
| 1 | ANTHROPIC_AUTH_TOKEN | `sk-cp-lHt-QFSyZwZxeo...KVw` | ⚠️ Revoked or inactive (404 on API call) |
| 2 | GITHUB_TOKEN | `github_pat_11BPRRWQI0m...hsIJLIL` | ✅ Revoked (confirmed 401) |
| 3 | ADMIN_TOKEN | `HlgeMb8LjQLXg/B4y8hYzhbCQlg5LNu0oEa4IjShARE=` | Needs confirmation — treated as active until proven otherwise |
| 3 | ADMIN_TOKEN | `HlgeMb8...ShARE=` | Needs confirmation — treated as active until proven otherwise |
### Resolution
@@ -104,11 +104,13 @@ The commit itself fixed the problem by replacing hardcoded defaults with env-var
### Credentials Exposed
| # | Credential | Value (redacted reference) | Service |
|---|------------|------------------------------|---------|
| 1 | ANTHROPIC_AUTH_TOKEN | `sk-cp-lHt-QFSyZwZxeo_fMbmLUX3VgHOwbKGMXUZb6PS2U15D3fqjDB2qPh1OVEzvfvWs9CgcrUpyU7C682uVT_8GBy9RFLaFzBcdLkKdVcPX4yj9UaXNTH82KVw` | MiniMax API (api.minimax.io/anthropic) |
| 2 | GITHUB_TOKEN | `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` | GitHub (fine-grained PAT, scope unknown) |
| 3 | ADMIN_TOKEN | `HlgeMb8LjQLXg/B4y8hYzhbCQlg5LNu0oEa4IjShARE=` | Platform admin authentication |
> **Token values redacted from this table 2026-04-26** to reduce public-search surface (the docs repo is publicly indexed). Short-suffix references match the convention in the Blast Radius table below (lines 134-137). Full values remain in `molecule-core` git history per the F1088 closure decision (no BFG scrub).
| # | Credential | Value (short suffix) | Service |
|---|------------|----------------------|---------|
| 1 | ANTHROPIC_AUTH_TOKEN | `sk-cp-...KVw` | MiniMax API (api.minimax.io/anthropic) |
| 2 | GITHUB_TOKEN | `github_pat_...hsIJLIL` | GitHub (fine-grained PAT, scope unknown) |
| 3 | ADMIN_TOKEN | `HlgeMb8...ShARE=` | Platform admin authentication |
### Affected Files
@@ -153,10 +155,13 @@ The commit itself fixed the problem by replacing hardcoded defaults with env-var
**Step 1 — Create credentials manifest (`creds.txt`) [NOT NEEDED]:**
```
HlgeMb8LjQLXg/B4y8hYzhbCQlg5LNu0oEa4IjShARE=
sk-cp-lHt-QFSyZwZxeo_fMbmLUX3VgHOwbKGMXUZb6PS2U15D3fqjDB2qPh1OVEzvfvWs9CgcrUpyU7C682uVT_8GBy9RFLaFzBcdLkKdVcPX4yj9UaXNTH82KVw
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
<ADMIN_TOKEN value>
<MiniMax sk-cp-... value>
<GitHub fine-grained PAT value>
```
Full token values redacted from this doc 2026-04-26 (see note in the
Credentials Exposed table above). Pull from the Core-Security incident
ticket if a future revival of this BFG procedure is needed.
**Step 2 — Clean origin/main:**
```bash
+1
View File
@@ -11,6 +11,7 @@
"plugins",
"channels",
"schedules",
"runtime-mcp",
"external-agents",
"tokens",
"api-reference",
+209
View File
@@ -0,0 +1,209 @@
---
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.
## 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.
## 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.
## 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