fix(mcplocal): rebind upstream auth token on every project refresh #133

Merged
michal merged 1 commits from fix/stale-upstream-token into main 2026-09-22 22:46:02 +00:00
Owner

A cached project router outlives the caller's bearer token. syncUpstreams only created a McpdUpstream (which binds the token at construction) for server names not already registered, so after the Sep 15 token rotation every pre-rotation upstream kept posting the old bearer: six attached, healthy servers (gitea, aws-docs, my-grafana, unifi-network, docmost, searxng) 401'd on tools/list forever with no client-visible error, while firecrawl and techdocs — attached after the rotation — worked. mcpctl errors stayed empty because the warnings only reached mcplocal's journal.

Changes:

  • discovery.ts: rebuild every upstream on every sync so it always carries the current caller token and current server id (also fixes a stale serverId after delete+recreate under the same name).
  • router.ts: record per-server discovery failures with messages; expose getToolDiscoveryFailures().
  • gate.ts: a partial catalog is now loud — the initialize instructions and the begin_session response name each attached server that contributed no tools and the error that silenced it.
  • tests: regressions for token rebinding and serverId refresh.

Verified: after restarting mcplocal, the sre project serves 163 tools from all 8 servers (was 39 from 2); full mcplocal suite 852/852 green.

🤖 Generated with Claude Code

A cached project router outlives the caller's bearer token. `syncUpstreams` only created a `McpdUpstream` (which binds the token at construction) for server names not already registered, so after the Sep 15 token rotation every pre-rotation upstream kept posting the old bearer: six attached, healthy servers (gitea, aws-docs, my-grafana, unifi-network, docmost, searxng) 401'd on `tools/list` forever with no client-visible error, while firecrawl and techdocs — attached after the rotation — worked. `mcpctl errors` stayed empty because the warnings only reached mcplocal's journal. Changes: - **discovery.ts**: rebuild every upstream on every sync so it always carries the current caller token and current server id (also fixes a stale `serverId` after delete+recreate under the same name). - **router.ts**: record per-server discovery failures with messages; expose `getToolDiscoveryFailures()`. - **gate.ts**: a partial catalog is now loud — the initialize instructions and the `begin_session` response name each attached server that contributed no tools and the error that silenced it. - **tests**: regressions for token rebinding and serverId refresh. Verified: after restarting mcplocal, the sre project serves 163 tools from all 8 servers (was 39 from 2); full mcplocal suite 852/852 green. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
michal added 1 commit 2026-09-22 22:45:56 +00:00
fix(mcplocal): rebind upstream auth token on every project refresh
Some checks failed
CI/CD / lint (pull_request) Successful in 1m13s
CI/CD / test (pull_request) Successful in 1m23s
CI/CD / typecheck (pull_request) Successful in 2m35s
CI/CD / smoke (pull_request) Failing after 2m0s
CI/CD / build (pull_request) Successful in 4m24s
CI/CD / publish (pull_request) Has been skipped
6fbd9c19fc
A cached project router outlives the caller's bearer token. syncUpstreams
only created a McpdUpstream (which binds the token at construction) for
server names not already registered, so after a token rotation every
pre-rotation upstream kept posting the old bearer: six attached, healthy
servers 401'd on tools/list forever — no error anywhere the client could
see — while the two servers attached after the rotation worked.

- discovery.ts: rebuild every upstream on every sync, so it always carries
  the current caller token and the current server id (also fixes a stale
  serverId after delete+recreate under the same name).
- router.ts: record per-server discovery failures with their messages and
  expose them (getToolDiscoveryFailures).
- gate.ts: a partial catalog is now loud — initialize instructions and the
  begin_session response name every attached server that contributed no
  tools and the error that silenced it.
- tests: regression tests for token rebinding and serverId refresh.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
michal merged commit 0515f99e17 into main 2026-09-22 22:46:02 +00:00
michal deleted branch fix/stale-upstream-token 2026-09-22 22:46:02 +00:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: michal/mcpctl#133