Driftless ships an MCP (Model Context Protocol) server that exposes your workspace context to AI clients. ChatGPT, Claude, Copilot, and any MCP-compatible client can read and write topics through it.
How it works
The MCP adapter runs at apps/mcp and translates MCP tool calls to the existing Driftless REST API. It is a protocol adapter only: it never accesses Postgres, internal libraries, or workspace admin operations directly.
Start here: retrieve
When you have a task but no topic slug yet, the first call is
driftless_context_retrieve: it returns the team’s most relevant recorded
context for a task description, a set of files, or both, ranked drifted-first and
bounded. It composes search + match-files + list filters so you don’t hand-chain
them. Bodies come back brief by default (the durable why, not the full
content); call driftless_context_get for the one topic whose full body you
need, or pass view: "full". See Payload views
below.
The MCP surface is documented by family in the MCP reference. Use this page for setup and auth; open a family page for tool names, actions, parameters, permissions, and examples.
| Family | What it covers | Reference |
|---|
| Knowledge and governance | Retrieve, read, write, graph, health, tags, areas, and the Note to Knowledge lifecycle | MCP: Knowledge and governance |
| Projects and operations | The project card loop, collections, records, and entities | MCP: Projects and operations |
| Integrations and Broker | Operating a connected provider (gated) | MCP: Integrations and Broker |
| Workspace and collaboration | Comments, members, workspaces, and proposal stats | MCP: Workspace and collaboration |
The surface covers context (topics, governance, the graph), the work surface (projects, cards, tags, areas), the operational substrate (collections, records, entities), and broker execution (operating connected providers). It never covers workspace admin, repo registration, key management, integration setup (connecting a provider), authoring/deploying integration scripts, or manual agent-run triggering. Topics live in the workspace and are visible to its members; another’s private drafts stay hidden. Work-surface writes require the work:write scope; merging into Knowledge needs owner/admin authority, and the MCP client runs it only when the authorizing owner/admin explicitly asks.
Every result (search, list, get) carries a flat trust field (reviewed | proposed | draft), so an agent can key on trust === "reviewed" directly instead of inferring it from classification.status + governance.authoritative. reviewed is Knowledge, the team’s source of truth; proposed/draft are Notes (hints).
Payload views keep reads fast
Reads default to a light payload so a result never floods your context. The
vocabulary is the same everywhere (summary / brief / full):
summary: an index row (id/slug, title, trust, badges, anchors). Lists and
search return this, bounded (top 5 search, top 40 list).
brief (the default for driftless_context_retrieve and
driftless_context_get_for_files) is the durable why: what / decisions /
gotchas / invariants, without the full content. Roughly 76% lighter than a
full body.
full: everything, including the heavy content body. Never a default
elsewhere; you opt in with view: "full". driftless_context_get is the
exception: it defaults to full because you named the one topic you want.
The pattern: retrieve / get_for_files in brief to see which topic governs
the work, then driftless_context_get (full) for the single body you actually
need, instead of pulling every full body up front.
Broker (execution) vs integration setup
driftless_broker only operates a connection that already exists
(operations / invoke / records / events / criterion). Connecting a
provider is integration setup: a privileged human-led flow done in the
dashboard (Settings → Connections) or via the CLI integration connect/confirm
commands; it is not on the MCP surface. Authoring or deploying a Nango action is a
third, human-only lane. If an agent needs a broker operation that operations
does not list, it must report the missing capability. Never write or
deploy a script to fill the gap.
Beyond the static tools above, the MCP server can synthesize extra read-only tools per
workspace from a provider’s ready capabilities: driftless_<provider>_records and
driftless_<provider>_page_content (for example, driftless_notion_page_content). They
appear only when broker tool synthesis is enabled and the provider exposes a ready,
read-effect capability of a synthesizable kind, capped per workspace. Two rules follow: a
listed tool is not a usable one (a synthesized or static broker tool still resolves through
the broker API, where an external caller is gated by rollout and grants), and write
capabilities are never synthesized. See Broker.
Typed relations from the MCP
create and update accept rels, typed graph edges, the same seven types as the CLI’s --rel:
{ "topic": "refund-flow", "rels": [
{ "to": "billing-flow", "type": "depends_on" },
{ "to": "stripe-webhook-ingest", "type": "relates_to" }
] }
Types: relates_to, depends_on, supersedes, blocks, implements, documents, risk_for. Each edge is created with per-relation tolerance: a bad edge reports {ok: false, error} in the tool result without losing the topic or the remaining edges. Both endpoints must exist and be visible to you.
Server-side anchor validation
Remote agents have no local checkout, so write responses carry anchor_validation, per-pattern match counts against the repo’s default branch: ok, overbroad (>100 files), or zero. Warnings never block the write (a glob anchoring unmerged branch code legitimately shows 0); read them in the tool result and tighten flagged globs.
MCP clients (claude.ai, ChatGPT) cache tool schemas per connector session. After Driftless ships a schema change, reconnect the connector (or start a fresh session) to pick it up. Otherwise new parameters or tools won’t be available. The work-surface tools (tags, areas, project, project_card) are action-based: pass action to pick the operation; if your client still shows the old per-operation tool names (e.g. driftless_tags_create), reconnect to refresh.
Governance from the MCP
A topic becomes Knowledge only once an owner/admin merges it in. An MCP client always puts a Note up for review (driftless_context_propose); it can also merge (driftless_context_approve), but only with owner/admin authority. The MCP token acts as the human who authorized it, so approve succeeds only when that human is an owner/admin, and the client should run it only when they explicitly ask (a member’s or faceless token is refused). The merge is stamped approved_via: agent. See Governance.
Authentication
All MCP requests require authentication. Unauthenticated requests receive HTTP 401 with a WWW-Authenticate header pointing to the OAuth discovery endpoints.
There are two ways to authenticate:
- API key: pass your Driftless API key in the
X-API-Key header. Best for CLI, agents, and CI.
- OAuth 2.0: for published AI clients (ChatGPT, Claude) that need per-user consent. The server supports dynamic client registration and PKCE.
Connecting with an API key
Add this to your claude_desktop_config.json or equivalent:
{
"mcpServers": {
"driftless": {
"url": "https://api.driftless.icu/mcp",
"headers": {
"X-API-Key": "drift_your_api_key_here"
}
}
}
}
For local development, use http://localhost:3020/mcp and your local API key.
Connecting with OAuth (Claude.ai, ChatGPT)
Published clients use OAuth 2.0 with PKCE. The flow is fully automatic for Claude.ai:
- Enter
https://api.driftless.icu/mcp as the MCP endpoint in Claude.ai
- Claude.ai discovers the OAuth endpoints automatically via
/.well-known/oauth-protected-resource and /.well-known/oauth-authorization-server
- You authorize in the Driftless consent screen
- Claude.ai receives a bearer token and uses it for all MCP tool calls
No manual configuration needed. Claude.ai handles registration, PKCE, and token refresh.
OAuth 2.0 reference
Dynamic client registration
Any client can register without authentication:
curl -X POST https://api.driftless.icu/api/v1/oauth/register \
-H "Content-Type: application/json" \
-d '{
"client_name": "My AI Client",
"redirect_uris": ["https://myapp.com/oauth/callback"]
}'
OAuth scopes
| Scope | Description |
|---|
context:read | Read topics and context |
topics:create | Create new topics |
topics:write | Update existing topics |
work:write | Write the work surface: projects, cards, collections, records, entities, comments, tags, areas, plus merge and share actions |
context:diff | Read topic diff for local changes |
broker:read | Read broker connections, capabilities, and records |
broker:invoke | Invoke a broker operation |
broker:admin | Manage broker grants and criterion |
offline_access | Refresh access without reconnecting |
The broker:* scopes are enforced only when the Broker is enabled, and they gate its lane on top of rollout and grants. Discovery metadata advertises a subset of scopes; the enforced set is the authority.
Endpoints
| Method | Path | Purpose |
|---|
GET | /.well-known/oauth-protected-resource | MCP resource metadata (RFC 9728) |
GET | /.well-known/oauth-authorization-server | Authorization server metadata (RFC 8414) |
GET | /.well-known/openid-configuration | OIDC-compatible discovery alias |
GET | /api/v1/oauth/authorize | Authorization consent screen (redirects to dashboard) |
POST | /api/v1/oauth/token | Exchange code for access token |
POST | /api/v1/oauth/register | Register an OAuth client (RFC 7591) |
POST | /api/v1/oauth/revoke | Revoke an access token |
Token security
- Authorization codes, access tokens, and refresh tokens are stored as hashes only, never plaintext
- Tokens are never logged or returned after initial issuance
- The MCP server does not import
@driftless/db, typeorm, or any internal library; it calls the REST API exclusively