Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f8a9b06323 | |||
| 32e7de04e3 | |||
| 5624261de8 | |||
| 988063e537 | |||
| 543906e4e5 | |||
| a29db81b92 | |||
| 017f846ce2 | |||
| fe49ed01d9 | |||
| be832ed826 | |||
| 7e366b6d17 | |||
| 80ddd05f20 | |||
| 7bcc2a65aa | |||
| 617fc09d7f | |||
| b4717e53e0 | |||
| 0fb2d53554 | |||
| 6d5c936165 |
@@ -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)"
|
||||
@@ -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.*
|
||||
@@ -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`)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
"plugins",
|
||||
"channels",
|
||||
"schedules",
|
||||
"runtime-mcp",
|
||||
"external-agents",
|
||||
"tokens",
|
||||
"api-reference",
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user