Skip to content

fix(mcp): enforce env regex on every create_* tool (BUG-MCP-003/010)#32

Merged
mastermanas805 merged 1 commit into
masterfrom
fix/p1-mcp-env-regex-2026-05-29
May 29, 2026
Merged

fix(mcp): enforce env regex on every create_* tool (BUG-MCP-003/010)#32
mastermanas805 merged 1 commit into
masterfrom
fix/p1-mcp-env-regex-2026-05-29

Conversation

@mastermanas805

Copy link
Copy Markdown
Member

Summary

Closes BUG-MCP-003 and BUG-MCP-010 from the 2026-05-29 QA wave.

What broke

The api enforces env against ^[a-z0-9-]{1,32}$ (invalid_env 400).
The MCP schema declared env as a bare z.string(). Effect:

  • A hostile or sloppy agent could send env=HACKERLAND (uppercase) or env=<33 chars> and the validation failure only surfaced from the api as a confusing 400 round trip.
  • Host UIs (Claude, Cursor, Windsurf) reading the tools/list JSON Schema had no pattern field to render to the user, so they couldn't pre-flight the value either.

What the fix does

  • Extract the api regex into a single ENV_REGEX = /^[a-z0-9-]{1,32}$/.
  • Wrap it in an envSchema ZodOptional and reuse from envArg — used by the 7 shared-shape tools.
  • create_deploy and create_stack carry an inline copy of the same regex so their input contracts stay grep-visible in one block.
  • One source of truth, surfaced everywhere, zero drift risk.

Test coverage

New test/env-regex-unit.test.ts is registry-iterating (per rule 18): it walks server._registeredTools, finds every tool that exposes env, and asserts:

  1. env.safeParse("HACKERLAND") fails (BUG-MCP-010 — uppercase rejected)
  2. env.safeParse("a".repeat(33)) fails (BUG-MCP-003 — over-32 rejected)
  3. env.safeParse("staging") succeeds (positive)
  4. env.safeParse(undefined) succeeds (optional)

A future create_* tool that forgets to apply the regex fails this test by construction.

Total mcp suite: 323 tests, 0 failures.

Rule 22 surface checklist

  • mcp/src/index.ts — env regex applied to envArg, create_deploy.env, create_stack.env
  • mcp/package.json — env-regex-unit added to test scripts
  • mcp/test/env-regex-unit.test.ts — registry-iterating regression test

API behaviour is unchanged — this PR brings the MCP client into line with the api's existing regex. CLAUDE.md / OpenAPI docs already reflect the api's regex; no doc edits required.

Drift discipline

  • ✅ No new tools, no new endpoints.
  • ✅ Single regex constant, applied minimally.
  • ✅ ~15 LOC of production change, ~140 LOC of registry-iterating tests.
  • ✅ Builds + every existing test in npm run test:nocov (323 tests) still passes.

🤖 Generated with Claude Code

…(BUG-MCP-003/010)

The api enforces `env` against the regex `^[a-z0-9-]{1,32}$` (see
api/internal/handlers/env.go + the `invalid_env` 400 branch).
Pre-fix the MCP schema declared `env` as a bare `z.string()` so:

  - `env: "HACKERLAND"` (uppercase) reached the api, got 400 → confusing
    extra round-trip
  - `env: <33-chars>` reached the api → same
  - the JSON-Schema served by `tools/list` had no `pattern` field, so
    host agents (Claude / Cursor / Windsurf) with strict JSON-Schema
    enforcement also couldn't pre-flight the value

Fix: extract the api regex into a single `ENV_REGEX` constant, build an
`envSchema` ZodOptional wrapping the regex + `.optional()`, and reuse
it from `envArg` (the shared spread used by create_postgres,
create_vector, create_cache, create_nosql, create_queue, create_webhook,
create_storage). create_deploy and create_stack get an inline copy of
the same regex so their input contracts stay grep-visible in one block
each. Single source of truth = ENV_REGEX, drift risk = nil.

Coverage block (per CLAUDE.md rule 17):
  Symptom:       env=HACKERLAND accepted client-side, only api 400's it
  Enumeration:   rg -n 'env: z' src/index.ts (3 hits — envArg + create_deploy + create_stack)
  Sites found:   3 (all 9 envelope tools route through one of these 3)
  Sites touched: 3
  Coverage test: env-regex-unit.test.ts iterates the registered tool list
                 from `server._registeredTools` so adding a future
                 create_* tool that forgets to apply the regex fails the
                 test by construction (registry-iterating, not hand-typed).
  Live verify:   call create_postgres({name:"x", env:"HACKERLAND"}) →
                 immediate zod error "env must match ^[a-z0-9-]{1,32}$"

Test results: 36 new test cases (4 per env-bearing tool × 9 tools),
total mcp suite = 323 tests, 0 failures.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@mastermanas805 mastermanas805 merged commit 63007d2 into master May 29, 2026
9 checks passed
@mastermanas805 mastermanas805 deleted the fix/p1-mcp-env-regex-2026-05-29 branch May 29, 2026 16:42
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.

1 participant