You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
LoopOver runs three MCP servers and is about to grow chat-platform tool catalogs (#9183/#9184) that are the same thing in different clothes:
Remote MCP — src/mcp/server.ts (~5,800 lines, ~116 tools), served at /mcp by both the Worker (Cloudflare Agents SDK) and the self-host container (src/selfhost/mcp-server-node.ts, stateless streamable HTTP). Zod input shapes; ~60 output schemas that are mostly z.unknown().optional() placeholders.
Stdio contributor wrapper — packages/loopover-mcp/bin/loopover-mcp.ts (~7,400 lines, 102 tools + 34-command CLI). Exactly one tool has an outputSchema; the registration helper erases all types (three anys, bin/loopover-mcp.ts:1740-1742), and every API response is consumed as unvalidated any across ~50 endpoints.
AMS miner MCP — packages/loopover-miner/bin/loopover-miner-mcp.ts (468 lines, 11 read-only tools, zero output schemas). The entire mutating AMS ops surface (governor, queue, claims, purge, migrate, tenants) is CLI-only.
The contracts behind these are declared in four unshared zod sites — src/openapi/schemas.ts (~150 response schemas, spec-only), src/api/routes.ts (38 inline request schemas), src/mcp/server.ts (tool shapes), packages/loopover-mcp/bin/loopover-mcp.ts (~85 shapes that hand-mirror the remote server's, with comments admitting it) — plus hand-copied enums from the engine ("The drift this invites is real and has bitten once already", bin/loopover-mcp.ts:154-157) and hand-copied auth/config logic in the miner (packages/loopover-miner/lib/github-token-resolution.ts:6-11, lib/tenant-credential-resolution.ts:2-3).
On the HTTP side, createApp() registers 242 routes while buildOpenApiSpec() hand-registers 128 paths — 91 live routes have no spec entry, including every ORB management surface (/v1/orb/*, /v1/internal/orb/*, /v1/app/fleet/config-push, /v1/app/kill-switch, DLQ admin, ~20 /v1/internal/jobs/*). control-plane/ has no zod and no spec at all. Nothing in CI can detect any of this.
metagraphed already landed the target pattern on main (types-epic batches #7860, #8068–#8076, #8138–#8149): a dedicated zod schema tree, z.toJSONSchema() at module load, a single listToolDefinitions() projection feeding MCP + OpenAI/Anthropic agent specs + a request-time server card, and a contract validator that Ajv-validates every tool's structuredContent against its declared outputSchema in CI. This epic transplants that pattern, fixes the residue metagraphed's version still carries, and then uses the standardized registry to make MCP the management plane for ORB (self-host + hosted) and AMS (self-host + hosted).
Program principles (binding for every sub-issue)
Nothing hand-maintained. Every schema, type, tool table, doc list, CLI help block, and client type is either the single source of truth or generated from it, with a --check drift gate in test:ci (matching the existing cf-typegen:check / ui:openapi:check / selfhost:env-reference:check convention).
Full runtime zod validation. Inputs are parsed at every boundary; outputs/responses are schema-validated (CI contract validator everywhere; runtime response validation env-gated — default ON outside the production Worker) — not just described in a spec.
Full test coverage. The repo's 99% branch-counted patch bar applies; each sub-issue additionally requires the metagraphed-style meta-tests (registry invariants, per-tool contract tests, one enforced smoke call per tool).
Fix what you find. Defects discovered inside a touched surface are fixed in the same PR (house bundling rule) or filed immediately with a reference back to the sub-issue. Known absorbed defects are listed per sub-issue.
One contract, three runtimes, one front door. Locality is physics (hosted state vs. local git vs. miner box) — the runtimes stay, the contract unifies, and the stdio binary ultimately fronts everything the caller is entitled to.
Scope groups (native sub-issues)
Hygiene sweep — orphaned config, dead schema literals, stale counts.
packages/loopover-contract — the schema/tool-contract package + pilot migration (decision record inside).
Registry migration — all three MCP servers register from the contract; real output schemas; typed handlers.
HTTP registration seam — one wrapper that validates and emits the spec; route↔spec ratchet to zero unspecced routes; control-plane + selfhost infra endpoints included (decision record inside).
Group 2 is the keystone; 3 depends on it; 5, 6, 9 depend on 3; 7 and 8 depend on 3 (7 also wants 4 for specced management routes); 10 depends on 3 + 5. Groups 1 and 4 can start immediately and in parallel. Within each group, work lands as small sequential batches exactly like metagraphed's types-epic — pilot first, ratchet check second, batches after.
Expected outcome
A single zod contract package feeds every MCP server, the OpenAPI spec, the chat-platform tool catalogs, all generated docs/types/clients, and the CI validators. grep finds zero hand-mirrored shapes; CI fails on any unspecced route, any tool without a validated output schema, any stale generated artifact. On top of that registry, MCP is the operational control surface for ORB self-host (config, redeploy, queue, kill-switch), ORB fleet/hosted (enrollments, instances, tenants), AMS self-host (governor-gated ops), and AMS hosted (tenant-scoped tools) — with PostHog error tracking and tracing on every tool call.
References
Advances #4877 (ORB Cloud Readiness), #9183 / #9184 (chat platforms — the tool catalogs come from this registry), #5230 (AMS Cloud Readiness convergence). Relates to #9282 (UI derived types), #8286 / #8294 / #8606 (PostHog consolidation), #9143 (tenant rollout), #9199 (tenant health tools), #8638 (MCP release cadence).
Context
LoopOver runs three MCP servers and is about to grow chat-platform tool catalogs (#9183/#9184) that are the same thing in different clothes:
src/mcp/server.ts(~5,800 lines, ~116 tools), served at/mcpby both the Worker (Cloudflare Agents SDK) and the self-host container (src/selfhost/mcp-server-node.ts, stateless streamable HTTP). Zod input shapes; ~60 output schemas that are mostlyz.unknown().optional()placeholders.packages/loopover-mcp/bin/loopover-mcp.ts(~7,400 lines, 102 tools + 34-command CLI). Exactly one tool has anoutputSchema; the registration helper erases all types (threeanys,bin/loopover-mcp.ts:1740-1742), and every API response is consumed as unvalidatedanyacross ~50 endpoints.packages/loopover-miner/bin/loopover-miner-mcp.ts(468 lines, 11 read-only tools, zero output schemas). The entire mutating AMS ops surface (governor, queue, claims, purge, migrate, tenants) is CLI-only.The contracts behind these are declared in four unshared zod sites —
src/openapi/schemas.ts(~150 response schemas, spec-only),src/api/routes.ts(38 inline request schemas),src/mcp/server.ts(tool shapes),packages/loopover-mcp/bin/loopover-mcp.ts(~85 shapes that hand-mirror the remote server's, with comments admitting it) — plus hand-copied enums from the engine ("The drift this invites is real and has bitten once already",bin/loopover-mcp.ts:154-157) and hand-copied auth/config logic in the miner (packages/loopover-miner/lib/github-token-resolution.ts:6-11,lib/tenant-credential-resolution.ts:2-3).On the HTTP side,
createApp()registers 242 routes whilebuildOpenApiSpec()hand-registers 128 paths — 91 live routes have no spec entry, including every ORB management surface (/v1/orb/*,/v1/internal/orb/*,/v1/app/fleet/config-push,/v1/app/kill-switch, DLQ admin, ~20/v1/internal/jobs/*).control-plane/has no zod and no spec at all. Nothing in CI can detect any of this.metagraphed already landed the target pattern on main (types-epic batches #7860, #8068–#8076, #8138–#8149): a dedicated zod schema tree,
z.toJSONSchema()at module load, a singlelistToolDefinitions()projection feeding MCP + OpenAI/Anthropic agent specs + a request-time server card, and a contract validator that Ajv-validates every tool'sstructuredContentagainst its declaredoutputSchemain CI. This epic transplants that pattern, fixes the residue metagraphed's version still carries, and then uses the standardized registry to make MCP the management plane for ORB (self-host + hosted) and AMS (self-host + hosted).Program principles (binding for every sub-issue)
--checkdrift gate intest:ci(matching the existingcf-typegen:check/ui:openapi:check/selfhost:env-reference:checkconvention).Scope groups (native sub-issues)
packages/loopover-contract— the schema/tool-contract package + pilot migration (decision record inside).validate:mcpcontract validator — Ajv structured-content validation, enforced per-tool smoke calls, three-way version lock.server.json,.well-knownsurfaces, registry publish, stdio gateway mode.Sequencing
Group 2 is the keystone; 3 depends on it; 5, 6, 9 depend on 3; 7 and 8 depend on 3 (7 also wants 4 for specced management routes); 10 depends on 3 + 5. Groups 1 and 4 can start immediately and in parallel. Within each group, work lands as small sequential batches exactly like metagraphed's types-epic — pilot first, ratchet check second, batches after.
Expected outcome
A single zod contract package feeds every MCP server, the OpenAPI spec, the chat-platform tool catalogs, all generated docs/types/clients, and the CI validators.
grepfinds zero hand-mirrored shapes; CI fails on any unspecced route, any tool without a validated output schema, any stale generated artifact. On top of that registry, MCP is the operational control surface for ORB self-host (config, redeploy, queue, kill-switch), ORB fleet/hosted (enrollments, instances, tenants), AMS self-host (governor-gated ops), and AMS hosted (tenant-scoped tools) — with PostHog error tracking and tracing on every tool call.References
Advances #4877 (ORB Cloud Readiness), #9183 / #9184 (chat platforms — the tool catalogs come from this registry), #5230 (AMS Cloud Readiness convergence). Relates to #9282 (UI derived types), #8286 / #8294 / #8606 (PostHog consolidation), #9143 (tenant rollout), #9199 (tenant health tools), #8638 (MCP release cadence).