Skip to content

Register an MCP endpoint

View as Markdown
POST
/v1/mcp/endpoints
curl --request POST \
--url https://example.com/v1/mcp/endpoints \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "endpointId": "example", "name": "example", "transport": "stdio", "config": { "transport": "stdio", "command": "example", "args": [ "example" ], "env": { "additionalProperty": "example" } }, "secretRef": { "envName": "example", "name": "example" }, "auth": { "scheme": "basic", "username": "example", "secretRef": { "envName": "example", "name": "example" } }, "secretEnv": { "additionalProperty": { "envName": "example", "name": "example" } }, "instructions": "example", "metadata": {}, "sendTraceparent": true, "scopeKind": "tenant", "scopeId": "example" }'

Body is a full MCPEndpoint plus the scope to register it in (scopeKind + scopeId); authorization checks that scope. Server validates the closed transport enum + the config.transport matches transport guardrail + per-variant required fields (command for stdio; url for http-sse / streamable-http), and refuses unknown fields. secretRef, auth and secretEnv name secrets in the deployment’s store — plaintext secrets never cross the wire — and never a model provider’s key (400 provider-key-refused). A credential in plaintext config.headers or a stdio endpoint’s config.env is refused (400 invalid-mcp-endpoint, reason credential-in-headers or credential-in-env). Where each secret it names is read is recorded on it now (secretScopes): the first of its own scope, its project’s org and the tenant that has the secret and that the caller administers, else the broadest they administer; the runtime reads it there only. A deployment with KINDGI_TENANT_HOST_ACCESS=deployed (the default outside development) refuses a stdio endpoint, which would run a command on the server’s host: 403 host-access-denied.

Idempotency-Key
string
>= 1 characters

Caller-supplied idempotency key, scoped to the caller: the same key from someone else in the tenant is their own request (from 0.1.5). Retries with the same key return the original response byte-identical (per docs/API-ROUTE-CONVENTIONS.md §3.1). A retry sent while the first request still runs is answered 409 idempotency-key-in-flight with Retry-After, on a runtime whose store holds keys (from 0.1.5); retry after it, and you get the first request’s answer. An answer that carries a secret (a new API key or public run token, a session token, a generated signing secret) isn’t kept: a retry gets 409 idempotency-key-replay-withheld, with the first request’s status and when it succeeded (from 0.1.5). A request whose key store can’t be read before it runs is answered 503 idempotency-store-unavailable with Retry-After: nothing ran, so retry with the same key (from 0.3.0).

Media typeapplication/json
object
endpointId
required

No .: an MCP tool’s id is <endpointId>.<tool name>, so it splits at its first .. An endpoint registered with one before keeps it.

string
>= 1 characters /^[^.]+$/
name
required

Human-readable display name.

string
>= 1 characters
transport
required

MCP transport variant. stdio — local subprocess (spawn a command). http-sse — the older MCP HTTP+SSE transport (separate POST + SSE endpoints). streamable-http — the Streamable HTTP transport (single endpoint, session id via header).

string
Allowed values: stdio http-sse streamable-http
config
required
One of:
object
transport
required
Allowed value: stdio
command
required
string
>= 1 characters
args
Array<string>
env

Variables for the server’s process, stored as given. Not for a credential: a name config.headers would refuse, its parts split on _ as well as - (GITHUB_TOKEN, OPENAI_API_KEY, AWS_SECRET_ACCESS_KEY, SLACK_BOT_TOKEN), is refused (invalid-mcp-endpoint, reason credential-in-env). Give it by reference through secretEnv. An empty name, a name with = or a NUL, a value with a NUL, or a value of [redacted] is refused too (reason invalid-stdio-env). Every value reads back as [redacted], its name kept, on endpoints registered before as well, so an export holds the names, not the values.

object
key
additional properties
string
secretRef

The secret sent as the endpoint’s bearer. HTTP transports only: on a stdio endpoint it’s refused (invalid-mcp-endpoint, reason secret-ref-on-stdio), since a stdio server gets no headers; give it its secret through secretEnv. An endpoint registered with one before keeps it, and the runtime reads it for no one.

