Skip to content

Commit 7330cfc

Browse files
Add stdio entrypoint for local development
Enables running the MCP server locally via stdio transport for testing with MCP clients without needing a full HTTP/Redis setup. Also fixes import.meta.dirname compatibility issue with tsx by using fileURLToPath(import.meta.url) instead. Usage: npm run dev:stdio 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent e040655 commit 7330cfc

File tree

3 files changed

+45
-1
lines changed

3 files changed

+45
-1
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"main": "dist/index.js",
77
"scripts": {
88
"dev": "tsx watch --inspect src/index.ts",
9+
"dev:stdio": "tsx src/stdio.ts",
910
"dev:internal": "AUTH_MODE=internal tsx watch --inspect src/index.ts",
1011
"dev:external": "concurrently \"AUTH_MODE=auth_server PORT=3001 BASE_URI=http://localhost:3001 tsx watch src/index.ts\" \"sleep 3 && AUTH_MODE=external AUTH_SERVER_URL=http://localhost:3001 tsx watch --inspect src/index.ts\"",
1112
"build": "tsc && npm run copy-static && npm run build:apps",

src/modules/mcp/services/mcp.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
22
import fs from "node:fs/promises";
33
import path from "node:path";
4+
import { fileURLToPath } from "node:url";
45
import {
56
CallToolRequestSchema,
67
CompleteRequestSchema,
@@ -293,7 +294,13 @@ export const createMcpServer = (): McpServerWrapper => {
293294

294295
// MCP Apps UI resources
295296
if (uri === HELLO_WORLD_APP_URI) {
296-
const distDir = path.join(import.meta.dirname, "../../../apps");
297+
// Always resolve to dist/apps from project root, regardless of whether
298+
// we're running from src/ (tsx dev) or dist/ (production)
299+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
300+
const projectRoot = __dirname.includes("/dist/")
301+
? path.join(__dirname, "../../../..")
302+
: path.join(__dirname, "../../..");
303+
const distDir = path.join(projectRoot, "dist/apps");
297304
const html = await fs.readFile(path.join(distDir, "mcp-app.html"), "utf-8");
298305
return {
299306
contents: [

src/stdio.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#!/usr/bin/env node
2+
/**
3+
* Stdio entrypoint for the MCP example server.
4+
* This allows running the server locally via stdio transport.
5+
*
6+
* Usage:
7+
* npx tsx src/stdio.ts
8+
* # or after building:
9+
* node dist/stdio.js
10+
*/
11+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
12+
import { createMcpServer } from "./modules/mcp/services/mcp.js";
13+
14+
async function main() {
15+
const { server, cleanup } = createMcpServer();
16+
17+
const transport = new StdioServerTransport();
18+
19+
// Handle cleanup on exit
20+
process.on("SIGINT", () => {
21+
cleanup();
22+
process.exit(0);
23+
});
24+
25+
process.on("SIGTERM", () => {
26+
cleanup();
27+
process.exit(0);
28+
});
29+
30+
await server.connect(transport);
31+
}
32+
33+
main().catch((error) => {
34+
console.error("Fatal error:", error);
35+
process.exit(1);
36+
});

0 commit comments

Comments
 (0)