-
Notifications
You must be signed in to change notification settings - Fork 0
Pitfall Anonymous vs Authenticated Server
Affects: Scope boundary, tool visibility
Category: Architecture, Security
The server runs four distinct MCP server instances, one per scope level:
| Instance | Scope | Tools registered |
|---|---|---|
anonServer |
"" (none) |
Anonymous tools only |
readServer |
content.read |
Anonymous + read tools |
writeServer |
content.write |
Anonymous + read + write tools |
siteAdminServer |
site.admin |
All tools |
Tools that require content.read (e.g. validate_site, validate_front_matter, build_agent_context) must NEVER be registered on anonServer.
When OAuth is enabled, all /mcp requests without a bearer token receive a 401 challenge — so anonServer is effectively unreachable from the internet. However, when OAuth is disabled (e.g. for a private deployment without auth), anonServer receives all requests directly. If authenticated tools leak onto anonServer, they become publicly accessible.
The scope ACL layer (scopePolicy.AllowRequest) provides a second line of defence, but the correct first defence is correct server registration.
TestAnonymousServerDoesNotExposeAuthenticatedTools in internal/server/server_test.go enforces this invariant automatically. It spins up a no-OAuth server and asserts that:
-
validate_site,validate_front_matter,build_agent_context,export_agent_context,get_broken_links,get_site_health,diff_page,search_contentare absent -
list_pages,get_page,list_tagsare present
Claude.ai labels tools as "Outils en lecture seule" (read-only) based on the tool's ReadOnlyHint annotation — whether the tool modifies data. This is Claude.ai's own approval model and has nothing to do with OAuth scope.
A tool can be:
-
Read-only (no side effects) AND require OAuth (
content.read) - Read-only AND be available anonymously
validate_site and validate_front_matter are read-only (no writes) but require content.read OAuth. They appear under "Outils en lecture seule" in Claude.ai because of their ReadOnlyHint, not because they are public.
To verify the anonymous tool set from the command line:
# No Authorization header → should get 401 when OAuth is enabled
curl -s https://mcp.arleo.eu/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
# Expected: 401 Unauthorized
# With a content.read token → should see validate_site but NOT build_site
curl -s https://mcp.arleo.eu/mcp \
-H "Authorization: Bearer $READ_TOKEN" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | jq '[.result.tools[].name]'