Skip to main content
DocumentationInference API · api.eu.ccsio.ai

MCP

The aggregated MCP endpoint of an organization's enabled installations (POST, GET and DELETE on `/mcp/`, also served as `/mcp`).

Documentation menu

The descriptions of the operations and fields are the contract’s own, in English.

GET/mcp/

Server-to-client stream (not offered)

Credential
API key
Permission
mcp.invoke

The Streamable HTTP GET stream is not offered: the answer is 405 method-not-allowed in the kernel ErrorEnvelope, with Allow: POST, DELETE, after the same authentication and mcp.invoke admission as POST. Any other method on this path (PUT, PATCH) is answered 405 by the server's mux, with an Allow header and a plain-text body.

curl
curl "https://api.eu.ccsio.ai/mcp/" \
  -H "Authorization: Bearer $CCSIO_API_KEY"

Parameters

NameInDescription
X-Request-ID
optional
headerstring

Optional request ULID. Lowercase input is accepted; the response X-Request-ID header uses the canonical uppercase form. When the header is absent, or is not a ULID, the platform mints the id: no request is refused for it.

X-Team-Id
optional
headerstring

The team the call acts for. Send it when the caller holds roles in more than one team: the platform cannot pick one, and without it the call is refused with 403 policy-denied.

Read more

Send it also to act for one team on purpose: the models that are listed and may be called then follow that team's entitlements, and the quota and the usage are attributed to it. The team must be one the caller is an active member of: a team the caller does not belong to, an archived team and a malformed identifier are refused with 403 team-not-selectable. A caller whose roles are organization-wide needs no team.

X-Organization-Id
optional
headerstring

The organization a signed-in person acts in, for a person who belongs to more than one.

Read more

A person with exactly one organization needs no header; a person with several is refused with 403 organization-selection-required without it, and a value that names an organization the person holds no active membership in is refused with 403 organization-not-selectable. An API key carries its own organization and ignores the header, except a platform administrator's credential and a platform operator signed in at the backoffice, who may name any existing organization (an operator who names none holds the platform context, which these operations refuse with 403 organization-selection-required). The header selects among memberships that already exist: it never grants one, and the residency of the organization it selects must be the plane's own (403 residency-mismatch).

Responses

  • 401

    A missing credential, a duplicate one (both Authorization:

    Read more

    Bearer and x-api-key) or one the platform has rejected as invalid; the codes are those of the 401 of the /v1 operations (invalid-request, api-key-*, token-*, issuer-*, jwks-*, identity-not-provisioned, organization-not-found, staff-*), listed in x-ccsio-boundary-error-codes, in the kernel ErrorEnvelope. A 401 can also be a refusal of the hop between core and the gateway (missing-verified-context, invalid-verified-context, context-signature-*): a fault of the platform.

  • 402

    payment-required: the organization has no active subscription. The call is refused before its body is read; platform operators are exempt. Rendered in the kernel ErrorEnvelope (on /v1 the same refusal is OpenAI-shaped).

  • 403

    Refused after the credential was accepted, in the kernel ErrorEnvelope: policy-denied (the caller does not hold mcp.invoke: a personal API key whose owner lacks it, a role without it; or the acting team is ambiguous or no longer authorized for MCP), organization-inactive and the other states of the organization (organization-provisioning, organization-suspended, organization-disabled, organization-deleted), user-disabled, tenant-mismatch, residency-mismatch, organization-selection-required, organization-not-selectable, no-active-organization-membership, team-not-selectable.

  • 405

    method-not-allowed: the Streamable HTTP GET stream is not offered. The answer carries Allow: POST, DELETE, after the same authentication and mcp.invoke admission as POST. Any other method on /mcp or /mcp/ (PUT, PATCH) is answered 405 by the server's mux with Allow and a plain-text body.

    Error codes:method-not-allowed
  • 508

    loop-detected: the request carried the X-Ccsio-Egress header, which the platform's own egress adds to every request it makes to a model provider or an MCP server. It is answered when a connection points back at the platform's own API; an ordinary client never meets it. Rendered in the kernel ErrorEnvelope.

    Error codes:loop-detected
POST/mcp/

Aggregated MCP server (Streamable HTTP): JSON-RPC requests, responses and notifications

Credential
API key
Permission
mcp.invoke
Request body
Body up to 4 MiB

