ekofyi
Security Research11 min read

That MCP Server You Just Deployed? It’s Probably Wide Open—And Someone’s Already Scanning for It

The @agenticmail/mcp package, an AI agent for email, shipped with a default HTTP endpoint that has zero authentication. Here's why that's a disaster, what it means for the MCP ecosystem, and how to lock it down.

Yesterday, a security advisory hit GitHub for @agenticmail/mcp, a popular MCP server that lets AI agents handle email—sending, reading, searching inboxes, the works. The headline: missing authentication for a critical function. The bug: when you start the server in HTTP mode (which is one of the two documented methods and arguably the easiest to get running), it exposes an /mcp endpoint that accepts requests from anyone who can reach the port. No API key. No token. No check whatsoever. If the server's on the public internet, congratulations—you just gave the world programmatic access to your Gmail account.

I’m not being dramatic. That’s exactly what this vulnerability enables. And the worst part? It’s not some obscure, deep-in-the-code edge case. It’s the default behavior of a tool that dozens of developers are wiring into their AI agents right now, blindly following the README and running npx @agenticmail/mcp --http.

Let’s walk through what actually happens, why it matters, and what it says about the entire MCP ecosystem’s readiness for production.

What is @agenticmail/mcp, and why should you care?

If you’ve been building LLM-powered agents, you’ve probably heard of the Model Context Protocol (MCP). It’s the open standard backed by Anthropic that defines how AI models can interact with external tools—searching the web, querying databases, sending email. MCP servers expose a set of tools (in this case, Gmail operations) that an MCP client (like Claude Desktop or a custom agent) can invoke. The protocol supports two transports: stdio (running as a local subprocess) and Streamable HTTP (exposing an HTTP server, usually over localhost or a network port).

@agenticmail/mcp is a Node.js MCP server that wraps the Gmail API. It lets an AI agent send emails, draft replies, search your inbox, fetch threads, manage labels—all the things you’d want an email assistant to do. It’s genuinely useful. The README shows you two ways to run it: via stdio for local development, or with --http to run an HTTP server that you can point your MCP client at.

That HTTP mode is where the trouble starts.

The bug: no authentication, period

When you start the server with --http, it spins up an Express server on port 3000 (configurable). The main endpoint is /mcp, which speaks the Streamable HTTP transport. Under the hood, this endpoint accepts POST requests containing MCP JSON-RPC messages: tools/list, tools/call, etc. You tell it which tool you want, pass the parameters, and off it goes.

The problem: the server does not require any authentication header, API key, or secret before acting on those requests. Any HTTP client that can reach the port can list the available tools and invoke them.

I haven't inspected the exact Express middleware setup, but based on the advisory and the fact the patch (which I assume is already out or being rushed) likely adds some form of token validation, it's clear the original code just mounted the MCP transport handler without any guard. Something like:

javascript
// vulnerable setup (illustrative)
app.use('/mcp', mcpStreamableHttpRouter);

No middleware to check an Authorization header. No environment variable for a shared secret. Nothing.

So what can an attacker actually do? Let's get concrete.

Exploitation: one HTTP request to inbox takeover

