Add MCP legacy tool parity coverage

This commit is contained in:
elpresidank 2026-06-04 08:17:49 -05:00
parent c48927b7c5
commit c40bd406f8
3 changed files with 77 additions and 18 deletions

View file

@ -1748,10 +1748,12 @@ Notes:
- Scratch-note triage: - Scratch-note triage:
- Metrics, in-process PubSub fanout, Claude Effect AI, RPC - Metrics, in-process PubSub fanout, Claude Effect AI, RPC
`S.TaggedErrorClass`, and `@effect/tsgo` setup are already migrated. `S.TaggedErrorClass`, and `@effect/tsgo` setup are already migrated.
- Remaining valid scratch targets are MCP protocol parity/flip, Duration - Scratch targets migrated or parked since this triage include MCP tool-name
config cleanup, Term/ClientTerm tagged-union matching, service parity, Duration config cleanup, Term/ClientTerm tagged-union matching,
`Effect.fn` normalization, `@effect/cli`, stream/RPC follow-ups, chunking service `Effect.fn` normalization, chunking `Chunk`, and long-lived
`Chunk`, cores Promise APIs, and long-lived `Map`/`Set` state. `Map`/`Set` state. Remaining follow-ups are future API design or
compatibility decisions: MCP tool-call parity before deleting legacy stdio,
`effect/unstable/cli`, stream/RPC public facades, and cores Promise APIs.
- Verification: - Verification:
- `cd ts/packages/mcp && bun run test` - `cd ts/packages/mcp && bun run test`
- `cd ts/packages/mcp && bun run build` - `cd ts/packages/mcp && bun run build`
@ -2355,14 +2357,36 @@ Notes:
- `cd ts && bun run lint` - `cd ts && bun run lint`
- `git diff --check` - `git diff --check`
### 2026-06-04: MCP Legacy Tool Name Parity Slice
- Status: migrated and package-verified.
- Completed:
- `ts/packages/mcp/src/__tests__/server-effect.test.ts` now verifies the
legacy SDK stdio server's registered tool names stay aligned with the
canonical Effect `TrustGraphMcpToolkit`.
- The test mocks the TrustGraph client constructor so parity inspection does
not open a gateway socket.
- `ts/packages/mcp/src/server.ts` uses a namespace `zod` import so the legacy
compatibility path works under the Bun/Vitest runtime used by the parity
test.
- Verification:
- `cd ts/packages/mcp && bunx --bun vitest run src/__tests__/server-effect.test.ts`
- `cd ts && bun run --cwd packages/mcp build`
- `cd ts && bun run check:tsgo`
- `cd ts && bun run build`
- `cd ts && bun run test`
- `cd ts && bun run lint`
- `git diff --check`
## Subagent Findings To Preserve ## Subagent Findings To Preserve
- MCP/workbench: - MCP/workbench:
- Make the Effect MCP server the canonical implementation. An Effect - Make the Effect MCP server the canonical implementation. An Effect
`McpServer.layerStdio` entrypoint now exists; the old stdio server should `McpServer.layerStdio` entrypoint now exists; the old stdio server should
remain only as compatibility until protocol-level `tools/list` and remain only as compatibility until protocol-level `tools/call` parity is
`tools/call` parity is proved. Do not delete `server.ts` until that parity proved. Tool-name parity with the Effect toolkit is now covered. Do not
coverage exists, with special attention to `text_completion` behavior. delete `server.ts` until call coverage exists, with special attention to
`text_completion` behavior.
- Workbench BaseApi atoms can move toward `AtomRpc` or `AtomHttpApi` after - Workbench BaseApi atoms can move toward `AtomRpc` or `AtomHttpApi` after
the client API is less Promise-first. the client API is less Promise-first.
- MCP env is now Config-backed; continue that policy for future MCP settings. - MCP env is now Config-backed; continue that policy for future MCP settings.
@ -2527,11 +2551,10 @@ Notes:
drift should keep service dispatch on `effect/Match` or Schema tagged-union drift should keep service dispatch on `effect/Match` or Schema tagged-union
helpers. helpers.
- Client RPC/BaseApi connection-state fanout now uses - Client RPC/BaseApi connection-state fanout now uses
`effect/SubscriptionRef`; remaining gateway/client P1 work is broader API `effect/SubscriptionRef`; future gateway/client stream work is broader API
design, not listener bookkeeping. design, not listener bookkeeping.
- Long-lived `Map` / `Set` state in remaining ref-backed services can move - Long-lived `Map` / `Set` state in ref-backed services is complete for the
toward Effect collections later; local pure traversal maps/sets remain current scratch inventory; local pure traversal maps/sets remain no-ops.
no-ops.
- Fresh strict signal sweep after the 2026-06-04 helper and collection - Fresh strict signal sweep after the 2026-06-04 helper and collection
slices found no production normal `Error`, raw `try`/`catch`, native slices found no production normal `Error`, raw `try`/`catch`, native
`switch`, or Effect-focused type assertions under `ts/packages`. `switch`, or Effect-focused type assertions under `ts/packages`.
@ -2694,16 +2717,20 @@ Notes:
- Qdrant embeddings tests prove graph cache hits skip repeated collection - Qdrant embeddings tests prove graph cache hits skip repeated collection
existence checks and deletion invalidates the cache. existence checks and deletion invalidates the cache.
### P2: Canonicalize MCP Around The Effect Server ### No-op: MCP Legacy Compatibility Surface
- Status: - Status:
- MCP now builds under strict tsgo, the stdio server has an Effect-backed - MCP now builds under strict tsgo, the stdio server has an Effect-backed
compatibility implementation, and an Effect `McpServer.layerStdio` compatibility implementation, and an Effect `McpServer.layerStdio`
entrypoint exists. entrypoint exists.
- Remaining shape: - The legacy SDK stdio server remains a compatibility boundary rather than an
active Effect-native rewrite blocker.
- Rule:
- Keep the old SDK/Zod stdio compatibility surface for now. - Keep the old SDK/Zod stdio compatibility surface for now.
- Prove `tools/list` and `tools/call` parity before deleting any public - Tool-name parity with the canonical Effect toolkit is covered by
entry point or dropping `zod`/server-side MCP SDK dependencies. `server-effect.test.ts`.
- Prove `tools/call` parity before deleting any public entry point or
dropping `zod`/server-side MCP SDK dependencies.
- Pay special attention to `text_completion`: legacy calls the TrustGraph - Pay special attention to `text_completion`: legacy calls the TrustGraph
gateway, while the Effect server currently uses an Effect AI gateway, while the Effect server currently uses an Effect AI
`LanguageModel`/OpenAI layer. `LanguageModel`/OpenAI layer.
@ -2729,7 +2756,7 @@ Notes:
## Recommended PR Order ## Recommended PR Order
1. MCP protocol parity tests and legacy stdio flip/removal decision. 1. MCP tool-call parity tests and legacy stdio flip/removal decision.
2. Flow/client RPC stream API design beyond callback/Promise compatibility. 2. Flow/client RPC stream API design beyond callback/Promise compatibility.
3. Long-lived ref-backed `HashMap` state cleanup where clone helpers remain. 3. Long-lived ref-backed `HashMap` state cleanup where clone helpers remain.
4. Sibling service `Effect.fn` normalization where arrow-returned generators 4. Sibling service `Effect.fn` normalization where arrow-returned generators