The aggregated MCP endpoint of the organization (https://api.<region>.ccsio.ai/mcp/; the same endpoint is also served without the trailing slash, documented as the alias /mcp). The body is one JSON-RPC 2.0 message (a JSON array, a batch, is refused with -32600).

Read more

Requires exactly one credential, Authorization: Bearer <ccsio key> or x-api-key, as every operation here, and the mcp.invoke permission in the organization: a personal API key is accepted only when its owner holds mcp.invoke there; a service-account key when its role holds it; a human OIDC token when the person's role holds it. To deny MCP to a person, give them a custom role without mcp.invoke (403 policy-denied). Protocol versions 2025-06-18 and 2025-03-26: initialize must carry params.protocolVersion, a string (without it the answer is -32602), and the answer names that version when it is one of the two and 2025-06-18 otherwise; the Mcp-Protocol-Version header is accepted and ignored. Methods: initialize (McpInitializeResult; creates the session and answers Mcp-Session-Id, capabilities {tools: {listChanged: false}}, serverInfo {name: ccsio, version: the gateway's version} and an instructions string saying that tools are prefixed with the installation alias: <alias>-<tool>, followed, for every user-scoped installation the caller has not connected, by 'Not connected for you: <alias> (connect at <connect_url>)'); notifications/* from the client (202, no body); ping ({}); tools/list (every tool of every enabled installation of the organization that is available to the caller, named <alias>-<tool>, after each installation's tool_policy and argument_bindings are applied, in one page: no cursor; an installation that fails is omitted; a user-scoped installation, whose item's auth.scope is user, is available only to a user who has stored every required credential slot of their own and contributes nothing to anyone else); tools/call {name: <alias>-<tool>, arguments} (the name is split on the FIRST hyphen; an unknown alias or tool is -32602; a name whose alias is a user-scoped installation the caller has not connected is -32602 'installation <alias> is not connected for this user; connect it at <connect_url>' (and, for a service-account key, which has no user, 'installation <alias> is not available to service accounts'); an argument outside a restrict_enum binding's configured values is -32602 'argument <arg> is not allowed by this installation'; a fixed binding overwrites its argument; the upstream's result is returned unchanged; a transport failure or timeout is -32000 with data {alias, reason}). Anything else is -32601. A notification (a message with no id, or a response of the client) is accepted only inside a session. Every JSON-RPC level error, whatever its code, is HTTP 200 with the JSON-RPC error object in the body, including -32700 for a body that is not parseable JSON; the HTTP status carries only transport-level facts: 200 (a JSON-RPC response), 202 (a notification or a client response was accepted, no body), 404 (the Mcp-Session-Id is missing on a request other than initialize, or is unknown, expired or foreign) and, from core before the gateway or the gateway itself, 400, 401, 402, 403, 413, 500, 502, 503 and 508; 405 is the answer to GET. Core relays the gateway's status, Content-Type, Mcp-Session-Id header and body unchanged. The answer is always one application/json JSON-RPC response (phase 1 never answers with an SSE stream, even when the upstream does). Core relays the answer of the gateway unchanged (status, Content-Type, Mcp-Session-Id, body); the headers Content-Type, Accept, Mcp-Session-Id, Mcp-Protocol-Version, Last-Event-ID, X-Request-ID and traceparent are forwarded to the gateway and nothing else, never Authorization or cookies. A session that is unknown, expired or belongs to another organization or principal is HTTP 404. The request body is capped at 4194304 bytes (413 request-body-too-large, in the kernel ErrorEnvelope, before the gateway). Each tools/call is metered as one usage record with operation tool, model <alias>-<tool> and deployment mcp:<alias>, visible in the request log. Every transport-level failure, whether core or the gateway writes it, is a kernel ErrorEnvelope with one of the codes of x-ccsio-error-codes and the root's tables: 404 mcp-session-not-found, 503 router-not-configured when core has no router, 503 session-store-unavailable when the gateway cannot read the session store (the client must not be told its session is gone), 402 payment-required, 508 loop-detected. The JSON-RPC error codes are those of McpJsonRpcError.

curl
curl -X POST "https://api.eu.ccsio.ai/mcp/" \
  -H "Authorization: Bearer $CCSIO_API_KEY"

Parameters

NameInDescription
Mcp-Session-Id
optional
headerstring

Absent on initialize, required on every later request and notification of the session: a missing, unknown, expired or foreign id is 404 mcp-session-not-found.

Mcp-Protocol-Version
optional
headerstring

Accepted and ignored: the gateway never reads it, and core only forwards it. The version of a session is the one initialize negotiates (2025-06-18 or 2025-03-26: a client that asks for another gets 2025-06-18 back), so any value, a malformed one or none is served.

X-Request-ID
optional
headerstring

Optional request ULID. Lowercase input is accepted; the response X-Request-ID header uses the canonical uppercase form. When the header is absent, or is not a ULID, the platform mints the id: no request is refused for it.

X-Team-Id
optional
headerstring

The team the call acts for. Send it when the caller holds roles in more than one team: the platform cannot pick one, and without it the call is refused with 403 policy-denied.

Read more

Send it also to act for one team on purpose: the models that are listed and may be called then follow that team's entitlements, and the quota and the usage are attributed to it. The team must be one the caller is an active member of: a team the caller does not belong to, an archived team and a malformed identifier are refused with 403 team-not-selectable. A caller whose roles are organization-wide needs no team.

X-Organization-Id
optional
headerstring

The organization a signed-in person acts in, for a person who belongs to more than one.

Read more

A person with exactly one organization needs no header; a person with several is refused with 403 organization-selection-required without it, and a value that names an organization the person holds no active membership in is refused with 403 organization-not-selectable. An API key carries its own organization and ignores the header, except a platform administrator's credential and a platform operator signed in at the backoffice, who may name any existing organization (an operator who names none holds the platform context, which these operations refuse with 403 organization-selection-required). The header selects among memberships that already exist: it never grants one, and the residency of the organization it selects must be the plane's own (403 residency-mismatch).

Responses

  • 200

    The JSON-RPC response (result or error).

    Schema
    • jsonrpcstringrequired

      always "2.0"

    • idstring or nulloptional
    • resultobjectoptional

      The result of the method: McpInitializeResult for initialize, McpToolsListResult for tools/list, {} for ping, and for tools/call the upstream's result returned unchanged.

    • errorobjectoptional

      The error object of a JSON-RPC response. The codes the aggregator writes: -32700 (parse error: an empty body, a body that is not JSON, more than one value in it), -32600 (invalid request: a batch, a message that is not JSON-RPC, jsonrpc other than 2.0, no method, an id that is not a string or a number, initialize without an id), -32601 (method not found), -32602 (invalid params: initialize without protocolVersion, tools/call without a name or with arguments that are not an object, an unknown tool or one whose installation the caller has not connected, an argument an installation's binding refuses), -32603 (internal error) and -32000 (an upstream that could not be reached or answered in time, with data {alias, reason}). An upstream's own JSON-RPC error is relayed as it is, so any other code can appear.

      • codeintegerrequired
      • messagestringrequired
      • dataanyoptional
  • 202

    A notification or a response from the client was accepted; no body.

  • 400

    invalid-request: the request body could not be read. The faults of the hop (decision-invalid) are listed in x-ccsio-hop-error-codes.

    Error codes:invalid-request
  • 401

    A missing credential, a duplicate one (both Authorization:

    Read more

    Bearer and x-api-key) or one the platform has rejected as invalid; the codes are those of the 401 of the /v1 operations (invalid-request, api-key-*, token-*, issuer-*, jwks-*, identity-not-provisioned, organization-not-found, staff-*), listed in x-ccsio-boundary-error-codes, in the kernel ErrorEnvelope. A 401 can also be a refusal of the hop between core and the gateway (missing-verified-context, invalid-verified-context, context-signature-*): a fault of the platform.

  • 402

    payment-required: the organization has no active subscription. The call is refused before its body is read; platform operators are exempt. Rendered in the kernel ErrorEnvelope (on /v1 the same refusal is OpenAI-shaped).

  • 403

    Refused after the credential was accepted, in the kernel ErrorEnvelope: policy-denied (the caller does not hold mcp.invoke: a personal API key whose owner lacks it, a role without it; or the acting team is ambiguous or no longer authorized for MCP), organization-inactive and the other states of the organization (organization-provisioning, organization-suspended, organization-disabled, organization-deleted), user-disabled, tenant-mismatch, residency-mismatch, organization-selection-required, organization-not-selectable, no-active-organization-membership, team-not-selectable.

    Error codes:organization-inactivepolicy-denied
  • 404

    mcp-session-not-found: the Mcp-Session-Id is missing on a request other than initialize, or is unknown, expired, or belongs to another organization or principal (the caller cannot tell which). A notification is accepted only inside a session, so one sent outside it is a 404 too.

    Error codes:mcp-session-not-found
  • 413

    request-body-too-large: the body exceeds 4194304 bytes. Answered after authentication and authorization.

    Error codes:request-body-too-large
  • 500

    internal-error: core could not load the organization's installations or had no resolved context; or unsupported-protocol-version, the router's refusal of the hop. Rendered without internal cause details.

    Error codes:internal-error
  • 502

    forwarder-failed: core could not reach the gateway before it answered; or internal-hop-body, the gateway's refusal of the body core sent. Nothing of the gateway's own text is relayed.

    Error codes:forwarder-failed
  • 503

    router-not-configured (this core has no router to forward to) or session-store-unavailable (the gateway could not read or write the sessions: the client must not be told its session is gone, so this is a 503 and not a 404; retry).

    Error codes:router-not-configuredsession-store-unavailable
  • 508

    loop-detected: the request carried the X-Ccsio-Egress header, which the platform's own egress adds to every request it makes to a model provider or an MCP server. It is answered when a connection points back at the platform's own API; an ordinary client never meets it. Rendered in the kernel ErrorEnvelope.

    Error codes:loop-detected
DELETE/mcp/

End the MCP session

Credential
API key
Permission
mcp.invoke

Drops the aggregated session named by Mcp-Session-Id and, best effort, the upstream sessions behind it: 204 with no body. An unknown, expired or foreign session is HTTP 404 mcp-session-not-found. Same credential and mcp.invoke admission as POST.

curl
curl -X DELETE "https://api.eu.ccsio.ai/mcp/" \
  -H "Authorization: Bearer $CCSIO_API_KEY"

Parameters

NameInDescription
Mcp-Session-Id
required
headerstring

The session to end, as returned by initialize.

X-Request-ID
optional
headerstring

Optional request ULID. Lowercase input is accepted; the response X-Request-ID header uses the canonical uppercase form. When the header is absent, or is not a ULID, the platform mints the id: no request is refused for it.

X-Team-Id
optional
headerstring

The team the call acts for. Send it when the caller holds roles in more than one team: the platform cannot pick one, and without it the call is refused with 403 policy-denied.

Read more

Send it also to act for one team on purpose: the models that are listed and may be called then follow that team's entitlements, and the quota and the usage are attributed to it. The team must be one the caller is an active member of: a team the caller does not belong to, an archived team and a malformed identifier are refused with 403 team-not-selectable. A caller whose roles are organization-wide needs no team.

X-Organization-Id
optional
headerstring

The organization a signed-in person acts in, for a person who belongs to more than one.

Read more

A person with exactly one organization needs no header; a person with several is refused with 403 organization-selection-required without it, and a value that names an organization the person holds no active membership in is refused with 403 organization-not-selectable. An API key carries its own organization and ignores the header, except a platform administrator's credential and a platform operator signed in at the backoffice, who may name any existing organization (an operator who names none holds the platform context, which these operations refuse with 403 organization-selection-required). The header selects among memberships that already exist: it never grants one, and the residency of the organization it selects must be the plane's own (403 residency-mismatch).

Responses

  • 204

    The session is dropped.

  • 401

    A missing credential, a duplicate one (both Authorization:

    Read more

    Bearer and x-api-key) or one the platform has rejected as invalid; the codes are those of the 401 of the /v1 operations (invalid-request, api-key-*, token-*, issuer-*, jwks-*, identity-not-provisioned, organization-not-found, staff-*), listed in x-ccsio-boundary-error-codes, in the kernel ErrorEnvelope. A 401 can also be a refusal of the hop between core and the gateway (missing-verified-context, invalid-verified-context, context-signature-*): a fault of the platform.

  • 402

    payment-required: the organization has no active subscription. The call is refused before its body is read; platform operators are exempt. Rendered in the kernel ErrorEnvelope (on /v1 the same refusal is OpenAI-shaped).

  • 403

    Refused after the credential was accepted, in the kernel ErrorEnvelope: policy-denied (the caller does not hold mcp.invoke: a personal API key whose owner lacks it, a role without it; or the acting team is ambiguous or no longer authorized for MCP), organization-inactive and the other states of the organization (organization-provisioning, organization-suspended, organization-disabled, organization-deleted), user-disabled, tenant-mismatch, residency-mismatch, organization-selection-required, organization-not-selectable, no-active-organization-membership, team-not-selectable.

    Error codes:organization-inactivepolicy-denied
  • 404

    mcp-session-not-found: the Mcp-Session-Id is missing on a request other than initialize, or is unknown, expired, or belongs to another organization or principal (the caller cannot tell which). A notification is accepted only inside a session, so one sent outside it is a 404 too.

    Error codes:mcp-session-not-found
  • 500

    internal-error: core could not load the organization's installations or had no resolved context; or unsupported-protocol-version, the router's refusal of the hop. Rendered without internal cause details.

    Error codes:internal-error
  • 502

    forwarder-failed: core could not reach the gateway before it answered; or internal-hop-body, the gateway's refusal of the body core sent. Nothing of the gateway's own text is relayed.

    Error codes:forwarder-failed
  • 503

    router-not-configured (this core has no router to forward to) or session-store-unavailable (the gateway could not read or write the sessions: the client must not be told its session is gone, so this is a 503 and not a 404; retry).

    Error codes:router-not-configuredsession-store-unavailable
  • 508

    loop-detected: the request carried the X-Ccsio-Egress header, which the platform's own egress adds to every request it makes to a model provider or an MCP server. It is answered when a connection points back at the platform's own API; an ordinary client never meets it. Rendered in the kernel ErrorEnvelope.

    Error codes:loop-detected

Generated from the platform contracts at commit 5f833620.

Explore the platform

Get your first API key

Registration is open. Four steps to your first call: create your account, create your organization, create your API key, and start using it.

  1. 01Create your account
  2. 02Create your organization
  3. 03Create your API key
  4. 04Start using it