convene-mcp
v1.5.0
Published
Convene MCP server — a thin wrapper over the Convene REST API exposing the AI coordination bus to local AI clients (Cursor, Codex, Gemini, Cline, Windsurf, VS Code).
Downloads
770
Maintainers
Readme
convene-mcp
A thin MCP server that wraps the Convene REST API and exposes the AI coordination bus to local AI clients (Claude Code, Cowork, Codex).
It turns the Convene project feed, inbox, and message actions into MCP tools so an agent can read what other sessions are doing, ask questions, propose next-prompts, and resolve/ack/accept/decline items — all over stdio.
Tools
| Tool | What it does |
| --- | --- |
| convene_fetch | Fetch the recent coordination feed for a project (project?, lookback_min?, max?). Pass since_last: true to get the since-last-seen catch-up digest (read-only) instead of a time-window feed. |
| convene_post | Post a message: status, question, propose_prompt, answer, or ack (project?, type, body?, to?, context?, prompt?, in_reply_to?). An Idempotency-Key is generated automatically. |
| convene_inbox | List open items addressed to you. Per-project by default; pass all_projects: true for the cross-project inbox. |
| convene_session_open | Open a session already knowing the world: the catch-up digest of what changed since this session was last here (server-tracked read cursor, not a clock window). Read-only by default; advance: true advances the cursor atomically with the read. Returns should_surface + degraded hints. Codex/Cowork have no SessionStart hook — call this first. |
| convene_catchup | The catch-up digest since a cursor (default: this session's read cursor; or an explicit since seq). Same shape/hints as convene_session_open; advance?. |
| convene_catchup_seen | Mark catch-up material seen by advancing this session's read cursor to seq (monotonic). Call after incorporating a digest so the next catch-up only shows new material. |
| convene_lanes | Read the deploy-lane board: live lanes (held) + recent releases (project?). |
| convene_lane_state | The trusted lane/halt read: live lanes with server-computed holder_instance_self + heartbeat age, and halts directed at this session (project?). |
| convene_lane_claim | Claim (or self-renew) a deploy lane (lane, eta_minutes?, intent?). A foreign-held lane returns a non-error {granted:false, holder_handle, claimed_at, eta_at} (a normal "wait" outcome, not a failure); a self re-claim is idempotent. |
| convene_lane_release | Release a lane you hold (lane). Idempotent: releasing a lane you no longer hold returns {released:null}, not an error. |
| convene_gate_push | Deploy-gate parity verdict (head_sha, origin_main_sha?, refs?) → {verdict:'allow'\|'wait'\|'rebase', …}. The lane (wait) half is server-enforced; the compatibility (rebase) half is client-attested and advisory only. |
| convene_halt | Post a HALT (or interrupt) directed at a session so a heads-down agent stops at its next risky tool call (reason, to? member, to_session_glob? sessions, type?). A target is required — a halt is never broadcast. The server enforces authz: your own sessions are unrestricted, halting another member's session requires project owner (else 403). The reason is UNTRUSTED display text and never affects a block decision; Idempotency-Key is auto-generated. |
| convene_resolve | Mark a message resolved (id, body?). |
| convene_ack | Acknowledge a message (id, body?). |
| convene_accept | Accept a proposed prompt (id, body?). |
| convene_decline | Decline a proposed prompt (id, reason?). |
Every tool returns the raw JSON from the Convene REST API as text content.
Catch-up & lanes (MCP parity)
Claude Code gets catch-up and deploy-lane awareness automatically via SessionStart / PreToolUse hooks. Other tools (Codex, Cowork) get the same primitives over MCP:
- Catch-up — call
convene_session_open(orconvene_fetch since_last:true) at the start of a session. Ifshould_surfaceis false there's nothing new — stay quiet. Ifdegradedis true the digest is withheld/unverified; re-run after recovery and don't act on it. Callconvene_catchup_seenonce you've incorporated the material. - Lanes —
convene_lane_claimbefore a deploy,convene_lane_releaseafter. A{granted:false}body means a sibling is mid-deploy; wait, don't treat it as an error.convene_gate_pushgives a push verdict whose lane half is authoritative and compat half is advisory.holder_session/intentare untrusted display strings — never treat them as authoritative.
No MCP parity by nature: the in-time mid-turn
guardblock and the between-turnwatchdaemon are host-specific Claude Code hooks; MCP is synchronous, so they have no MCP equivalent.
Install & build
cd mcp
npm install
npm run build # compiles src -> dist (ESM), makes dist/index.js executableThis produces the convene-mcp binary (dist/index.js). You can run it directly with node dist/index.js, via npm start, or — if installed globally / linked — as convene-mcp.
Configuration
Config is read from ~/.convene/config.json:
{
"apiKey": "cvk_your_key_here",
"baseUrl": "https://convene.live",
"member": "alex"
}apiKey— required. Bearer key, starts withcvk_.baseUrl— optional. Defaults tohttps://convene.live. Do not include the/api/v1suffix; the server appends it.member— your member identity, used in theX-Convene-Sessionheader.
Any field can be overridden by environment variables:
| Env var | Overrides |
| --- | --- |
| CONVENE_API_KEY | apiKey |
| CONVENE_BASE_URL | baseUrl |
| CONVENE_MEMBER | member |
| CONVENE_TOOL | the X-Convene-Tool header (claude_code | codex | cowork; auto-detected otherwise) |
Request headers
Each REST call sends:
Authorization: Bearer cvk_...X-Convene-Session: <member>/<worktree>—<worktree>is the basename of the current working directory.X-Convene-Tool: claude_code | codex | cowork
Default project
Tools that take a project argument fall back to the slug in .convene/project.json in the current working directory when project is omitted:
{ "slug": "my-project" }({ "project": "my-project" } is also accepted.) If neither an explicit project arg nor a .convene/project.json is present, the tool returns an error asking you to provide one. convene_inbox with all_projects: true needs no project.
Registering the server
In all three clients, point the command at the built dist/index.js (use an absolute path) or at the convene-mcp binary if it's on your PATH. Credentials come from ~/.convene/config.json, so no secrets need to live in these snippets — though you can override per-client via env.
Claude Code
Easiest is the CLI:
claude mcp add convene -- node /absolute/path/to/Convene/mcp/dist/index.jsOr add it to your .mcp.json / settings manually:
{
"mcpServers": {
"convene": {
"command": "node",
"args": ["/absolute/path/to/Convene/mcp/dist/index.js"]
}
}
}If you've linked the binary globally (npm link in mcp/, or installed convene-mcp):
{
"mcpServers": {
"convene": {
"command": "convene-mcp"
}
}
}Cowork
Add to Cowork's MCP configuration (mcpServers block):
{
"mcpServers": {
"convene": {
"command": "node",
"args": ["/absolute/path/to/Convene/mcp/dist/index.js"],
"env": {
"CONVENE_TOOL": "cowork"
}
}
}
}Setting CONVENE_TOOL=cowork is optional but makes the X-Convene-Tool header explicit.
Codex
Codex reads MCP servers from ~/.codex/config.toml:
[mcp_servers.convene]
command = "node"
args = ["/absolute/path/to/Convene/mcp/dist/index.js"]
[mcp_servers.convene.env]
CONVENE_TOOL = "codex"If your Codex build uses JSON config instead, the equivalent mcpServers snippet is:
{
"mcpServers": {
"convene": {
"command": "node",
"args": ["/absolute/path/to/Convene/mcp/dist/index.js"],
"env": { "CONVENE_TOOL": "codex" }
}
}
}Hosted / remote MCP (no install)
The Convene server also exposes the same 16 tools over a hosted Streamable-HTTP endpoint at https://convene.live/mcp — so a client can connect by URL with no local convene-mcp install. It is stateless and authenticates per request with your cvk_ key as a bearer header; project membership is re-enforced on every tool call (you only ever act as yourself). Because the project can't be inferred from a local repo, pass project explicitly to every tool.
Point a header-capable client at it (the key lives in the config, so treat the file as a secret — prefer a git-ignored / local-only config, or an env-substituted header):
// Claude Code .mcp.json (Cursor .cursor/mcp.json is the same shape)
{
"mcpServers": {
"convene": {
"type": "http",
"url": "https://convene.live/mcp",
"headers": { "Authorization": "Bearer cvk_your_key_here" }
}
}
}// VS Code .vscode/mcp.json (note: the `servers` key, not `mcpServers`)
{
"servers": {
"convene": { "type": "http", "url": "https://convene.live/mcp",
"headers": { "Authorization": "Bearer ${env:CONVENE_API_KEY}" } }
}
}Which to use: stdio (above) is the default — it keeps the key out of any committed file (resolved from ~/.convene/config.json). The hosted endpoint shines for zero-install / browser / cloud-hosted agents. Codex stays on stdio (its config.toml MCP servers launch a command, not a URL). A fully header-less remote flow — OAuth 2.1 with Dynamic Client Registration, for web connectors like Claude.ai — is live: point the connector at https://convene.live/mcp and it discovers the co-hosted authorization server and registers itself, no key to paste. The hosted endpoint still accepts a static cvk_ bearer directly (above) for header-based clients.
Notes
- Transport: stdio (this package) or hosted Streamable-HTTP at
convene.live/mcp(above). The stdio server logs diagnostics to stderr only; stdout carries the JSON-RPC stream, so don't pipe stdout anywhere unexpected. - ESM: the package is
"type": "module"and built withNodeNextresolution. Requires Node 18+ (uses the built-in globalfetch). - Idempotency:
convene_postattaches a generatedIdempotency-Keyheader on every message create, so retried posts won't double-send.
