winhelm-mcp 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/CHANGELOG.md +96 -0
  2. package/LICENSE +21 -0
  3. package/README.md +646 -0
  4. package/dist/config/config-manager.d.ts +50 -0
  5. package/dist/config/config-manager.d.ts.map +1 -0
  6. package/dist/config/config-manager.js +300 -0
  7. package/dist/config/config-manager.js.map +1 -0
  8. package/dist/config/default-config.d.ts +4 -0
  9. package/dist/config/default-config.d.ts.map +1 -0
  10. package/dist/config/default-config.js +48 -0
  11. package/dist/config/default-config.js.map +1 -0
  12. package/dist/config/profiles.d.ts +16 -0
  13. package/dist/config/profiles.d.ts.map +1 -0
  14. package/dist/config/profiles.js +208 -0
  15. package/dist/config/profiles.js.map +1 -0
  16. package/dist/engine/filesystem.d.ts +52 -0
  17. package/dist/engine/filesystem.d.ts.map +1 -0
  18. package/dist/engine/filesystem.js +499 -0
  19. package/dist/engine/filesystem.js.map +1 -0
  20. package/dist/engine/http-client.d.ts +10 -0
  21. package/dist/engine/http-client.d.ts.map +1 -0
  22. package/dist/engine/http-client.js +93 -0
  23. package/dist/engine/http-client.js.map +1 -0
  24. package/dist/engine/pdf-generator.d.ts +15 -0
  25. package/dist/engine/pdf-generator.d.ts.map +1 -0
  26. package/dist/engine/pdf-generator.js +325 -0
  27. package/dist/engine/pdf-generator.js.map +1 -0
  28. package/dist/engine/powershell-runner.d.ts +23 -0
  29. package/dist/engine/powershell-runner.d.ts.map +1 -0
  30. package/dist/engine/powershell-runner.js +148 -0
  31. package/dist/engine/powershell-runner.js.map +1 -0
  32. package/dist/engine/ripgrep.d.ts +20 -0
  33. package/dist/engine/ripgrep.d.ts.map +1 -0
  34. package/dist/engine/ripgrep.js +173 -0
  35. package/dist/engine/ripgrep.js.map +1 -0
  36. package/dist/engine/system.d.ts +67 -0
  37. package/dist/engine/system.d.ts.map +1 -0
  38. package/dist/engine/system.js +558 -0
  39. package/dist/engine/system.js.map +1 -0
  40. package/dist/engine/task-manager.d.ts +66 -0
  41. package/dist/engine/task-manager.d.ts.map +1 -0
  42. package/dist/engine/task-manager.js +203 -0
  43. package/dist/engine/task-manager.js.map +1 -0
  44. package/dist/gateway/dashboard-html.d.ts +7 -0
  45. package/dist/gateway/dashboard-html.d.ts.map +1 -0
  46. package/dist/gateway/dashboard-html.js +624 -0
  47. package/dist/gateway/dashboard-html.js.map +1 -0
  48. package/dist/gateway/preview-html.d.ts +5 -0
  49. package/dist/gateway/preview-html.d.ts.map +1 -0
  50. package/dist/gateway/preview-html.js +351 -0
  51. package/dist/gateway/preview-html.js.map +1 -0
  52. package/dist/gateway/rate-limiter.d.ts +8 -0
  53. package/dist/gateway/rate-limiter.d.ts.map +1 -0
  54. package/dist/gateway/rate-limiter.js +51 -0
  55. package/dist/gateway/rate-limiter.js.map +1 -0
  56. package/dist/gateway/server.d.ts +18 -0
  57. package/dist/gateway/server.d.ts.map +1 -0
  58. package/dist/gateway/server.js +337 -0
  59. package/dist/gateway/server.js.map +1 -0
  60. package/dist/gateway/sse-gateway.d.ts +43 -0
  61. package/dist/gateway/sse-gateway.d.ts.map +1 -0
  62. package/dist/gateway/sse-gateway.js +161 -0
  63. package/dist/gateway/sse-gateway.js.map +1 -0
  64. package/dist/gateway/streamable-gateway.d.ts +39 -0
  65. package/dist/gateway/streamable-gateway.d.ts.map +1 -0
  66. package/dist/gateway/streamable-gateway.js +176 -0
  67. package/dist/gateway/streamable-gateway.js.map +1 -0
  68. package/dist/index.d.ts +5 -0
  69. package/dist/index.d.ts.map +1 -0
  70. package/dist/index.js +164 -0
  71. package/dist/index.js.map +1 -0
  72. package/dist/tools/desktop-tools.d.ts +3 -0
  73. package/dist/tools/desktop-tools.d.ts.map +1 -0
  74. package/dist/tools/desktop-tools.js +280 -0
  75. package/dist/tools/desktop-tools.js.map +1 -0
  76. package/dist/tools/file-tools.d.ts +3 -0
  77. package/dist/tools/file-tools.d.ts.map +1 -0
  78. package/dist/tools/file-tools.js +433 -0
  79. package/dist/tools/file-tools.js.map +1 -0
  80. package/dist/tools/index.d.ts +12 -0
  81. package/dist/tools/index.d.ts.map +1 -0
  82. package/dist/tools/index.js +16 -0
  83. package/dist/tools/index.js.map +1 -0
  84. package/dist/tools/network-tools.d.ts +3 -0
  85. package/dist/tools/network-tools.d.ts.map +1 -0
  86. package/dist/tools/network-tools.js +108 -0
  87. package/dist/tools/network-tools.js.map +1 -0
  88. package/dist/tools/registry.d.ts +50 -0
  89. package/dist/tools/registry.d.ts.map +1 -0
  90. package/dist/tools/registry.js +54 -0
  91. package/dist/tools/registry.js.map +1 -0
  92. package/dist/tools/terminal-tools.d.ts +3 -0
  93. package/dist/tools/terminal-tools.d.ts.map +1 -0
  94. package/dist/tools/terminal-tools.js +152 -0
  95. package/dist/tools/terminal-tools.js.map +1 -0
  96. package/dist/tools/tool-wrapper.d.ts +7 -0
  97. package/dist/tools/tool-wrapper.d.ts.map +1 -0
  98. package/dist/tools/tool-wrapper.js +47 -0
  99. package/dist/tools/tool-wrapper.js.map +1 -0
  100. package/dist/types/index.d.ts +261 -0
  101. package/dist/types/index.d.ts.map +1 -0
  102. package/dist/types/index.js +2 -0
  103. package/dist/types/index.js.map +1 -0
  104. package/dist/utils/file-logger.d.ts +24 -0
  105. package/dist/utils/file-logger.d.ts.map +1 -0
  106. package/dist/utils/file-logger.js +117 -0
  107. package/dist/utils/file-logger.js.map +1 -0
  108. package/dist/utils/logger.d.ts +51 -0
  109. package/dist/utils/logger.d.ts.map +1 -0
  110. package/dist/utils/logger.js +189 -0
  111. package/dist/utils/logger.js.map +1 -0
  112. package/dist/utils/sanitizer.d.ts +13 -0
  113. package/dist/utils/sanitizer.d.ts.map +1 -0
  114. package/dist/utils/sanitizer.js +60 -0
  115. package/dist/utils/sanitizer.js.map +1 -0
  116. package/docs/EXAMPLES.md +171 -0
  117. package/docs/PROFILES.md +423 -0
  118. package/docs/SECURITY.md +190 -0
  119. package/docs/TOOLS.md +366 -0
  120. package/manifest.json +74 -0
  121. package/package.json +89 -0
  122. package/scripts/build-exe.ps1 +37 -0
  123. package/scripts/manage-service.ps1 +112 -0
  124. package/server.json +23 -0
  125. package/winhelm.config.example.json +30 -0
