Skip to content

[ponytail] MCP server: generate inputSchema from zod, single reflect/explore renderer, dispatch and worker-pool trims #119

Description

@devinmlowe

Cut

Shrink the MCP server module by generating tool input schemas from the zod schemas already defined in the same file, and by rendering each result shape once.

Findings

  • shrink: about 700 lines of hand-written JSON Schema in MCP_TOOL_DEFINITIONS (src/interfaces/mcp/server.ts:389) restate the zod schemas defined 250 lines above. zod is ^4.6.5, so keep the name / description / annotations table and generate inputSchema with z.toJSONSchema(Schema). Compare the generated schema against the hand-written one for every tool before deleting (a snapshot test that fails on drift is acceptable), and keep any description strings the zod schemas lack by adding .describe() to them.
  • shrink: formatReflectXml and printReflectResult render the same ReflectResult twice, and the explore result is formatted inline in two more places (src/interfaces/mcp/server.ts:1993). One renderer with a format switch (~120 lines).
  • shrink: extractSessionId regex-scrapes the session id back out of the XML this process just serialised (src/interfaces/mcp/dispatch.ts:131). Return it on ToolResult instead (~10 lines).
  • shrink: worker-pool knobs never tuned in production: hangMultiplier, readyTimeoutMs, generation counters, three custom Error classes, finishInflight(slot) whose slot is void-ed, respawn(reason) whose reason is void-ed (src/interfaces/mcp/worker-pool.ts:56, ~90 lines). Keep the timeout plus respawn-on-exit; keep the 2x-timeout kill documented in CLAUDE.md.

Verification

npm run build and npm run test:run green before and after. tests/interfaces/mcp/tool-schemas*.test.ts (or equivalent) proves every tool's generated inputSchema is equivalent to the previous hand-written one. The Hermes plugin checker (interfaces/hermes-plugin/tests) still sees 16 tools.

Activity

  1. added
    sub-issueChild task of a parent issue
    ponytailOver-engineering audit cut (2026-09-20)
    on Sep 21, 2026
  2. devinmlowe commented on Sep 21, 2026

    @devinmlowe
    OwnerAuthor

    PR: #137 (branch ponytail/mcp-server, not merged).

    • Before: 131 files / 1689 tests passing (main at fa8219f). After, with origin/main merged in: 133 files / 1702 tests passing, build clean.
    • All four findings done. No finding skipped. Two deliberate schema differences, both reported by the comparison test and in the CHANGELOG: unbounded .int() fields advertise integer instead of number, and ingest_turn tool_calls[] items no longer claim additionalProperties: false (never enforced). No schema was made .strict() because Hermes' warm-up recall sends an undeclared limit.
    • Removed test: dispatch.test.ts "extracts the session id from a recall_session result" (covered the deleted extractSessionId).
    • Extra verification: built server on port 9917 answered /health, initialize and tools/list with 16 tools, every inputSchema populated and closed (output in the PR). The 9907 daemon was not touched.
    • Follow-up noticed, out of scope: interfaces/hermes-plugin/tests/test_stdio_e2e_real_server.py bridges to a healthy 9907 daemon (the provider spawns server.js without --standalone), so it is not hermetic and fails when the fixture memory already exists there.
  3. added a commit that references this issue on Sep 21, 2026
  4. devinmlowe commented on Sep 21, 2026

    @devinmlowe
    OwnerAuthor

    Merged PR #137 into main with --no-ff (commit b5ef060). Post-merge on main: build clean, 133 test files / 1702 tests passing (was 131 / 1679; +23 from the schema-drift snapshot and renderer tests, -1 for the deleted extractSessionId case). server.ts 2220 to 1414 lines. Follow-up filed separately: the Hermes stdio e2e pytest needs ENGRAM_MCP_STANDALONE=1 to stay hermetic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    ponytailOver-engineering audit cut (2026-09-20)sub-issueChild task of a parent issue

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions