highLogins, sessions and access

MCP Server Reachable Over HTTP Without Authentication

The MCP server listens on the network and accepts tool calls from anyone.

Why it matters

Over stdio an MCP server only talks to the client that started it. Over HTTP it talks to anything that can reach the port, including other software on the same machine and, behind a careless reverse proxy, the internet. The tools it exposes run with the server's own file system, credentials and network access.

What it looks like

This is the shape of code that triggers the rule. AI tools produce it because it works, and nothing tells them it is unsafe.

FastMCP over SSE with no auth
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("files")

@mcp.tool()
def read(path: str) -> str:
    return open(path).read()

if __name__ == "__main__":
    mcp.run(transport="sse")

The smallest fix

minimal patch
import os
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.responses import PlainTextResponse

class RequireToken(BaseHTTPMiddleware):
    async def dispatch(self, request, call_next):
        if request.headers.get("authorization") != f"Bearer {os.environ['MCP_TOKEN']}":
            return PlainTextResponse("unauthorized", status_code=401)
        return await call_next(request)

app = mcp.streamable_http_app()
app.add_middleware(RequireToken)

The better fix

If you have a few more minutes, this is the approach that holds up as the app grows.

safe alternative
# For servers other people will use, FastMCP supports OAuth:
# mcp = FastMCP("name", auth=AuthSettings(...), token_verifier=MyVerifier())
# For a personal tool, run with transport="stdio" and skip HTTP entirely.

Let your AI tool fix it

When the scanner finds this in your project, it fills in the file and line for you. This is the prompt it gives you to paste into Claude Code, Cursor or whatever you use.

In [the file] at line [the line number] an MCP server is exposed over HTTP without authentication: [the flagged code]. If this server is only used locally, run it with transport="stdio". Otherwise add middleware that rejects requests without a valid bearer token (or configure FastMCP auth with a token verifier), bind to 127.0.0.1 unless remote access is intended, and add a test that an unauthenticated tools/list request gets 401.

How to check the fix worked

1. Send a tools/list request with no Authorization header and confirm a
   401 response.
2. Send the same request with a valid token and confirm the tool list.