Skip to content

Warn when compiled output is stale #160

Description

@williamthorsen

Problem

When developing the MCP server locally, it's easy to modify source files in packages/mcp/src/ and forget to rebuild before starting a new Claude Code session. The server runs from packages/mcp/dist/esm/cli.js, so stale compiled output means tool behavior doesn't match the source — and nothing alerts the user.

This caused a real issue in #157 where init_run returned a run ID format ({projectSlug}.{timestamp}) that didn't match the current source code's format ({timestamp} only), because the running server was built from an older version.

Proposed solution

Add a staleness check that warns once per session when the compiled output is older than the source files.

Detection logic

Compare the most recent mtime across src/**/*.ts against the mtime of dist/esm/cli.js. If any source file is newer than the compiled output, the build is stale.

Dev vs production: Resolve src/ relative to the server's own file location (../../src/ from dist/esm/). If src/ doesn't exist (published package), skip silently — the feature activates only in local development.

Warning delivery

Prepend a warning to the first tool call response in each session. Module-level let hasWarned = false persists for the session's lifetime (stdio process = one session).

⚠️ MCP server build is stale — source files are newer than compiled output. Run `pnpm run ws compile` in packages/mcp/ to rebuild.

Implementation approach

  • packages/mcp/src/staleness.ts (new) — isBuildStale(compiledFileUrl?) with recursive mtime comparison. Optional parameter enables testing without mocking import.meta.url.
  • packages/mcp/src/server.ts (modify) — wrapHandler() factory applied to all 5 tool registrations. prependWarning() helper mutates the first text content entry.

Key design decisions

  1. Module-level boolean, not protocol-level session tracking — stdio transport means one process = one session.
  2. Warning in tool response, not MCP logging — tool responses are guaranteed visible in Claude's context.
  3. Silent in production — the src/ directory check means the feature is a no-op from a published package.
  4. Fail-safe — any staleness detection error returns false, never blocks tool execution.

Acceptance criteria

  • When source files are newer than compiled output, the first tool call in a session includes a staleness warning
  • Subsequent tool calls in the same session do not repeat the warning
  • When compiled output is up to date, no warning appears
  • When running from a published package (no src/ directory), no warning appears
  • Staleness detection errors are silently swallowed — never block tool execution
  • Unit tests cover: stale detection, fresh detection, missing src directory, detection error handling

Metadata

Metadata

Labels

featureAdded or improved external functionalityscope:mcp

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions