FarcasterGateway

Farcaster Routing & Proxy

In the path, not in the way.

A caller invokes the agent through Farcaster instead of calling the upstream directly. Farcaster resolves the upstream, injects the agent's credential, forwards the body untouched, and records what happened. The upstream sees its own protocol — not ours.

shipped Apache-2.0 /v1/proxy

Two modes

Hold the connection, or don't.

The same agent is reachable two ways, and the caller picks by use case rather than by configuration. Both return an inv_ ID, so a call is addressable in observability no matter which one you used.

Transactional

$ curl localhost:8080/v1/proxy/{id} \
    -H "Authorization: Bearer $TOKEN" -d '{}'

202 Accepted
X-Farcaster-Invocation-ID: inv_019842…
{ "invocation_id": "inv_019842…" }

Returns immediately, runs the upstream call server-side, and you poll /v1/proxy/{id}/invocations/{inv_id} for the result. Suits long thinking flows where holding a connection open buys you nothing.

Streaming

$ curl -N localhost:8080/v1/proxy/{id}/stream \
    -H "Authorization: Bearer $TOKEN" -d '{}'

← request and response stream through
  verbatim, with no buffering

A long-lived connection for token-by-token responses or hefty payloads. The invocation ID is set on the response before any upstream byte is written, whatever the outcome — so a call is traceable even when it fails mid-stream.

The mechanic

There is no envelope to unwrap.

Farcaster forwards the caller's request body unmodified. No wrapper, no re-encoding, no schema of ours in the middle. An upstream built before Farcaster existed needs no change to sit behind it, and moving off Farcaster does not mean unpicking a format.

Header What it does Set by
X-Request-ID Correlates the call end to end. Yours is honoured; if absent, one is injected Caller or gateway
X-Farcaster-Model Optional label recorded on the invocation, capped at 256 bytes Caller
Authorization Always stripped. The upstream never sees the caller's token Gateway

Headers forward through a block-list, not a pass-all. That is the deliberate direction: the caller's OAuth token is removed on the way out, and the agent's own credential is injected in its place — so the upstream is authenticated as your integration, never as whoever happened to call you.

The transactional endpoint caps request bodies at 32 MiB. The streaming endpoint has no cap, because it never buffers.

Policy

A call you refuse is never asked to pay.

Policy is evaluated inline on the proxy path, after the call is parsed and before the payment gate. The ordering is the point: a request your policy denies gets a 403, not a 402 followed by a 403 once they've signed for it.

Action What happens Recorded
allow Forwarded unchanged — also the behaviour when nothing matches and the policy's default is allow Yes
warn Forwarded, plus an X-Farcaster-Policy-Warning header on the transactional response Yes
deny Rejected with 403 and a single coarse reason. Never forwarded Yes

The no-match and on-error actions are read from your policy, not hardcoded. You decide whether an unevaluable call fails open or closed — we don't decide it for you. And a tenant with no policy configured sees zero change: calls proxy exactly as they did before this surface existed.

When you get it wrong

Refused early, and without a map of your network.

The checks that can be made before an upstream call is attempted are made before an upstream call is attempted. What comes back says what happened without describing where anything lives.

What you did What you get Why
Invoked a pending, suspended, or soft-deleted agent 422 Decided from the catalog record, before any upstream call is made
Pointed at an upstream that won't answer 502 Transient failures are retried and a circuit breaker opens on an upstream that keeps failing, so one bad host doesn't become your latency
Pointed at an upstream that answers too slowly 504
Sent a call your policy denies 403 One coarse reason — a precise one would let a caller map your rules by probing
Read any error body above No internals Error bodies never carry upstream addresses or internal detail

One limit worth knowing before you rely on it. If the policy store is unreachable — a database timeout, say — your configured on-error posture can't be read, so it can't be honoured. The gateway fails closed and returns 500 for the duration. That's the safe direction, and it's a documented interim posture rather than a surprise waiting for you in production.

Where the line falls

The whole traffic path is free.

Routing is not the part we sell. Everything that carries a request from your caller to your upstream and back is Apache-2.0.

Capability Tier
Transactional and streaming proxy, verbatim body forwarding OSS
Credential injection, SSRF guarding, retries and the circuit breaker OSS
Policy evaluation on the proxy path OSS
Governance and a control plane across tenants Commercial

The full boundary →

Next

The proxy forwards bytes. MCP lets it read them.

Declaring an agent's protocol as MCP keeps everything on this page and adds what a protocol-agnostic pipe structurally cannot have: method- and tool-level visibility, and a retry rule that knows which calls are safe to repeat.