MCP servers
Register workspace MCP servers and test listed HTTP/SSE tools.
MCP server records under /api/v1/mcp-servers. A workspace, personal, or Copilot bearer key
with current membership can perform the read-only GET routes. Personal and Copilot reads use
the stable workspace-safe.v1 projection; they never expose connection coordinates or stored
headers. A workspace-scoped key is required for POST, PATCH, DELETE, and tool tests. Missing
token → 401 { "error": "Valid bearer API key is required" }; a valid key without the required
workspace authority → 403.
No cursor pagination. No Idempotency-Key. Session copies: /api/mcp-servers/*. Distinct from the platform MCP surface that exposes Confluye itself.
Endpoints
| Method | Path | Envelope |
|---|---|---|
| GET | /api/v1/mcp-servers | { servers[] } |
| POST | /api/v1/mcp-servers | 201 { server } |
| GET | /api/v1/mcp-servers/{id} | { server } |
| PATCH | /api/v1/mcp-servers/{id} | { server } |
| DELETE | /api/v1/mcp-servers/{id} | { deleted: true } |
| POST | /api/v1/mcp-servers/{id}/tools/{toolName}/test | Test result (see below) |
Missing id → 404 { "error": "MCP server not found." }.
Server object
Reads from a key with the workspace.secret.read capability return id, workspaceId, name,
transport (http | sse | stdio), endpoint, headers, enabled, tools (string[]),
createdAt, optional lastSeenAt. A Viewer or other key without that capability receives the safe
projection below, regardless of whether its scope is workspace, personal, or Copilot.
Keys without that capability return the safe-content contract instead:
{
"redaction": { "applied": true, "projection": "safe-content", "contractVersion": "workspace-safe.v1" },
"id": "mcp_…",
"workspaceId": "ws_…",
"name": "Docs",
"transport": "http",
"enabled": true,
"tools": ["search"],
"createdAt": "2026-08-24T00:00:00.000Z"
}
The safe projection intentionally omits endpoint and headers. Clients that need connection
configuration must migrate to a workspace key with the appropriate secret capability; clients that
only enumerate servers should consume redaction.contractVersion and the safe fields above.
Create (upsert by name)
Required trimmed name and endpoint. Else 400 { "error": "MCP server name and endpoint are required." }.
| Field | Notes |
|---|---|
headers | Object or JSON string object |
transport | Default http. Other values must be http, sse, or stdio |
tools | Array of strings; trimmed; empty entries dropped; duplicates collapsed in order |
enabled | Default true. When enabled, lastSeenAt is set |
POST upserts @@unique([workspaceId, name]): same name returns 201 with the same id and updated endpoint/headers/transport/tools/enabled. This is the mutation idempotency story (not Idempotency-Key).
Parse/validation errors → 400 { "error": "<message>" } ("Headers must be a JSON object.", "MCP tools must be an array of strings.", "MCP transport must be http, sse, or stdio.").
Update and delete
PATCH: enabled, endpoint, headers, tools. Not name or transport. Enabled servers refresh lastSeenAt.
DELETE is hard-delete.
Tool test
POST .../tools/{toolName}/test — toolName is URL-decoded. Body { arguments } (object, JSON object string, or omitted → {}).
| Condition | HTTP |
|---|---|
| Server missing | 404 |
enabled: false | 400 { "error": "MCP server is disabled." } |
Non-empty tools list and name not listed | 400 "MCP tool \"{name}\" is not listed on server \"{serverName}\"." |
Empty tools | Any tool name is allowed |
Bad arguments | 400 "MCP tool arguments must be a JSON object." |
| Live call success | 200 { ok: true, serverId, serverName, toolName, arguments, content, metadata, latencyMs, checkedAt } |
Live call failure (including stdio) | 200 { ok: false, ..., error, latencyMs, checkedAt } — not 5xx |
Runner POSTs JSON-RPC tools/call to endpoint for http and sse only. Timeout: WORKFLOW_MCP_TIMEOUT_MS or 10s. Max body: WORKFLOW_MCP_MAX_RESPONSE_BYTES or 1 MiB. Protocol header MCP-Protocol-Version: 2025-06-18. stdio → error "MCP stdio transport is not supported by the workflow runner." inside ok: false. Test payloads do not echo stored Authorization headers.
Known gaps
- PATCH cannot rename or change transport.
stdiocan be stored but cannot be executed here.- Empty
toolsdoes not discover remote tools; it only skips the allow-list. - Duplicate create is upsert, not
409.
