Skip to content

MCP Gateway ​

The MCP Gateway is a second Cloud Harness MCP endpoint that fronts the downstream MCP servers you register yourself — GitHub, PostHog, Supabase, Cloudflare, or any other remote MCP server. Instead of adding each of those servers to Claude, ChatGPT, Codex, and Cursor separately, you configure one URL in each client:

text
https://<your-cloud-harness-host>/mcp-gateway

Cloud Harness keeps your registry, cached tool metadata, permissions, and logs. Your MCP client talks only to Cloud Harness; Cloud Harness talks to the downstream servers.

One endpoint, a constant tool list

The gateway always exposes exactly five tools — search, inspect, execute, permissions, and status — no matter how many downstream tools you configure. Your client's context window does not grow as you add servers.

Add an MCP server ​

  1. Open the Operator Dashboard and select MCP Servers in the rail.
  2. Select Add MCP server and provide:
    • Name — a short lowercase identifier, unique to you, such as github.
    • Transport — streamable-http or sse.
    • Endpoint — the server's MCP URL, usually ending in /mcp.
    • Headers — any custom headers the server requires, such as an Authorization header.
    • Authentication — optionally, Authenticate with OAuth for a server that signs you in with OAuth instead of a static token. See Connect an OAuth-protected server.
    • Default permission — allow or deny for every tool on that server.
  3. Save the server. Use Test to confirm Cloud Harness can reach it, and Refresh tools to cache the server's tool list. For an OAuth server, select Connect first.

Enable, disable, edit, and delete servers from the same list. Deleting a server also deletes its cached tools, permissions, and recorded logs.

Reference a secret instead of pasting one ​

A header value can be a literal or a reference to one of your global secrets:

text
Authorization: Bearer <literal value>
Authorization: { secretRef: my-vendor-token }

A secret reference stays write-only. The dashboard shows only the secret name, the resolved value is never stored in the server configuration, and it is never returned to the browser, a tool result, a trace, or a log. Cloud Harness attaches the resolved credential only to requests for that server's configured endpoint.

If the referenced secret is missing, the gateway tells you which reference is unavailable — never a value.

Connect an OAuth-protected server ​

Some remote MCP servers do not issue static tokens and instead ask you to sign in with OAuth. Cloud Harness can sign in to those servers on your behalf.

Two different OAuth flows

This is Cloud Harness signing in to a downstream MCP server. It is separate from the Cloudflare Access sign-in your AI client uses to reach Cloud Harness. Nothing you configure here changes how your client connects.

  1. In the server form, keep Transport as streamable-http and check Authenticate with OAuth. Optionally enter:
    • Scopes — space-separated scopes to request.
    • Client ID — only if the provider requires a client you registered manually with them.
    • Client secret — a global secret reference for that manual client; leave as None for a public client.
  2. Save the server, open it, and select Connect in the OAuth panel of the Overview tab. Your browser goes to the provider's sign-in page and then returns to the server page, which announces whether the connection succeeded.
  3. Select Test or Refresh tools to load the server's tools.

Things to know:

  • No custom Authorization header. OAuth supplies that header, so saving an OAuth server with your own Authorization header is refused. Other custom headers still work.
  • streamable-http only. OAuth cannot be enabled on an sse server.
  • Tokens are never shown. They are stored encrypted, renewed automatically while the provider allows it, and never appear in the dashboard, tool results, logs, or the audit trail. The OAuth panel shows only safe details such as the issuer, granted scopes, registration type, and expiry.
  • When sign-in is needed again, gateway calls to that server fail with AUTHORIZATION_REQUIRED and the panel shows Reauthorize. Calls from your AI client never open a browser; reconnect from the dashboard.
  • Disconnect asks the provider to revoke the token where it supports that, then deletes it from Cloud Harness either way. Changing the endpoint or the manual client, or turning OAuth off, also discards the stored sign-in.
  • A failed reconnect keeps a working sign-in. If you cancel or the provider rejects a Reconnect, the existing sign-in keeps working and the panel shows the failure as a warning until the next successful sign-in.
  • Your operator must enable it. Until the deployment sets MCP_DOWNSTREAM_OAUTH_REDIRECT_URL, the panel reads Not configured and offers no Connect. A sign-in made before then keeps working and can still be disconnected.

Connect an MCP client ​