@@ -0,0 +1,337 @@
1
+ import express from "express";
2
+ import cors from "cors";
3
+ import crypto from "node:crypto";
4
+ import { ConfigManager } from "../config/config-manager.js";
5
+ import { SseGateway } from "./sse-gateway.js";
6
+ import { StreamableGateway } from "./streamable-gateway.js";
7
+ import { logger } from "../utils/logger.js";
8
+ import { fileLogger } from "../utils/file-logger.js";
9
+ import { taskManager } from "../engine/task-manager.js";
10
+ import { RateLimiter } from "./rate-limiter.js";
11
+ import { getDashboardHtml } from "./dashboard-html.js";
12
+ import { getFilePreviewHtml } from "./preview-html.js";
13
+ import { getGpuInfo, getSystemInfo } from "../engine/system.js";
14
+ export function safeCompare(a, b) {
15
+ const bufA = Buffer.from(a);
16
+ const bufB = Buffer.from(b);
17
+ if (bufA.length !== bufB.length)
18
+ return false;
19
+ return crypto.timingSafeEqual(bufA, bufB);
20
+ }
21
+ /**
22
+ * Validate Host header against loopback, bound interface, and allowed hosts whitelist (DNS Rebinding protection)
23
+ */
24
+ export function isHostAllowed(hostHeader, allowedHosts = ["localhost", "127.0.0.1", "[::1]", "*.ts.net"], bindHost = "127.0.0.1") {
25
+ if (!hostHeader)
26
+ return false;
27
+ let hostname;
28
+ const cleanHeader = hostHeader.trim().toLowerCase();
29
+ // Handle IPv6 literal with brackets [::1]:port or naked ::1
30
+ if (cleanHeader.startsWith("[")) {
31
+ const endBracket = cleanHeader.indexOf("]");
32
+ hostname = endBracket !== -1 ? cleanHeader.slice(1, endBracket) : cleanHeader;
33
+ }
34
+ else if (cleanHeader === "::1" || cleanHeader.startsWith("::1:")) {
35
+ hostname = "::1";
36
+ }
37
+ else {
38
+ hostname = cleanHeader.split(":")[0];
39
+ }
40
+ // Always permit loopback interfaces
41
+ if (hostname === "localhost" ||
42
+ hostname === "127.0.0.1" ||
43
+ hostname === "::1" ||
44
+ hostname === "[::1]") {
45
+ return true;
46
+ }
47
+ // Permit explicitly configured bind host interface
48
+ if (bindHost && hostname === bindHost.toLowerCase()) {
49
+ return true;
50
+ }
51
+ // Check allowed hosts whitelist (supports wildcard prefixes like *.ts.net, *.example.com)
52
+ return allowedHosts.some((pattern) => {
53
+ const p = pattern.trim().toLowerCase();
54
+ if (p === "*")
55
+ return true;
56
+ if (p.startsWith("*.")) {
57
+ const suffix = p.slice(1);
58
+ return hostname.endsWith(suffix) || hostname === p.slice(2);
59
+ }
60
+ return hostname === p;
61
+ });
62
+ }
63
+ export function createServer(options) {
64
+ const app = express();
65
+ // Trust proxy for loopback reverse proxies (Tailscale Funnel, local tunnel clients)
66
+ app.set("trust proxy", "loopback");
67
+ const configManager = ConfigManager.getInstance();
68
+ const config = configManager.getConfig();
69
+ const authToken = options.authToken ?? config.authToken;
70
+ // 1. Global Security Headers (Prevent MIME sniffing and Clickjacking)
71
+ app.use((_req, res, next) => {
72
+ res.setHeader("X-Content-Type-Options", "nosniff");
73
+ res.setHeader("X-Frame-Options", "DENY");
74
+ next();
75
+ });
76
+ // 2. Host Header Validation Guard (Mitigates DNS Rebinding attacks)
77
+ app.use((req, res, next) => {
78
+ const hostHeader = req.get("host") || "";
79
+ const allowed = config.allowedHosts || ["localhost", "127.0.0.1", "[::1]", "*.ts.net"];
80
+ if (!isHostAllowed(hostHeader, allowed, options.host)) {
81
+ logger.security("Blocked request with unauthorized Host header (DNS Rebinding protection)", `Host: ${hostHeader} | IP: ${req.ip}`);
82
+ res.status(403).json({
83
+ error: "Forbidden: Host header not permitted by WinHelm security policy",
84
+ });
85
+ return;
86
+ }
87
+ next();
88
+ });
89
+ // 3. Remote Proxy / Tunnel Security Guard (Fail-closed when no auth token is configured)
90
+ if (!authToken) {
91
+ app.use((req, res, next) => {
92
+ if (req.headers["x-forwarded-for"] || req.headers["forwarded"]) {
93
+ logger.security("Blocked unauthenticated remote proxy/tunnel request", `Path: ${req.path} | IP: ${req.ip} | X-Forwarded-For: ${req.headers["x-forwarded-for"]}`);
94
+ res.status(403).json({
95
+ error: "Forbidden: Remote proxy/tunnel access is strictly blocked when no authentication token is configured. Set an authToken or --auth.",
96
+ });
97
+ return;
98
+ }
99
+ next();
100
+ });
101
+ }
102
+ const sseGateway = new SseGateway(config.sessionIdleTimeoutMs, config.maxConcurrentSessions);
103
+ const streamableGateway = new StreamableGateway(config.sessionIdleTimeoutMs, config.maxConcurrentSessions);
104
+ const rateLimiter = new RateLimiter();
105
+ // Cache system info for 2.5s to avoid PowerShell overhead during continuous polling
106
+ let cachedSystemInfo = null;
107
+ let lastSystemInfoFetch = 0;
108
+ async function getCachedSystemInfo() {
109
+ const now = Date.now();
110
+ if (!cachedSystemInfo || now - lastSystemInfoFetch > 2500) {
111
+ try {
112
+ cachedSystemInfo = await getSystemInfo();
113
+ lastSystemInfoFetch = now;
114
+ }
115
+ catch {
116
+ // Fallback to previous cache if exists
117
+ }
118
+ }
119
+ return cachedSystemInfo || {};
120
+ }
121
+ // Cache GPU info for 5s
122
+ let cachedGpuInfo = null;
123
+ let lastGpuInfoFetch = 0;
124
+ async function getCachedGpuInfo() {
125
+ const now = Date.now();
126
+ if (!cachedGpuInfo || now - lastGpuInfoFetch > 5000) {
127
+ try {
128
+ cachedGpuInfo = await getGpuInfo();
129
+ lastGpuInfoFetch = now;
130
+ }
131
+ catch {
132
+ // Fallback
133
+ }
134
+ }
135
+ return cachedGpuInfo;
136
+ }
137
+ // 4. CORS configuration: restricts web browser cross-origin requests
138
+ const corsOption = config.corsOrigins;
139
+ if (corsOption === true || corsOption === "*") {
140
+ app.use(cors({ origin: "*" }));
141
+ }
142
+ else if (Array.isArray(corsOption) || typeof corsOption === "string") {
143
+ app.use(cors({ origin: corsOption }));
144
+ }
145
+ else {
146
+ // Default: permit local requests and loopback origins
147
+ app.use(cors({
148
+ origin: (origin, callback) => {
149
+ if (!origin)
150
+ return callback(null, true);
151
+ if (/^https?:\/\/(localhost|127\.0\.0\.1)(:\d+)?$/.test(origin)) {
152
+ return callback(null, true);
153
+ }
154
+ return callback(new Error("CORS origin not allowed by WinHelm security policy"));
155
+ },
156
+ }));
157
+ }
158
+ // Detailed Request Logger Middleware
159
+ app.use((req, res, next) => {
160
+ const start = Date.now();
161
+ res.on("finish", () => {
162
+ const duration = Date.now() - start;
163
+ const isInternalPolling = req.path === "/health" ||
164
+ req.path.startsWith("/api/monitor/") ||
165
+ req.path === "/" ||
166
+ req.path === "/dashboard";
167
+ // Only print terminal logs for MCP protocol and external actions, keeping terminal clean & stable
168
+ if (!isInternalPolling) {
169
+ const sessionId = (req.headers["mcp-session-id"] || req.query.sessionId);
170
+ const clientIp = req.ip || req.socket.remoteAddress || "-";
171
+ logger.req(req.method, req.originalUrl, res.statusCode, duration, clientIp, sessionId);
172
+ }
173
+ });
174
+ next();
175
+ });
176
+ // Rate Limiting Guard
177
+ app.use(rateLimiter.middleware());
178
+ // Bearer Authentication Guard
179
+ if (authToken) {
180
+ logger.security("Bearer authentication guard is ACTIVE");
181
+ app.use((req, res, next) => {
182
+ // Allow only lightweight public endpoints: health check and basic dashboard shell
183
+ if (req.path === "/health" || req.path === "/" || req.path === "/dashboard") {
184
+ return next();
185
+ }
186
+ // 1. Check standard Authorization header (timing-safe comparison)
187
+ const authHeader = req.headers.authorization;
188
+ if (authHeader && safeCompare(authHeader, `Bearer ${authToken}`)) {
189
+ return next();
190
+ }
191
+ // 2. Fallback for URL query parameter (Claude.ai custom connectors without header UI, browser dashboard, preview) or cookie
192
+ const queryToken = (req.query.token || req.query.auth);
193
+ const cookieHeader = req.headers.cookie;
194
+ let cookieToken;
195
+ if (cookieHeader) {
196
+ const match = cookieHeader.match(/(?:^|;\s*)(?:authToken|token|auth)=([^;]+)/);
197
+ if (match) {
198
+ cookieToken = decodeURIComponent(match[1]);
199
+ }
200
+ }
201
+ const browserToken = queryToken || cookieToken;
202
+ if (browserToken && safeCompare(browserToken, authToken)) {
203
+ if (queryToken && !cookieToken) {
204
+ const isSecure = req.secure || req.headers["x-forwarded-proto"] === "https";
205
+ res.setHeader("Set-Cookie", `authToken=${encodeURIComponent(queryToken)}; Path=/; HttpOnly; SameSite=Lax; Max-Age=2592000${isSecure ? "; Secure" : ""}`);
206
+ }
207
+ return next();
208
+ }
209
+ logger.security("Unauthorized request blocked", `Path: ${req.path} | IP: ${req.ip}`);
210
+ res.status(401).json({ error: "Unauthorized: Invalid or missing Bearer token" });
211
+ });
212
+ }
213
+ else {
214
+ logger.info("Public network mode active (No auth token set)");
215
+ }
216
+ // Web Monitor Dashboard
217
+ app.get(["/", "/dashboard"], (_req, res) => {
218
+ res.setHeader("Content-Type", "text/html; charset=utf-8");
219
+ const activeProfile = configManager.getConfig().profile || "full";
220
+ res.send(getDashboardHtml(activeProfile));
221
+ });
222
+ // Interactive File & Markdown Previewer
223
+ app.get("/preview", async (req, res) => {
224
+ const filePath = req.query.path;
225
+ if (!filePath) {
226
+ res.status(400).send("Missing ?path= parameter");
227
+ return;
228
+ }
229
+ const html = await getFilePreviewHtml(filePath);
230
+ res.setHeader("Content-Type", "text/html; charset=utf-8");
231
+ res.setHeader("Content-Security-Policy", "default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; img-src data:; frame-src data:; connect-src 'none'; form-action 'none'; frame-ancestors 'none';");
232
+ res.send(html);
233
+ });
234
+ // Health check endpoint
235
+ app.get("/health", (_req, res) => {
236
+ res.json({
237
+ status: "ok",
238
+ server: "winhelm-mcp",
239
+ version: "1.1.0",
240
+ activeSessions: {
241
+ sse: sseGateway.getActiveSessionCount(),
242
+ streamableHttp: streamableGateway.getActiveSessionCount(),
243
+ },
244
+ uptimeSeconds: Math.floor(process.uptime()),
245
+ timestamp: new Date().toISOString(),
246
+ });
247
+ });
248
+ // Monitor Stats API
249
+ app.get("/api/monitor/stats", async (_req, res) => {
250
+ const sys = await getCachedSystemInfo();
251
+ const gpu = await getCachedGpuInfo();
252
+ res.json({
253
+ server: "winhelm-mcp",
254
+ version: "1.1.0",
255
+ port: options.port,
256
+ host: options.host,
257
+ readOnly: configManager.isReadOnly(),
258
+ uptimeSeconds: Math.floor(process.uptime()),
259
+ activeSessions: {
260
+ sse: sseGateway.getActiveSessionCount(),
261
+ streamableHttp: streamableGateway.getActiveSessionCount(),
262
+ },
263
+ backgroundTasks: taskManager.listTasks().length,
264
+ system: sys,
265
+ gpu: gpu,
266
+ });
267
+ });
268
+ // Monitor Logs API
269
+ app.get("/api/monitor/logs", (_req, res) => {
270
+ res.json({
271
+ logs: logger.getRecentLogs(100),
272
+ });
273
+ });
274
+ app.delete("/api/monitor/logs", (_req, res) => {
275
+ logger.clearLogs();
276
+ res.json({ success: true, message: "Logs cleared" });
277
+ });
278
+ // Audit Logs Export API (JSON or CSV)
279
+ app.get("/api/monitor/export", async (req, res) => {
280
+ const format = req.query.format === "csv" ? "csv" : "json";
281
+ const data = await fileLogger.exportLogs(format);
282
+ if (format === "csv") {
283
+ res.setHeader("Content-Type", "text/csv");
284
+ res.setHeader("Content-Disposition", 'attachment; filename="winhelm-audit.csv"');
285
+ }
286
+ else {
287
+ res.setHeader("Content-Type", "application/json");
288
+ res.setHeader("Content-Disposition", 'attachment; filename="winhelm-audit.json"');
289
+ }
290
+ res.send(data);
291
+ });
292
+ // Streamable HTTP Endpoint (/mcp)
293
+ app.all("/mcp", (req, res) => streamableGateway.handleRequest(req, res));
294
+ // SSE Endpoints (/sse & /message)
295
+ app.get("/sse", (req, res) => sseGateway.handleSseConnect(req, res));
296
+ app.post("/message", (req, res) => sseGateway.handlePostMessage(req, res));
297
+ const start = () => {
298
+ return new Promise((resolve) => {
299
+ const server = app.listen(options.port, options.host, () => {
300
+ console.log(`\n======================================================`);
301
+ console.log(` 🚀 WinHelm MCP Server is running!`);
302
+ console.log(`======================================================`);
303
+ console.log(` - Web Monitor: http://localhost:${options.port}/`);
304
+ console.log(` - Streamable HTTP: http://${options.host}:${options.port}/mcp`);
305
+ console.log(` - SSE Endpoint: http://${options.host}:${options.port}/sse`);
306
+ console.log(` - SSE Message: http://${options.host}:${options.port}/message`);
307
+ console.log(` - Health Check: http://${options.host}:${options.port}/health`);
308
+ console.log(`======================================================\n`);
309
+ resolve(server);
310
+ });
311
+ });
312
+ };
313
+ const stop = async (server) => {
314
+ // 1. Kill any active background tasks
315
+ taskManager.killAll();
316
+ // 2. Close MCP Sessions
317
+ await Promise.all([
318
+ sseGateway.closeAll().catch(() => { }),
319
+ streamableGateway.closeAll().catch(() => { }),
320
+ ]);
321
+ // 3. Close network sockets
322
+ return new Promise((resolve) => {
323
+ if (typeof server.closeAllConnections === "function") {
324
+ server.closeAllConnections();
325
+ }
326
+ server.close(() => {
327
+ resolve();
328
+ });
329
+ const safetyTimer = setTimeout(() => {
330
+ resolve();
331
+ }, 800);
332
+ safetyTimer.unref();
333
+ });
334
+ };
335
+ return { app, start, stop };
336
+ }
337
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/gateway/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ import type { Request, Response } from "express";
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
4
+ interface SseSession {
5
+ transport: SSEServerTransport;
6
+ mcpServer: McpServer;
7
+ lastActivityAt: number;
8
+ }
9
+ export declare class SseGateway {
10
+ private sessions;
11
+ private cleanupTimer;
12
+ private idleTimeoutMs;
13
+ private maxSessions;
14
+ constructor(idleTimeoutMs?: number, maxSessions?: number);
15
+ private createMcpServerInstance;
16
+ /**
17
+ * Evict least recently used session if capacity is reached
18
+ */
19
+ private evictOldestIfNeeded;
20
+ /**
21
+ * Cleanup sessions that have been idle longer than idleTimeoutMs
22
+ */
23
+ cleanupIdleSessions(): number;
24
+ /**
25
+ * Handle GET /sse - Client initializes SSE stream
26
+ */
27
+ handleSseConnect(req: Request, res: Response): Promise<void>;
28
+ /**
29
+ * Handle POST /message - Client sends JSON-RPC message for SSE session
30
+ */
31
+ handlePostMessage(req: Request, res: Response): Promise<void>;
32
+ getActiveSessionCount(): number;
33
+ getSession(sessionId: string): SseSession | undefined;
34
+ setSessionLastActivity(sessionId: string, timestamp: number): boolean;
35
+ registerSessionForTest(sessionId: string, session?: {
36
+ transport?: any;
37
+ mcpServer?: any;
38
+ lastActivityAt?: number;
39
+ }): void;
40
+ closeAll(): Promise<void>;
41
+ }
42
+ export {};
43
+ //# sourceMappingURL=sse-gateway.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sse-gateway.d.ts","sourceRoot":"","sources":["../../src/gateway/sse-gateway.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAG7E,UAAU,UAAU;IAClB,SAAS,EAAE,kBAAkB,CAAC;IAC9B,SAAS,EAAE,SAAS,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAiC;IACjD,OAAO,CAAC,YAAY,CAA+B;IACnD,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,WAAW,CAAS;IAE5B,YAAY,aAAa,SAAiB,EAAE,WAAW,SAAM,EAW5D;IAED,OAAO,CAAC,uBAAuB;IAS/B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAwB3B;;OAEG;IACI,mBAAmB,IAAI,MAAM,CAWnC;IAED;;OAEG;IACU,gBAAgB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CA4BxE;IAED;;OAEG;IACU,iBAAiB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAuBzE;IAEM,qBAAqB,IAAI,MAAM,CAErC;IAEM,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAE3D;IAEM,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAO3E;IAEM,sBAAsB,CAC3B,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE;QAAE,SAAS,CAAC,EAAE,GAAG,CAAC;QAAC,SAAS,CAAC,EAAE,GAAG,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAO,GAC1E,IAAI,CAON;IAEY,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAarC;CACF"}
@@ -0,0 +1,161 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
3
+ import { registerAllTools } from "../tools/index.js";
4
+ export class SseGateway {
5
+ sessions = new Map();
6
+ cleanupTimer = null;
7
+ idleTimeoutMs;
8
+ maxSessions;
9
+ constructor(idleTimeoutMs = 45 * 60 * 1000, maxSessions = 100) {
10
+ this.idleTimeoutMs = idleTimeoutMs;
11
+ this.maxSessions = maxSessions;
12
+ const intervalMs = Math.min(60000, Math.max(1000, Math.floor(this.idleTimeoutMs / 2)));
13
+ this.cleanupTimer = setInterval(() => {
14
+ this.cleanupIdleSessions();
15
+ }, intervalMs);
16
+ if (this.cleanupTimer && this.cleanupTimer.unref) {
17
+ this.cleanupTimer.unref();
18
+ }
19
+ }
20
+ createMcpServerInstance() {
21
+ const server = new McpServer({
22
+ name: "winhelm-mcp",
23
+ version: "1.1.0",
24
+ });
25
+ registerAllTools(server);
26
+ return server;
27
+ }
28
+ /**
29
+ * Evict least recently used session if capacity is reached
30
+ */
31
+ evictOldestIfNeeded() {
32
+ while (this.sessions.size >= this.maxSessions) {
33
+ let oldestKey = null;
34
+ let oldestTime = Infinity;
35
+ for (const [key, session] of this.sessions.entries()) {
36
+ if (session.lastActivityAt < oldestTime) {
37
+ oldestTime = session.lastActivityAt;
38
+ oldestKey = key;
39
+ }
40
+ }
41
+ if (oldestKey) {
42
+ const session = this.sessions.get(oldestKey);
43
+ this.sessions.delete(oldestKey);
44
+ if (session) {
45
+ session.mcpServer.close().catch(() => { });
46
+ }
47
+ }
48
+ else {
49
+ break;
50
+ }
51
+ }
52
+ }
53
+ /**
54
+ * Cleanup sessions that have been idle longer than idleTimeoutMs
55
+ */
56
+ cleanupIdleSessions() {
57
+ const now = Date.now();
58
+ let count = 0;
59
+ for (const [key, session] of this.sessions.entries()) {
60
+ if (now - session.lastActivityAt > this.idleTimeoutMs) {
61
+ this.sessions.delete(key);
62
+ session.mcpServer.close().catch(() => { });
63
+ count++;
64
+ }
65
+ }
66
+ return count;
67
+ }
68
+ /**
69
+ * Handle GET /sse - Client initializes SSE stream
70
+ */
71
+ async handleSseConnect(req, res) {
72
+ console.log(`[SSE] New SSE client connecting from ${req.ip}`);
73
+ try {
74
+ this.evictOldestIfNeeded();
75
+ const mcpServer = this.createMcpServerInstance();
76
+ const transport = new SSEServerTransport("/message", res);
77
+ await mcpServer.connect(transport);
78
+ const sessionId = transport.sessionId;
79
+ this.sessions.set(sessionId, {
80
+ transport,
81
+ mcpServer,
82
+ lastActivityAt: Date.now(),
83
+ });
84
+ console.log(`[SSE] Session initialized: ${sessionId}`);
85
+ req.on("close", () => {
86
+ console.log(`[SSE] Client disconnected (session: ${sessionId})`);
87
+ this.sessions.delete(sessionId);
88
+ mcpServer.close().catch(() => { });
89
+ });
90
+ }
91
+ catch (err) {
92
+ console.error("[SSE] Failed to establish SSE connection:", err);
93
+ if (!res.headersSent) {
94
+ res.status(500).send("Failed to initialize SSE connection");
95
+ }
96
+ }
97
+ }
98
+ /**
99
+ * Handle POST /message - Client sends JSON-RPC message for SSE session
100
+ */
101
+ async handlePostMessage(req, res) {
102
+ const sessionId = req.query.sessionId;
103
+ if (!sessionId) {
104
+ res.status(400).send("Missing sessionId parameter");
105
+ return;
106
+ }
107
+ const session = this.sessions.get(sessionId);
108
+ if (!session) {
109
+ res.status(404).send(`Active session not found for ID: ${sessionId}`);
110
+ return;
111
+ }
112
+ session.lastActivityAt = Date.now();
113
+ try {
114
+ await session.transport.handlePostMessage(req, res);
115
+ }
116
+ catch (err) {
117
+ console.error(`[SSE] Error processing POST message for session ${sessionId}:`, err);
118
+ if (!res.headersSent) {
119
+ res.status(500).send("Error handling message");
120
+ }
121
+ }
122
+ }
123
+ getActiveSessionCount() {
124
+ return this.sessions.size;
125
+ }
126
+ getSession(sessionId) {
127
+ return this.sessions.get(sessionId);
128
+ }
129
+ setSessionLastActivity(sessionId, timestamp) {
130
+ const session = this.sessions.get(sessionId);
131
+ if (session) {
132
+ session.lastActivityAt = timestamp;
133
+ return true;
134
+ }
135
+ return false;
136
+ }
137
+ registerSessionForTest(sessionId, session = {}) {
138
+ this.evictOldestIfNeeded();
139
+ this.sessions.set(sessionId, {
140
+ transport: session.transport || {},
141
+ mcpServer: session.mcpServer || { close: async () => { } },
142
+ lastActivityAt: session.lastActivityAt ?? Date.now(),
143
+ });
144
+ }
145
+ async closeAll() {
146
+ if (this.cleanupTimer) {
147
+ clearInterval(this.cleanupTimer);
148
+ this.cleanupTimer = null;
149
+ }
150
+ for (const session of this.sessions.values()) {
151
+ try {
152
+ await session.mcpServer.close();
153
+ }
154
+ catch {
155
+ // ignore
156
+ }
157
+ }
158
+ this.sessions.clear();
159
+ }
160
+ }
161
+ //# sourceMappingURL=sse-gateway.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sse-gateway.js","sourceRoot":"","sources":["../../src/gateway/sse-gateway.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ import type { Request, Response } from "express";
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
4
+ interface StreamableSession {
5
+ transport: StreamableHTTPServerTransport;
6
+ mcpServer: McpServer;
7
+ lastActivityAt: number;
8
+ }
9
+ export declare class StreamableGateway {
10
+ private sessions;
11
+ private cleanupTimer;
12
+ private idleTimeoutMs;
13
+ private maxSessions;
14
+ constructor(idleTimeoutMs?: number, maxSessions?: number);
15
+ private createMcpServerInstance;
16
+ /**
17
+ * Evict the least recently used session if capacity is reached
18
+ */
19
+ private evictOldestIfNeeded;
20
+ /**
21
+ * Cleanup sessions that have been idle longer than idleTimeoutMs
22
+ */
23
+ cleanupIdleSessions(): number;
24
+ /**
25
+ * Handle ALL /mcp - Streamable HTTP transport
26
+ */
27
+ handleRequest(req: Request, res: Response): Promise<void>;
28
+ getActiveSessionCount(): number;
29
+ getSession(sessionId: string): StreamableSession | undefined;
30
+ setSessionLastActivity(sessionId: string, timestamp: number): boolean;
31
+ registerSessionForTest(sessionId: string, session?: {
32
+ transport?: any;
33
+ mcpServer?: any;
34
+ lastActivityAt?: number;
35
+ }): void;
36
+ closeAll(): Promise<void>;
37
+ }
38
+ export {};
39
+ //# sourceMappingURL=streamable-gateway.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"streamable-gateway.d.ts","sourceRoot":"","sources":["../../src/gateway/streamable-gateway.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEjD,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AAGnG,UAAU,iBAAiB;IACzB,SAAS,EAAE,6BAA6B,CAAC;IACzC,SAAS,EAAE,SAAS,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAwC;IACxD,OAAO,CAAC,YAAY,CAA+B;IACnD,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,WAAW,CAAS;IAE5B,YAAY,aAAa,SAAiB,EAAE,WAAW,SAAM,EAY5D;IAED,OAAO,CAAC,uBAAuB;IAS/B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAwB3B;;OAEG;IACI,mBAAmB,IAAI,MAAM,CAWnC;IAED;;OAEG;IACU,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAsErE;IAEM,qBAAqB,IAAI,MAAM,CAErC;IAEM,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS,CAElE;IAEM,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAO3E;IAEM,sBAAsB,CAC3B,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE;QAAE,SAAS,CAAC,EAAE,GAAG,CAAC;QAAC,SAAS,CAAC,EAAE,GAAG,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAO,GAC1E,IAAI,CAON;IAEY,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAarC;CACF"}