Skip to content

Commit dad53e9

Browse files
committed
move tests
1 parent 34b7a78 commit dad53e9

File tree

7 files changed

+119
-76
lines changed

7 files changed

+119
-76
lines changed

src/index.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,18 @@ import { StreamableHttpRunner } from "./transports/streamableHttp.js";
88
async function main() {
99
const runner = config.transport === "stdio" ? new StdioRunner() : new StreamableHttpRunner();
1010

11-
const shutdown = async () => {
11+
const shutdown = () => {
1212
logger.info(LogId.serverCloseRequested, "server", `Server close requested`);
1313

14-
try {
15-
const exitCode = await runner.close();
16-
process.exit(exitCode);
17-
} catch (error: unknown) {
18-
logger.error(LogId.serverCloseFailure, "server", `Error closing server: ${error as string}`);
19-
process.exit(1);
20-
}
14+
runner
15+
.close()
16+
.then(() => {
17+
process.exit(0);
18+
})
19+
.catch((error: unknown) => {
20+
logger.error(LogId.serverCloseFailure, "server", `Error closing server: ${error as string}`);
21+
process.exit(1);
22+
});
2123
};
2224

2325
process.once("SIGINT", shutdown);

src/transports/base.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,5 @@ export abstract class Runner {
3030

3131
abstract run(): Promise<void>;
3232

33-
abstract close(): Promise<number>;
33+
abstract close(): Promise<void>;
3434
}

src/transports/stdio.ts

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -65,17 +65,7 @@ export class StdioRunner extends Runner {
6565
}
6666
}
6767

68-
async close(): Promise<number> {
69-
logger.info(LogId.serverCloseRequested, "server", `Server close requested`);
70-
71-
try {
72-
await this.server?.close();
73-
logger.info(LogId.serverClosed, "server", `Server closed successfully`);
74-
return 0;
75-
} catch (error: unknown) {
76-
const err = error instanceof Error ? error : new Error(String(error));
77-
logger.error(LogId.serverCloseFailure, "server", `Error closing server: ${err.message}`);
78-
return 1;
79-
}
68+
async close(): Promise<void> {
69+
await this.server?.close();
8070
}
8171
}

src/transports/streamableHttp.ts

Lines changed: 31 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -36,25 +36,14 @@ export class StreamableHttpRunner extends Runner {
3636

3737
await server.connect(transport);
3838

39-
res.on("close", async () => {
40-
try {
41-
await transport.close();
42-
} catch (error: unknown) {
43-
logger.error(
44-
LogId.streamableHttpTransportCloseFailure,
45-
"streamableHttpTransport",
46-
`Error closing transport: ${error instanceof Error ? error.message : String(error)}`
47-
);
48-
}
49-
try {
50-
await server.close();
51-
} catch (error: unknown) {
39+
res.on("close", () => {
40+
Promise.all([transport.close(), server.close()]).catch((error: unknown) => {
5241
logger.error(
5342
LogId.streamableHttpTransportCloseFailure,
5443
"streamableHttpTransport",
5544
`Error closing server: ${error instanceof Error ? error.message : String(error)}`
5645
);
57-
}
46+
});
5847
});
5948

6049
try {
@@ -77,31 +66,25 @@ export class StreamableHttpRunner extends Runner {
7766
})
7867
);
7968

80-
app.get(
81-
"/mcp",
82-
promiseHandler(async (req: express.Request, res: express.Response) => {
83-
res.status(405).json({
84-
jsonrpc: "2.0",
85-
error: {
86-
code: JSON_RPC_ERROR_CODE_METHOD_NOT_ALLOWED,
87-
message: `method not allowed`,
88-
},
89-
});
90-
})
91-
);
69+
app.get("/mcp", (req: express.Request, res: express.Response) => {
70+
res.status(405).json({
71+
jsonrpc: "2.0",
72+
error: {
73+
code: JSON_RPC_ERROR_CODE_METHOD_NOT_ALLOWED,
74+
message: `method not allowed`,
75+
},
76+
});
77+
});
9278

93-
app.delete(
94-
"/mcp",
95-
promiseHandler(async (req: express.Request, res: express.Response) => {
96-
res.status(405).json({
97-
jsonrpc: "2.0",
98-
error: {
99-
code: JSON_RPC_ERROR_CODE_METHOD_NOT_ALLOWED,
100-
message: `method not allowed`,
101-
},
102-
});
103-
})
104-
);
79+
app.delete("/mcp", (req: express.Request, res: express.Response) => {
80+
res.status(405).json({
81+
jsonrpc: "2.0",
82+
error: {
83+
code: JSON_RPC_ERROR_CODE_METHOD_NOT_ALLOWED,
84+
message: `method not allowed`,
85+
},
86+
});
87+
});
10588

10689
this.httpServer = await new Promise<http.Server>((resolve, reject) => {
10790
const result = app.listen(config.httpPort, config.httpHost, (err?: Error) => {
@@ -120,14 +103,15 @@ export class StreamableHttpRunner extends Runner {
120103
);
121104
}
122105

123-
async close(): Promise<number> {
124-
try {
125-
await this.httpServer?.close();
126-
return 0;
127-
} catch (error: unknown) {
128-
const err = error instanceof Error ? error : new Error(String(error));
129-
logger.error(LogId.serverCloseFailure, "server", `Error closing server: ${err.message}`);
130-
return 1;
131-
}
106+
async close(): Promise<void> {
107+
await new Promise<void>((resolve, reject) => {
108+
this.httpServer?.close((err) => {
109+
if (err) {
110+
reject(err);
111+
return;
112+
}
113+
resolve();
114+
});
115+
});
132116
}
133117
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import { JSONRPCMessage } from "@modelcontextprotocol/sdk/types.js";
2+
import { describe, expect, it, beforeAll, afterAll } from "vitest";
3+
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
4+
5+
describe("StdioRunner", () => {
6+
describe("client connects successfully", () => {
7+
let client: StdioClientTransport;
8+
beforeAll(async () => {
9+
client = new StdioClientTransport({
10+
command: "node",
11+
args: ["dist/index.js"],
12+
env: {
13+
MDB_MCP_TRANSPORT: "stdio",
14+
},
15+
});
16+
await client.start();
17+
});
18+
19+
afterAll(async () => {
20+
await client.close();
21+
});
22+
23+
it("handles requests and sends responses", async () => {
24+
let fixedResolve: ((value: JSONRPCMessage) => void) | undefined = undefined;
25+
const messagePromise = new Promise<JSONRPCMessage>((resolve) => {
26+
fixedResolve = resolve;
27+
});
28+
29+
client.onmessage = (message: JSONRPCMessage) => {
30+
fixedResolve?.(message);
31+
};
32+
33+
await client.send({
34+
jsonrpc: "2.0",
35+
id: 1,
36+
method: "tools/list",
37+
params: {
38+
_meta: {
39+
progressToken: 1,
40+
},
41+
},
42+
});
43+
44+
const message = (await messagePromise) as {
45+
jsonrpc: string;
46+
id: number;
47+
result: {
48+
tools: {
49+
name: string;
50+
description: string;
51+
}[];
52+
};
53+
error?: {
54+
code: number;
55+
message: string;
56+
};
57+
};
58+
59+
expect(message.jsonrpc).toBe("2.0");
60+
expect(message.id).toBe(1);
61+
expect(message.result).toBeDefined();
62+
expect(message.result?.tools).toBeDefined();
63+
expect(message.result?.tools.length).toBeGreaterThan(0);
64+
const tools = message.result?.tools;
65+
tools.sort((a, b) => a.name.localeCompare(b.name));
66+
expect(tools[0]?.name).toBe("aggregate");
67+
expect(tools[0]?.description).toBe("Run an aggregation against a MongoDB collection");
68+
});
69+
});
70+
});

tests/unit/transports/streamableHttp.test.ts renamed to tests/integration/transports/streamableHttp.test.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
11
import { StreamableHttpRunner } from "../../../src/transports/streamableHttp.js";
2-
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
32
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
4-
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
53
import { JSONRPCMessage } from "@modelcontextprotocol/sdk/types.js";
6-
import { z } from "zod";
74
import { describe, expect, it, beforeAll, afterAll } from "vitest";
85

9-
describe("streamableHttpTransport", () => {
6+
describe("StreamableHttpRunner", () => {
107
let runner: StreamableHttpRunner;
118

12-
beforeAll(async () => {
9+
beforeAll(() => {
1310
runner = new StreamableHttpRunner();
1411
void runner.run();
1512
});

tests/unit/transports/stdio.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import { Decimal128, MaxKey, MinKey, ObjectId, Timestamp, UUID } from "bson";
2-
import { createStdioTransport, EJsonReadBuffer } from "../../../src/transports/stdio.js";
2+
import { createStdioTransport, EJsonReadBuffer, StdioRunner } from "../../../src/transports/stdio.js";
33
import { JSONRPCMessage } from "@modelcontextprotocol/sdk/types.js";
44
import { AuthInfo } from "@modelcontextprotocol/sdk/server/auth/types.js";
55
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
66
import { Readable } from "stream";
77
import { ReadBuffer } from "@modelcontextprotocol/sdk/shared/stdio.js";
8-
import { describe, expect, it, beforeEach, afterEach } from "vitest";
9-
8+
import { describe, expect, it, beforeEach, afterEach, beforeAll, afterAll } from "vitest";
9+
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
1010
describe("stdioTransport", () => {
1111
let transport: StdioServerTransport;
1212
beforeEach(async () => {

0 commit comments

Comments
 (0)