Docs

The Gateway

What the K-Block Gateway is, how agents connect to it, and what happens to every tools/list and tools/call that passes through it.

The Gateway is the MCP server your agents connect to instead of connecting to your tools directly. It speaks MCP over Streamable HTTP. For every tool call it checks the organization's policy, records a protected action, holds the call for an approval when the policy requires one, forwards approved and allowed calls to the upstream MCP server, and signs the evidence that becomes a receipt.

The Gateway is the only component that executes tool calls. The dashboard and the Cloud API manage configuration, decisions and receipts, but they never call an upstream tool.

  1. Agent

    tools/call over MCP

  2. Gateway

    authenticate, decide, record

  3. Approval

    only if the policy requires it

  4. Upstream MCP server

    called once

  5. Receipt

    signed RESULT and bundle

A tool call through the Gateway (concept)

What the Gateway is

PropertyValue
ProtocolMCP over Streamable HTTP, at the path /mcp (POST only)
Server name and version reported to agentskblock-gateway 0.1.0
SessionsNone: the Gateway is stateless and issues no Mcp-Session-Id. GET and DELETE on /mcp are answered 405 (after authentication)
Capabilitiestools only
Request bodyAt most 1 MiB; larger requests get HTTP 413

At initialization the Gateway sends agents short instructions that explain the optional _meta keys and the shape of refusals, including the optional retryable and policy members (retryable: false means: check the protected action before repeating the call).

You get the Gateway's URL from the dashboard, which shows the Gateway's MCP endpoint right after you create a gateway API key. If it does not show it, contact K-Block support.

Authentication with gateway API keys

Every HTTP request to /mcp must carry a gateway API key:

POST /mcp HTTP/1.1
Host: gateway.example.com
Authorization: Bearer kb_live_…
Content-Type: application/json
Accept: application/json, text/event-stream

A gateway API key (kb_live_… or kb_test_…) belongs to one agent of one organization. Owners, admins and developers create them in the dashboard; the secret is shown once. See API keys.

Because the Gateway is stateless, every request is authenticated again. A key that is revoked or expires, or whose agent is disabled, fails on the next request even if the agent's MCP client is still connected. These all get the same answer, so the response does not reveal why:

  • HTTP 401 with WWW-Authenticate: Bearer realm="kblock-gateway" and a JSON-RPC error -32001;
  • for a missing, malformed, unknown, revoked or expired key, a management API key (management keys only work with the Cloud API), a disabled agent, or a key whose creator left the organization or lost the role needed to create it.

Each key may send a burst of 120 requests, refilled at 20 per second, to each Gateway. Beyond that the Gateway answers HTTP 429 with Retry-After; wait that many seconds before you retry.

What an agent sees in tools/list

tools/list returns only the tools this agent can call through the Gateway right now; the policy still decides each call. A tool is listed when all of these hold:

  • the tool is enabled, and its MCP server is active;
  • the organization has a principal, and a usable delegation from that principal to the Gateway names this agent and grants the tool's action;
  • the tool's binding is the one an owner or admin authorized (a tool whose configuration changed since is left out until it is re-authorized);
  • the server URL has no query, fragment or user information, so it can be signed;
  • the stored input schema is a valid MCP object schema.

Each tool is listed with its exposed name, its input schema and its description. The Gateway never declares an outputSchema. Tools of other organizations, and tools no delegation grants, are never shown. See Tools and MCP servers.

The tools/call flow

  1. Read the K-Block _meta keys

    Two optional keys are accepted in the request's _meta:

    • kblock/idempotency-key — 1 to 200 characters, scoped to the calling agent. A repeat with the same key returns the first call's stored outcome; the same key with another tool or other arguments is refused IDEMPOTENCY_KEY_REUSED.
    • kblock/wait-seconds — a whole number of seconds to hold the call while it waits for an approval.

    Any other key that starts with kblock/ is refused invalid_request / INVALID_META.

  2. Resolve the tool

    The name must be an enabled tool on an active server of the caller's organization. Otherwise the call is refused invalid_request / UNKNOWN_TOOL and nothing is recorded.

  3. Decide and record

    The Gateway looks for an earlier outcome first: the action of the same idempotency key, or, without a key, the open action of the identical call. If there is none, it decides: it checks the tool's authorized binding, reads the amount, evaluates the agent's active policy version, selects the delegation, resolves the approvers, signs a TASK and a PROPOSAL, and records the protected action, all or nothing. Denials are recorded too, except two refusals that record nothing: a tool whose binding is not the authorized one (TOOL_REAUTHORIZATION_REQUIRED) and a call over the plan limit (PLAN_LIMIT_EXCEEDED).

  4. Settle

    Depending on the action's state, the Gateway executes it (allowed, or approved), waits for a decision (pending, with kblock/wait-seconds), or answers with a refusal.

  5. Execute and record

    For an allowed or approved action, the Gateway re-checks everything, consumes the action exactly once, calls the upstream, signs the RESULT and issues the receipt. See Execution and results.

What the agent receives

A completed call returns the upstream's result with _meta.kblock. Every other outcome is an MCP error result (isError: true) whose structuredContent.kblock has status, code and detail, and, when the call was recorded, protected_action_id and, where they apply, approval_request_id and expires_at. Some refusals add retryable and the policy's explanation (policy, and a second text line starting Why:), depending on what your organization discloses to agents (see What agents are told).

statusTypical codesMeaning
— (success)—The upstream result, with _meta.kblock IDs of the action and receipt
deniedPOLICY_DENIED, NO_POLICY, NO_DELEGATION, NO_APPROVERS, TOOL_REAUTHORIZATION_REQUIRED, and at execution UPSTREAM_CHANGED, POLICY_CHANGEDRefused; nothing ran
approval_pendingAPPROVAL_PENDINGHeld for approval; repeat the identical call later
rejectedREJECTEDAn approver rejected it (receipt IDs included)
expiredAPPROVAL_EXPIRED, TASK_EXPIRED, SUPERSEDEDThe action ended without running
cancelledCANCELLEDThe organization cancelled it (receipt IDs included)
replayEXECUTION_IN_PROGRESS, REPLAY, DUPLICATE_IN_FLIGHTAnother request is running, or already ran, this action or an identical call
upstream_errorUPSTREAM_TOOL_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_BLOCKED, …The upstream failed or could not be called
unavailableDATABASE_UNAVAILABLE, GATEWAY_SHUTTING_DOWNThe Gateway cannot process the call right now
invalid_requestUNKNOWN_TOOL, INVALID_META, INVALID_ARGUMENTS, IDEMPOTENCY_KEY_REUSEDThe request itself is wrong
plan_limitPLAN_LIMIT_EXCEEDEDThe organization's monthly limit is reached; nothing recorded
unauthorizedUNAUTHORIZEDThe key or agent became unusable during the call

All codes: Error codes and Action statuses.

Waiting for an approval

Without kblock/wait-seconds, a call that needs approval is answered approval_pending at once. With it, the Gateway holds the request until the approver decides or the time is up:

  • The wait is capped at 60 seconds. A longer kblock/wait-seconds is lowered to the cap.
  • The Gateway learns of a decision as soon as it is recorded, with periodic checks as a fallback, so a waiting call reacts within moments, whichever Gateway it waits on.
  • If the agent sent an MCP progressToken, the Gateway sends a progress notification every 10 seconds while it waits.
  • On each Gateway, at most 20 calls per API key, and at most 1,000 calls in all, wait at the same time. Beyond that the call is answered approval_pending at once, with "(not waited: …)" in the detail; repeat the call later to resume it.

When the wait ends, the Gateway acts on the current state: it executes an approved call in the same request, returns the rejection, expiry or cancellation, or answers approval_pending again if nothing was decided. If the agent disconnects at the moment the approval lands, the call may still execute; its outcome is recorded and a repeat with the same idempotency key returns it.

Resuming a call

To continue a pending call, the agent repeats the identical call: same tool, same arguments, and the same idempotency key if it used one. The Gateway finds the existing protected action instead of deciding again:

  • with a key, only the action recorded with that key;
  • without a key, the open action of the exact call (the keyless one first, else the oldest keyed one).