I'll sketch out a realistic attack. Imagine you're running the server on a cloud VM or a developer machine that has port 3000 exposed (maybe you followed a tutorial that says to bind to 0.0.0.0, or you're using a reverse proxy without extra auth). An attacker performs a simple scan and finds your /mcp endpoint responding.

They send a tools/list request to see what's available:

http
POST /mcp HTTP/1.1
Host: your-server:3000
Content-Type: application/json

{"jsonrpc":"2.0","method":"tools/list","params":{},"id":1}

The response enumerates all the Gmail tools—send_email, search_emails, get_thread, modify_labels, and likely draft_reply. Now the attacker knows they have full access, authenticated as whatever OAuth credentials you configured for the server.

Next, they could send a tools/call to read your inbox:

json
{"jsonrpc":"2.0","method":"tools/call","params":{"name":"search_emails","arguments":{"query":"password reset"}},"id":2}

Boom. They get back email snippets, sender addresses, maybe message bodies. Or worse, they send email from your account:

json
{"jsonrpc":"2.0","method":"tools/call","params":{"name":"send_email","arguments":{"to":"ceo@company.com","subject":"Urgent: wire transfer update","body":"Please use the following account ..."}},"id":3}

It's not just data exfiltration—it's impersonation. And because the server runs with your actual Gmail OAuth token, there's zero indication to Google that anything is wrong. From their perspective, you're just sending emails via the API.

I've done enough pentesting to know that email inbox access is a pivot goldmine. Password resets, 2FA codes, sensitive contracts, internal announcements—it's all in there. An attacker who gets this far can escalate to nearly every service tied to your identity.

The deeper issue: MCP's authentication vacuum

Here's the thing that really gets me: this wasn't some clever exploit chain involving session hijacking or a subtle logic flaw. It's not even a "vulnerability" in the traditional sense—it's a missing feature that the ecosystem hasn't yet made a hard requirement.

Right now, MCP itself doesn't mandate any authentication mechanism for HTTP transports. The spec says you can use Streamable HTTP, but it's agnostic about how you secure it. As a server author, you're on your own. And when the easiest path—the one the README shows—is wide open, every developer in a hurry is going to ship that insecure configuration.

This is a systemic problem. I've looked at other MCP servers for things like database queries, filesystem operations, and blockchain interactions. Many default to localhost-only binding with a tiny note that says "for remote access, use a reverse proxy with auth." But how many junior devs know how to properly layer on token-based auth? How many tutorials even mention it?

The @agenticmail/mcp advisory is a canary in the coal mine. It's the most dangerous flavor of MCP server—one that gates access to a high-value personal account—and it shipped with zero auth. Others will follow.

My take: if you ship a tool that touches email, you must assume hostile network access

The way I see it, any software that interacts with email, financial accounts, or health data needs to assume it will be exposed on a hostile network eventually. It's not paranoia; it's the reality of modern development. Containers get misconfigured. Devs expose ports with ngrok or Cloudflare Tunnels without thinking. Reverse proxies get bypassed. Internal networks get compromised laterally.

So the default should be secure by default. If you can't authenticate a request, you shouldn't act on it. Period.

For MCP servers, the absolute minimum should be a requirement to set an MCP_API_KEY environment variable, and the server should reject any request without a matching Authorization: Bearer header. Even better: make the server refuse to start in HTTP mode if no key is configured. Fail loud, fail early.

But we're not there yet. The MCP specification, while promising, is still in a "move fast" phase where ease-of-demo trumps production hardening. And every time a high-profile tool like an email agent hits this kind of bug, it exposes real users to real harm. It also feeds the narrative that AI agents are inherently unsafe, which hurts all of us building in this space.

How to check if you're affected (and what to do now)

First, if you're running @agenticmail/mcp with the --http flag or MCP_HTTP=1, stop what you're doing and check.

Step 1: Determine if your endpoint is reachable. If it's bound to 127.0.0.1 only and you haven't set up any port forwarding or tunneling, you're _probably_ safe from remote attacks (but local malware or a compromised container could still hit it). If you've bound to 0.0.0.0, or you're behind an nginx proxy that sends traffic to this port, assume the worst.

Step 2: Test with curl. From an external machine (or use a service like requestbin), send a POST to your server's /mcp endpoint:

bash
curl -X POST http://YOUR_IP:3000/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"tools/list","params":{},"id":1}'

If you get back a JSON response with a list of tools rather than a 401 Unauthorized, you're vulnerable.

Step 3: Mitigate immediately.

  • Upgrade to the patched version of @agenticmail/mcp as soon as it's released (keep an eye on the GitHub advisory for details).
  • In the meantime, put the server behind a reverse proxy that requires a token or client certificate. Nginx with auth_request or a simple X-API-Key check in a sidecar container works.
  • Move to stdio transport if HTTP isn't strictly necessary. Most local agent setups can use stdio and avoid the network surface entirely.
  • Rotate the Gmail OAuth credentials you used for the server. If exploitation happened, you should revoke the token and generate a new one.

Step 4: Learn from this for other MCP servers. Audit every MCP server you're running. Ask: Does it require authentication? Is it bound to localhost? If it's a database connector, a filesystem tool, a browser automation tool—these are all capable of doing serious damage when left unauthenticated. Treat them like you would a production API.

A call to MCP server authors

If you're building an MCP server and plan to support HTTP transport, please, for the love of all that is secure, bake authentication into the first release. A simple shared secret is better than nothing. Even better, implement OAuth2 or support the upcoming MCP authentication extensions that are being drafted. Document the security implications clearly—not in a collapsed expander at the bottom of the README, but right next to the --http flag.

I'm not singling out the agenticmail maintainer; they're probably a solo developer who built something useful and didn't think about network security. That's exactly the problem: the ecosystem hasn't made security thinking a prerequisite. It's on all of us—bug bounty hunters, pentesters, open-source contributors—to raise these issues loudly and early before a large-scale breach forces retroactive fixes.

What this says about the state of AI tool security

Look, we're in the wild west of AI agents. Every week a new tool drops that gives an LLM access to your browser, your terminal, your payment APIs. The velocity is exhilarating, but the guardrails are practically nonexistent. The @agenticmail/mcp advisory is a perfect example: a critical capability—sending and reading email—shipped with the equivalent of a database that has no password and is listening on a public interface.

And it's not just about missing authentication. It's about the entire chain of trust. When an LLM can invoke these tools, prompt injection becomes a whole new class of threat. If your email agent is configured to obey any MCP command without user confirmation, a malicious prompt could trick it into forwarding a sensitive thread to an attacker. But that's a topic for another post. For now, we need to at least lock the front door.

The fix is probably simple—but the impact isn't. I fully expect the fix to be a one-line addition: a middleware that checks for a pre-shared key from an environment variable. Something like:

javascript
const AUTH_TOKEN = process.env.MCP_AUTH_TOKEN;
if (!AUTH_TOKEN) {
  console.error("MCP_AUTH_TOKEN must be set when running with --http");
  process.exit(1);
}
app.use('/mcp', (req, res, next) => {
  if (req.headers.authorization !== `Bearer ${AUTH_TOKEN}`) {
    return res.status(401).json({error: "Unauthorized"});
  }
  next();
});
app.use('/mcp', mcpStreamableHttpRouter);

That’s it. The hard part is rolling it out to every deployment, and the window between disclosure and patching can be days or weeks in the home-lab crowd where these tools live. Attackers don't wait. Given how scan-friendly an unauthenticated JSON-RPC endpoint is, I'd bet money that automated scanners are already crawling for /mcp endpoints returning a tools/list response.

Secure the tool, not just the model. The AI security conversation so far has been dominated by model-level attacks—jailbreaks, prompt injection, data poisoning. Those are real, but they're the glamorous vulnerabilities that get conference talks. The dull, unglamorous bugs like missing authentication are what will actually burn organizations. A misconfigured MCP server is the 2026 equivalent of an open MongoDB or an Redis instance with no password that got swept up by ransomware bots. The pattern repeats because fundamentals get skipped when we're chasing the shiny.

So here’s my challenge: if you're deploying any AI agent tool today, go look at its network surface. Are you sure it requires authentication? Are you sure it's not listening on all interfaces with no password? Because I’m not sure about most of them. And that should scare you.

Stay paranoid. Patch fast. And let's not give threat actors an easy in just because we were too excited to ship.

Related posts

Written by Eko

If you found this useful, follow @ekofyi on X for more notes like this — or get in touch if you have a problem to solve.