Documentation Index
Fetch the complete documentation index at: https://docs.cowboy.inc/llms.txt
Use this file to discover all available pages before exploring further.
Status: Draft
Type: Standards Track
Category: Core
Created: 2026-04-28
Requires: CIP-14 (DNS-Addressable Actors), CIP-15 (Public Asset Hosting and HTTP Routing)
Companions: CIP-18 (Payments) — required to gate MCP tool calls behind payment
1. Abstract
This proposal defines Gateway MCP Ingress — a system for exposing every CIP-14 actor as a Model Context Protocol server, terminated at the Gateway. The core primitive is a new entitlement (ingress.mcp) that opts an actor into MCP exposure, and a Gateway behavior that:
- Hosts an MCP server at
https://<actor>.cowboy.network/_cowboy/mcpusing MCP’s streamable HTTP transport (spec version2025-11-25). - Auto-generates the
tools/listresponse from the actor’s CIP-15 routes table — every Method-target route becomes one MCP tool. - Translates
tools/callinvocations into the same actor dispatch (query path or command path) that the equivalent HTTP request would have used. Actor handlers are unchanged; they do not know whether the invocation arrived as HTTP or MCP. - Applies CIP-18 payment gating over MCP’s JSON-RPC transport extension. Payment challenges ride JSON-RPC error code
-32402; credentials and receipts ride the MCP_metafield.
- MCP resources and prompts. v1 is tools-only.
- Streaming tool results. SSE-style streaming is acknowledged but deferred to a follow-on CIP.
- Custom tool name remapping. Tool names are derived mechanically from route method names.
- Server-initiated notifications and sampling.
2. Motivation
CIP-14 made Cowboy actors HTTP-addressable. CIP-15 added verb-aware routing and per-route payment policy. Together they let agents call actor handlers as a familiar REST API. MCP changes the audience. The Model Context Protocol is becoming the standard interface between LLM agents and external tools. Every major agent runtime (Claude Code, Anthropic API tool use, OpenAI Agents SDK, Microsoft Copilot Studio, the Anthropic SDK) speaks MCP. An agent that knows MCP can pick up any MCP server and start using its tools — without per-server SDK glue. By contrast, an agent that only knows HTTP must be told the API contract. Cowboy actors are an unusually good fit for MCP:- Verifiable tools. An MCP tool backed by a Cowboy actor has on-chain, deterministic code. An agent can audit what the tool actually does before calling it.
- Natively payable. Combined with CIP-18, an MCP tool call can require payment up front. Agents that already speak the JSON-RPC payment transport Just Work.
- Self-sovereign. No hosting provider, no API key issuance, no DNS acrobatics. Deploy an actor, grant
ingress.httpandingress.mcp, and you have a payable MCP server reachable at<actor>.cowboy.network/_cowboy/mcp. - Discoverable. The CIP-18 OpenAPI document and the MCP
tools/listcome from the same source — the routes table — so agents can discover Cowboy actors through whichever surface they prefer.
3. Design Goals
- Zero actor opt-in for the wire. An actor author declares routes (CIP-15). The Gateway exposes those routes as MCP tools. The handler code is unchanged.
- One source of truth. Tool list is derived from the routes table. The CIP-18 OpenAPI document is generated from the same data. Skew is impossible.
- Same dispatch as HTTP. A
tools/callinvocation dispatches through CIP-14’s existing query/command paths. No new actor-side execution model. - Payment via CIP-18. MCP gating reuses CIP-18 wire formats over MPP’s JSON-RPC transport. No new payment code path.
- Gateway-terminated, not runner-terminated. Mirrors CIP-14: the Gateway is the public edge, runners are private compute.
- Standard MCP wire. The Gateway speaks unmodified MCP
2025-11-25over streamable HTTP. Any conformant MCP client works.
4. Non-goals
- MCP resources and prompts. Tools only in v1. CIP-15 volumes could plausibly back resources in a future revision.
- Streaming tool results. SSE / chunked tool results are deferred; v1 returns one response per call.
- Server-initiated requests. MCP supports server → client
sampling/createMessageandnotifications/*. v1 does not implement these. - Tool name customization. Tool names are derived from the CIP-15 route’s
target.name. A future CIP may add an explicitmcp_nameoverride. - MCP authentication outside CIP-18. OAuth, API keys, and other MCP auth modes are out of scope. Payment is the only gating mechanism in v1.
- Actor-side MCP client. This CIP is about actors as MCP servers. Actor consumption of external MCP servers (the existing
runner-mcpcrate) is unrelated.
5. Definitions
- MCP: The Model Context Protocol, version
2025-11-25(the spec dated 2025-11-25 on modelcontextprotocol.io). Uses JSON-RPC 2.0 framing. - Streamable HTTP transport: MCP’s HTTP-based transport mode (replaces the older HTTP+SSE transport from earlier MCP revisions).
- Tool: An MCP-discoverable, callable function with a JSON-Schema-described input and a structured output. In Cowboy, a tool corresponds 1:1 with a Method-target route from CIP-15.
- Tool name: The string identifying a tool. Derived from
route.target.nameper §10. - MCP
_metafield: A reserved JSON-RPC field for protocol extensions. Used by CIP-18 to carry payment credentials and receipts.
6. Architecture
7. The ingress.mcp Entitlement
| Param | Type | Description | Default |
|---|---|---|---|
server_name | string? | MCP serverInfo.name | <actor>.cowboy.network |
server_instructions | string? | Human-readable hint for clients (initialize.result.instructions) | empty |
tool_name_prefix | string? | Prepended to every generated tool name | empty |
exclude_routes | array<string>? | Method names to NOT expose as tools | [] |
max_tool_input_bytes | u32? | Limit on encoded arguments size | MAX_TOOL_INPUT_BYTES_DEFAULT |
ingress.http (CIP-14). MCP exposure without HTTP ingress is undefined.
Composition with CIP-18: if the actor also holds payment.gate, MCP tool calls inherit the route’s pays policy from CIP-15. pays = "actor" routes are free over MCP. pays = "caller" routes require payment via §11 below.
8. MCP Endpoint
The Gateway exposes:2025-11-25 over the streamable HTTP transport. It accepts both POST (for client→server JSON-RPC requests) and GET (for the optional server→client SSE stream that the streamable HTTP transport defines). v1 does not emit server-initiated notifications, so the SSE stream is open-but-empty.
A request to any other method on /_cowboy/mcp returns 405 Method Not Allowed.
The endpoint is reserved per CIP-18 §17 and CIP-14 §8.6. It is intercepted by the Gateway before route resolution; the routes table is not consulted to dispatch the MCP endpoint itself.
8.1 Session lifecycle
The streamable HTTP transport assigns aMcp-Session-Id header on the initial initialize response. Subsequent requests in the same session MUST include this header. Sessions are terminated by an explicit DELETE to /_cowboy/mcp or by inactivity beyond MCP_SESSION_IDLE_TIMEOUT_SECONDS.
Session state held by the Gateway is limited to:
- The negotiated
protocolVersion(always2025-11-25in v1). - The client’s
clientInfo. - The cached routes-table version observed at session start (for consistent
tools/list).
9. Capability Negotiation (initialize)
The Gateway responds to initialize with:
capabilities.tools.listChanged: true means the Gateway will emit notifications/tools/list_changed over the SSE stream when the routes table changes. Clients that rely on a fresh tool list MUST handle this notification or re-query tools/list periodically.
resources and prompts capabilities are NOT advertised in v1.
completions and sampling are NOT advertised — Cowboy actors do not initiate model calls back to the client.
10. tools/list
The tool list is generated from the actor’s CIP-15 routes table. Generation is deterministic and verifiable.
10.1 Generation algorithm
- Read the routes table at
__cowboy/routesfrom the actor’s KV state (using the CIP-15 §8.12 Gateway-to-Runner fetch protocol). - Filter to routes where:
target.kind == "method"(Volume targets are not tools)enabled == truetarget.nameis not iningress.mcp.exclude_routes
- Group routes by
target.name. Each unique method name produces one tool. - For each group, validate that all routes share a compatible input schema (§10.3). If not, the group is skipped and a warning is logged in the Gateway’s structured-error output.
- Emit one
Toolentry per group.
10.2 Tool entry shape
_meta.cowboy block is non-normative metadata that lets MCP-aware Cowboy clients introspect routing details without re-fetching the OpenAPI doc.
10.3 Input schema derivation
For each tool, the Gateway constructs the JSON Schema from:- Path parameters from
route.path(CIP-15 §6.3). Each{param}becomes a required string property. - Query parameters and body from the actor’s OpenAPI document (CIP-18 §14). Path-Item schemas under the matching verb supply property types and descriptions.
- No declared schema → fall back to a permissive
additionalProperties: trueobject.
GET /users/{id} and HEAD /users/{id} both → users.get), the Gateway requires that path parameters and bodies are identical. If they differ, the routes are considered incompatible and the tool is skipped (§10.1 step 4).
10.4 Tool name mapping
The MCP tool name is:sanitize replaces any character outside [a-zA-Z0-9_] with _. CIP-15 method names typically use dotted notation (e.g., users.get); after sanitization this becomes users_get.
Names beginning with _cowboy are reserved for system tools (§14). If tool_name_prefix + sanitize(...) would collide with a reserved name, the route is skipped.
11. tools/call (Dispatch Contract)
A tools/call request maps onto the same actor dispatch as the equivalent HTTP request.
11.1 Request shape
11.2 Translation to HTTP equivalent
The Gateway:- Looks up the route group for
params.name(reverse of §10.1). - Picks the canonical route in the group (highest priority; ties broken by storage order).
- Substitutes path parameters from
argumentsintoroute.path. - Splits remaining arguments into query parameters and body per the OpenAPI schema for the selected verb.
- Constructs a synthetic
HttpRequestEnvelope(CIP-14 §8.5) with:verb=route.verb(orPOSTifroute.verb == "ANY")path= the substituted pathquery= serialized query parametersbody= serialized body (JSON, unless OpenAPI declares otherwise)headers= a synthesized minimal set (content-type,accept, plusX-Cowboy-Mcp-Session-Id)path_params= the matched named parameters
11.3 Dispatch
The Gateway dispatches the envelope per CIP-14 §8:- Safe verbs (
GET,HEAD): CIP-14 query path viaread_handler. No transaction, no consensus. - Unsafe verbs (
POST,PUT,PATCH,DELETE): CIP-14 command path viaGatewayRegistry.dispatch(). Consensus-required.
11.4 Response shape
The actor handler returns anHttpResponseEnvelope (CIP-14 §8.5). The Gateway maps it to MCP:
content-type: application/json→ emit as a singletextcontent block with the JSON, AND a siblingstructuredContentfield carrying the parsed JSON (per MCP2025-11-25).content-type: text/*→ emit as a singletextcontent block.- Binary types (
image/*,application/octet-stream) → emit as oneimageorresourcecontent block per MCP’s content-type rules. Bodies exceedingMAX_TOOL_OUTPUT_BYTESare truncated and the response is markedisError: truewith atruncatedflag in_meta.cowboy.
11.5 Error mapping
- HTTP 4xx (other than 402):
result.isError = true, content describes the error, no JSON-RPC error frame. - HTTP 5xx: JSON-RPC error frame with
code = -32603(internal error),message = "Actor handler failed",datacarrying the response body if size-bounded. - HTTP 402: see §12.
- Network / timeout: JSON-RPC error frame with
code = -32000,message = "Gateway dispatch failed".
12. Authentication and Payment
This section defers to CIP-18 §13 for the wire format. CIP-19 specifies only how it integrates with the dispatch contract.12.1 No payment required
Routes withpays = "actor" (CIP-15 default) require no payment. The Gateway dispatches per §11 and pays the actor’s hot balance per CIP-14.
12.2 Payment required, no credential
Routes withpays = "caller" and no _meta.payment-authorization in the request: the Gateway returns a JSON-RPC error frame:
data.challenges array follows the MPP challenge schema (CIP-18 §9.1). The data.x402_compat block is a parallel x402 representation for clients that prefer it. Both describe the same payment requirement.
12.3 Payment provided
Routes withpays = "caller" and a credential in _meta.payment-authorization:
- The Gateway normalizes the credential to a
PaymentIntentper CIP-18 §11. - PaymentGate verifies and (atomically with dispatch on the command path, or fire-and-forget on the query path) settles per CIP-18 §15.
- On verification failure, the Gateway returns a JSON-RPC
-32402error with a fresh challenge. - On success, the Gateway dispatches per §11.3 and includes the receipt in
result._meta.payment-receipt.
12.4 Pass and subscription credentials
intent="pass" and intent="subscription" credentials are carried in the same _meta.payment-authorization field. The Gateway evaluates them ahead of intent="charge" per the CIP-18 §7.5 fallback chain.
13. Reserved Tool Names
Tool names beginning with_cowboy_ (after tool_name_prefix is applied) are reserved for system tools the Gateway exposes alongside actor-derived tools. v1 reserves but does not yet implement:
| Reserved name | Description |
|---|---|
_cowboy_payment_quote | Get a quote for a hypothetical request without dispatching (mirrors /_cowboy/payment/quote). |
_cowboy_payment_subscribe | Purchase or extend an epoch subscription. |
_cowboy_pass_purchase | Purchase a prepaid pass. |
_cowboy_health | Liveness probe (mirrors /_cowboy/health). |
_cowboy_info | Actor metadata (mirrors /_cowboy/info). |
14. Gateway Integration
14.1 New responsibilities
The Gateway gains:- An MCP server implementation per §8 — streamable HTTP transport, JSON-RPC 2.0 framing, session management.
- A tools-list generator that materializes
Toolentries from the routes table on session start and onnotifications/tools/list_changed. - A
tools/calltranslator that maps to the existing dispatch path. No new dispatch primitives. - Hooks into CIP-18’s payment enforcement: the JSON-RPC frame inspector for
_meta.payment-authorization, the error mapper for-32402, and the receipt emitter.
14.2 No actor-side changes
Actor handler code is unchanged. An actor that already serves HTTP via CIP-14 + CIP-15 becomes MCP-callable by adding theingress.mcp entitlement. The handler does not see a “tool call” — it sees an HTTP request envelope, exactly as today.
14.3 Caching
The Gateway caches the per-actor tool list keyed by(actor, routes_state_root). Cache is invalidated when the actor’s state root changes (signaled by the same block-by-block cache refresh that CIP-14 §10 already uses for the route registry).
15. Reserved Paths
| Path | Method | Description |
|---|---|---|
/_cowboy/mcp | POST / GET / DELETE | MCP streamable HTTP endpoint. Already reserved by CIP-18 §17; this CIP defines its semantics. |
16. Protocol Constants
17. Security Considerations
- Tool name collision. Reserved
_cowboy_*prefix prevents actor routes from impersonating system tools. Routes that would collide are dropped fromtools/list(§10.4). The dropped-route warning is observable in the Gateway’s structured-error logs. - Path-parameter injection. Path parameters from
argumentsare URL-encoded before substitution intoroute.path(§11.2 step 3). Arguments cannot smuggle additional path segments via slashes or... - Payment replay over MCP. Each MPP credential carries a
nonceconsumed atomically by PaymentGate (CIP-18 §21). Submitting the same credential as both an HTTP retry and an MCP tool call settles once. - Cross-session credential reuse. Payment credentials are bound to
request_hash; an MCP_meta.payment-authorizationissued for one tool call cannot be replayed against another. - Session hijacking.
Mcp-Session-Idis a server-issued opaque token withMCP_SESSION_IDLE_TIMEOUT_SECONDSlifetime. Sessions are tied to TLS-terminated connections; the Gateway rejects requests whoseMcp-Session-Idcame from a different TLS endpoint or expired. - Tool argument size.
MAX_TOOL_INPUT_BYTES(governance default1 MiB) bounds attacker payload size before any actor dispatch occurs. - Tool output size.
MAX_TOOL_OUTPUT_BYTESbounds the response body. Truncation is signaled in_meta.cowboy.truncated. - Unbounded tools/list. The MCP
tools/listresponse is bounded by the routes table’sMAX_ROUTES(CIP-15 §10). Pagination is not required. - Server-initiated requests are disabled. v1 does not advertise
samplingornotifications/*capabilities. A malicious client cannot induce the Gateway to call back into it. - Schema mismatch DoS. Routes that target the same method name with mismatched schemas are dropped (§10.1 step 4) rather than producing inconsistent tools. An attacker cannot poison
tools/listby registering a conflicting low-priority route, because the Gateway picks the canonical route deterministically. - Information leakage in errors. HTTP 5xx response bodies are size-bounded before inclusion in JSON-RPC
error.data. Actors that return secrets in 5xx bodies have a CIP-14 problem, not a CIP-19 problem; this CIP does not amplify the leak. - Prompt injection. Tool-call arguments arrive as opaque strings from the agent’s perspective. The Gateway does not interpret tool descriptions or arguments as prompts. Prompt-injection risks live in the agent runtime and are out of scope for this CIP.
18. Rationale
Why Gateway-terminated MCP, not runner-terminated? The Gateway is the public, DNS-addressable, payment-enforcing edge. Runners are private compute. Putting MCP on runners would require (a) exposing them publicly, (b) duplicating CIP-18 payment enforcement, (c) forcing actors to opt into “I’m an MCP server” beyond just declaring routes. Gateway termination preserves CIP-14’s architectural separation and makes MCP exposure free for any actor that already has HTTP routes. Why derivetools/list from the routes table? A separate MCP-tool declaration would create skew between HTTP and MCP surfaces. CIP-15’s routes table is already the authoritative description of “what this actor exposes.” Deriving the OpenAPI doc (CIP-18 §14) and the MCP tool list from the same source means an agent that uses HTTP and an agent that uses MCP see the same actor.
Why one tool per method name, not one per route? Routes are a transport concern (verb × path → handler). Tools are a logical concern (named callable). Multiple routes can target the same method (e.g., GET /users/{id} and HEAD /users/{id} both → users.get); collapsing them into one tool matches the conceptual layer MCP operates at.
Why version-pin to MCP 2025-11-25? It is the current (as of 2026-04-28) MCP spec, has the streamable HTTP transport, and has stable _meta semantics required by MPP’s JSON-RPC payment transport. Earlier versions lack _meta; later versions are unspecified at this CIP’s creation. Future CIPs can advance the pin.
Why not implement MCP resources? Volume-target routes (CIP-15) are the natural backing for MCP resources (URI-addressable read-only content). Wiring this up requires careful thinking about resource templates vs. concrete URIs and the read-time consistency guarantees clients expect. Deferring keeps v1 small and lets us learn from tools-only deployment first.
Why not stream tool results in v1? SSE-style streaming changes the dispatch contract: the actor would need to emit chunks rather than a single envelope. This is conceptually compatible with CIP-7 streams but operationally requires Gateway buffering and cancellation propagation. Out of scope for the first MCP CIP.
Why a new entitlement instead of riding ingress.http? Some actors may want HTTP exposure but not MCP exposure — for example, web-only frontends, SEO landing pages, or actors whose route handlers were not designed for agent invocation. Making MCP opt-in via ingress.mcp lets authors decide explicitly.
19. Future Work
- Resources. Map CIP-15 Volume-target routes to MCP resources, with URI templates corresponding to wildcard paths.
- Prompts. Allow actors to declare reusable prompt templates as a separate KV table, exposed via MCP
prompts/listandprompts/get. - Streaming. Bridge CIP-7 streams to MCP streamed tool results.
- Tool name customization. An optional
mcp_namefield on Route entries (CIP-15 schema extension) for friendlier names. - Sampling and notifications. If actor-initiated agent interaction becomes a use case, advertise the
samplingcapability and add a runner-side outbound MCP client. - MCP version progression. Pin advancement as the MCP spec evolves. Deprecation policy is governed by CIP-12.
- System tools (§13). Implement
_cowboy_payment_quote,_cowboy_payment_subscribe, etc., so MCP-only clients can interact with PaymentGate without a separate HTTP path.
20. Backwards Compatibility
This CIP is fully additive:- Actors without
ingress.mcpare unaffected. No MCP endpoint is exposed. - Actors with
ingress.mcpand existing CIP-15 routes need no code changes — the routes table is the source of truth and is already populated. - The
/_cowboy/mcpreserved path was reserved by CIP-18 §17. This CIP defines its semantics; it does not introduce a new reservation. - No changes to CIP-14 dispatch semantics, CIP-15 route schema, CIP-18 PaymentGate, or any other CIP.
- The MCP version pin is a Gateway-side concern; advancing it does not require an actor-side migration.