A pending request can be resumed through any Gateway, not only the one that created it. In @kblockai/client, use client.resume(result) or client.waitForApproval(result); see TypeScript client.

Upstream forwarding

The Gateway calls the upstream MCP server as an MCP client over Streamable HTTP, with the Authorization header stored for that server. The stored credential is encrypted at rest and never shown back. The Gateway:

  • resolves the upstream's host once, checks every address, and connects only to those addresses;
  • connects only to public https addresses: plain http URLs and private, loopback and internal addresses are refused with upstream_error / UPSTREAM_BLOCKED (see URL rules);
  • follows no redirects, and accepts responses of at most 1 MiB;
  • gives the whole exchange one deadline of 30 seconds;
  • sends the tools/call once and never retries it;
  • ignores requests and notifications the upstream sends back.

For a K-Block-aware upstream (registered with a server KID), the Gateway also sends the evidence in _meta.kblock and requires a signed attestation back. See Identities and KIDs.

Evidence generation

The Gateway signs evidence with its service identity, whose KID is the Gateway KID (see Identities and KIDs):

WhenObjects signed
A call is decided (allow or require approval)TASK and PROPOSAL (nothing is signed for a denial)
The action is consumedEXECUTION
The upstream call endsRESULT, and the RECEIPT with its .kbundle

Approvals and rejections are signed in the approver's browser, and cancellations with the organization principal. The Cloud API verifies them when they are submitted and issues the receipts of rejections and cancellations; the Gateway verifies the approval again before it executes.

If the Gateway's identity no longer matches the one K-Block has on record, new decisions and executions fail with a JSON-RPC internal error (-32603, "internal gateway error (request …)"). Your agent cannot fix this: contact K-Block support with the error code and the request ID from the error.

Several Gateways

K-Block may run several Gateways, for availability or load. They share the state of every call: decisions, approvals, executions and idempotency keys are kept by K-Block, not by one Gateway, so any Gateway can serve any request.

  • All Gateways sign with the same identity, so receipts carry the same Gateway KID.
  • An approved call retried on several Gateways at once still executes exactly once.
  • A call waiting on one Gateway learns of the decision wherever the approval was given.
  • If one Gateway stops, the others keep serving; work it left unfinished is recovered (see Execution and results).
  • Rate limits and limits on waiting calls are counted by each Gateway separately, so with several Gateways the totals add up.

Effect of an emergency stop

An emergency stop (Emergency stop… on a policy) activates a stop version of the policy at once:

  • The very next call decided on any Gateway uses it; no observe window relaxes it.
  • Calls that were allowed before the stop but have not run yet are refused at consumption with denied / POLICY_CHANGED; nothing runs.
  • With the default for "deny all", pending approvals and approved calls that have not run are closed (expired / SUPERSEDED). A keyless repeat of such a call gets a new decision under the stop; a repeat with the same idempotency key is answered expired / SUPERSEDED.
  • An execution that already started finishes and is recorded.

See Emergency stop and Emergency controls.

When the Gateway cannot serve

SituationWhat agents receive
K-Block is temporarily unavailable and cannot check or record the call in timeHTTP 503 with Retry-After: 5, or a refusal unavailable / DATABASE_UNAVAILABLE with retryable: true (for tools/list, a JSON-RPC error that names DATABASE_UNAVAILABLE). Nothing is executed or consumed by that request; the exception is a failure at the moment an approval is being consumed (retryable: false, see Execution and results)
The Gateway is shutting downHTTP 503 or a refusal unavailable / GATEWAY_SHUTTING_DOWN, retryable. Calls waiting for approval end with approval_pending
The upstream is down or slowupstream_error with the precise code, after the approval was consumed. See Execution and results

The Gateway fails closed: if it cannot check or record a call, it does not run it.

For a retryable answer, wait for Retry-After (or a few seconds) and repeat the call, with the same idempotency key if you used one. If the Gateway stays unavailable, contact K-Block support with the error code, the request ID (every Gateway answer carries it in the x-request-id header) and the time it happened. See also Gateway and tools.

Next steps