mirror of
https://github.com/trustgraph-ai/trustgraph.git
synced 2026-06-30 17:09:38 +02:00
Add Effect stdio MCP entrypoint
This commit is contained in:
parent
0fb10aca73
commit
e311315556
5 changed files with 136 additions and 16 deletions
|
|
@ -1477,13 +1477,45 @@ Notes:
|
|||
- `cd ts && bun run lint`
|
||||
- `git diff --check`
|
||||
|
||||
### 2026-06-02: MCP Effect Stdio Entrypoint Slice
|
||||
|
||||
- Status: migrated and root-verified.
|
||||
- Completed:
|
||||
- Added an Effect-native stdio layer and process entrypoint with
|
||||
`McpServer.layerStdio`, `NodeStdio.layer`, and `NodeRuntime.runMain`.
|
||||
- Reused the same `TrustGraphMcpToolkitLive` path for HTTP and stdio through
|
||||
a shared toolkit-layer helper.
|
||||
- Kept the legacy SDK/Zod stdio export as a compatibility surface until
|
||||
protocol-level `tools/list` and `tools/call` parity tests prove it can be
|
||||
flipped or removed.
|
||||
- Added focused coverage that the Effect toolkit names remain stable and
|
||||
the stdio layer/entrypoint are exported.
|
||||
- Updated the MCP test script to ignore compiled `dist/**` output so root
|
||||
builds do not cause duplicate Vitest runs from generated tests.
|
||||
- Scratch-note triage:
|
||||
- Metrics, in-process PubSub fanout, Claude Effect AI, RPC
|
||||
`S.TaggedErrorClass`, and `@effect/tsgo` setup are already migrated.
|
||||
- Remaining valid scratch targets are MCP protocol parity/flip, Duration
|
||||
config cleanup, Term/ClientTerm tagged-union matching, service
|
||||
`Effect.fn` normalization, `@effect/cli`, stream/RPC follow-ups, chunking
|
||||
`Chunk`, cores Promise APIs, and long-lived `Map`/`Set` state.
|
||||
- Verification:
|
||||
- `cd ts/packages/mcp && bun run test`
|
||||
- `cd ts/packages/mcp && bun run 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
|
||||
|
||||
- MCP/workbench:
|
||||
- Make the Effect MCP server the canonical implementation. The old stdio
|
||||
server should remain only as compatibility while parity tests and an
|
||||
Effect `McpServer.layerStdio` entrypoint are missing. Do not delete
|
||||
`server.ts` until stdio `tools/list`/`tools/call` parity is proved.
|
||||
- Make the Effect MCP server the canonical implementation. An Effect
|
||||
`McpServer.layerStdio` entrypoint now exists; the old stdio server should
|
||||
remain only as compatibility until protocol-level `tools/list` and
|
||||
`tools/call` parity is proved. Do not delete `server.ts` until that parity
|
||||
coverage exists, with special attention to `text_completion` behavior.
|
||||
- Workbench BaseApi atoms can move toward `AtomRpc` or `AtomHttpApi` after
|
||||
the client API is less Promise-first.
|
||||
- MCP env is now Config-backed; continue that policy for future MCP settings.
|
||||
|
|
@ -1701,13 +1733,13 @@ Notes:
|
|||
### P2: Canonicalize MCP Around The Effect Server
|
||||
|
||||
- Status:
|
||||
- First blocker slice complete: MCP now builds under strict tsgo and the
|
||||
stdio server has an Effect-backed compatibility implementation.
|
||||
- MCP now builds under strict tsgo, the stdio server has an Effect-backed
|
||||
compatibility implementation, and an Effect `McpServer.layerStdio`
|
||||
entrypoint exists.
|
||||
- Remaining shape:
|
||||
- Keep the old SDK/Zod stdio compatibility surface for now.
|
||||
- Add an Effect stdio entrypoint with `McpServer.layerStdio`, then prove
|
||||
`tools/list` and `tools/call` parity before deleting any public entry
|
||||
point or dropping `zod`/server-side MCP SDK dependencies.
|
||||
- Prove `tools/list` and `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
|
||||
gateway, while the Effect server currently uses an Effect AI
|
||||
`LanguageModel`/OpenAI layer.
|
||||
|
|
@ -1733,7 +1765,7 @@ Notes:
|
|||
|
||||
## Recommended PR Order
|
||||
|
||||
1. MCP Effect stdio parity and canonicalization.
|
||||
1. MCP protocol parity tests and legacy stdio flip/removal decision.
|
||||
2. Term/ClientTerm Schema tagged-union and Match normalization.
|
||||
3. FlowManager/service `Effect.fn` normalization.
|
||||
4. Messaging runtime `Config.duration` / `Duration` cleanup.
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ primitive exists.
|
|||
| Promise loops, top-level async orchestration | `Effect`, `Effect.fn`, `Effect.scoped`, `Effect.runPromiseWith` at boundaries | `effect` | `packages/effect/src/Effect.ts` |
|
||||
| Resource construction and teardown | `Layer`, `Scope`, `Effect.acquireRelease`, `Effect.addFinalizer` | `effect` | `packages/effect/src/Layer.ts`, `packages/effect/src/Scope.ts` |
|
||||
| Mutable service state | `Ref`, `SynchronizedRef`, `SubscriptionRef` | `effect` | `packages/effect/src/Ref.ts`, `packages/effect/src/SynchronizedRef.ts` |
|
||||
| Long-lived keyed state and set membership | `HashMap`, `MutableHashMap`, `HashSet`, `MutableHashSet` | `effect` | `packages/effect/src/HashMap.ts`, `packages/effect/src/MutableHashMap.ts`, `packages/effect/src/HashSet.ts`, `packages/effect/src/MutableHashSet.ts` |
|
||||
| Polling, delays, retry/backoff | `Schedule`, `Effect.sleep`, `Effect.retry` | `effect` | `packages/effect/src/Schedule.ts`, `packages/effect/src/Effect.ts` |
|
||||
| Callback queues and streaming fanout | `Queue`, `PubSub`, `Stream`, `Channel` | `effect` | `packages/effect/src/Queue.ts`, `packages/effect/src/PubSub.ts`, `packages/effect/src/Stream.ts`, `packages/effect/src/Channel.ts` |
|
||||
| Env/config decoding | `Config`, `ConfigProvider`, platform config providers | `effect`, `effect/ConfigProvider`, provider packages | `packages/effect/src/Config.ts`, `packages/effect/src/ConfigProvider.ts`, `packages/platform/src/PlatformConfigProvider.ts` |
|
||||
|
|
@ -95,6 +96,10 @@ Known concrete exports useful to scouts:
|
|||
- `Effect.try`, `Effect.tryPromise`, and `Result.try` for exception capture.
|
||||
Treat `try`/`catch` blocks as migration evidence unless they are host/tool
|
||||
boundaries or test-only helpers.
|
||||
- `S.toTaggedUnion(...).match` and `effect/Match` discriminator helpers for
|
||||
discriminated unions. Treat native `switch` statements as migration evidence
|
||||
unless the code is a host parser/traversal boundary with no useful Effect
|
||||
schema or match primitive.
|
||||
|
||||
## Scout Workflow
|
||||
|
||||
|
|
@ -112,7 +117,7 @@ Known concrete exports useful to scouts:
|
|||
4. Run quick signal scans:
|
||||
|
||||
```sh
|
||||
rg -n "try \\{|new Error|new Promise|setTimeout|while \\(|receive\\(|Effect\\.runPromise|toPromiseRequestor|makeAsyncProcessor|process\\.env|JSON\\.parse|JSON\\.stringify|localStorage|new Map|WebSocket" ts/packages --glob '*.ts' --glob '*.tsx'
|
||||
rg -n "S\\.ErrorClass|try \\{|catch \\(|new Error|new Promise|setTimeout|while \\(|switch \\(|receive\\(|Effect\\.runPromise|toPromiseRequestor|makeAsyncProcessor|process\\.env|JSON\\.parse|JSON\\.stringify|localStorage|new Map|new Set|Map<|Set<|WebSocket" ts/packages --glob '*.ts' --glob '*.tsx'
|
||||
```
|
||||
|
||||
5. Split scouts by lane. If the thread cannot spawn every scout in parallel,
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
"build": "bunx --bun tsc",
|
||||
"dev": "tsc --watch",
|
||||
"clean": "rm -rf dist",
|
||||
"test": "bunx --bun vitest run --passWithNoTests"
|
||||
"test": "bunx --bun vitest run --passWithNoTests --exclude=dist/**"
|
||||
},
|
||||
"dependencies": {
|
||||
"@trustgraph/base": "workspace:*",
|
||||
|
|
|
|||
51
ts/packages/mcp/src/__tests__/server-effect.test.ts
Normal file
51
ts/packages/mcp/src/__tests__/server-effect.test.ts
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
makeTrustGraphMcpStdioLayer,
|
||||
runStdio,
|
||||
TrustGraphMcpToolkit,
|
||||
} from "../server-effect.js";
|
||||
|
||||
const expectedToolNames = [
|
||||
"text_completion",
|
||||
"graph_rag",
|
||||
"document_rag",
|
||||
"agent",
|
||||
"embeddings",
|
||||
"triples_query",
|
||||
"graph_embeddings_query",
|
||||
"get_config_all",
|
||||
"get_config",
|
||||
"put_config",
|
||||
"delete_config",
|
||||
"get_flows",
|
||||
"get_flow",
|
||||
"start_flow",
|
||||
"stop_flow",
|
||||
"get_documents",
|
||||
"load_document",
|
||||
"remove_document",
|
||||
"get_prompts",
|
||||
"get_prompt",
|
||||
"get_knowledge_cores",
|
||||
"delete_kg_core",
|
||||
"load_kg_core",
|
||||
];
|
||||
|
||||
describe("Effect MCP server", () => {
|
||||
it("keeps the canonical Effect toolkit names stable", () => {
|
||||
expect(Object.keys(TrustGraphMcpToolkit.tools)).toEqual(expectedToolNames);
|
||||
});
|
||||
|
||||
it("exposes an Effect stdio layer and process entrypoint", () => {
|
||||
expect(
|
||||
makeTrustGraphMcpStdioLayer({
|
||||
gatewayUrl: "ws://localhost:8088/api/v1/rpc",
|
||||
user: "mcp-test",
|
||||
flowId: "default",
|
||||
openAiApiKey: "test-key",
|
||||
}),
|
||||
).toBeDefined();
|
||||
|
||||
expect(runStdio).toEqual(expect.any(Function));
|
||||
});
|
||||
});
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
import {OpenAiClient, OpenAiLanguageModel} from "@effect/ai-openai";
|
||||
import {BunHttpServer, BunRuntime} from "@effect/platform-bun";
|
||||
import {NodeRuntime, NodeStdio} from "@effect/platform-node";
|
||||
import {createTrustGraphSocket, type BaseApi, type Term as ClientTerm} from "@trustgraph/client";
|
||||
import {Config, Context, Effect, Layer, Redacted} from "effect";
|
||||
import * as O from "effect/Option";
|
||||
|
|
@ -1725,10 +1726,7 @@ export const TrustGraphMcpHttpApiRoutes = HttpApiBuilder.layer(
|
|||
const makeTrustGraphMcpHttpLayerFromConfig = (
|
||||
config: TrustGraphMcpConfigShape,
|
||||
) => {
|
||||
const tools = McpServer.toolkit(TrustGraphMcpToolkit).pipe(
|
||||
Layer.provide(TrustGraphMcpToolkitLive),
|
||||
Layer.provide(makeOpenAiProviderLayerFromConfig(config)),
|
||||
)
|
||||
const tools = makeTrustGraphMcpToolkitLayerFromConfig(config)
|
||||
|
||||
return Layer.mergeAll(
|
||||
TrustGraphMcpHttpApiRoutes,
|
||||
|
|
@ -1744,6 +1742,27 @@ const makeTrustGraphMcpHttpLayerFromConfig = (
|
|||
)
|
||||
}
|
||||
|
||||
const makeTrustGraphMcpToolkitLayerFromConfig = (
|
||||
config: TrustGraphMcpConfigShape,
|
||||
) =>
|
||||
McpServer.toolkit(TrustGraphMcpToolkit).pipe(
|
||||
Layer.provide(TrustGraphMcpToolkitLive),
|
||||
Layer.provide(makeOpenAiProviderLayerFromConfig(config)),
|
||||
)
|
||||
|
||||
const makeTrustGraphMcpStdioLayerFromConfig = (
|
||||
config: TrustGraphMcpConfigShape,
|
||||
) =>
|
||||
makeTrustGraphMcpToolkitLayerFromConfig(config).pipe(
|
||||
Layer.provide(McpServer.layerStdio({
|
||||
name: config.name,
|
||||
version: config.version,
|
||||
})),
|
||||
Layer.provide(NodeStdio.layer),
|
||||
Layer.provide(TrustGraphSocket.layer),
|
||||
Layer.provide(Layer.succeed(TrustGraphMcpConfig, TrustGraphMcpConfig.of(config))),
|
||||
)
|
||||
|
||||
export const makeTrustGraphMcpHttpServerLayer = (
|
||||
options: TrustGraphMcpOptions = {},
|
||||
) =>
|
||||
|
|
@ -1766,6 +1785,19 @@ export const makeTrustGraphMcpHttpLayer = (
|
|||
),
|
||||
)
|
||||
|
||||
export const makeTrustGraphMcpStdioLayer = (
|
||||
options: TrustGraphMcpOptions = {},
|
||||
) =>
|
||||
Layer.unwrap(
|
||||
loadTrustGraphMcpConfig(options).pipe(
|
||||
Effect.map(makeTrustGraphMcpStdioLayerFromConfig),
|
||||
),
|
||||
)
|
||||
|
||||
export const runHttp = (options: TrustGraphMcpOptions = {}): void => {
|
||||
Layer.launch(makeTrustGraphMcpHttpServerLayer(options)).pipe(BunRuntime.runMain)
|
||||
}
|
||||
|
||||
export const runStdio = (options: TrustGraphMcpOptions = {}): void => {
|
||||
Layer.launch(makeTrustGraphMcpStdioLayer(options)).pipe(NodeRuntime.runMain)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue