Skip to content

test(mcp): pin /graphql to honouring the local default token - #59

Merged
radiosilence merged 1 commit into
mainfrom
test/graphql-config-fallback
Jul 26, 2026
Merged

test(mcp): pin /graphql to honouring the local default token#59
radiosilence merged 1 commit into
mainfrom
test/graphql-config-fallback

Conversation

@radiosilence

Copy link
Copy Markdown
Owner

Summary

The behaviour here is already correct — this PR only pins it with a test, it does not change any credential resolution logic.

graphql_endpoint (src/mcp/mod.rs:314-352) already calls resolve_token(Some(&headers), mcp.default_token.as_deref()), the same central resolver the /mcp graphql tool uses, so a request with no x-fastmail-token header correctly falls back to the local config/env token.

The gap: nothing exercised graphql_endpoint itself. The existing tests (src/mcp/mod.rs:452-506) only covered the pure resolve_token() function. Issue #56 is a guardrail for the planned migration to a headers-only mcp subcommand — if that's implemented by passing None instead of mcp.default_token.as_deref() at that call site, every existing test still passes, but GraphiQL breaks: a browser cannot attach the token header, so the IDE becomes unusable, which is the one thing --graphql/--graphiql exist for.

What changed

  • New test graphql_falls_back_to_local_config_when_no_headers: builds a FastmailMcp directly (not FastmailMcp::http(), so it never touches the developer's real config) with a fake default token, pre-seeds the client cache with a client pointed at http://127.0.0.1:1 (so the resolver's JMAP call fails fast/hermetically instead of hitting the live API), calls graphql_endpoint with empty headers and a real field selection ({ session { status } }, not introspection), and asserts the response does not contain "No Fastmail token available".
  • One-line comment at the src/mcp/mod.rs:330 call site stating the invariant for future reviewers.

No behaviour change, no version bump, no changelog — test-only.

Proof the test actually guards something

Temporarily changed the :330 call site to pass None instead of mcp.default_token.as_deref(), re-ran the new test, and it failed:

thread 'mcp::tests::graphql_falls_back_to_local_config_when_no_headers' panicked at src/mcp/mod.rs:544:9:
expected the default token to be used, got: {"data":null,"errors":[{"message":"No Fastmail token available. Configure one via `fastmail auth` or send the x-fastmail-token header."}]}

Reverted, and cargo test was green again (174 passed).

Test plan

  • cargo test — 174 passed, 0 failed
  • cargo clippy --all-targets --all-features -- -D warnings — clean
  • cargo fmt --all — no changes needed
  • Confirmed regression fails the new test, then reverted and confirmed green
  • git diff origin/main --stat — only src/mcp/mod.rs touched

Closes #56

🤖 Generated with Claude Code

https://claude.ai/code/session_01SWusZmJbmiuciJYJs78V4P

Behaviour is already correct: graphql_endpoint's resolve_token call
already falls back to mcp.default_token when a request has no headers.
But nothing exercised graphql_endpoint itself — the existing tests only
covered the pure resolve_token() function. If a future edit made that
call site headers-only (e.g. for a headers-only mcp subcommand), every
existing test would still pass while GraphiQL silently broke: a browser
cannot attach the x-fastmail-token header, so the IDE would have no way
to authenticate.

Adds a regression test that calls graphql_endpoint directly with a
FastmailMcp built with a fake default token, empty headers, and a
non-introspection query, pre-seeding the client cache so the resolver's
network attempt hits a refusing loopback address instead of the real
Fastmail API. Also adds a one-line comment at the call site pinning the
invariant for future reviewers.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SWusZmJbmiuciJYJs78V4P
@radiosilence
radiosilence merged commit b9fd143 into main Jul 26, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

GraphQL surfaces must keep honouring local config

1 participant