Point the client at https://<your-cloud-harness-host>/mcp-gateway. The gateway uses the same authentication as your /mcp endpoint: your Cloudflare Access session in Access mode, or your owner bearer token in owner-bearer mode.

Static-header clients: use the API-key lane

Clients that can only send a static Authorization header (Claude Code, Cursor, Codex, scripts) connect to the gateway through the managed API-key lane:

text
https://api.harness.zuey.me/mcp-gateway

Send a key from API Keys as Authorization: Bearer <key>. The client sees the same five tools, scoped to the account that created the key. The MCP Servers gateway card in the dashboard shows this URL with a Copy button when the deployment enables the lane. An API key works only on api.harness.zuey.me; it is rejected on https://<your-cloud-harness-host>/mcp-gateway.

Find and run a tool: search, inspect, execute ​

The gateway does not dump every downstream tool into your client's tool list. Work through it in three steps:

  1. search — describe what you want to do, for example "create a GitHub issue". You get back qualified tool names in the form <server>.<tool>, ranked and filtered to tools you are allowed to use. Optionally restrict the search to one server. If the operator enabled semantic routing, the response says ranking: "semantic" and the matches are reordered by meaning rather than shared words. Otherwise it says ranking: "lexical". Semantic routing only reorders tools you could already see. It never adds a denied tool.
  2. inspect — pass one qualified name to receive that tool's real input schema, annotations, availability, and effective permission. Read the schema before you call it.
  3. execute — run the tool with arguments that match the inspected schema. Cloud Harness re-checks permission at execution time and routes the call server-side. A mutating call is never automatically retried.

Two more tools round out the surface:

  • permissions — show the effective allow/deny decision for one tool, for every tool on a server, or for every configured server.
  • status — show each server's enabled state, connection state, cached tool count, last successful connection, and a sanitized error when one is stored.

Permissions ​

Each server has a default permission (allow or deny), and any individual tool can override it with the opposite decision. The effective decision is the tool override when one exists, otherwise the server default. Permission is enforced on every execution, not only when you browse tools. Only allow and deny exist — there is no approval prompt state.

Default permission is allow. A newly added server's tools are immediately executable with your credential, which is a deliberate usability decision for a single-owner harness. If you want default-deny, set permissionDefault: deny on the server; a deny-by-default server stays testable because Test and Refresh tools use the separate, audited connect credential purpose instead of the execution gate.

Test and Refresh tools always work, even on a deny-by-default server, because they use a separate, audited connection purpose that only proves reachability.

Logs ​

Every gateway call writes a trace you can review in the server's Logs tab: the time, the tool, the outcome, the duration, when the client identified itself, and the request and response sizes. Argument and result contents are not stored, and credential values are removed. Logs are bounded by a retention cap, and deleting a server deletes its logs.

Supported downstream transports ​

TransportSupportedNotes
streamable-httpYesThe standard remote MCP transport. Supports a secret-reference header or OAuth.
sseYesLegacy remote SSE transport. Literal headers only; a secret-reference header or OAuth is rejected at save time.
stdioNoCloud Harness does not run package-based local MCP servers.

Limitations ​

  • HTTP redirects are refused. If your vendor's base URL redirects, configure its final URL directly.
  • stdio servers are unsupported. Use streamable-http or sse.
  • OAuth is streamable-http only and connected from the dashboard. Your AI client cannot start a sign-in through the gateway tools.
  • The managed API-key lane uses a separate managed key. The owner must deploy the API-key Worker and origin route before it is reachable.
  • Connections are per-process and bounded. They are not shared across API replicas and are rebuilt after a restart.
  • Search is lexical, not semantic. It matches words and names; it is not an embedding search.
  • Only allow and deny. There is no confirm decision.
  • Deleting a server deletes its logs.
  • Schema size is capped. A downstream tool whose schema is too large is reported as unavailable rather than truncated.
  • Authenticated SSE servers are unsupported and refused when you save them. Your credential is attached only to requests whose origin and pathname equal your configured endpoint, so an SSE server that needs a header credential on its separate message/POST endpoint never receives one. Saving sse with a secret-reference header fails immediately and tells you to use a Streamable HTTP server, so the mistake cannot pass Test/Refresh and fail on real calls.
  • status and permissions read the whole catalog. Only search needs to by design; inspect and execute load a single tool.

Released under the MIT License. Single-owner private remote coding harness.