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,176 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
4
+ import { registerAllTools } from "../tools/index.js";
5
+ export class StreamableGateway {
6
+ sessions = new Map();
7
+ cleanupTimer = null;
8
+ idleTimeoutMs;
9
+ maxSessions;
10
+ constructor(idleTimeoutMs = 45 * 60 * 1000, maxSessions = 100) {
11
+ this.idleTimeoutMs = idleTimeoutMs;
12
+ this.maxSessions = maxSessions;
13
+ // Check periodically for idle sessions; unref timer so it doesn't prevent process exit
14
+ const intervalMs = Math.min(60000, Math.max(1000, Math.floor(this.idleTimeoutMs / 2)));
15
+ this.cleanupTimer = setInterval(() => {
16
+ this.cleanupIdleSessions();
17
+ }, intervalMs);
18
+ if (this.cleanupTimer && this.cleanupTimer.unref) {
19
+ this.cleanupTimer.unref();
20
+ }
21
+ }
22
+ createMcpServerInstance() {
23
+ const server = new McpServer({
24
+ name: "winhelm-mcp",
25
+ version: "1.1.0",
26
+ });
27
+ registerAllTools(server);
28
+ return server;
29
+ }
30
+ /**
31
+ * Evict the least recently used session if capacity is reached
32
+ */
33
+ evictOldestIfNeeded() {
34
+ while (this.sessions.size >= this.maxSessions) {
35
+ let oldestKey = null;
36
+ let oldestTime = Infinity;
37
+ for (const [key, session] of this.sessions.entries()) {
38
+ if (session.lastActivityAt < oldestTime) {
39
+ oldestTime = session.lastActivityAt;
40
+ oldestKey = key;
41
+ }
42
+ }
43
+ if (oldestKey) {
44
+ const session = this.sessions.get(oldestKey);
45
+ this.sessions.delete(oldestKey);
46
+ if (session) {
47
+ session.mcpServer.close().catch(() => { });
48
+ }
49
+ }
50
+ else {
51
+ break;
52
+ }
53
+ }
54
+ }
55
+ /**
56
+ * Cleanup sessions that have been idle longer than idleTimeoutMs
57
+ */
58
+ cleanupIdleSessions() {
59
+ const now = Date.now();
60
+ let count = 0;
61
+ for (const [key, session] of this.sessions.entries()) {
62
+ if (now - session.lastActivityAt > this.idleTimeoutMs) {
63
+ this.sessions.delete(key);
64
+ session.mcpServer.close().catch(() => { });
65
+ count++;
66
+ }
67
+ }
68
+ return count;
69
+ }
70
+ /**
71
+ * Handle ALL /mcp - Streamable HTTP transport
72
+ */
73
+ async handleRequest(req, res) {
74
+ try {
75
+ const sessionId = req.headers["mcp-session-id"];
76
+ // If an existing session ID is provided and active, use it.
77
+ // If provided but not found (evicted, idle timeout, or server restart),
78
+ // return 404 with JSON-RPC error immediately according to MCP specification.
79
+ if (sessionId) {
80
+ const session = this.sessions.get(sessionId);
81
+ if (!session) {
82
+ res.status(404).json({
83
+ jsonrpc: "2.0",
84
+ error: { code: -32001, message: "Session not found" },
85
+ id: null,
86
+ });
87
+ return;
88
+ }
89
+ session.lastActivityAt = Date.now();
90
+ await session.transport.handleRequest(req, res);
91
+ return;
92
+ }
93
+ // Create a new session for initialize requests
94
+ const mcpServer = this.createMcpServerInstance();
95
+ const transport = new StreamableHTTPServerTransport({
96
+ sessionIdGenerator: () => randomUUID(),
97
+ onsessioninitialized: (newSessionId) => {
98
+ this.evictOldestIfNeeded();
99
+ this.sessions.set(newSessionId, {
100
+ transport,
101
+ mcpServer,
102
+ lastActivityAt: Date.now(),
103
+ });
104
+ },
105
+ onsessionclosed: (closedSessionId) => {
106
+ const session = this.sessions.get(closedSessionId);
107
+ if (session) {
108
+ this.sessions.delete(closedSessionId);
109
+ session.mcpServer.close().catch(() => { });
110
+ }
111
+ },
112
+ });
113
+ // Set transport.onclose BEFORE mcpServer.connect(transport)
114
+ // so Protocol.connect preserves our handler alongside Protocol._onclose
115
+ transport.onclose = () => {
116
+ const sid = transport.sessionId;
117
+ if (sid) {
118
+ this.sessions.delete(sid);
119
+ }
120
+ mcpServer.close().catch(() => { });
121
+ };
122
+ await mcpServer.connect(transport);
123
+ await transport.handleRequest(req, res);
124
+ // If transport.sessionId is still undefined after handleRequest
125
+ // (not an initialize request or request was rejected/invalid), clean up immediately to prevent leaks
126
+ if (!transport.sessionId) {
127
+ await transport.close().catch(() => { });
128
+ await mcpServer.close().catch(() => { });
129
+ }
130
+ }
131
+ catch (err) {
132
+ console.error("[StreamableHTTP] Error handling /mcp request:", err);
133
+ if (!res.headersSent) {
134
+ res.status(500).json({ error: "Internal server error", message: err.message });
135
+ }
136
+ }
137
+ }
138
+ getActiveSessionCount() {
139
+ return this.sessions.size;
140
+ }
141
+ getSession(sessionId) {
142
+ return this.sessions.get(sessionId);
143
+ }
144
+ setSessionLastActivity(sessionId, timestamp) {
145
+ const session = this.sessions.get(sessionId);
146
+ if (session) {
147
+ session.lastActivityAt = timestamp;
148
+ return true;
149
+ }
150
+ return false;
151
+ }
152
+ registerSessionForTest(sessionId, session = {}) {
153
+ this.evictOldestIfNeeded();
154
+ this.sessions.set(sessionId, {
155
+ transport: session.transport || {},
156
+ mcpServer: session.mcpServer || { close: async () => { } },
157
+ lastActivityAt: session.lastActivityAt ?? Date.now(),
158
+ });
159
+ }
160
+ async closeAll() {
161
+ if (this.cleanupTimer) {
162
+ clearInterval(this.cleanupTimer);
163
+ this.cleanupTimer = null;
164
+ }
165
+ for (const session of this.sessions.values()) {
166
+ try {
167
+ await session.mcpServer.close();
168
+ }
169
+ catch {
170
+ // ignore
171
+ }
172
+ }
173
+ this.sessions.clear();
174
+ }
175
+ }
176
+ //# sourceMappingURL=streamable-gateway.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"streamable-gateway.js","sourceRoot":"","sources":["../../src/gateway/streamable-gateway.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AACnG,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAQrD,MAAM,OAAO,iBAAiB;IACpB,QAAQ,GAAG,IAAI,GAAG,EAA6B,CAAC;IAChD,YAAY,GAA0B,IAAI,CAAC;IAC3C,aAAa,CAAS;IACtB,WAAW,CAAS;IAE5B,YAAY,aAAa,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,WAAW,GAAG,GAAG;QAC3D,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;QACnC,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAE/B,uFAAuF;QACvF,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACvF,IAAI,CAAC,YAAY,GAAG,WAAW,CAAC,GAAG,EAAE;YACnC,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAC7B,CAAC,EAAE,UAAU,CAAC,CAAC;QACf,IAAI,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC;YACjD,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC;QAC5B,CAAC;IACH,CAAC;IAEO,uBAAuB;QAC7B,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;YAC3B,IAAI,EAAE,aAAa;YACnB,OAAO,EAAE,OAAO;SACjB,CAAC,CAAC;QACH,gBAAgB,CAAC,MAAM,CAAC,CAAC;QACzB,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;OAEG;IACK,mBAAmB;QACzB,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YAC9C,IAAI,SAAS,GAAkB,IAAI,CAAC;YACpC,IAAI,UAAU,GAAG,QAAQ,CAAC;YAE1B,KAAK,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC;gBACrD,IAAI,OAAO,CAAC,cAAc,GAAG,UAAU,EAAE,CAAC;oBACxC,UAAU,GAAG,OAAO,CAAC,cAAc,CAAC;oBACpC,SAAS,GAAG,GAAG,CAAC;gBAClB,CAAC;YACH,CAAC;YAED,IAAI,SAAS,EAAE,CAAC;gBACd,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;gBAC7C,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;gBAChC,IAAI,OAAO,EAAE,CAAC;oBACZ,OAAO,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;gBAC5C,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,MAAM;YACR,CAAC;QACH,CAAC;IACH,CAAC;IAED;;OAEG;IACI,mBAAmB;QACxB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,KAAK,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC;YACrD,IAAI,GAAG,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;gBACtD,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBAC1B,OAAO,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;gBAC1C,KAAK,EAAE,CAAC;YACV,CAAC;QACH,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;OAEG;IACI,KAAK,CAAC,aAAa,CAAC,GAAY,EAAE,GAAa;QACpD,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAuB,CAAC;YAEtE,4DAA4D;YAC5D,wEAAwE;YACxE,6EAA6E;YAC7E,IAAI,SAAS,EAAE,CAAC;gBACd,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;gBAC7C,IAAI,CAAC,OAAO,EAAE,CAAC;oBACb,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;wBACnB,OAAO,EAAE,KAAK;wBACd,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,mBAAmB,EAAE;wBACrD,EAAE,EAAE,IAAI;qBACT,CAAC,CAAC;oBACH,OAAO;gBACT,CAAC;gBAED,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;gBACpC,MAAM,OAAO,CAAC,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;gBAChD,OAAO;YACT,CAAC;YAED,+CAA+C;YAC/C,MAAM,SAAS,GAAG,IAAI,CAAC,uBAAuB,EAAE,CAAC;YACjD,MAAM,SAAS,GAAG,IAAI,6BAA6B,CAAC;gBAClD,kBAAkB,EAAE,GAAG,EAAE,CAAC,UAAU,EAAE;gBACtC,oBAAoB,EAAE,CAAC,YAAoB,EAAE,EAAE;oBAC7C,IAAI,CAAC,mBAAmB,EAAE,CAAC;oBAC3B,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,YAAY,EAAE;wBAC9B,SAAS;wBACT,SAAS;wBACT,cAAc,EAAE,IAAI,CAAC,GAAG,EAAE;qBAC3B,CAAC,CAAC;gBACL,CAAC;gBACD,eAAe,EAAE,CAAC,eAAuB,EAAE,EAAE;oBAC3C,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;oBACnD,IAAI,OAAO,EAAE,CAAC;wBACZ,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;wBACtC,OAAO,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;oBAC5C,CAAC;gBACH,CAAC;aACF,CAAC,CAAC;YAEH,4DAA4D;YAC5D,wEAAwE;YACxE,SAAS,CAAC,OAAO,GAAG,GAAG,EAAE;gBACvB,MAAM,GAAG,GAAG,SAAS,CAAC,SAAS,CAAC;gBAChC,IAAI,GAAG,EAAE,CAAC;oBACR,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBAC5B,CAAC;gBACD,SAAS,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YACpC,CAAC,CAAC;YAEF,MAAM,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YAEnC,MAAM,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YAExC,gEAAgE;YAChE,qGAAqG;YACrG,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,CAAC;gBACzB,MAAM,SAAS,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;gBACxC,MAAM,SAAS,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YAC1C,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,+CAA+C,EAAE,GAAG,CAAC,CAAC;YACpE,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;gBACrB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,uBAAuB,EAAE,OAAO,EAAG,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;YAC5F,CAAC;QACH,CAAC;IACH,CAAC;IAEM,qBAAqB;QAC1B,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;IAC5B,CAAC;IAEM,UAAU,CAAC,SAAiB;QACjC,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACtC,CAAC;IAEM,sBAAsB,CAAC,SAAiB,EAAE,SAAiB;QAChE,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC7C,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC;YACnC,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAEM,sBAAsB,CAC3B,SAAiB,EACjB,OAAO,GAAkE,EAAE;QAE3E,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAC3B,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE;YAC3B,SAAS,EAAE,OAAO,CAAC,SAAS,IAAK,EAAU;YAC3C,SAAS,EAAE,OAAO,CAAC,SAAS,IAAK,EAAE,KAAK,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC,EAAU;YAClE,cAAc,EAAE,OAAO,CAAC,cAAc,IAAI,IAAI,CAAC,GAAG,EAAE;SACrD,CAAC,CAAC;IACL,CAAC;IAEM,KAAK,CAAC,QAAQ;QACnB,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACtB,aAAa,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YACjC,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QAC3B,CAAC;QACD,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;YAC7C,IAAI,CAAC;gBACH,MAAM,OAAO,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;YAClC,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS;YACX,CAAC;QACH,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC;CACF"}
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+ import { ConfigManager } from "./config/config-manager.js";
3
+ import { createServer } from "./gateway/server.js";
4
+ export { createServer, ConfigManager };
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AA+KnD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,164 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { ConfigManager } from "./config/config-manager.js";
5
+ import { createServer } from "./gateway/server.js";
6
+ import { isValidProfile, resolveCustomTools } from "./config/profiles.js";
7
+ import { registerAllTools } from "./tools/index.js";
8
+ // Parse CLI arguments
9
+ const args = process.argv.slice(2);
10
+ function getArg(flag, fallback) {
11
+ for (const arg of args) {
12
+ if (arg.startsWith(`${flag}=`)) {
13
+ return arg.slice(flag.length + 1);
14
+ }
15
+ }
16
+ const idx = args.indexOf(flag);
17
+ return idx !== -1 && args[idx + 1] && !args[idx + 1].startsWith("-") ? args[idx + 1] : fallback;
18
+ }
19
+ if (args.includes("--help") || args.includes("-h")) {
20
+ console.log(`
21
+ WinHelm - Windows Native MCP Server
22
+ Usage:
23
+ winhelm [options]
24
+
25
+ Options:
26
+ --config <path> Load configuration from a specific JSON file (e.g. project-specific config)
27
+ --port <number> Port to listen on (default: 8788 or PORT env)
28
+ --host <string> Host interface (default: 127.0.0.1 or HOST env)
29
+ --profile, -p <name> Tool profile: minimal (6), core (15), dev (28), sysadmin (37), full (38) (default: full)
30
+ --stdio Run in stdio mode for local MCP clients (OpenAI tunnel-client, Claude, Cursor)
31
+ --transport <type> Transport mode: http (default) or stdio
32
+ --auth <token> Bearer authentication token (or MCP_AUTH_TOKEN env)
33
+ --read-only Enable read-only mode (block mutating actions)
34
+ --allowed-dirs <list> Comma-separated allowed directories (e.g. "D:\\mcp,C:\\Projects")
35
+ --tools <list> Explicit comma-separated tools to load or +tool/-tool modifiers
36
+ --no-persist Do not persist CLI overrides to config file (default behavior)
37
+ --persist Persist CLI overrides back to config file
38
+ --help, -h Show this help message
39
+ `);
40
+ process.exit(0);
41
+ }
42
+ async function main() {
43
+ const IS_STDIO = args.includes("--stdio") || getArg("--transport") === "stdio";
44
+ if (IS_STDIO) {
45
+ // In stdio mode, process.stdout is the JSON-RPC wire. All logs must go to stderr.
46
+ console.log = (...a) => console.error(...a);
47
+ }
48
+ const CONFIG_ARG = getArg("--config");
49
+ const NO_PERSIST = args.includes("--no-persist");
50
+ const configManager = ConfigManager.getInstance(CONFIG_ARG);
51
+ await configManager.init(CONFIG_ARG);
52
+ const PORT = parseInt(getArg("--port", process.env.PORT || "8788"), 10);
53
+ const HOST = getArg("--host", process.env.HOST || "127.0.0.1");
54
+ const AUTH_TOKEN = getArg("--auth", process.env.MCP_AUTH_TOKEN || undefined);
55
+ const ALLOWED_DIRS = getArg("--allowed-dirs", process.env.MCP_ALLOWED_DIRECTORIES || undefined);
56
+ const READ_ONLY = args.includes("--read-only") || process.env.MCP_READ_ONLY === "true" || process.env.MCP_READ_ONLY === "1";
57
+ const PROFILE_ARG = getArg("--profile", getArg("-p", process.env.WINHELM_PROFILE || undefined));
58
+ const TOOLS_ARG = getArg("--tools");
59
+ const updates = {};
60
+ if (AUTH_TOKEN)
61
+ updates.authToken = AUTH_TOKEN;
62
+ if (READ_ONLY)
63
+ updates.readOnly = true;
64
+ if (PROFILE_ARG) {
65
+ if (isValidProfile(PROFILE_ARG)) {
66
+ updates.profile = PROFILE_ARG;
67
+ }
68
+ else {
69
+ console.error(`[WinHelm] Unknown profile: "${PROFILE_ARG}". Valid profiles: minimal, core, dev, sysadmin, full, custom`);
70
+ process.exit(1);
71
+ }
72
+ }
73
+ if (TOOLS_ARG) {
74
+ const baseProfile = (updates.profile || configManager.getConfig().profile || "full");
75
+ updates.customTools = resolveCustomTools(baseProfile, TOOLS_ARG);
76
+ if (!updates.profile)
77
+ updates.profile = "custom";
78
+ }
79
+ if (ALLOWED_DIRS) {
80
+ updates.allowedDirectories = ALLOWED_DIRS.split(",")
81
+ .map((d) => d.trim())
82
+ .filter(Boolean);
83
+ }
84
+ if (Object.keys(updates).length > 0) {
85
+ // By default, CLI overrides are in-memory session-only unless --persist is explicitly passed
86
+ const shouldPersist = args.includes("--persist") && !NO_PERSIST;
87
+ await configManager.updateConfig(updates, shouldPersist);
88
+ }
89
+ // Security warning if bound to non-loopback with no authentication token
90
+ const isLoopback = HOST === "127.0.0.1" || HOST.toLowerCase() === "localhost" || HOST === "::1";
91
+ const effectiveAuthToken = AUTH_TOKEN || configManager.getConfig().authToken;
92
+ if (!isLoopback && !effectiveAuthToken && !IS_STDIO) {
93
+ console.warn("\n" + "=".repeat(78));
94
+ console.warn("⚠️ WARNING: Server is bound to a non-loopback address with NO authentication token.");
95
+ console.warn(` Interface: ${HOST}:${PORT}`);
96
+ console.warn(" Anyone on this network can execute commands on this machine.");
97
+ console.warn(" To protect your system, specify --auth <token> or set MCP_AUTH_TOKEN in environment.");
98
+ console.warn("=".repeat(78) + "\n");
99
+ }
100
+ if (IS_STDIO) {
101
+ const mcpServer = new McpServer({
102
+ name: "winhelm-mcp",
103
+ version: "1.1.0",
104
+ });
105
+ registerAllTools(mcpServer);
106
+ const transport = new StdioServerTransport();
107
+ await mcpServer.connect(transport);
108
+ console.error(`[WinHelm] Connected via stdio transport (Profile: ${configManager.getConfig().profile || "full"}).`);
109
+ const shutdown = async () => {
110
+ await mcpServer.close().catch(() => { });
111
+ process.exit(0);
112
+ };
113
+ process.on("SIGINT", shutdown);
114
+ process.on("SIGTERM", shutdown);
115
+ return;
116
+ }
117
+ const { start, stop } = createServer({
118
+ port: PORT,
119
+ host: HOST,
120
+ authToken: AUTH_TOKEN,
121
+ });
122
+ const server = await start();
123
+ let isShuttingDown = false;
124
+ const shutdown = async () => {
125
+ if (isShuttingDown) {
126
+ console.log("\n[WinHelm] Force exit.");
127
+ process.exit(0);
128
+ }
129
+ isShuttingDown = true;
130
+ console.log("\n[WinHelm] Shutting down server gracefully...");
131
+ // Safety timeout in case of any lingering event loop handles
132
+ const forceExitTimer = setTimeout(() => {
133
+ console.log("[WinHelm] Server stopped. Goodbye!");
134
+ process.exit(0);
135
+ }, 1200);
136
+ forceExitTimer.unref();
137
+ try {
138
+ await stop(server);
139
+ }
140
+ catch {
141
+ // ignore
142
+ }
143
+ console.log("[WinHelm] Server stopped. Goodbye!");
144
+ process.exit(0);
145
+ };
146
+ process.on("SIGINT", shutdown);
147
+ process.on("SIGTERM", shutdown);
148
+ }
149
+ // Auto-run if executed directly or in standalone SEA binary
150
+ const argv1 = process.argv[1] || "";
151
+ const isSeaBinary = process.execPath.toLowerCase().endsWith(".exe") && !process.execPath.toLowerCase().endsWith("node.exe");
152
+ const isDirectEntry = isSeaBinary ||
153
+ argv1.endsWith("index.ts") ||
154
+ argv1.endsWith("index.js") ||
155
+ argv1.endsWith("winhelm") ||
156
+ (typeof import.meta !== "undefined" && import.meta?.url && argv1 && import.meta.url.includes(argv1.replace(/\\/g, "/")));
157
+ if (isDirectEntry) {
158
+ main().catch((err) => {
159
+ console.error("[WinHelm] Fatal error on startup:", err);
160
+ process.exit(1);
161
+ });
162
+ }
163
+ export { createServer, ConfigManager };
164
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerDesktopTools(server: McpServer): void;
3
+ //# sourceMappingURL=desktop-tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"desktop-tools.d.ts","sourceRoot":"","sources":["../../src/tools/desktop-tools.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAmBzE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAoU5D"}
@@ -0,0 +1,280 @@
1
+ import { z } from "zod";
2
+ import { captureScreen, checkPort, controlService, getClipboard, getGpuInfo, getServiceStatus, getSystemInfo, killProcess, listProcesses, listServices, openTarget, queryEventLog, sendNotification, setClipboard, } from "../engine/system.js";
3
+ import { registerTracedTool } from "./tool-wrapper.js";
4
+ export function registerDesktopTools(server) {
5
+ // 1. Clipboard Get
6
+ registerTracedTool(server, "clipboard_get", {}, async () => {
7
+ try {
8
+ const text = await getClipboard();
9
+ return {
10
+ content: [{ type: "text", text: text || "(Clipboard is empty or contains non-text data)" }],
11
+ };
12
+ }
13
+ catch (err) {
14
+ return {
15
+ content: [{ type: "text", text: `Failed to get clipboard: ${err.message}` }],
16
+ isError: true,
17
+ };
18
+ }
19
+ });
20
+ // 2. Clipboard Set
21
+ registerTracedTool(server, "clipboard_set", {
22
+ text: z.string().describe("Text content to copy to Windows clipboard"),
23
+ }, async ({ text }) => {
24
+ try {
25
+ await setClipboard(text);
26
+ return {
27
+ content: [
28
+ { type: "text", text: `Successfully copied ${text.length} characters to clipboard` },
29
+ ],
30
+ };
31
+ }
32
+ catch (err) {
33
+ return {
34
+ content: [{ type: "text", text: `Failed to set clipboard: ${err.message}` }],
35
+ isError: true,
36
+ };
37
+ }
38
+ });
39
+ // 3. Screen Capture
40
+ registerTracedTool(server, "screen_capture", {}, async () => {
41
+ try {
42
+ const base64 = await captureScreen();
43
+ return {
44
+ content: [
45
+ {
46
+ type: "image",
47
+ data: base64,
48
+ mimeType: "image/png",
49
+ },
50
+ {
51
+ type: "text",
52
+ text: "Screenshot captured successfully (primary display).",
53
+ },
54
+ ],
55
+ };
56
+ }
57
+ catch (err) {
58
+ return {
59
+ content: [{ type: "text", text: `Screenshot failed: ${err.message}` }],
60
+ isError: true,
61
+ };
62
+ }
63
+ });
64
+ // 4. System Open (URL, Folder, File)
65
+ registerTracedTool(server, "system_open", {
66
+ target: z.string().describe("URL, folder path, or file to open with default application"),
67
+ }, async ({ target }) => {
68
+ try {
69
+ const res = await openTarget(target);
70
+ return {
71
+ content: [{ type: "text", text: `Opened: ${res.target}` }],
72
+ };
73
+ }
74
+ catch (err) {
75
+ return {
76
+ content: [{ type: "text", text: `Open failed: ${err.message}` }],
77
+ isError: true,
78
+ };
79
+ }
80
+ });
81
+ // 5. System Info
82
+ registerTracedTool(server, "system_info", {}, async () => {
83
+ try {
84
+ const info = await getSystemInfo();
85
+ return {
86
+ content: [{ type: "text", text: JSON.stringify(info, null, 2) }],
87
+ };
88
+ }
89
+ catch (err) {
90
+ return {
91
+ content: [{ type: "text", text: `Failed to get system info: ${err.message}` }],
92
+ isError: true,
93
+ };
94
+ }
95
+ });
96
+ // 6. Process Kill
97
+ registerTracedTool(server, "process_kill", {
98
+ pid: z.number().optional().describe("Process ID to terminate"),
99
+ name: z.string().optional().describe("Process Name (e.g. 'node', 'notepad')"),
100
+ }, async ({ pid, name }) => {
101
+ try {
102
+ const res = await killProcess(pid, name);
103
+ return {
104
+ content: [{ type: "text", text: JSON.stringify(res, null, 2) }],
105
+ };
106
+ }
107
+ catch (err) {
108
+ return {
109
+ content: [{ type: "text", text: `Kill process failed: ${err.message}` }],
110
+ isError: true,
111
+ };
112
+ }
113
+ });
114
+ // 7. Port Check
115
+ registerTracedTool(server, "port_check", {
116
+ port: z.number().describe("TCP port number to check (e.g. 8788, 3000)"),
117
+ }, async ({ port }) => {
118
+ try {
119
+ const res = await checkPort(port);
120
+ return {
121
+ content: [{ type: "text", text: JSON.stringify(res, null, 2) }],
122
+ };
123
+ }
124
+ catch (err) {
125
+ return {
126
+ content: [{ type: "text", text: `Port check failed: ${err.message}` }],
127
+ isError: true,
128
+ };
129
+ }
130
+ });
131
+ // 8. GPU Info
132
+ registerTracedTool(server, "gpu_info", {}, async () => {
133
+ try {
134
+ const info = await getGpuInfo();
135
+ return {
136
+ content: [{ type: "text", text: JSON.stringify(info, null, 2) }],
137
+ };
138
+ }
139
+ catch (err) {
140
+ return {
141
+ content: [{ type: "text", text: `Failed to query GPU info: ${err.message}` }],
142
+ isError: true,
143
+ };
144
+ }
145
+ });
146
+ // 9. Windows Services List
147
+ registerTracedTool(server, "service_list", {
148
+ filter: z.string().optional().describe("Filter services by name substring (e.g. 'docker', 'ssh', 'postgres')"),
149
+ }, async ({ filter }) => {
150
+ try {
151
+ const services = await listServices(filter);
152
+ return {
153
+ content: [
154
+ {
155
+ type: "text",
156
+ text: services.length > 0
157
+ ? JSON.stringify(services, null, 2)
158
+ : `No services matching filter "${filter || ""}"`,
159
+ },
160
+ ],
161
+ };
162
+ }
163
+ catch (err) {
164
+ return {
165
+ content: [{ type: "text", text: `Failed to list services: ${err.message}` }],
166
+ isError: true,
167
+ };
168
+ }
169
+ });
170
+ // 10. Windows Service Status
171
+ registerTracedTool(server, "service_status", {
172
+ service_name: z.string().describe("Exact name of the Windows service (e.g. 'ssh-agent', 'wslservice')"),
173
+ }, async ({ service_name }) => {
174
+ try {
175
+ const status = await getServiceStatus(service_name);
176
+ return {
177
+ content: [{ type: "text", text: JSON.stringify(status, null, 2) }],
178
+ };
179
+ }
180
+ catch (err) {
181
+ return {
182
+ content: [{ type: "text", text: `Failed to get service status: ${err.message}` }],
183
+ isError: true,
184
+ };
185
+ }
186
+ });
187
+ // 11. Windows Service Control
188
+ registerTracedTool(server, "service_control", {
189
+ service_name: z.string().describe("Exact name of the Windows service to control"),
190
+ action: z.enum(["start", "stop", "restart"]).describe("Action to perform on the service"),
191
+ }, async ({ service_name, action }) => {
192
+ try {
193
+ const res = await controlService(service_name, action);
194
+ return {
195
+ content: [{ type: "text", text: JSON.stringify(res, null, 2) }],
196
+ };
197
+ }
198
+ catch (err) {
199
+ return {
200
+ content: [{ type: "text", text: `Failed to ${action} service: ${err.message}` }],
201
+ isError: true,
202
+ };
203
+ }
204
+ });
205
+ // 12. Process List & Top Processes
206
+ registerTracedTool(server, "process_list", {
207
+ limit: z.number().optional().describe("Maximum number of processes to return (default: 20, max: 100)"),
208
+ sort_by: z.enum(["cpu", "memory", "name", "pid"]).optional().describe("Sort processes by resource or property (default: memory)"),
209
+ filter: z.string().optional().describe("Filter process name or path substring"),
210
+ }, async ({ limit, sort_by, filter }) => {
211
+ try {
212
+ const procs = await listProcesses({
213
+ limit,
214
+ sortBy: sort_by,
215
+ filter,
216
+ });
217
+ return {
218
+ content: [{ type: "text", text: JSON.stringify(procs, null, 2) }],
219
+ };
220
+ }
221
+ catch (err) {
222
+ return {
223
+ content: [{ type: "text", text: `Failed to list processes: ${err.message}` }],
224
+ isError: true,
225
+ };
226
+ }
227
+ });
228
+ // 13. Windows Event Log Query
229
+ registerTracedTool(server, "eventlog_query", {
230
+ log_name: z.string().optional().describe("Windows Event Log name (e.g. 'Application', 'System', default: 'Application')"),
231
+ level: z.enum(["Critical", "Error", "Warning", "Information", "All"]).optional().describe("Event severity level (default: Error)"),
232
+ hours: z.number().optional().describe("Query events from past N hours (default: 24)"),
233
+ source: z.string().optional().describe("Filter by provider or application source name"),
234
+ limit: z.number().optional().describe("Maximum number of events to return (default: 20, max: 100)"),
235
+ }, async ({ log_name, level, hours, source, limit }) => {
236
+ try {
237
+ const events = await queryEventLog({
238
+ logName: log_name,
239
+ level,
240
+ hours,
241
+ source,
242
+ limit,
243
+ });
244
+ return {
245
+ content: [
246
+ {
247
+ type: "text",
248
+ text: events.length > 0 ? JSON.stringify(events, null, 2) : "[] (No matching events found)",
249
+ },
250
+ ],
251
+ };
252
+ }
253
+ catch (err) {
254
+ return {
255
+ content: [{ type: "text", text: `Failed to query event log: ${err.message}` }],
256
+ isError: true,
257
+ };
258
+ }
259
+ });
260
+ // 14. Windows Toast Notification
261
+ registerTracedTool(server, "notification_send", {
262
+ title: z.string().describe("Toast notification title (e.g. 'Task Complete')"),
263
+ message: z.string().describe("Notification body text"),
264
+ sound: z.boolean().optional().describe("Play alert sound with notification (default: true)"),
265
+ }, async ({ title, message, sound }) => {
266
+ try {
267
+ const res = await sendNotification(title, message, sound !== false);
268
+ return {
269
+ content: [{ type: "text", text: `Notification sent: "${res.title}" - ${res.message}` }],
270
+ };
271
+ }
272
+ catch (err) {
273
+ return {
274
+ content: [{ type: "text", text: `Failed to send notification: ${err.message}` }],
275
+ isError: true,
276
+ };
277
+ }
278
+ });
279
+ }
280
+ //# sourceMappingURL=desktop-tools.js.map