Corveil MCP (connect a client)
Corveil exposes all of its first-party tools as a remote MCP (Model Context Protocol) server at one endpoint: /mcp. Any MCP-aware client — Claude Code, Codex CLI, Claude Desktop, ChatGPT Desktop, Cursor — can point at it, authenticate with a virtual API key or a browser OAuth flow, and call Corveil's tools alongside its own.
Two MCP surfaces
This page is inbound: connect a client to Corveil's own tools at /mcp.
To govern external MCP servers (GitHub, AWS, …) behind Corveil — one org-held credential, RBAC, and audit — see MCP Gateway (govern external servers).
One connection carries three families of tools, delivered as namespaces:
ontology_*— read your organizational knowledge graph: the entities, meetings, decisions, and people the gateway has already indexed for your org.insights_*— read generated intelligence: rolling summaries, activity-derived recommendations, and auto-built user profiles.control_*— operate Corveil itself: models, keys, guardrails, prompts, teams, sensors, org settings, billing. Mutating, and destructive operations require an explicitconfirm: true.
Which namespaces you receive depends on how you authenticate — see The three namespaces below. This page is for wiring an external client to the /mcp endpoint.
Endpoint & authentication
Streamable HTTP transport. Org scoping is by construction: the credential's organization is the only data the server can return, and a cross-org probe comes back empty rather than erroring.
POST https://your-corveil-host/mcp
X-Corveil-Key: sk-citadel-your-key-here
Content-Type: application/json
Accept: application/json, text/event-streamThere are two ways to authenticate the same endpoint:
| Method | Header | Best for |
|---|---|---|
| Virtual API key | X-Corveil-Key: sk-citadel-… (or x-api-key:) | Headless clients, CI, scripts. Create one under People & Access → API Keys. |
| OAuth 2.0 + DCR | Authorization: Bearer crv_at_… | Interactive clients with native OAuth (Claude Desktop, ChatGPT Desktop, Codex CLI ≥ 0.4). No key ever leaves Corveil — see Connect without an API key. |
The two paths are additive: OAuth is purely a keyless alternative for clients that support it, and the API-key path stays as-is for everything else.
The three namespaces
A single connection can carry well over a hundred tools. Which of the three namespaces you actually receive is decided by your credential class, so the same endpoint is safe to hand to a browser connector and to a CI key alike:
| Credential | ontology_* | insights_* | control_* |
|---|---|---|---|
| Virtual API key / dashboard session | ✅ | ✅ | ✅ † |
| OAuth / DCR bearer | ✅ | — | — |
| Unauthenticated / in-process | ✅ | ✅ | — |
† The control_* namespace is offered to a control-capable credential only when the deployment has the control plane enabled.
The MCP resource scopes advertised on the RFC 9728 protected-resource metadata and the Connect page catalog (GET /api/oauth/scopes) are mcp.read, mcp.tools, and mcp.write. A client that requests only mcp.read + mcp.tools stays read-only on the graph — that is the common Claude Desktop / ChatGPT Desktop path. mcp.write is what "whose grant permits it" means for the write tools already on this page; it is not implied by mcp.tools. control_* is still never granted to an OAuth bearer, so a browser-consented connector can never mutate your configuration. Crow connected-app scopes (orgs.read, keys.provision) are authorization-server-wide and are deliberately excluded from the MCP catalog — do not treat them as MCP connector scopes.
Tools you are not entitled to are absent from tools/list and refused on tools/call — knowing a tool's name is not enough to invoke it.
Narrowing the tool list
Because one connection can expose the whole first-party surface, you can narrow it to just the namespaces a given agent needs — smaller tool lists keep a model focused and cheaper. Append ?ns= to the URL:
https://your-corveil-host/mcp?ns=ontology,insights…or send an X-Corveil-MCP-Namespaces: ontology header. Narrowing only ever shrinks the list — a selector can never grant a namespace your credential lacks, and an unrecognized selector yields an empty list rather than everything.
Tool reference
Ontology (ontology_*) — read the knowledge graph
Three ergonomic primitives cover most work:
| Tool | Purpose |
|---|---|
ontology_lookup | "Tell me about X." Resolve an entity by name (+ optional entity_type) or entity_id; returns the synthesized context bundle — properties, 1-hop relationships, identity records, source-event count. |
ontology_search | Open-ended search. query plus optional entity_types[], a time_range (since/until), and conversation_id/thread_id to scope to one chat. |
ontology_related | The 1..N-hop neighborhood of an entity. entity_id (preferred) or name+entity_type, optional depth (default 1, max 5). |
Lower-level reads for drilling into a specific entity or source:
| Tool | Purpose |
|---|---|
ontology_entity | The entity's own fields (no edges). |
ontology_context | Full synthesized page + relationships + identity records. |
ontology_graph | Explore connected entities and relationships within N hops. |
ontology_evidence | The source events that produced or mention an entity (newest first). |
ontology_timeline | Those source events in chronological order. |
ontology_history | Per-entity change history: one attributed, newest-first feed merging the decision/audit log (edits, with a field-level diff) and the source-event timeline. Identify the entity by id, or by type + name. Optional limit (default 50) and offset. |
ontology_event | The full original content of one source event, by id. |
ontology_source_fetch | The full session transcript behind a session-derived entity. |
ontology_stats | Scalar counts + extraction status for the graph. |
ontology_decisions | The decision / guardrail audit trail. |
ontology_policies | Active organizational policies governing AI usage. |
Write tools — present only for callers whose org has the ontology-write feature and whose grant permits it (mcp.write on an OAuth bearer; it is not implied by mcp.tools), and concealed from tools/list otherwise:
| Tool | Purpose |
|---|---|
ontology_create_entity | Create (or merge into) an entity. Idempotent on entity_type + name. |
ontology_update_entity | Update a known entity's properties, name, or aliases. |
ontology_link | Create a directional relationship between two existing entities. |
ontology_unlink | Remove a relationship (destructive — pass confirm: true). |
ontology_propose_merge | File a reviewable proposal to merge duplicate entities (does not merge). |
ontology_set_content | Write the entity's synthesized knowledge page (markdown). Replaces any prior page wholesale — fold existing facts in rather than dropping them. Distinct from ontology_update_entity, which sets structured attributes. |
Insights (insights_*) — read generated intelligence
| Tool | Purpose |
|---|---|
insights_summaries | Organizational summaries (type: hourly / daily / weekly) — markdown digests of what teams are working on. Optional user_id, limit, offset. |
insights_recommendations | Activity-derived, actionable recommendations as markdown. Optional limit, offset. |
insights_profiles | Auto-built user profiles — expertise, projects, focus areas. Optional user_id; omit for all. |
Control (control_*) — operate Corveil itself
The control namespace is one tool per control-plane operation — around a hundred of them — named control_<area>_<verb>, e.g. control_keys_list, control_keys_create, control_teams_delete, control_guardrails_update. They span:
| Area | What it manages |
|---|---|
| Keys & credentials | Virtual API keys, provider credentials |
| Models & pricing | The model registry and pricing |
| Guardrails & prompts | Content guardrails and saved prompts |
| Teams, users & org | Teams, members, invitations, org settings |
| Sensors & jobs | Sensor configuration and scheduled jobs |
| Billing, usage & logs | Billing, usage rollups, request logs |
| Sessions & export | Sessions and data export |
Because the set is large and evolves, treat tools/list as the source of truth for the exact names your build and credential expose. Four conventions apply across the namespace:
- Destructive operations return a
requires_confirmationpreview unless you passconfirm: true— the mutation never runs on the first, un-confirmed call. - Privilege / enable–disable flips require the same
confirm: true, but only when the call actually sets the gated field. - Idempotent operations accept an optional retry key so a re-sent call returns the original result instead of acting twice.
- Optimistic concurrency: operations that support it accept an
If-Matchprecondition (a resource'supdated_at, or*for "must exist").
Client setup
Point the client at /mcp over the HTTP (Streamable HTTP) transport and set the X-Corveil-Key header.
Claude Code (~/.config/claude-code/mcp.json)
{
"mcpServers": {
"corveil": {
"transport": {
"type": "http",
"url": "https://your-corveil-host/mcp",
"headers": {
"X-Corveil-Key": "sk-citadel-your-key-here"
}
}
}
}
}Codex CLI (~/.codex/config.toml)
[mcp_servers.corveil]
url = "https://your-corveil-host/mcp"
http_headers = { "X-Corveil-Key" = "sk-citadel-your-key-here" }Verify the connection
# tools/list returns the namespaces your credential is entitled to.
curl -sS https://your-corveil-host/mcp \
-H "X-Corveil-Key: sk-citadel-your-key-here" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'Connect without an API key (OAuth + DCR)
Corveil's MCP endpoint also speaks OAuth 2.0 + RFC 7591 Dynamic Client Registration, so clients with native OAuth support connect without ever seeing an sk-citadel-… key. The user clicks Connect in their MCP client, a browser opens to a Corveil consent screen, they approve, and the client is authorized.
- In the client's "Add remote server" dialog, paste your Corveil host URL —
https://your-corveil-host/mcp— and leave the API-key field empty. - The client fetches the endpoint's protected-resource metadata (
/mcp/.well-known/oauth-protected-resource, or the equivalent/.well-known/oauth-protected-resource/mcp), discovers the authorization server, registers itself viaPOST /mcp/oauth/register, and opens the consent screen. - If you're not already signed in, you'll bounce through WorkOS login first. The consent screen shows the MCP resource scopes the client requested from the catalog —
mcp.read,mcp.tools, and optionallymcp.write. A client that asks only formcp.readandmcp.toolsstays read-only on the graph and lands theontology_*namespace (the common Claude Desktop / ChatGPT Desktop path).mcp.writeunlocks the write tools on this page; it is not implied bymcp.tools.control_*is never granted to an OAuth bearer. Approve, and the client exchanges the returned code for a bearer token automatically. - Manage every authorized client from People & Access → OAuth Clients (page title Clients). Revoking immediately invalidates every outstanding bearer token issued to that application, and disables any gateway API keys it provisioned on your behalf.
Discovery + token endpoints, for reference:
# RFC 8414 authorization-server metadata (issuer-global)
curl -sS https://your-corveil-host/.well-known/oauth-authorization-server | jq .
# RFC 9728 protected-resource metadata for the /mcp resource
curl -sS https://your-corveil-host/mcp/.well-known/oauth-protected-resource | jq .
# Subsequent calls use the issued bearer in place of X-Corveil-Key
curl -sS https://your-corveil-host/mcp \
-H "Authorization: Bearer crv_at_..." \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'PKCE (S256) is mandatory; public clients receive a token without a client secret (PKCE-only). Access tokens last 1 hour; refresh tokens last 30 days and rotate on every use.
Rate limit & observability
Requests share the per-key RPM/TPM rate limit applied to every /v1/* and /mcp surface — bursting from a desktop client will eventually hit the same 429 your other API-key traffic would, under the same global auth + key throttle as /v1/messages and /v1/responses.
The MCP per-tool rate limit (mcp_rate_limits) and per-call audit rows (mcp_audit_logs) do not fire on the remote Streamable HTTP /mcp endpoint — that path is direct to the in-process MCP server. Per-tool granularity and per-call audit attribution are not available on this transport.
Troubleshooting
- 401: the
X-Corveil-Key(orAuthorization: Bearer) is missing, malformed, or revoked. Re-issue under People & Access → API Keys, or re-run the OAuth connect flow. - Empty results for a known entity: the entity belongs to another org. Cross-org probes return empty by row-level security — verify the credential's org owns the data.
- A tool you expected is absent from
tools/list: you are not entitled to its namespace with this credential (an OAuth bearer seesontology_*only), or — for theontology_*write tools — your org lacks the write feature, or your OAuth grant does not includemcp.write. Re-check the namespace table. control_*tools missing entirely: either you authenticated with an OAuth bearer (control_*is never granted to an OAuth bearer) or the deployment has the control plane disabled.