object
envName
required
string
/^[a-z][a-z0-9-]{0,62}$/
name
required
string
>= 1 characters <= 256 characters
auth
One of: discriminator: scheme

HTTP Basic: the runtime sends Authorization: Basic base64(<username>:<secret>), with the secret secretRef names (a WordPress Application Password, for one).

object
scheme
required
Allowed value: basic
username
required

The user name. Not a secret, and without :.

string
>= 1 characters <= 256 characters /^[^:]+$/
secretRef
required

The secret an MCP endpoint authenticates with: a name in the deployment’s secrets store, resolved at the endpoint’s tenant scope by the runtime (the shape webhooks and providers use). As the endpoint’s own secretRef, it is sent as its bearer; inside auth, it is the scheme’s password, client secret or header value; in secretEnv, a variable’s value for a stdio server. The endpoint keeps only this reference.

object
envName
required
string
/^[a-z][a-z0-9-]{0,62}$/
name
required
string
>= 1 characters <= 256 characters
secretEnv

A stdio server’s secrets, as variables of its process: each variable’s name (GITHUB_TOKEN) with the secret its value is read from, at the endpoint’s recorded scope, when the runtime starts the server. The value is never stored or answered. 1 to 16 variables, each name without =, and none also in config.env (invalid-mcp-endpoint, reason secret-env-twice); otherwise reason invalid-secret-env. Each secret counts for the provider-key guard and the env a runtime serves, as secretRef’s does. stdio only: on an HTTP endpoint it’s refused (reason secret-env-on-http). An older runtime refuses the field as unknown. A runtime rolled back to one without it starts the server without these variables, so the server fails its own calls; no value is exposed.

object
>= 1 properties <= 16 properties
key
additional properties

The secret an MCP endpoint authenticates with: a name in the deployment’s secrets store, resolved at the endpoint’s tenant scope by the runtime (the shape webhooks and providers use). As the endpoint’s own secretRef, it is sent as its bearer; inside auth, it is the scheme’s password, client secret or header value; in secretEnv, a variable’s value for a stdio server. The endpoint keeps only this reference.

object
envName
required
string
/^[a-z][a-z0-9-]{0,62}$/
name
required
string
>= 1 characters <= 256 characters
instructions

Optional pass-through to the MCP client serverInfo.instructions.

string
metadata

Optional caller-defined metadata bag.

object
key
additional properties
any
sendTraceparent

Send the W3C traceparent of the run calling a tool to this endpoint, as a request header, so the server’s logs can be matched to the run. Ids only, never content. Default false. HTTP transports only: true on a stdio endpoint is refused (invalid-mcp-endpoint, reason invalid-send-traceparent). An older runtime ignores it and sends none.

boolean
scopeKind
required

Discriminator for the ?scopeKind + ?scopeId + ?inherit triplet. Tenant carries no id (implicit from session); org/project require scopeId.

string
Allowed values: tenant org project
scopeId

Required when scopeKind is org or project; absent for tenant (implicit from the session).

string
>= 1 characters

MCP endpoint registered.

Media typeapplication/json
object
endpointId
required
string
Examplegenerated
{
"endpointId": "example"
}

Validation failed (see details.reason). Or provider-key-refused: secretRef names a model provider’s key (details.secret, details.providerId). Or reserved-name-prefix: it names a secret under the reserved kindgi. prefix (details.secret).

Media typeapplication/json
object
error
required
object
code
required

Stable machine-readable discriminant. Values match domain error codes (see docs/API-ROUTE-CONVENTIONS.md §4.3).

string
message
required
string
details

Optional, kind-specific.

object
key
additional properties
any
requestId
required

Server-assigned request id; also echoed via X-Request-Id header.

string
Examplegenerated
{
"error": {
"code": "example",
"message": "example",
"details": {},
"requestId": "example"
}
}

Missing / malformed / expired / revoked bearer token.

Media typeapplication/json
object
error
required
object
code
required

Stable machine-readable discriminant. Values match domain error codes (see docs/API-ROUTE-CONVENTIONS.md §4.3).

string
message
required
string
details

Optional, kind-specific.

object
key
additional properties
any
requestId
required

Server-assigned request id; also echoed via X-Request-Id header.

string
Examplegenerated
{
"error": {
"code": "example",
"message": "example",
"details": {},
"requestId": "example"
}
}

host-access-denied: a stdio endpoint on a deployment that refuses commands on its host (KINDGI_TENANT_HOST_ACCESS=deployed or isolated); or authz-denied.

Media typeapplication/json
object
error
required
object
code
required

Stable machine-readable discriminant. Values match domain error codes (see docs/API-ROUTE-CONVENTIONS.md §4.3).

string
message
required
string
details

Optional, kind-specific.

object
key
additional properties
any
requestId
required

Server-assigned request id; also echoed via X-Request-Id header.

string
Examplegenerated
{
"error": {
"code": "example",
"message": "example",
"details": {},
"requestId": "example"
}
}

MCP endpoint already registered at that id. Or env-not-served: this runtime keeps every value under the env it serves (whoami’s servedEnv, with refusesOtherEnvs), and the secret reference names another. Name it under details.servedEnv. Nothing is stored.

Media typeapplication/json
object
error
required
object
code
required

Stable machine-readable discriminant. Values match domain error codes (see docs/API-ROUTE-CONVENTIONS.md §4.3).

string
message
required
string
details

Optional, kind-specific.

object
key
additional properties
any
requestId
required

Server-assigned request id; also echoed via X-Request-Id header.

string
Examplegenerated
{
"error": {
"code": "example",
"message": "example",
"details": {},
"requestId": "example"
}
}

The request body is over the API’s limit (request-too-large; details.maxBytes says how much).

Media typeapplication/json
object
error
required
object
code
required

Stable machine-readable discriminant. Values match domain error codes (see docs/API-ROUTE-CONVENTIONS.md §4.3).

string
message
required
string
details

Optional, kind-specific.

object
key
additional properties
any
requestId
required

Server-assigned request id; also echoed via X-Request-Id header.

string
Examplegenerated
{
"error": {
"code": "example",
"message": "example",
"details": {},
"requestId": "example"
}
}

rate-limit-exceeded with details.limit: "schema-compile-time", on a server with a compile budget (Kindgi Cloud): this tenant’s schemas spent details.budgetMs compiling in the last 60 seconds. Nothing was stored; Retry-After says when to send it again.

Media typeapplication/json
object
error
required
object
code
required

Stable machine-readable discriminant. Values match domain error codes (see docs/API-ROUTE-CONVENTIONS.md §4.3).

string
message
required
string
details

Optional, kind-specific.

object
key
additional properties
any
requestId
required

Server-assigned request id; also echoed via X-Request-Id header.

string
Examplegenerated
{
"error": {
"code": "example",
"message": "example",
"details": {},
"requestId": "example"
}
}

Server error (unmapped domain code or framework crash).

Media typeapplication/json
object
error
required
object
code
required

Stable machine-readable discriminant. Values match domain error codes (see docs/API-ROUTE-CONVENTIONS.md §4.3).

string
message
required
string
details

Optional, kind-specific.

object
key
additional properties
any
requestId
required

Server-assigned request id; also echoed via X-Request-Id header.

string
Examplegenerated
{
"error": {
"code": "example",
"message": "example",
"details": {},
"requestId": "example"
}
}

The Idempotency-Key store couldn’t be read before the request ran (idempotency-store-unavailable), so nothing was changed; Retry-After (whole seconds) says when to try again with the same key.

Media typeapplication/json
object
error
required
object
code
required

Stable machine-readable discriminant. Values match domain error codes (see docs/API-ROUTE-CONVENTIONS.md §4.3).

string
message
required
string
details

Optional, kind-specific.

object
key
additional properties
any
requestId
required

Server-assigned request id; also echoed via X-Request-Id header.

string
Examplegenerated
{
"error": {
"code": "example",
"message": "example",
"details": {},
"requestId": "example"
}
}

See also