SynthBoard MCP help center
Connect Claude Desktop, Cursor, ChatGPT, or any MCP-compatible client to a full SynthBoard account. 42 tools, 18 resources, 11 prompts — one engine.
Quick start
From zero to your first board in 4 steps.
- 1Create an API keyOpen the Control Center → API Keys and click Create key. The key is shown exactly once — copy it somewhere safe.
- 2Paste into your client configPick your client below. Each has a dedicated config file — paste the snippet and replace
sb_live_...with your real key. - 3Restart the clientQuit fully and reopen. The SynthBoard tools + prompts should appear in the client's tool menu.
- 4Try a promptType
/synthboard-boardroomand ask a real strategic question. The decision brief staffs the board; the board debates and delivers a memo.
Client setup
All 6 supported clients. Click a tab to switch.
{
"mcpServers": {
"synthboard": {
"url": "https://synthboard.ai/api/mcp",
"headers": { "Authorization": "Bearer sb_live_..." }
}
}
}Your first board
What actually happens when your agent starts a SynthBoard session.
Ask a real strategic question. Your agent calls synthboard.session.plan, shows you the proposal, then starts the run. No synth-picking needed — an adaptive decision brief reads the question and staffs the right advisors.
// 1. Plan — nothing charged yet
{ "name": "synthboard.session.plan",
"arguments": {
"question": "Should we launch a free tier next quarter?",
"session_type": "boardroom",
"mode": "decision"
} }
// → { plan_id, proposal, estimated_credits, expires_at }
// 2. Start with the approved plan
{ "name": "synthboard.session.start",
"arguments": { "plan_id": "<plan_id>" } }
// → { session_id, task_id, session_type: "boardroom", session_url }
// 3. Wait for the run (long-poll up to 60s per call)
{ "name": "synthboard.session.get",
"arguments": { "session_id": "<id>", "wait_ms": 60000 } }
// → { v4_phase: "done", decision_brief, memo: { verdict,
// confidence_0_100, conditions, dissent } }What you'll see
- Within seconds:
session_id,task_id, and a link to watch live on synthboard.ai. - Phase progress as the board moves: intake → staffed → research → debate → memo.
- On completion: the decision memo — verdict, confidence, conditions, and the strongest dissent — or a shaped artifact for non-decision asks.
For a 1-on-1 instead of a full board, plan with session_type: "consult" and a synth_id, then drive turns with synthboard.consult.message.
Plan-before-start
The product rule: no surprise sessions. Sessions must be approved or explicitly configured.
Sessions can't auto-start from a bare question. That protects users and their credit balance from runaway agent loops. You have two paths:
Path A — preview, then start
- Call
synthboard.session.planwith the question (+ optional session_type / mode / synth_id). - Receive a
plan_idvalid for 15 min + the full proposal (staffing note, mode, credit estimate). - Show it to the user in whatever client invoked the tool.
- If approved → call
synthboard.session.start({plan_id}). The plan is consumed; replay is blocked.
Best for interactive clients (Claude Desktop, ChatGPT). Users see what they're about to spend before committing.
Path B — explicit start
Call synthboard.session.start with an explicit setup: boardroom = question + session_type or mode; consult = question + synth_id. The explicit setup counts as consent. Best for automation (n8n, cron, scripts) where you've already decided.
Legacy fields (synth_ids, rounds, llm_model) are still accepted — they map to pinned seats and per-seat model overrides.
Bare calls (question only, no plan_id and no setup signal) return validation_error with actionable guidance.
How sessions run
The concepts behind every MCP/API session — same engine as the web app.
Two rooms
boardroomThe BoardroomA staffed board of advisors debates your question across research + debate phases and delivers a decision memo or shaped artifact.
consultThe ConsultA 1-on-1 session with a single named expert. Conversational, turn-based, billed per turn.
Express intake & the decision brief
Sessions started over MCP/API skip the interactive intake: a single facilitator pass turns your question + context into a decision brief — the framed question, the known facts, and the staffed board (which advisors, which seats, why). The brief is returned on session.get as decision_brief.
Board phases
v4_phase tracks the run: intake → staffed → research → debate → memo → done. Each seated advisor researches independently, the board debates with genuinely opposed theses, and the run terminates in a deliverable.
The deliverable: memo or shaped artifact
- Decision boards deliver a decision memo: the verdict, confidence (0–100), the conditions that would flip it, and the strongest dissent — under a named author.
- Every other ask delivers a board artifact shaped to the question — a plan, forecast, comparison, research brief, diagnosis, and more. Read it via
board_artifactor thesynthboard://session/{id}/memoresource.
Reconvene: Round N+1
A finished board isn't continued — it's reconvened. When something changed, call synthboard.session.reconvene({session_id, whats_changed}). The new round opens from the board's delivered call (verdict, confidence, dissent) plus your update, re-briefs, and runs — returning a new session_id linked to the parent. (session.continue remains for legacy-engine sessions and redirects boards here.)
Consult turns
A Consult is a conversation, billed per turn. Each synthboard.consult.message call sends one message to the seated expert and returns their reply — plus a composed document when the ask calls for one (a memo, an email, a plan). If wait_ms elapses, the turn keeps running server-side; re-read via session.get.
Your World Model & wm_scope
The board keeps a dossier on your world — identity, situation, goals, constraints, the names that matter — and a searchable memory of every delivered call. Agents read it via the synthboard://world-model resource and search it with synthboard.world_model.search (decisions, memos, board artifacts, world-model facts). Every session binds a wm_scope at creation (accepted by session.plan and session.start):
| wm_scope | Board reads your world | Session writes back |
|---|---|---|
| grounded (default) | Yes | Yes — learnings update the dossier and memory |
| read_only | Yes | No — nothing from this session is remembered |
| off_record | No | No — fully off the record, excluded from search too |
A reconvened round inherits its parent's scope — an off-record board's Round 2 stays off the record. The weekly Board Brief is readable at synthboard://briefs/latest.
Pricing & billing
MCP uses the same credit system as the web UI. Tier controls capacity.
| Tier | Concurrent | Max synths | Web / vision | Max rounds |
|---|---|---|---|---|
| Free | 1 | 3 | — | 1 |
| ProPopular | 3 | 5 | ✓ | 5 |
| Max | 10 | 8 | ✓ | 5 |
| Ultra | 25 | 12 | ✓ | 5 |
Every paid tier gets the full feature surface — no lockouts. Credits self-price richness. Max synths shows the default per tier; the live value is account-configurable and enforced server-side.
What does a typical session cost?
session.plan returns a pre-flight estimated_credits before anything is charged.Can I cap spend per key?
Failed session — do I get refunded?
Does MCP cost more than the web UI?
Rate limits & concurrency
Operational caps, not feature gates. Baselines below are the Pro tier; other tiers multiply.
Rate limits are per-user (or per-OAuth-client) per bucket. The baseline numbers below apply to Pro; other tiers multiply the baseline — Free ×0.15, Max ×3.3, Ultra ×16 (minimum 1). Buckets without explicit config get a bounded default of 30/min. Concurrent-session caps are enforced atomically — there's no way to race past them.
| Bucket | Pro baseline | Window |
|---|---|---|
| session.plan | 120 | 1 h |
| session.start | 60 | 1 h |
| session.get | 60 | 1 min |
| session.list | 60 | 1 min |
| session.continue | 20 | 1 min |
| session.fork / session.reconvene | 30 | 1 h |
| session.outcomes / session.share | 30 | 1 h |
| session.export | 60 | 1 h |
| synth.chat / consult.message | 100 | 1 h |
| assistant.ask | 100 | 1 h |
| bookmark.create / decision.capture | 200 | 1 h |
| catalog.search / resource reads | 60 / 120 | 1 min |
| action.execute / action.undo | 10 | 1 min |
| share.verify_password | 10 | 1 min |
| webhooks read / write (REST) | 60 / 20 | 1 min |
Hit a limit? The error tells you exactly which cap and when to retry (retry_after_s). Watch live headroom on the usage dashboard.
Scopes (8)
Every tool demands exactly one scope. Create keys with only what the workload needs.
| Scope | Grants |
|---|---|
| session:read | Read sessions, tasks, transcripts, exports, shares |
| session:write | Create/reconvene/cancel/fork/share sessions + bookmarks/decisions |
| synth:chat | 1-on-1 synth chat + Consult turns |
| synth:read | Read synth profiles + knowledge listings |
| synth:write | Create/edit/delete custom synths, preferences, knowledge |
| assistant:use | Session Assistant Q&A |
| integrations:read | List connected integration providers |
| integrations:write | Execute/undo tool actions + webhook subscription CRUD |
Security
Built for production from day one.
Your API key is shown exactly once, then hashed. Revoke or rotate anytime — it takes effect instantly.
Lock any key to the IPs you trust. Calls from anywhere else are rejected before they reach a tool.
Claude.ai, ChatGPT and other browser-based clients authenticate through modern, short-lived OAuth tokens.
Webhooks can't reach internal networks. Only public HTTPS endpoints are allowed.
Tool inputs are sandboxed before they ever reach a model, with layered guards on top.
Every call logged with caller, tool, session, and cost. Filterable and exportable as CSV from the Control Center.
Key management
Stay out of trouble.
- One key per client. Separate keys for Claude Desktop, Cursor, and automation scripts — revocation stays surgical.
- Rotate quarterly. Click Rotate on a key to create a replacement with the same scopes. Old key works for 24 hours while you update clients.
- Set a cap for automation. For n8n, Zapier, cron, anywhere you can't watch — a daily credit cap prevents runaway loops.
- Never commit keys. Keep them out of git. If exposed, revoke instantly — it takes effect in real time.
- Scope down. A read-only automation doesn't need
session:write. Create keys with just the scopes you need.
OAuth 2.1 (for web clients)
How Claude.ai web, ChatGPT apps, and other browser-embedded clients authenticate.
Most MCP clients (Claude Desktop, Cursor, Windsurf, Zed, scripts) authenticate with a Bearer API key — simplest, fastest. Browser-based clients like Claude.ai web don't accept raw keys; they use OAuth 2.1 for user-mediated consent. SynthBoard exposes a native, spec-compliant Authorization Server at the standard discovery endpoints.
Discovery metadata
GET /.well-known/oauth-authorization-server— RFC 8414 AS metadataGET /.well-known/oauth-protected-resource— RFC 9728 protected-resource metadataGET /.well-known/jwks.json— public JWKS for token verification
Flow
- Dynamic client registration (RFC 7591):
POST /api/oauth/registerwith your client metadata. https-only redirect URIs required. - Authorize: send user to
/api/oauth/authorizewithresponse_type=code,code_challenge(S256),resource(your MCP URL), scopes. - Consent page: user sees plain-English scope descriptions and approves. CSRF-protected.
- Token exchange:
POST /api/oauth/tokenwith the code + PKCE verifier. Receive a 10-minute access token and 7-day rotating refresh token. - Use on /api/mcp — JWT in
Authorization: Bearer. Server validates signature, audience (audmust match resource URL, RFC 8707), expiry, and revocation status on every call. - Refresh: rotate the refresh token before the access expires. Reused old refreshes trigger grant-chain revocation.
Webhooks
Two delivery systems coexist. Use subscriptions — the per-key mechanism is legacy.
Board runs take 30 seconds to a few minutes. Instead of polling, subscribe and let SynthBoard call you. There are two contracts with different signatures — verify with the right one:
Subscriptions — X-SynthBoard-Signature
- Manage in Control Center → Webhooks or via
POST /api/v1/webhooks. Multiple subscriptions, per-event filters. - All 6 events:
session.complete,session.failed,session.cancelled,session.continued,session.reconvened,outcomes.ready. - Fired by the engine itself — session completion/failure from the orchestrator, cancellation and follow-up rounds from the tools, deliverables from outcomes.
- Signature:
X-SynthBoard-Signature: sha256=<hex>— HMAC-SHA256 of`${timestamp}.${body}`with the subscription's secret (returned once on create). - Headers:
X-SynthBoard-Event,X-SynthBoard-Timestamp(unix seconds),X-SynthBoard-Delivery-Id.
Per-key webhook — X-Mcp-Signature
- Configured as a Webhook URL on an API key (not via /webhooks). Kept for existing integrations — new setups should use subscriptions.
- Fires
session.completeonly, when a session started with that key finishes. - Signature:
X-Mcp-Signature: sha256=<hex>— HMAC-SHA256 of the raw body alone (no timestamp in the MAC) with the key'swhsec_secret. - Headers:
X-Mcp-Event,X-Mcp-Timestamp,X-Mcp-Delivery-Id.
Delivery guarantee
Every started session ends in exactly one terminal event — session.complete, session.failed (including engine timeouts swept by the watchdog, delivered with reason: "timeout"), or session.cancelled. Build state machines on that invariant.
Retries — both systems
Any non-2xx retries with backoff at 1, 5, 15, 60, 240 minutes — 5 attempts total. Subscriptions additionally auto-disable after 10 consecutive failures (re-enable in the Control Center, which resets the breaker).
Verify — subscriptions (Node.js)
import { createHmac, timingSafeEqual } from "node:crypto";
function verifySubscriptionWebhook(
rawBody: string, sigHeader: string, tsHeader: string, secret: string,
): boolean {
if (Math.abs(Date.now() / 1000 - Number(tsHeader)) > 300) return false; // replay guard
const expected = "sha256=" + createHmac("sha256", secret)
.update(`${tsHeader}.${rawBody}`).digest("hex");
const a = Buffer.from(sigHeader), b = Buffer.from(expected);
return a.length === b.length && timingSafeEqual(a, b);
}Verify — legacy per-key (Node.js)
import { createHmac, timingSafeEqual } from "node:crypto";
function verifyLegacyKeyWebhook(
rawBody: string, sigHeader: string, secret: string, // whsec_...
): boolean {
const expected = "sha256=" +
createHmac("sha256", secret).update(rawBody).digest("hex");
const a = Buffer.from(sigHeader), b = Buffer.from(expected);
return a.length === b.length && timingSafeEqual(a, b);
}Use webhook.site for a zero-setup inbox, or the Send test button on any subscription in the Control Center — it fires a signed test.ping without touching your delivery stats.
Tool reference (42)
The complete tool surface, grouped. Every tool demands one scope.
Session lifecycle (13)
synthboard.session.plansession:writePropose a full session setup + credit estimate without starting. Returns a single-use plan_id (15 min).
question, session_type?, mode?, synth_id? (consult), context?, web_search?, language?
synthboard.session.startsession:writeLaunch a session from an approved plan_id or an explicit setup. Boardroom: the decision brief staffs the advisors. Consult: requires synth_id.
plan_id | (question + session_type/mode) | (question + synth_id), preselected_synth_ids?, focus_synth_id?, synth_model_overrides?, images?, tags?
synthboard.session.getsession:readSession state + latest task. On finished boards: v4_phase, decision_brief, memo, board_artifact.
session_id, wait_ms? (≤60000), include_transcript?, include_tool_calls?, include_action_items?
synthboard.session.continuesession:writeFollow-up round on a legacy-engine session. Current boards redirect to session.reconvene.
session_id, message
synthboard.session.reconvenesession:writeReconvene a completed board as Round N+1 — opens from the delivered verdict plus what changed, re-briefs, runs.
session_id, whats_changed, question?, keep_board?
synthboard.session.cancelsession:writeCancel the in-flight task. Work delivered is retained; the remainder is refunded.
session_id, reason?
synthboard.session.updatesession:writeMid-session mutations on legacy-engine sessions — add/remove synths, change mode, tune DNA/model/temperature. Current boards redirect to session.reconvene.
session_id, add_synths?, remove_synths?, change_mode?, tune?
synthboard.session.forksession:writeDuplicate a session with altered context; rerun=true starts the fork immediately.
session_id, new_context?, rerun?
synthboard.session.listsession:readFilter, search, sort, and paginate your sessions.
status?, mode?, tag?, q?, since?, until?, sort?, limit?, cursor?
synthboard.session.update_metasession:writeRename a session or update its tags.
session_id, topic?, tags?
synthboard.session.deletesession:writeHard-delete a draft. Non-drafts archive instead.
session_id, confirm: true
synthboard.session.archivesession:writeHide a session from default listings (or bring it back). Idempotent.
session_id, action: archive | unarchive
synthboard.session.exportsession:readExport as markdown, JSON, or plain text with selectable parts.
session_id, format, include? (transcript/synthesis/bookmarks/decision/action_items/full_reasoning)
The Consult (1)
synthboard.consult.messagesynth:chatSend one message to the seated expert of a Consult session; returns the reply and any composed document. Billed per turn.
session_id, message (≤5000), wait_ms? (≤290000)
In-session interaction (7)
synthboard.session.outcomessession:writeGenerate a polished deliverable — action plan, report, decision memo, or bullets.
session_id, format?, include?
synthboard.session.live_summarysession:readLive consensus snapshot — who agrees, who dissents, running confidence.
session_id
synthboard.session.cross_roundsession:readHow positions evolved across rounds.
session_id
synthboard.synth.chatsynth:chatDirect message to a specific synth inside a session.
session_id, synth_id, message
synthboard.assistant.askassistant:useQ&A grounded in the session transcript + synthesis.
session_id, question
synthboard.bookmark.createsession:writeSave a moment — a claim, agreement, conflict, or pinned thread.
session_id, type, item_text, synth_id?, note?
synthboard.decision.capturesession:writeRecord a formal decision with rationale, stakeholders, deadline, action items.
session_id, decision, rationale?, stakeholders?, deadline?, action_items?, confidence?
Your World Model (1)
synthboard.world_model.searchsession:readHybrid semantic + keyword search over your board's memory — captured decisions, delivered memos, board artifacts, and world-model facts. Off-record material is never returned.
query, types? (decision | memo | board_artifact | wm_fact), limit?
Synth management (7)
synthboard.synth.createsynth:writeCreate a custom advisor — name, role, persona, expertise, DNA, model, training files.
name, role, system_prompt, tagline?, expertise_tags?, dna_*?, preferred_model?, training_files?
synthboard.synth.updatesynth:writeEdit one of your custom synths. Core synths use preferences.set.
synth_id + any editable field
synthboard.synth.deletesynth:writePermanently delete a custom synth.
synth_id, confirm: true
synthboard.synth.getsynth:readFetch one synth — core, public, or your own (own prompt included).
synth_id
synthboard.synth.listsynth:readList core, public, and your own synths with search + filters.
search?, core_only?, expertise?, limit?, offset?
synthboard.synth.preferences.setsynth:writePer-user overlay for a core synth — DNA, model, temperature, directions.
synth_id, dna_*?, preferred_model?, temperature?, user_directions?
synthboard.synth.preferences.resetsynth:writeReset your core-synth overlay to defaults.
synth_id, confirm: true
Synth knowledge (4)
synthboard.synth.knowledge.addsynth:writeGive a custom synth permanent knowledge from a URL or text (RAG). 1 credit per source.
synth_id, source: url | text, url?, text?, label?
synthboard.synth.knowledge.listsynth:readList a custom synth's knowledge files.
synth_id
synthboard.synth.knowledge.removesynth:writeDelete a knowledge file and its chunks.
synth_id, file_id, confirm: true
synthboard.synth.knowledge.promote_sessionsynth:writePersist a session's uploaded documents into a synth's permanent knowledge. Idempotent.
session_id, synth_id, source_files?
Shares (4)
synthboard.session.sharesession:writeCreate a share link — public, password, or invite.
session_id, type, password?, invite_emails?, expires_in_days?, share_scope?
synthboard.share.listsession:readEvery active share for a session, with codes, URLs, and expiry.
session_id
synthboard.share.revokesession:writeInvalidate a share link immediately.
share_code, confirm: true
synthboard.share.verify_passwordsession:readValidate a guest password against a protected share.
share_code, password
Actions & integrations (3)
synthboard.integrations.listintegrations:readYour connected providers across the live integration catalog.
synthboard.action.executeintegrations:writeRun a Recommended Action through a connected tool — same Skeptic gate, undo window, and audit as the web.
session_id, action_item_id, tool_slug, arguments?, skeptic_token?
synthboard.action.undointegrations:writeBest-effort reversal within the 30-second undo window.
event_id
Utilities (2)
synthboard.pingno scopeConnectivity check — returns the authenticated principal. No billing.
synthboard.catalog.searchsession:readSearch synths, modes, templates, strategies, and models.
query?, kind?, limit?
Resources (18) & prompts (11)
Deep-linkable, cacheable read surfaces — plus slash commands.
MCP Resources are the "GET" side of SynthBoard — read them any time for the latest state. Resource subscriptions are not supported: for live board tracking, poll synthboard.session.get with wait_ms (long-polls up to 60s per call), or use webhooks to be called when a run finishes.
| URI | Returns |
|---|---|
| synthboard://session/{id} | Full session state — plus decision brief, memo, and board artifact on finished boards. |
| synthboard://session/{id}/memo | The board's terminal deliverable alone — decision memo or shaped artifact. |
| synthboard://session/{id}/synthesis | Round summaries + synthesis blocks. |
| synthboard://session/{id}/outcomes | Captured decisions, action plan, outcomes. |
| synthboard://session/{id}/transcript | Complete agent message transcript. |
| synthboard://session/{id}/bookmarks | Saved moments with notes. |
| synthboard://session/{id}/citations | Web-search citations used in the session. |
| synthboard://session/{id}/canvas | Canvas layout, positions, metadata. |
| synthboard://synth/{id} | Public-safe profile — role, tagline, expertise, rating. |
| synthboard://catalog/synths | The full public synth library. |
| synthboard://catalog/modes | All session modes with recommended setups. |
| synthboard://catalog/templates | Pre-built decision templates. |
| synthboard://catalog/synthesis_strategies | All 5 synthesis strategies with best-for guidance. |
| synthboard://catalog/models | LLM models available at your tier — same list as the web UI. |
| synthboard://recent | Your 20 most recent sessions, engine + phase aware. |
| synthboard://account | Credit balance, tier, engine, available session types. |
| synthboard://world-model | The board's dossier on your world — identity, situation, goals, constraints, named entities — plus per-section counts, freshness, and per-seat calibration records (whose judgment has held up, per decision type). |
| synthboard://briefs/latest | Your most recent weekly Board Brief — the standing board's proactive read on your world. |
All session-scoped resources enforce ownership — cross-tenant reads return not_found, never a leak. Catalog resources are public read-only.
11 slash-prompts
Pre-configured commands — each routes through the plan-first flow with a mode signal./synthboard-consult opens the 1-on-1 room.
/synthboard-boardroom/synthboard-debate/synthboard-stress-test/synthboard-quick-take/synthboard-deep-dive/synthboard-decision/synthboard-war-room/synthboard-forecast/synthboard-research/synthboard-brainstorm/synthboard-consultError code reference (29)
Every error carries a code, message, correlation_id, and — over REST — the HTTP status below.
| Code | HTTP | Meaning | Fix |
|---|---|---|---|
| unauthorized | 401 | Missing / malformed Authorization header | Send Authorization: Bearer sb_live_... |
| forbidden | 403 | Authenticated but not allowed | Check ownership and key scopes |
| invalid_credentials | 401 | Key invalid, expired, or revoked | Create a new key |
| key_revoked | 401 | This key was revoked | Create a new key |
| ip_not_allowed | 403 | Request IP not in the key's allowlist | Remove the allowlist or add your IP |
| scope_missing | 403 | Key lacks the required scope | Create a key with the scope |
| mcp_disabled | 403 | The MCP/API surface is disabled | Contact support |
| validation_error | 400 | Tool argument failed schema validation | Check error details for the field |
| not_found | 404 | Resource doesn't exist or isn't yours | Verify the ID |
| rate_limited | 429 | Too many calls for your tier | Wait retry_after_s seconds |
| concurrent_session_limit | 429 | Max parallel sessions reached | Wait or cancel one |
| insufficient_credits | 402 | Balance below the estimate | Top up credits |
| insufficient_credits_mid_execution | 402 | Credits ran out mid-run | Top up; delivered work is retained |
| daily_spend_cap_exceeded | 429 | The key's daily credit cap is reached | Wait for reset (midnight UTC) or raise the cap |
| monthly_budget_exceeded | 429 | The key's monthly credit budget is reached | Wait for month start (UTC) or raise the budget |
| idempotency_mismatch | 400 | Same idempotency_key, different arguments | Use a fresh key per distinct call |
| invalid_synth | 400 | Synth ID not in the library | Check synthboard.synth.list |
| invalid_mode | 400 | Unknown session mode | Check synthboard://catalog/modes |
| invalid_session_state | 400 | Session can't accept this operation (e.g. continue on a finished board) | Follow the guidance in details — usually session.reconvene |
| session_not_complete | 500 | Operation needs a completed session | Wait for the run to finish |
| session_failed | 500 | The session run failed | Check the error, re-run or fork |
| task_not_found | 404 | No task execution for this ID | Verify the task_id |
| user_banned | 403 | Account suspended | Contact support |
| ssrf_blocked | 403 | URL pointed at a private/internal host | Use a public https URL |
| upstream_error | 500 | An upstream model/provider failed | Retry; fallback chains handle most cases |
| timeout | 504 | The operation exceeded its time budget | Retry; check session.get for partial state |
| internal_error | 500 | Unexpected server error | Contact support with the correlation_id |
| failed_precondition | 412 | A precondition isn't met (e.g. provider not connected) | Check details; connect the integration |
| resource_exhausted | 429 | Provider-side quota exhausted | Wait and retry |
A few statuses differ over REST where HTTP semantics demand it (e.g. concurrent_session_limit → 409, upstream_error → 502).
Troubleshooting
Client says 'connection refused'
- URL:
https://synthboard.ai/api/mcp - Confirm the
Authorizationheader includes the full key including thesb_live_prefix. - Quit + relaunch the client. Config is read at startup.
- Hit /api/mcp/health — should return
{ "ok": true }.
session.continue says invalid_session_state
synthboard.session.reconvene with whats_changed.concurrent_session_limit error
synthboard.session.cancel. Tier limits appear in the error details.insufficient_credits
Session stuck 'running' forever
session.failed webhook with reason timeout. Cancel via synthboard.session.cancel; credits charged up to that point are retained.401 Unauthorized
Claude.ai web isn't discovering OAuth
https://synthboard.ai/api/mcp — the /api/mcp suffix is required for metadata discovery.Still stuck?
Every error response includes a correlation_id. Include it in any support request and we can trace the full call in our audit log.