Skip to content
route402.dev
Documentation
read as markdown

Publish MCP server

The remote MCP server at /mcp — connection, OAuth, and the six publishing tools.

A remote MCP server that lets an agent publish an API end to end. No npx, no local install, no config file editing.

Connect

https://route402.dev/mcp

Paste that into any MCP client that supports remote servers. The client will:

  1. POST /mcp without a token and receive 401 with WWW-Authenticate: Bearer resource_metadata="…".
  2. Fetch /.well-known/oauth-protected-resource (RFC 9728) to find the authorization server.
  3. Fetch /.well-known/oauth-authorization-server (RFC 8414) for the endpoints.
  4. Register itself at /register (RFC 7591) — no manually provisioned client_id needed.
  5. Send you to a consent screen, then exchange the code with PKCE.

Copy-pasteable client config:

{
  "mcpServers": {
    "route402": {
      "type": "http",
      "url": "https://route402.dev/mcp"
    }
  }
}

Transport

Streamable HTTP. POST /mcp carries JSON-RPC and answers with application/json; GET /mcp with Accept: text/event-stream opens the server stream; DELETE /mcp ends the session. Protocol versions 2025-06-18, 2025-03-26 and 2024-11-05 are accepted.

Scopes

Scope What it grants
registry:read Browse public listings. The directory is public; nothing needs authorizing to read it.
services:write Create services, store credentials, and publish under your account.

Tokens are audience-bound to https://route402.dev/mcp. A token minted for the wallet is rejected here, and vice versa. This server will never issue wallet:spend — payment authority lives on a different resource server and is consented separately.

Access tokens last one hour. Refresh tokens rotate on every use.

Tools

Every tool returns JSON, never prose.

create_service

Registers an upstream API. Requires name, description (≥ 20 characters) and upstream_base_url. Optional: tags, pay_to, network, icon_url.

Returns service_id, slug, and the gateway base URL. The upstream must resolve to a public address — private and reserved ranges are refused.

set_upstream_auth

Stores the credential the gateway injects when calling your upstream. Requires service_id, placement (header, query, or bearer) and value; param_name is required unless placement is bearer.

Write-only. No tool returns this value, the web console cannot display it, and there is no read API. The response carries a keyed digest — useful only for answering "did this change?". Call the tool again to rotate.

add_endpoint

Defines one path and its price. Requires service_id, method, path, description (≥ 10 characters) and price_usd. Optional: input_schema, example_input, output_schema, output_example.

Calling it again for the same method and path updates the definition and clears its test result — the contract changed, so the old proof no longer applies.

test_endpoint

Calls the upstream once, exactly as the gateway will, with the stored credential injected. Returns status_code, latency_ms, content_type, a body_preview, and a hint when it fails.

Requires service_id and endpoint_id. query_params overrides the endpoint's example_input for this call.

publish_service

Registers every endpoint into the public Bazaar registry.

Fails unless test_endpoint has passed for every endpoint. A listing that 500s on its first call poisons the directory for everyone. When it cannot publish, it returns blockers — a list of {code, message} — so the whole set can be fixed in one turn instead of one at a time.

When the registry rejects a listing, rejected_reason carries its reason verbatim.

Publishing is all-or-nothing. The service goes live only once every endpoint is in the registry. If the registry rejects a listing or cannot be reached, nothing is published — a service is never live but undiscoverable, and an already-published service is not taken down because the registry hiccuped. publish_service is idempotent, so retrying it is the whole recovery procedure.

Prices are resolved here, not downstream. price_usd is converted to atomic units of the network's settlement asset before it reaches the registry or the gateway, which do no currency resolution of their own. A price with more decimal places than the asset can express is refused rather than rounded, and a network with no configured settlement asset is a blocker — a price nobody can pay is not a listing.

get_service_status

Health, listing state, endpoint test results, 30-day analytics, and any outstanding blockers. Every endpoint carries its own registry_status (listed, rejected, unreachable, not_registered) and registry_reason, because the registry accepts or rejects each resource independently. Omit service_id to list every service on the account.

The five-turn flow

create_service      → svc_8f31 · acme-weather
set_upstream_auth   → stored, write-only
add_endpoint        → GET /current · $0.001
test_endpoint       → 200 in 198 ms ✓
publish_service     → bazaar.status = success

Errors

Tool failures come back as a structured result with isError: true and a body of {ok: false, error, message, …}. Common codes:

Code Meaning
insufficient_scope The token lacks services:write.
upstream_not_allowed The URL is malformed, or resolves to a private range.
invalid_arguments Schema validation failed; the message names the field.
not_publishable See blockers for the full list.
temporarily_unavailable The platform database is unreachable. Nothing changed.
NextUpstream credentials