View file

@ -1,10 +1,22 @@
import { describe, expect, it } from "vitest"; import { describe, expect, it, vi } from "vitest";
import * as Predicate from "effect/Predicate";
import { createMcpServer } from "../server.js";
import { import {
makeTrustGraphMcpStdioLayer, makeTrustGraphMcpStdioLayer,
runStdio, runStdio,
TrustGraphMcpToolkit, TrustGraphMcpToolkit,
} from "../server-effect.js"; } from "../server-effect.js";
const clientMock = vi.hoisted(() => ({
createTrustGraphSocket: vi.fn(() => ({
close: vi.fn(),
})),
}));
vi.mock("@trustgraph/client", () => ({
createTrustGraphSocket: clientMock.createTrustGraphSocket,
}));
const expectedToolNames = [ const expectedToolNames = [
"text_completion", "text_completion",
"graph_rag", "graph_rag",
@ -31,11 +43,31 @@ const expectedToolNames = [
"load_kg_core", "load_kg_core",
]; ];
const registeredToolNames = (value: unknown): Array<string> => {
if (!Predicate.isObject(value) || !Predicate.hasProperty(value, "_registeredTools")) {
return [];
}
return Predicate.isObject(value._registeredTools)
? Object.keys(value._registeredTools)
: [];
};
describe("Effect MCP server", () => { describe("Effect MCP server", () => {
it("keeps the canonical Effect toolkit names stable", () => { it("keeps the canonical Effect toolkit names stable", () => {
expect(Object.keys(TrustGraphMcpToolkit.tools)).toEqual(expectedToolNames); expect(Object.keys(TrustGraphMcpToolkit.tools)).toEqual(expectedToolNames);
}); });
it("keeps legacy SDK stdio tools aligned with the Effect toolkit", () => {
const { server, socket } = createMcpServer({
gatewayUrl: "ws://localhost:8088/api/v1/rpc",
user: "mcp-test",
flowId: "default",
});
expect(registeredToolNames(server)).toEqual(Object.keys(TrustGraphMcpToolkit.tools));
expect(socket.close).toEqual(expect.any(Function));
});
it("exposes an Effect stdio layer and process entrypoint", () => { it("exposes an Effect stdio layer and process entrypoint", () => {
expect( expect(
makeTrustGraphMcpStdioLayer({ makeTrustGraphMcpStdioLayer({

View file

@ -13,7 +13,7 @@ import {createTrustGraphSocket, type BaseApi, type Term} from "@trustgraph/clien
import {Effect, Layer, ManagedRuntime} from "effect"; import {Effect, Layer, ManagedRuntime} from "effect";
import * as Predicate from "effect/Predicate"; import * as Predicate from "effect/Predicate";
import * as S from "effect/Schema"; import * as S from "effect/Schema";
import {z} from "zod"; import * as z from "zod";
import {loadTrustGraphMcpConfig} from "./server-effect.js"; import {loadTrustGraphMcpConfig} from "./server-effect.js";
interface ToolTextContent { interface ToolTextContent {