Skip to content

Commit d764629

Browse files
committed
Share MCP echo test fixture
1 parent bcc7bc9 commit d764629

5 files changed

Lines changed: 64 additions & 53 deletions

File tree

packages/plugins/mcp/src/sdk/connection-pool.test.ts

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,32 +23,24 @@
2323

2424
import { describe, expect, it } from "@effect/vitest";
2525
import { Effect } from "effect";
26-
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2726
import z from "zod";
2827

2928
import { createExecutor } from "@executor-js/sdk";
3029
import { makeTestConfig } from "@executor-js/sdk/testing";
3130

3231
import { mcpPlugin } from "./plugin";
33-
import { serveMcpServer } from "../testing";
32+
import { makeEchoMcpServer, serveMcpServer } from "../testing";
3433

3534
// ---------------------------------------------------------------------------
3635
// Test MCP server — counts session connects (each = one cold handshake)
3736
// ---------------------------------------------------------------------------
3837

3938
function createTestMcpServer() {
40-
const server = new McpServer(
41-
{ name: "pool-test-server", version: "1.0.0" },
42-
{ capabilities: {} },
43-
);
44-
45-
server.registerTool(
46-
"echo",
47-
{ description: "Echo a value", inputSchema: { value: z.string() } },
48-
async ({ value }: { value: string }) => ({
49-
content: [{ type: "text" as const, text: value }],
50-
}),
51-
);
39+
const server = makeEchoMcpServer({
40+
name: "pool-test-server",
41+
toolName: "echo",
42+
toolDescription: "Echo a value",
43+
});
5244

5345
server.registerTool(
5446
"echo2",

packages/plugins/mcp/src/sdk/per-user-auth-isolation.test.ts

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import { describe, expect, it } from "@effect/vitest";
22
import { Cause, Effect, Exit, Predicate } from "effect";
3-
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
4-
import z from "zod";
53

64
import {
75
ConnectionId,
@@ -18,7 +16,7 @@ import {
1816
import { makeTestConfig, memorySecretsPlugin } from "@executor-js/sdk/testing";
1917

2018
import { mcpPlugin } from "./plugin";
21-
import { serveMcpServer } from "../testing";
19+
import { makeEchoMcpServer, serveMcpServer } from "../testing";
2220

2321
const USER_A = ScopeId.make("user-a");
2422
const USER_B = ScopeId.make("user-b");
@@ -32,20 +30,14 @@ const failureError = <E>(exit: Exit.Exit<unknown, E>): E | undefined =>
3230
const isToolInvocationError = (error: unknown): error is ToolInvocationError =>
3331
Predicate.isTagged(error, "ToolInvocationError");
3432

35-
const createAuthRecordingMcpServer = () => {
36-
const mcpServer = new McpServer({ name: "iso-test", version: "1.0.0" }, { capabilities: {} });
37-
mcpServer.registerTool(
38-
"whoami",
39-
{
40-
description: "Echoes a marker so the test can prove the invoke reached the server",
41-
inputSchema: { marker: z.string() },
42-
},
43-
async ({ marker }: { marker: string }) => ({
44-
content: [{ type: "text" as const, text: `ok:${marker}` }],
45-
}),
46-
);
47-
return mcpServer;
48-
};
33+
const createAuthRecordingMcpServer = () =>
34+
makeEchoMcpServer({
35+
name: "iso-test",
36+
toolName: "whoami",
37+
toolDescription: "Echoes a marker so the test can prove the invoke reached the server",
38+
inputName: "marker",
39+
text: (marker) => `ok:${marker}`,
40+
});
4941

5042
const serveAuthRecordingMcpServer = serveMcpServer(createAuthRecordingMcpServer);
5143

packages/plugins/mcp/src/sdk/testing-fixtures.test.ts

Lines changed: 9 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,18 @@ import { expect, layer } from "@effect/vitest";
22
import { Effect } from "effect";
33
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
44
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
5-
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
65
import { OAuthTestServer } from "@executor-js/sdk/testing";
7-
import z from "zod";
86

9-
import { serveMcpServerWithOAuth } from "../testing";
7+
import { makeEchoMcpServer, serveMcpServerWithOAuth } from "../testing";
108

11-
const createGreetingMcpServer = () => {
12-
const server = new McpServer(
13-
{ name: "executor-test-mcp", version: "1.0.0" },
14-
{ capabilities: {} },
15-
);
16-
17-
server.registerTool(
18-
"hello",
19-
{
20-
description: "Greets a person",
21-
inputSchema: { name: z.string() },
22-
},
23-
async ({ name }: { readonly name: string }) => ({
24-
content: [{ type: "text" as const, text: `Hello ${name}` }],
25-
}),
26-
);
27-
28-
return server;
29-
};
9+
const createGreetingMcpServer = () =>
10+
makeEchoMcpServer({
11+
name: "executor-test-mcp",
12+
toolName: "hello",
13+
toolDescription: "Greets a person",
14+
inputName: "name",
15+
text: (name) => `Hello ${name}`,
16+
});
3017

3118
const makeClient = (endpoint: string, accessToken: string) => {
3219
const client = new Client({ name: "executor-test-client", version: "1.0.0" });

packages/plugins/mcp/src/testing/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
export {
22
McpTestServerError,
33
McpTestServerLayer,
4+
makeEchoMcpServer,
45
makeGreetingMcpServer,
56
serveMcpServer,
67
serveMcpServerWithOAuth,

packages/plugins/mcp/src/testing/server.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import * as http from "node:http";
33
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
44
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
55
import { OAuthTestServer } from "@executor-js/sdk/testing";
6+
import z from "zod";
67

78
export type McpTestServer = {
89
readonly url: string;
@@ -287,3 +288,41 @@ export const makeGreetingMcpServer = (
287288

288289
return server;
289290
};
291+
292+
export const makeEchoMcpServer = (
293+
options: {
294+
readonly name?: string;
295+
readonly version?: string;
296+
readonly toolName?: string;
297+
readonly toolDescription?: string;
298+
readonly inputName?: "name" | "value" | "marker";
299+
readonly text?: (value: string) => string;
300+
} = {},
301+
) => {
302+
const inputName = options.inputName ?? "value";
303+
const server = new McpServer(
304+
{
305+
name: options.name ?? "executor-echo-mcp",
306+
version: options.version ?? "1.0.0",
307+
},
308+
{ capabilities: {} },
309+
);
310+
311+
server.registerTool(
312+
options.toolName ?? "echo",
313+
{
314+
description: options.toolDescription ?? "Echoes a string value",
315+
inputSchema: { [inputName]: z.string() },
316+
},
317+
async (input) => ({
318+
content: [
319+
{
320+
type: "text" as const,
321+
text: options.text ? options.text(input[inputName]) : input[inputName],
322+
},
323+
],
324+
}),
325+
);
326+
327+
return server;
328+
};

0 commit comments

Comments
 (0)