w
This commit is contained in:
@@ -1,9 +1,24 @@
|
|||||||
import { McpServer } from "@modelcontextprotocol/server";
|
import { McpServer } from "@modelcontextprotocol/server";
|
||||||
import { serveStdio } from "@modelcontextprotocol/server/stdio";
|
import { serveStdio } from "@modelcontextprotocol/server/stdio";
|
||||||
|
import { NodeStreamableHTTPServerTransport } from "@modelcontextprotocol/node";
|
||||||
|
import { Command } from "commander";
|
||||||
|
import http from "node:http";
|
||||||
|
import crypto from "node:crypto";
|
||||||
import { registerAuthTools } from "./tools/auth.ts";
|
import { registerAuthTools } from "./tools/auth.ts";
|
||||||
import { registerEmailTools } from "./tools/email.ts";
|
import { registerEmailTools } from "./tools/email.ts";
|
||||||
import { registerFolderTools } from "./tools/folders.ts";
|
import { registerFolderTools } from "./tools/folders.ts";
|
||||||
|
|
||||||
|
const program = new Command()
|
||||||
|
.name("exchange-mcp")
|
||||||
|
.description("Exchange MCP Server — EWS integration via MCP")
|
||||||
|
.option("--transport <type>", "Transport: stdio or sse", "stdio")
|
||||||
|
.option("--token-hash <hash>", "SHA-256 hash of bearer token for HTTP transport auth")
|
||||||
|
.option("--host <host>", "HTTP host", "127.0.0.1")
|
||||||
|
.option("--port <port>", "HTTP port", "8000");
|
||||||
|
|
||||||
|
program.parse(process.argv);
|
||||||
|
const options = program.opts();
|
||||||
|
|
||||||
function buildServer(): McpServer {
|
function buildServer(): McpServer {
|
||||||
const server = new McpServer({
|
const server = new McpServer({
|
||||||
name: "exchange-mcp",
|
name: "exchange-mcp",
|
||||||
@@ -17,4 +32,62 @@ function buildServer(): McpServer {
|
|||||||
return server;
|
return server;
|
||||||
}
|
}
|
||||||
|
|
||||||
serveStdio(buildServer);
|
async function main() {
|
||||||
|
const transportType: string = options.transport;
|
||||||
|
|
||||||
|
if (transportType === "stdio") {
|
||||||
|
serveStdio(buildServer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transportType === "sse") {
|
||||||
|
const server = buildServer();
|
||||||
|
|
||||||
|
const mcpTransport = new NodeStreamableHTTPServerTransport({
|
||||||
|
sessionIdGenerator: () => crypto.randomUUID(),
|
||||||
|
});
|
||||||
|
|
||||||
|
await server.connect(mcpTransport);
|
||||||
|
|
||||||
|
const httpServer = http.createServer(async (req, res) => {
|
||||||
|
if (options.tokenHash) {
|
||||||
|
const auth = req.headers.authorization || "";
|
||||||
|
const token = auth.startsWith("Bearer ") ? auth.slice(7) : "";
|
||||||
|
const hash = crypto.createHash("sha256").update(token).digest("hex");
|
||||||
|
if (hash !== options.tokenHash) {
|
||||||
|
res.writeHead(401, { "Content-Type": "text/plain" });
|
||||||
|
res.end("Unauthorized");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
||||||
|
res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
||||||
|
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
|
||||||
|
|
||||||
|
if (req.method === "OPTIONS") {
|
||||||
|
res.writeHead(200);
|
||||||
|
res.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await mcpTransport.handleRequest(req, res);
|
||||||
|
});
|
||||||
|
|
||||||
|
const port = Number(options.port);
|
||||||
|
httpServer.listen(port, options.host);
|
||||||
|
|
||||||
|
console.error(
|
||||||
|
`Exchange MCP Server running via SSE on http://${options.host}:${port}`,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.error(`Unsupported transport: ${transportType}. Use "stdio" or "sse".`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch((error) => {
|
||||||
|
console.error("Fatal error:", error);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
Generated
+54
@@ -8,7 +8,9 @@
|
|||||||
"name": "exchange-mcp",
|
"name": "exchange-mcp",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@modelcontextprotocol/node": "^2.0.0-beta.2",
|
||||||
"@modelcontextprotocol/server": "^2.0.0-beta.2",
|
"@modelcontextprotocol/server": "^2.0.0-beta.2",
|
||||||
|
"commander": "^15.0.0",
|
||||||
"fast-xml-parser": "^5.2.0",
|
"fast-xml-parser": "^5.2.0",
|
||||||
"httpntlm": "^1.8.13",
|
"httpntlm": "^1.8.13",
|
||||||
"zod": "^4.4.3"
|
"zod": "^4.4.3"
|
||||||
@@ -461,6 +463,39 @@
|
|||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@hono/node-server": {
|
||||||
|
"version": "1.19.14",
|
||||||
|
"resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.14.tgz",
|
||||||
|
"integrity": "sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18.14.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"hono": "^4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@modelcontextprotocol/node": {
|
||||||
|
"version": "2.0.0-beta.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/node/-/node-2.0.0-beta.2.tgz",
|
||||||
|
"integrity": "sha512-1ZV1t98ZpwsoiSpIxKOxZCB2qMhDkh4XMQIWhQVDsCG2pVyhSqduxsFiwMd1R0333+KzJ+ELY3RIR+iEvM9A+g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@hono/node-server": "^1.19.9"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=20"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@modelcontextprotocol/server": "^2.0.0-beta.2",
|
||||||
|
"hono": "^4.11.4"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"hono": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@modelcontextprotocol/server": {
|
"node_modules/@modelcontextprotocol/server": {
|
||||||
"version": "2.0.0-beta.2",
|
"version": "2.0.0-beta.2",
|
||||||
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/server/-/server-2.0.0-beta.2.tgz",
|
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/server/-/server-2.0.0-beta.2.tgz",
|
||||||
@@ -507,6 +542,15 @@
|
|||||||
],
|
],
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/commander": {
|
||||||
|
"version": "15.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/commander/-/commander-15.0.0.tgz",
|
||||||
|
"integrity": "sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=22.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/des.js": {
|
"node_modules/des.js": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz",
|
||||||
@@ -613,6 +657,16 @@
|
|||||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/hono": {
|
||||||
|
"version": "4.12.28",
|
||||||
|
"resolved": "https://registry.npmjs.org/hono/-/hono-4.12.28.tgz",
|
||||||
|
"integrity": "sha512-YwUvVpSF7m1yOblFPrU3Hbo8XhPheBoiyfGuII6z19LnOr6JpDnyyp7LFNrfV56wS8tpvtBFGRISHN02pDdLOA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16.9.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/httpntlm": {
|
"node_modules/httpntlm": {
|
||||||
"version": "1.8.13",
|
"version": "1.8.13",
|
||||||
"resolved": "https://registry.npmjs.org/httpntlm/-/httpntlm-1.8.13.tgz",
|
"resolved": "https://registry.npmjs.org/httpntlm/-/httpntlm-1.8.13.tgz",
|
||||||
|
|||||||
@@ -7,7 +7,9 @@
|
|||||||
"format": "dprint fmt"
|
"format": "dprint fmt"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@modelcontextprotocol/node": "^2.0.0-beta.2",
|
||||||
"@modelcontextprotocol/server": "^2.0.0-beta.2",
|
"@modelcontextprotocol/server": "^2.0.0-beta.2",
|
||||||
|
"commander": "^15.0.0",
|
||||||
"fast-xml-parser": "^5.2.0",
|
"fast-xml-parser": "^5.2.0",
|
||||||
"httpntlm": "^1.8.13",
|
"httpntlm": "^1.8.13",
|
||||||
"zod": "^4.4.3"
|
"zod": "^4.4.3"
|
||||||
|
|||||||
Reference in New Issue
Block a user