Confluye
Endpoints

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

MethodPathEnvelope
GET/api/v1/mcp-servers{ servers[] }
POST/api/v1/mcp-servers201 { 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}/testTest 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." }.

FieldNotes
headersObject or JSON string object
transportDefault http. Other values must be http, sse, or stdio
toolsArray of strings; trimmed; empty entries dropped; duplicates collapsed in order
enabledDefault 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}/testtoolName is URL-decoded. Body { arguments } (object, JSON object string, or omitted → {}).

ConditionHTTP
Server missing404
enabled: false400 { "error": "MCP server is disabled." }
Non-empty tools list and name not listed400 "MCP tool \"{name}\" is not listed on server \"{serverName}\"."
Empty toolsAny tool name is allowed
Bad arguments400 "MCP tool arguments must be a JSON object."
Live call success200 { 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.
  • stdio can be stored but cannot be executed here.
  • Empty tools does not discover remote tools; it only skips the allow-list.
  • Duplicate create is upsert, not 409.

Next steps