If your MCP server uses OAuth, every directory thinks it has zero tools

2026年8月22日2 次浏览来源:Dev.to阅读原文

We shipped a remote MCP server, registered it everywhere, and then noticed something odd: every directory listed it as having no tools at all.

Not the wrong tools.

Not a stale count.

Zero. glama's API returned this: Smithery's page rendered the same nothing.

So did mcp.directory.

Four working tools, and every discovery surface in the ecosystem said the server did nothing.

If you run a remote MCP server behind OAuth 2.1, this is almost certainly happening to you too, and nothing in your logs will tell you.

Why it happens An MCP client discovers what a server can do by calling .

That's a normal JSON-RPC method, and if you wrapped your handler in auth — which the docs and every example encourage — then is behind auth along with everything else.

Our handler looked like this: Correct, and completely sensible.

Every tool call spends credits, so every tool call needs a user.

But a directory crawler has no account.

It performs the handshake, gets a 401, and records what it can see — which is a name, a URL, and an empty capability list.

It cannot tell the difference between "this server requires auth" and "this server does nothing".

The most telling part was Smithery's scanner log: It stopped dead.

Only after a human clicked through an interactive OAuth authorization did it get: Its scanner found all four — but that result came from a one-off human authorization, and it isn't what the public page renders.

So the listing still told visitors the server had no capabilities.

Why it matters more than it looks MCP directories are the discovery layer.

Someone browsing for a server reads the tool list to decide whether to install it.

A listing with no tools isn't a weak listing, it's a dead one — and every directory that mirrors another directory copies the emptiness forward.

You can register on every registry that exists and still be invisible.

The fix Describing what a server offers is not a privileged operation.

Calling those tools is.

So split them: The three narrowings that keep this from being an auth bypass This is the part worth copying carefully.

Each of these exists for a specific reason.

1.

An header means validate it.

If a request carries a token, it goes down the authenticated path even when the method is public.

Without this, a client holding an expired token would silently fall back to anonymous access instead of getting the 401 that triggers a refresh.

Failing quietly is worse than failing.

2.

POST only.

In Streamable HTTP, opens the SSE stream and terminates the session.

Neither carries a JSON-RPC method you can inspect, so neither can be classified as public.

They stay authenticated.

3.

Every message in a batch, not just one.

JSON-RPC allows batching.

A batch mixing with is not a public request. , never .

There's also a second line of defence: the public path runs with no caller in context, so if a ever reached it, the charging function finds no user and refuses.

The gate fails closed from both directions.

Verify it properly The failure mode that would actually hurt is losing OAuth discovery.

If your 401 stops advertising , compliant clients no longer know where to authenticate, and they fail silently instead of prompting.

Check that explicitly: Check Expected , no auth 200 , no auth full tool list , no auth 401 with an invalid token 401 Batch mixing + 401 (SSE stream), no auth 401 on any 401 present, with That last row is the one to actually run: You want to see: After the change, Smithery's scanner ran clean with no browser step at all: The bug this uncovered on the way Look again at that log line: .

Before the fix, it said this: from defaults to v0.1.0 if you don't set it.

We hadn't.

So our server had been introducing itself to every connected client — Claude Desktop, Cursor, all of them — under the library's placeholder name.

One line: It goes in the same options object as .

Worth checking yours right now; it costs nothing and it's the string every client displays.

The takeaway If you run a remote MCP server with auth, go

分享
Baike.dev

baike.dev helps you discover great languages, frameworks, databases, DevOps and cloud-native tools.

Quick links

About

Contribute

Found a great developer tool? Share it with the community.

Submit a tool
© 2026 baike.dev Developer EncyclopediaUpdated daily · Discover great developer tools