MCP server

An AI assistant can read a board over Model Context Protocol. It can list the workspace's cycles, read a cycle's board and read one objective — and it can do nothing else.

A person connects an assistant by signing in; see Signing in, below. Until 14 January 2027 a workspace API key also opens this door, for a client that cannot sign in. From that day a key opens the HTTP API only; see Authentication.

Signing in

Claude (claude.ai, Desktop and mobile), Claude Code and ChatGPT connect with the URL alone. The first request is refused with a challenge naming /.well-known/oauth-protected-resource/api/mcp; the client reads it, sends you to Improbable's sign-in, and asks which workspace to connect. One connection reads one workspace, as you.

A sign-in reads exactly what a key reads, needs the same plan, and stops working within a minute of you leaving the workspace. It asks for board:read user:org:read.

In the product, Set up MCP for Claude & ChatGPT — on your account menu, or MCP on the navigation rail — has your server URL and the steps for each client.

Picking the workspace

Every client reaches the same consent screen. Its list starts on the workspace your browser last had open in Improbable, or on the first one if it has none, so check it before you allow: a wrong pick reads that workspace — or nothing, if its plan does not include API access. To pick again:

  • Claude: see below.
  • Claude Code: run /mcp, choose the server, then Re-authenticate.
  • ChatGPT: see below.

Claude

Claude keeps connectors under Customize; Settings → Connectors only points there. Add the connector in claude.ai or Claude Desktop; it works in the mobile apps too:

  1. Open Customize → Connectors, press Add and choose Add custom connector.
  2. Name it, paste the server URL and press Continue. Claude finds the sign-in through the server's resource metadata, and preselects Sign in now and Use Claude's published identity — its client ID metadata document. Keep both and press Add.
  3. Press Connect and sign in.
  4. Pick the workspace to connect. The list may start on another one, so check it before you go on.

Picked the wrong workspace? In Customize → Connectors, open the connector, press Disconnect, then Connect, and pick again. If that workspace's plan has no API access, Claude shows Connection issue instead, with Reconnect: press it and pick again.

On Team and Enterprise, an Owner adds the connector first; members then connect it and sign in.

ChatGPT

On Plus and Pro, ChatGPT calls a custom server a plugin, and there is no developer mode to turn on first:

  1. Open Plugins, press Add at the top right and choose Add custom MCP server.
  2. Name it, paste the server URL and leave Authentication on OAuth. ChatGPT finds the sign-in through the server's resource metadata and registers itself with its client ID metadata document.
  3. Tick I understand and want to continue, then press Create as a plugin.
  4. Press Connect, then Continue to Improbable on ChatGPT's notice, and sign in.
  5. Pick the workspace to connect. The list may start on another one, so check it before you go on.

Picked the wrong workspace? On the plugin's page, choose Reconnect from your account's ⋯ menu and pick again. If that workspace's plan has no API access, ChatGPT shows the plugin as connected but with no tools, and does not fetch the tool list again on its own.

In the Mac app, sign-in finishes in your default browser ("Finish connecting in your browser"). That browser must be signed in to chatgpt.com with the same ChatGPT account as the app; finish in one signed in to another account and the app's account stays unconnected.

On Business and Enterprise, a workspace admin creates the plugin and publishes it; members then connect it and sign in.

Connecting a client that needs a bridge

Most desktop assistants speak MCP over a local process rather than over HTTP. mcp-remote is the bridge, and this is the block their config file wants:

{
  "mcpServers": {
    "improbable-board": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "https://app.improbable.work/api/mcp",
               "--header", "Authorization: Bearer imp_key_…"]
    }
  }
}

Replace the placeholder with a workspace API key, which an admin mints and which opens this door until 14 January 2027. The server key — improbable-board — is the name inside your own config file, not a protocol identifier: rename it freely, and give two workspaces two different names if you wire both into one client.

Connecting a client that speaks remote MCP

POST https://app.improbable.work/api/mcp

That URL, and nothing else for a client that signs in. Until 14 January 2027, an Authorization: Bearer header carrying a workspace API key opens it too.

The transport is streamable HTTP with JSON responses: one JSON-RPC request per POST, one JSON body back. There is no GET, so there is no server-initiated stream — which means no sampling, no elicitation, no progress notifications and no listChanged. There are no sessions either; nothing issues or validates an Mcp-Session-Id, so each request stands alone.

The server advertises itself as improbable-board version 1.0.0. That version tracks the tool surface below, not the product.

What the assistant can see

The assistant sees the same board a public embed link shows and nothing else — no email addresses, no employment records, no salary bands. The field list is on Read a board, and it is the same document.

That matters more here than on the HTTP door, and it is worth saying why: a model's copy of a payload lands in a context window, a chat log, a summary and a vendor's inference logs. None of those can be un-leaked by a revert.

Tools

The three tools
ToolArgumentsWhat it returns
list_cyclesNone.Every cycle the workspace has cut, with the id and ref that address it, and which one is current.
get_boardcycle, optional — a cycle id like 2026-C03 or a ref like 2026/Q3. Omit it for the current cycle.The whole board document, the same one the HTTP API returns.
get_objectiveid, required — an objective id from get_board.One objective, byte for byte the entry get_board would have returned. Current cycle only.

Every tool is annotated read-only, non-destructive and idempotent, and every result is said twice: as structuredContent, and as a single text block of the same JSON.

There are no write tools, and there is no plan under which there will be. A tool called update_objective on a read-only credential is a tool that exists to fail at runtime; the absence is cheaper than the refusal.

Resources

One resource template:

improbable://cycles/{cycle}/board

{"{cycle}"} takes a cycle id, a ref, or the literal current. Listing resources returns one entry per cycle, named by its id and titled by its label, with the current one marked. Reading one returns the board document as JSON.

The scheme is improbable:// rather than https:// on purpose: the URI names a resource this server holds, and it is not a URL anything can fetch.

Limits and refusals

How the MCP door refuses
SituationHTTPJSON-RPC code
No usable credential: no header, a malformed one, or a key that does not resolve. A self-hosted server with no sign-in says Invalid or missing API key, to a sign-in token too. The hosted app, where people sign in, names where to sign in and says Not signed in. Connect Improbable from your assistant and sign in — Set up MCP for Claude & ChatGPT has the steps.401-32001
A sign-in that is invalid or has expired. The response names where to sign in again.401-32001
A sign-in that did not grant board access. The response says which scopes to ask for.403-32006
A sign-in that names no workspace, or one you are no longer a member of; from 14 January 2027, a workspace key.403-32005
The sign-in could not be checked just now. Retry shortly; signing in again will not help.503-32603
Over the rate limit. Retry-After names the seconds.429-32002
The request carried an Origin header — this server does not accept requests from a browser.403-32003
The key is valid; the workspace's plan does not include this.403-32004
A batch — an array of requests. This server takes one request per call.400-32600
Unparseable JSON, or a body over 64 KB400 / 413-32700
An unknown tool, or a resource URI that is not the template above.200-32601
A bad argument — wrong type, or a missing required one.200-32602

The body's own refusals — a batch, unparseable JSON, a body over the cap — come only once every check above them in the table has passed. A request with no credential is a 401 whatever its body, a client's empty first request included; only an Origin header is refused ahead of it.

The rate limit is the HTTP API's — 60 requests a minute per key, shared across both doors, or per person per workspace for a sign-in, and per-process rather than cluster-wide. See Rate limits and errors.

The Origin refusal is worth reading twice if you are testing from a browser tool: any Origin header at all is refused, including the literal null a sandboxed frame sends. Nothing here sends a CORS header, so there is no browser client to be had.