Skip to content

update_server resolves config twice across the probe window (TOCTOU) #151

Closed

Description

@ViperJuice

Found during board review of #147 (round 3). Narrow race, filed rather than fixed.

What

gateway.update_server resolves the server's effective config via _resolve_lifecycle_config (around handlers.py:5033), then runs the update probe — which has a 60 second timeout — and only afterwards calls self.restart_server(...), which independently resolves the config again (handlers.py:2888).

Both calls go through the same function with the same precedence, so under a stable configuration they cannot disagree. But they are two separate reads separated by a potentially long await.

Why it matters

If .mcp.json is edited during the probe window, update_server can probe and install package A, restart onto package B, and then persist A's version and A-derived bookkeeping for B. That is the same silent-misreport class #147 exists to eliminate, reachable through a TOCTOU window rather than through resolver divergence.

The PR's own code comments claim the config is "resolved once", which is true of the function but not of the read. Worth correcting either the comment or the behaviour.

Fix sketch

Thread the already-resolved ResolvedServerConfig through to the restart instead of re-resolving — e.g. call self._client_manager.restart_server(resolved_config.config, force=...) directly. The tradeoff: the public restart_server handler also performs policy checks, credential-gap detection, and remote-header validation, so bypassing it would mean either duplicating those or accepting their loss. An alternative is to re-resolve and compare against the first result, refusing if it changed.

Blast radius

Requires a config edit landing inside the probe window. Unlikely in normal operation, plausible during automated config rollouts.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions