Published Build3 min read
Anonymous by Default: What Happens When a FastMCP Server Leaves Localhost
A FastMCP server accepts every request from every client until you tell it otherwise. Put it behind an ingress and the failure mode is not a breach alert, it is an agent quietly reporting that its tools are unavailable.
Written for builders.See today for builders

What happened
- A FastMCP server started with `fastmcp run server.py` accepts every request from every client, because the default configuration ships with no authentication at all.
- Moving the same unchanged server behind a Kubernetes IngressRoute with TLS and pointing three different agent sessions at it produced an agent reporting that its mail tools "aren't available" while the pod logs showed a stream of 403 Forbidden.
- In local MCP development on stdio transport, the client spawns the server process directly, so authentication is just filesystem permissions and there is no network boundary.
- Switching to streamable HTTP, which is needed for multiple agents sharing one server, means anyone who can reach the port can call initialize, list the tools, and invoke them.
- For an agent mail server, unauthenticated access means reading every message between agents and injecting new ones; if agents treat inbound mail as instructions, an unauthenticated mail endpoint is a prompt injection channel with a REST API.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
A dev.to writeup on running an agent-mail server over MCP restates something that keeps catching people: a server launched with `fastmcp run server.py` accepts every request from every client, because the default configuration ships with no authentication at all [1]. That is fine on localhost, and it stops being fine the moment the same process sits behind a Kubernetes IngressRoute with TLS and three agent sessions are pointed at it, at which point the agent reports that its mail tools "aren't available" while the pod logs show a stream of 403 Forbidden [2].
The reason local development teaches you nothing here is transport. On stdio the client spawns the server process directly, so authentication is filesystem permissions and there is no network boundary to get wrong [3]. Streamable HTTP, which you need if several agents are to share one server, inverts that: anyone who can reach the port can call `initialize`, list your tools, and invoke them [4]. For a mail server that means reading every message between your agents and injecting new ones, and since coordination servers exist precisely so that agents act on each other's messages, the author's framing is fair: an unauthenticated mail endpoint is a prompt injection channel with a REST API [5]. FastMCP 2.x makes auth opt-in through the `auth` parameter on the server constructor, and omitting it yields anonymous access [6]. The documentation says so; the gap is between reading it and doing it before the ingress goes up [7].
The diagnostic part is worth more than the warning. A 403 on an MCP endpoint can come from three layers that look nearly identical to the client: an ingress middleware such as Traefik ForwardAuth, IPAllowList or BasicAuth rejecting the request before it reaches the pod, in which case the body is Traefik's plain 403 text and the pod logs show nothing; the FastMCP auth provider rejecting a credential; or a tool-level check that fails after the handshake succeeded, which surfaces as a protocol-level tool error rather than an HTTP status [8][9]. Strictly, a missing or malformed bearer token should return 401 with a `WWW-Authenticate` header, while a valid token lacking a required scope returns 403 [10]. That single digit tells you whether to look at client configuration or at server scope requirements [11]. It also gives you a shortcut: if you never passed an `auth` provider, the server itself accepts everything [1][6], so a 403 you are seeing has to be coming from the ingress or from a tool check, not from FastMCP [12].
The client side is what makes this expensive. Claude Code does not surface the HTTP status prominently; the server simply shows as failed in `/mcp`, the tools vanish from the toolset, and the agent either says the capability does not exist or improvises around it [13]. A running pod, a green health check and a completely non-functional toolset coexist happily [14]. Combine that with an ingress rejection leaving no trace in pod logs, and neither end of the pipeline records why the tool disappeared [8][13][15].
For an internal deployment the author's recommendation is not OAuth. FastMCP 2.12 ships a `StaticTokenVerifier` that maps opaque token strings to identities and scopes, with per-agent client IDs and scopes such as `mail:read` and `mail:write` loaded from environment variables [16][17].
Claim ledger
Ranked by verification strength, evidence, and original report placement.
- [1]
A FastMCP server started with `fastmcp run server.py` accepts every request from every client, because the default configuration ships with no authentication at all.
- [2]
Moving the same unchanged server behind a Kubernetes IngressRoute with TLS and pointing three different agent sessions at it produced an agent reporting that its mail tools "aren't available" while the pod logs showed a stream of 403 Forbidden.
- [3]
In local MCP development on stdio transport, the client spawns the server process directly, so authentication is just filesystem permissions and there is no network boundary.
ReportedView cited source - [4]
Switching to streamable HTTP, which is needed for multiple agents sharing one server, means anyone who can reach the port can call initialize, list the tools, and invoke them.
ReportedView cited source - [5]
For an agent mail server, unauthenticated access means reading every message between agents and injecting new ones; if agents treat inbound mail as instructions, an unauthenticated mail endpoint is a prompt injection channel with a REST API.
- [6]
FastMCP 2.x makes auth opt-in via the `auth` parameter on the server constructor; if no auth provider is passed, the result is anonymous access.
ReportedView cited source
Sources & coverage · 1 publisher
The reporting this story was synthesized from, earliest first. Every link goes to the original.
Cited in this coverage: dev.to post on FastMCP Agent Mail

