Skip to content

50% off your first year. Join before 2027. Claim →

List protected tools before sign-in

This check verifies that tools/list returns the same tools with and without a token, so no tool is visible only after sign-in.

Check id hidden_tools (hidden tools). Results:

pass warn skipped

Agents decide what a server can do from the tool list they get when they connect, and on a server that lets anonymous clients in, that list is fetched before anyone signs in.

  • Claude connects and lists tools without a token on a server that allows it, calls the public tools right away, and asks for sign-in only when it calls a protected tool (Claude: Lazy authentication). A tool that is not in that list is never called, so the user is never asked to sign in for it.
  • ChatGPT learns from each listed tool’s securitySchemes which tools need OAuth (OpenAI: Authentication). A tool it does not see cannot offer sign-in either.

The result is a feature nobody can reach: the tool exists, but users of these agents never see it. Filtering tools/list by the token’s permissions was proposed as SEP-1881 (scope-filtered tool discovery). The proposal was closed without being adopted; it was still closed in October 2026. Servers that filter their tool list this way still exist, which is why MCP Tower checks for it.

  1. MCP Tower lists your tools twice: once without a token (the anonymous pass) and once with the token of the person who signed in (the signed-in pass). It follows nextCursor in both.
  2. A tool that appears only in the signed-in list is hidden. It is marked “Visible only when signed in” in the tools step and counted as needing sign-in.
  3. Any hidden tool gives warn, naming the tools. When both lists hold the same tools, the result is pass.
  4. The check needs both lists. It is skipped when the anonymous pass could not list tools (your server needs a token for everything) or when no signed-in pass succeeded.

A server that needs a token for every request is not affected: agents sign in before listing tools there, and the check is skipped.

StatusMessageMeaningFix
passEvery tool is listed before sign-in.Agents see all your tools when they connect.
warnThese tools are listed only to signed-in clients: <tools>.Agents that list tools before sign-in never see these tools.List every tool anonymously
skippedNeeds an anonymous and a signed-in tool list.Your server needs a token for tools/list, or no signed-in scan has succeeded yet.Select Sign in to scan, or see token accepted

The next step for the warning is: “Claude and ChatGPT list tools before sign-in, so users never see these. List them anonymously and declare oauth2.”

  1. Find where your server builds the tools/list result and remove the filter on the caller’s token or scopes. Return every tool to every caller.
  2. On each tool that needs sign-in, declare securitySchemes with oauth2 and the scopes it needs, so agents know before calling it; see declared schemes.
  3. Move the access check into the tool call: a call to a protected tool without a valid token gets the challenge described in call-time responses.

nginx does not build the tool list. If nginx routes tools/list to a different backend for signed-in callers, for example with a map on $http_authorization, remove that routing so every caller reaches the same handler.

List the tools without a token, then with one, and compare the names. Servers on protocol 2025-11-25 need an initialize first and the Mcp-Session-Id it returns.

Terminal window
curl -s https://mcp.example.com/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
curl -s https://mcp.example.com/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-H 'Authorization: Bearer <access-token>' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'

Follow nextCursor in both until it is absent. The problem is fixed when both lists name the same tools, for example:

anonymous: search_products, get_order, admin_export
signed in: search_products, get_order, admin_export

Then select Scan again on the server’s page. The check needs a signed-in scan, so use Sign in to scan if the scan has no token yet.