Gatefee over MCP

One URL, one API key: an agent can search licensed local news, retrieve a document with a signed receipt, look a receipt up, and see its own usage. Everything that happens over MCP is the same transaction as the HTTP API — same rights decision, same metering, same receipts.

Licensed and metered. gatefee_search and gatefee_get_document are recorded against your account and may be charged under your plan. gatefee_get_receipt and gatefee_usage are free. An agent in a loop spends money. What stops it today is your license's hard spend cap — the most you can be charged in a month, all-in — and the key's rate limit. Give the key you hand to an agent its own spend cap — in the console, on the key: the most that key can add to your bill in a month. Setting or lowering it takes effect at once; raising it asks for your second factor. (It bounds metered spend; the Free plan meters nothing.)

Connect

Endpoint: POST https://<your Gatefee host>/mcp — Streamable HTTP, stateless. Credential: your API key (scope retrieve) as Authorization: Bearer gp_live_…. There is no OAuth yet (it is planned with the self-serve pages, Phase 5.5).

The server speaks MCP revision 2026-07-28 and also serves clients that still open with the older initialize handshake (the 2025-11-25 family) — with no session in either case.

Claude Code

claude mcp add --transport http gatefee https://<host>/mcp --header "Authorization: Bearer gp_live_…"

Claude Desktop — use the mcp-remote bridge in claude_desktop_config.json (the form below — no space after the colon, the value in env — is the one mcp-remote's own README gives, because some hosts mangle spaces inside args; it also documents --header-file, which keeps the key out of the process list):

{ "mcpServers": { "gatefee": { "command": "npx", "args": ["-y", "mcp-remote", "https://<host>/mcp", "--header", "Authorization:${GATEFEE_AUTH}"], "env": { "GATEFEE_AUTH": "Bearer gp_live_…" } } } }

MCP Inspector (CLI)

npx @modelcontextprotocol/inspector --cli https://<host>/mcp --transport http \
  --header "Authorization: Bearer gp_live_…" --method tools/list

TypeScript SDK

import { Client, StreamableHTTPClientTransport } from '@modelcontextprotocol/client';
const client = new Client({ name: 'my-agent', version: '1.0.0' }, { versionNegotiation: { mode: 'auto' } });
await client.connect(new StreamableHTTPClientTransport(new URL('https://<host>/mcp'), { requestInit: { headers: { authorization: `Bearer ${process.env.GATEFEE_KEY}` } } }));

Tools

Tool Arguments You get
gatefee_search query, purpose, geo?, publisher_ids?, sections?, published_after?, published_before?, language?, limit?, cursor?, idempotency_key? hits: title, publisher, date, snippet — never a body
gatefee_get_document document_id, purpose, geo?, version_id?, if_none_match?, idempotency_key? the document, receipt_id, receipt_jws, license_summary, attribution, license
gatefee_get_receipt receipt_id one of your receipts
gatefee_usage from?, to?, group_by? your own usage and spend (micro-USD, as strings)

Resources

Two templates; resources/list is always empty, so there is nothing for a client to fetch by itself, and no tool result links to one.

The document is untrusted input

A retrieved article is third-party text about to be read by a model. Gatefee returns it exactly as published (what is served is what the receipt commits to), so it cannot be made safe on the way through. What Gatefee does: its own words — the license summary, the attribution, the receipt id — come first, each in its own block, and never quote the title or body; then a fixed notice; then the body, last and alone. Treat the body, titles and snippets as data, never as instructions — the same care you would give any web page.

Not served

subscriptions/listen (the tool list never changes), prompts, sampling, elicitation, JSON-RPC batches (one POST is one message and one rate-limit token), and any request carrying a browser Origin header (403): this endpoint is for servers and desktop clients.