hoolix 0.0.1-beta.19

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 (263) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +337 -0
  3. package/STABILITY.md +109 -0
  4. package/bin/hoolix.js +50 -0
  5. package/bin/mcp-portal.js +12 -0
  6. package/bin/postinstall.js +61 -0
  7. package/dist/app/contracts.d.ts +105 -0
  8. package/dist/app/contracts.d.ts.map +1 -0
  9. package/dist/app/contracts.js +2 -0
  10. package/dist/app/contracts.js.map +1 -0
  11. package/dist/app/events.d.ts +13 -0
  12. package/dist/app/events.d.ts.map +1 -0
  13. package/dist/app/events.js +13 -0
  14. package/dist/app/events.js.map +1 -0
  15. package/dist/app/services/analytics.d.ts +42 -0
  16. package/dist/app/services/analytics.d.ts.map +1 -0
  17. package/dist/app/services/analytics.js +106 -0
  18. package/dist/app/services/analytics.js.map +1 -0
  19. package/dist/app/services/catalog.d.ts +14 -0
  20. package/dist/app/services/catalog.d.ts.map +1 -0
  21. package/dist/app/services/catalog.js +26 -0
  22. package/dist/app/services/catalog.js.map +1 -0
  23. package/dist/app/services/credentials.d.ts +42 -0
  24. package/dist/app/services/credentials.d.ts.map +1 -0
  25. package/dist/app/services/credentials.js +143 -0
  26. package/dist/app/services/credentials.js.map +1 -0
  27. package/dist/app/services/servers.d.ts +15 -0
  28. package/dist/app/services/servers.d.ts.map +1 -0
  29. package/dist/app/services/servers.js +445 -0
  30. package/dist/app/services/servers.js.map +1 -0
  31. package/dist/catalog/community.d.ts +19 -0
  32. package/dist/catalog/community.d.ts.map +1 -0
  33. package/dist/catalog/community.js +53 -0
  34. package/dist/catalog/community.js.map +1 -0
  35. package/dist/catalog/templates.d.ts +436 -0
  36. package/dist/catalog/templates.d.ts.map +1 -0
  37. package/dist/catalog/templates.js +489 -0
  38. package/dist/catalog/templates.js.map +1 -0
  39. package/dist/commands/audit.d.ts +2 -0
  40. package/dist/commands/audit.d.ts.map +1 -0
  41. package/dist/commands/audit.js +122 -0
  42. package/dist/commands/audit.js.map +1 -0
  43. package/dist/commands/bundle.d.ts +11 -0
  44. package/dist/commands/bundle.d.ts.map +1 -0
  45. package/dist/commands/bundle.js +299 -0
  46. package/dist/commands/bundle.js.map +1 -0
  47. package/dist/commands/clients.d.ts +6 -0
  48. package/dist/commands/clients.d.ts.map +1 -0
  49. package/dist/commands/clients.js +242 -0
  50. package/dist/commands/clients.js.map +1 -0
  51. package/dist/commands/completion.d.ts +18 -0
  52. package/dist/commands/completion.d.ts.map +1 -0
  53. package/dist/commands/completion.js +495 -0
  54. package/dist/commands/completion.js.map +1 -0
  55. package/dist/commands/connect.d.ts +10 -0
  56. package/dist/commands/connect.d.ts.map +1 -0
  57. package/dist/commands/connect.js +463 -0
  58. package/dist/commands/connect.js.map +1 -0
  59. package/dist/commands/create.d.ts +2 -0
  60. package/dist/commands/create.d.ts.map +1 -0
  61. package/dist/commands/create.js +607 -0
  62. package/dist/commands/create.js.map +1 -0
  63. package/dist/commands/delete.d.ts +2 -0
  64. package/dist/commands/delete.d.ts.map +1 -0
  65. package/dist/commands/delete.js +44 -0
  66. package/dist/commands/delete.js.map +1 -0
  67. package/dist/commands/doctor.d.ts +2 -0
  68. package/dist/commands/doctor.d.ts.map +1 -0
  69. package/dist/commands/doctor.js +259 -0
  70. package/dist/commands/doctor.js.map +1 -0
  71. package/dist/commands/export.d.ts +2 -0
  72. package/dist/commands/export.d.ts.map +1 -0
  73. package/dist/commands/export.js +93 -0
  74. package/dist/commands/export.js.map +1 -0
  75. package/dist/commands/gui.d.ts +2 -0
  76. package/dist/commands/gui.d.ts.map +1 -0
  77. package/dist/commands/gui.js +19 -0
  78. package/dist/commands/gui.js.map +1 -0
  79. package/dist/commands/import.d.ts +2 -0
  80. package/dist/commands/import.d.ts.map +1 -0
  81. package/dist/commands/import.js +102 -0
  82. package/dist/commands/import.js.map +1 -0
  83. package/dist/commands/info.d.ts +2 -0
  84. package/dist/commands/info.d.ts.map +1 -0
  85. package/dist/commands/info.js +151 -0
  86. package/dist/commands/info.js.map +1 -0
  87. package/dist/commands/list.d.ts +2 -0
  88. package/dist/commands/list.d.ts.map +1 -0
  89. package/dist/commands/list.js +90 -0
  90. package/dist/commands/list.js.map +1 -0
  91. package/dist/commands/reindex.d.ts +2 -0
  92. package/dist/commands/reindex.d.ts.map +1 -0
  93. package/dist/commands/reindex.js +186 -0
  94. package/dist/commands/reindex.js.map +1 -0
  95. package/dist/commands/rotate.d.ts +2 -0
  96. package/dist/commands/rotate.d.ts.map +1 -0
  97. package/dist/commands/rotate.js +67 -0
  98. package/dist/commands/rotate.js.map +1 -0
  99. package/dist/commands/secrets.d.ts +10 -0
  100. package/dist/commands/secrets.d.ts.map +1 -0
  101. package/dist/commands/secrets.js +293 -0
  102. package/dist/commands/secrets.js.map +1 -0
  103. package/dist/commands/start.d.ts +2 -0
  104. package/dist/commands/start.d.ts.map +1 -0
  105. package/dist/commands/start.js +234 -0
  106. package/dist/commands/start.js.map +1 -0
  107. package/dist/commands/stats.d.ts +2 -0
  108. package/dist/commands/stats.d.ts.map +1 -0
  109. package/dist/commands/stats.js +220 -0
  110. package/dist/commands/stats.js.map +1 -0
  111. package/dist/commands/stop.d.ts +2 -0
  112. package/dist/commands/stop.d.ts.map +1 -0
  113. package/dist/commands/stop.js +24 -0
  114. package/dist/commands/stop.js.map +1 -0
  115. package/dist/commands/templates.d.ts +2 -0
  116. package/dist/commands/templates.d.ts.map +1 -0
  117. package/dist/commands/templates.js +168 -0
  118. package/dist/commands/templates.js.map +1 -0
  119. package/dist/commands/trial.d.ts +2 -0
  120. package/dist/commands/trial.d.ts.map +1 -0
  121. package/dist/commands/trial.js +61 -0
  122. package/dist/commands/trial.js.map +1 -0
  123. package/dist/commands/uninstall.d.ts +2 -0
  124. package/dist/commands/uninstall.d.ts.map +1 -0
  125. package/dist/commands/uninstall.js +114 -0
  126. package/dist/commands/uninstall.js.map +1 -0
  127. package/dist/commands/update.d.ts +2 -0
  128. package/dist/commands/update.d.ts.map +1 -0
  129. package/dist/commands/update.js +104 -0
  130. package/dist/commands/update.js.map +1 -0
  131. package/dist/commands/verify.d.ts +2 -0
  132. package/dist/commands/verify.d.ts.map +1 -0
  133. package/dist/commands/verify.js +301 -0
  134. package/dist/commands/verify.js.map +1 -0
  135. package/dist/core/config.d.ts +25 -0
  136. package/dist/core/config.d.ts.map +1 -0
  137. package/dist/core/config.js +54 -0
  138. package/dist/core/config.js.map +1 -0
  139. package/dist/core/errors.d.ts +25 -0
  140. package/dist/core/errors.d.ts.map +1 -0
  141. package/dist/core/errors.js +53 -0
  142. package/dist/core/errors.js.map +1 -0
  143. package/dist/core/logger.d.ts +3 -0
  144. package/dist/core/logger.d.ts.map +1 -0
  145. package/dist/core/logger.js +12 -0
  146. package/dist/core/logger.js.map +1 -0
  147. package/dist/core/paths.d.ts +15 -0
  148. package/dist/core/paths.d.ts.map +1 -0
  149. package/dist/core/paths.js +51 -0
  150. package/dist/core/paths.js.map +1 -0
  151. package/dist/core/registry.d.ts +474 -0
  152. package/dist/core/registry.d.ts.map +1 -0
  153. package/dist/core/registry.js +186 -0
  154. package/dist/core/registry.js.map +1 -0
  155. package/dist/core/updater.d.ts +16 -0
  156. package/dist/core/updater.d.ts.map +1 -0
  157. package/dist/core/updater.js +317 -0
  158. package/dist/core/updater.js.map +1 -0
  159. package/dist/core/version.d.ts +2 -0
  160. package/dist/core/version.d.ts.map +1 -0
  161. package/dist/core/version.js +3 -0
  162. package/dist/core/version.js.map +1 -0
  163. package/dist/index.d.ts +13 -0
  164. package/dist/index.d.ts.map +1 -0
  165. package/dist/index.js +270 -0
  166. package/dist/index.js.map +1 -0
  167. package/dist/ingestion/chunker.d.ts +13 -0
  168. package/dist/ingestion/chunker.d.ts.map +1 -0
  169. package/dist/ingestion/chunker.js +107 -0
  170. package/dist/ingestion/chunker.js.map +1 -0
  171. package/dist/ingestion/cleaners.d.ts +10 -0
  172. package/dist/ingestion/cleaners.d.ts.map +1 -0
  173. package/dist/ingestion/cleaners.js +61 -0
  174. package/dist/ingestion/cleaners.js.map +1 -0
  175. package/dist/ingestion/detectors.d.ts +5 -0
  176. package/dist/ingestion/detectors.d.ts.map +1 -0
  177. package/dist/ingestion/detectors.js +25 -0
  178. package/dist/ingestion/detectors.js.map +1 -0
  179. package/dist/ingestion/fetchers.d.ts +38 -0
  180. package/dist/ingestion/fetchers.d.ts.map +1 -0
  181. package/dist/ingestion/fetchers.js +296 -0
  182. package/dist/ingestion/fetchers.js.map +1 -0
  183. package/dist/ingestion/github.d.ts +60 -0
  184. package/dist/ingestion/github.d.ts.map +1 -0
  185. package/dist/ingestion/github.js +314 -0
  186. package/dist/ingestion/github.js.map +1 -0
  187. package/dist/ingestion/pipeline.d.ts +3 -0
  188. package/dist/ingestion/pipeline.d.ts.map +1 -0
  189. package/dist/ingestion/pipeline.js +160 -0
  190. package/dist/ingestion/pipeline.js.map +1 -0
  191. package/dist/ingestion/types.d.ts +51 -0
  192. package/dist/ingestion/types.d.ts.map +1 -0
  193. package/dist/ingestion/types.js +2 -0
  194. package/dist/ingestion/types.js.map +1 -0
  195. package/dist/lib/auth.d.ts +2 -0
  196. package/dist/lib/auth.d.ts.map +1 -0
  197. package/dist/lib/auth.js +6 -0
  198. package/dist/lib/auth.js.map +1 -0
  199. package/dist/lib/embedding.d.ts +10 -0
  200. package/dist/lib/embedding.d.ts.map +1 -0
  201. package/dist/lib/embedding.js +21 -0
  202. package/dist/lib/embedding.js.map +1 -0
  203. package/dist/mcp/host.d.ts +16 -0
  204. package/dist/mcp/host.d.ts.map +1 -0
  205. package/dist/mcp/host.js +307 -0
  206. package/dist/mcp/host.js.map +1 -0
  207. package/dist/mcp/proxy-host.d.ts +25 -0
  208. package/dist/mcp/proxy-host.d.ts.map +1 -0
  209. package/dist/mcp/proxy-host.js +393 -0
  210. package/dist/mcp/proxy-host.js.map +1 -0
  211. package/dist/mcp/stdio-host.d.ts +19 -0
  212. package/dist/mcp/stdio-host.d.ts.map +1 -0
  213. package/dist/mcp/stdio-host.js +175 -0
  214. package/dist/mcp/stdio-host.js.map +1 -0
  215. package/dist/process/manager.d.ts +74 -0
  216. package/dist/process/manager.d.ts.map +1 -0
  217. package/dist/process/manager.js +322 -0
  218. package/dist/process/manager.js.map +1 -0
  219. package/dist/rag/models.d.ts +30 -0
  220. package/dist/rag/models.d.ts.map +1 -0
  221. package/dist/rag/models.js +30 -0
  222. package/dist/rag/models.js.map +1 -0
  223. package/dist/rag/store.d.ts +63 -0
  224. package/dist/rag/store.d.ts.map +1 -0
  225. package/dist/rag/store.js +505 -0
  226. package/dist/rag/store.js.map +1 -0
  227. package/dist/rag/types.d.ts +56 -0
  228. package/dist/rag/types.d.ts.map +1 -0
  229. package/dist/rag/types.js +2 -0
  230. package/dist/rag/types.js.map +1 -0
  231. package/dist/sources/plugins.d.ts +25 -0
  232. package/dist/sources/plugins.d.ts.map +1 -0
  233. package/dist/sources/plugins.js +55 -0
  234. package/dist/sources/plugins.js.map +1 -0
  235. package/dist/sources/registry.d.ts +19 -0
  236. package/dist/sources/registry.d.ts.map +1 -0
  237. package/dist/sources/registry.js +183 -0
  238. package/dist/sources/registry.js.map +1 -0
  239. package/dist/sources/types.d.ts +361 -0
  240. package/dist/sources/types.d.ts.map +1 -0
  241. package/dist/sources/types.js +59 -0
  242. package/dist/sources/types.js.map +1 -0
  243. package/dist/tui/index.d.ts +22 -0
  244. package/dist/tui/index.d.ts.map +1 -0
  245. package/dist/tui/index.js +711 -0
  246. package/dist/tui/index.js.map +1 -0
  247. package/dist/ui/format.d.ts +27 -0
  248. package/dist/ui/format.d.ts.map +1 -0
  249. package/dist/ui/format.js +80 -0
  250. package/dist/ui/format.js.map +1 -0
  251. package/dist/ui/help.d.ts +2 -0
  252. package/dist/ui/help.d.ts.map +1 -0
  253. package/dist/ui/help.js +106 -0
  254. package/dist/ui/help.js.map +1 -0
  255. package/dist/web/assets.d.ts +2 -0
  256. package/dist/web/assets.d.ts.map +1 -0
  257. package/dist/web/assets.js +659 -0
  258. package/dist/web/assets.js.map +1 -0
  259. package/dist/web/server.d.ts +9 -0
  260. package/dist/web/server.d.ts.map +1 -0
  261. package/dist/web/server.js +349 -0
  262. package/dist/web/server.js.map +1 -0
  263. package/package.json +105 -0
@@ -0,0 +1,393 @@
1
+ /**
2
+ * MCP Proxy Host — bridges a stdio MCP server process to Hono + Streamable HTTP.
3
+ *
4
+ * Spawns the underlying stdio MCP server (defined in the server's template run config)
5
+ * as a persistent child process, then exposes it over authenticated HTTP with the same
6
+ * auth, rate-limiting, and audit middleware as host.ts.
7
+ *
8
+ * Features:
9
+ * - Auto-restart on child exit (exponential backoff, max MAX_RESTARTS attempts)
10
+ * - 30-second health ping to detect silent child hangs
11
+ * - SSE response wrapping: when client sends Accept: text/event-stream, the
12
+ * synchronous JSON-RPC response is streamed as an SSE event (phase 1 compatibility)
13
+ * - Batch JSON-RPC requests supported
14
+ * - Notifications (no id) forwarded without response
15
+ *
16
+ * See AGENTS.md Rule 9 "Two-Kind Template System" and "Proxy Mode".
17
+ */
18
+ import { Hono } from 'hono';
19
+ import { serve } from '@hono/node-server';
20
+ import { spawn } from 'node:child_process';
21
+ import readline from 'node:readline';
22
+ import fs from 'fs-extra';
23
+ import path from 'node:path';
24
+ import { logger } from '../core/logger.js';
25
+ import { getServerDataDir, getServerRuntimePath, getServerDir } from '../core/paths.js';
26
+ import { getServerMetadata } from '../core/registry.js';
27
+ import { loadCredentials, interpolateRunConfig } from '../app/services/credentials.js';
28
+ import { getTemplate } from '../app/services/catalog.js';
29
+ const PROXY_REQUEST_TIMEOUT_MS = 30_000;
30
+ const MAX_RESTARTS = 5;
31
+ const HEALTH_PING_INTERVAL_MS = 30_000;
32
+ function maskSecret(value, visible = 6) {
33
+ if (!value)
34
+ return '';
35
+ if (value.length <= visible * 2)
36
+ return `${value.slice(0, 2)}...`;
37
+ return `${value.slice(0, visible)}...${value.slice(-visible)}`;
38
+ }
39
+ /**
40
+ * Manages a persistent stdio child process with JSON-RPC request/response multiplexing.
41
+ * Auto-restarts on unexpected child exit (exponential backoff, max MAX_RESTARTS).
42
+ * Responses are matched to pending requests by JSON-RPC id.
43
+ */
44
+ class StdioJsonRpcProxy {
45
+ command;
46
+ args;
47
+ env;
48
+ child = null;
49
+ rl = null;
50
+ pending = new Map();
51
+ _dead = false;
52
+ restartCount = 0;
53
+ healthTimer = null;
54
+ constructor(command, args, env) {
55
+ this.command = command;
56
+ this.args = args;
57
+ this.env = env;
58
+ }
59
+ async start() {
60
+ await this._spawnChild();
61
+ // 30-second health monitoring: send ping → expect pong or any response
62
+ this.healthTimer = setInterval(() => {
63
+ if (!this.isAlive)
64
+ return;
65
+ // Fire-and-forget: if ping hangs for >timeout, the pending map cleans up
66
+ this.send({ jsonrpc: '2.0', id: `__health-${Date.now()}`, method: 'ping', params: {} })
67
+ .catch(() => {
68
+ // ping failure is expected for servers that don't implement ping
69
+ });
70
+ }, HEALTH_PING_INTERVAL_MS);
71
+ // Don't let health timer prevent process exit
72
+ if (this.healthTimer.unref)
73
+ this.healthTimer.unref();
74
+ }
75
+ async _spawnChild() {
76
+ // On Windows, bare 'npx' needs shell resolution
77
+ const cmd = process.platform === 'win32' && this.command === 'npx' ? 'npx.cmd' : this.command;
78
+ this.child = spawn(cmd, this.args, {
79
+ stdio: ['pipe', 'pipe', 'pipe'],
80
+ env: { ...process.env, ...this.env },
81
+ shell: false,
82
+ });
83
+ // Pipe child stderr to the proxy-host's stderr (→ host.log via manager redirection)
84
+ this.child.stderr?.on('data', (data) => {
85
+ process.stderr.write(`[child] ${data}`);
86
+ });
87
+ this.rl = readline.createInterface({ input: this.child.stdout });
88
+ this.rl.on('line', (line) => {
89
+ const trimmed = line.trim();
90
+ if (!trimmed)
91
+ return;
92
+ try {
93
+ const msg = JSON.parse(trimmed);
94
+ const id = msg?.id;
95
+ if (id !== undefined && id !== null) {
96
+ const resolve = this.pending.get(id);
97
+ if (resolve) {
98
+ this.pending.delete(id);
99
+ resolve(msg);
100
+ }
101
+ }
102
+ // Notifications (no id) are consumed — they don't need a forwarded response.
103
+ }
104
+ catch {
105
+ // Ignore non-JSON output from child (startup messages, etc.)
106
+ }
107
+ });
108
+ this.child.on('exit', (exitCode, exitSignal) => {
109
+ logger.error(`Proxy child exited: code=${exitCode ?? 'null'}, signal=${exitSignal ?? 'null'}`);
110
+ this.rl?.close();
111
+ this._tryRestart(exitCode, exitSignal);
112
+ });
113
+ // Brief wait for child to boot
114
+ await new Promise((r) => setTimeout(r, 600));
115
+ if (this._dead) {
116
+ throw new Error('Proxy child exited immediately. Check host.log for details.');
117
+ }
118
+ }
119
+ _tryRestart(_code, _signal) {
120
+ if (this.restartCount >= MAX_RESTARTS) {
121
+ logger.error(`Proxy child has exited ${MAX_RESTARTS} times — giving up. Proxy will remain in degraded state.`);
122
+ this._dead = true;
123
+ // Fail all pending requests
124
+ const err = { jsonrpc: '2.0', id: null, error: { code: -32000, message: 'Server process exited after too many restarts' } };
125
+ for (const [, resolve] of this.pending)
126
+ resolve(err);
127
+ this.pending.clear();
128
+ return;
129
+ }
130
+ // Fail existing pending requests while we restart
131
+ const restartErr = { jsonrpc: '2.0', id: null, error: { code: -32000, message: 'Server process restarting' } };
132
+ for (const [, resolve] of this.pending)
133
+ resolve(restartErr);
134
+ this.pending.clear();
135
+ const delay = Math.min(16000, 1000 * 2 ** this.restartCount);
136
+ this.restartCount++;
137
+ logger.warn(`Proxy child restarting (attempt ${this.restartCount}/${MAX_RESTARTS}) in ${delay}ms…`);
138
+ setTimeout(async () => {
139
+ if (this._dead)
140
+ return;
141
+ try {
142
+ await this._spawnChild();
143
+ logger.info(`Proxy child restarted successfully (attempt ${this.restartCount})`);
144
+ }
145
+ catch (e) {
146
+ logger.error(`Proxy child restart failed: ${e?.message || e}`);
147
+ this._tryRestart(null, null);
148
+ }
149
+ }, delay);
150
+ }
151
+ get isAlive() {
152
+ return !this._dead && this.child != null && !this.child.killed;
153
+ }
154
+ get childPid() {
155
+ return this.child?.pid;
156
+ }
157
+ async send(message) {
158
+ if (!this.isAlive)
159
+ throw new Error('Proxy child process is not running');
160
+ const msg = message;
161
+ const hasId = msg.id !== undefined && msg.id !== null;
162
+ return new Promise((resolve, reject) => {
163
+ const line = JSON.stringify(msg) + '\n';
164
+ if (hasId) {
165
+ const timer = setTimeout(() => {
166
+ this.pending.delete(msg.id);
167
+ reject(new Error(`Proxy request ${msg.id} timed out after ${PROXY_REQUEST_TIMEOUT_MS}ms`));
168
+ }, PROXY_REQUEST_TIMEOUT_MS);
169
+ this.pending.set(msg.id, (response) => {
170
+ clearTimeout(timer);
171
+ resolve(response);
172
+ });
173
+ }
174
+ this.child.stdin.write(line, (err) => {
175
+ if (err) {
176
+ if (hasId)
177
+ this.pending.delete(msg.id);
178
+ reject(new Error(`Failed to write to proxy child: ${err.message}`));
179
+ }
180
+ else if (!hasId) {
181
+ // Notification — no response expected
182
+ resolve(null);
183
+ }
184
+ });
185
+ });
186
+ }
187
+ kill() {
188
+ try {
189
+ if (this.healthTimer)
190
+ clearInterval(this.healthTimer);
191
+ this._dead = true;
192
+ this.rl?.close();
193
+ if (this.child && !this.child.killed)
194
+ this.child.kill('SIGTERM');
195
+ }
196
+ catch { }
197
+ }
198
+ }
199
+ // ── SSE helper ────────────────────────────────────────────────────────────────
200
+ /**
201
+ * Wrap a JSON-RPC response in SSE format for clients that send
202
+ * `Accept: text/event-stream`. Per Streamable HTTP spec phase 1:
203
+ * single response sent as `data:` event, then stream closed.
204
+ */
205
+ function jsonRpcToSSE(response) {
206
+ const encoder = new TextEncoder();
207
+ const json = JSON.stringify(response);
208
+ const body = new ReadableStream({
209
+ start(controller) {
210
+ controller.enqueue(encoder.encode(`data: ${json}\n\n`));
211
+ controller.close();
212
+ },
213
+ });
214
+ return new Response(body, {
215
+ headers: {
216
+ 'Content-Type': 'text/event-stream',
217
+ 'Cache-Control': 'no-cache',
218
+ 'Connection': 'keep-alive',
219
+ 'X-Accel-Buffering': 'no',
220
+ },
221
+ });
222
+ }
223
+ export async function startProxyHost(opts) {
224
+ const { slug, port, authKey, bindHost = '127.0.0.1' } = opts;
225
+ logger.info(`Starting proxy host for "${slug}" on ${bindHost}:${port}`);
226
+ // ── Load run config ─────────────────────────────────────────────────────────
227
+ const meta = await getServerMetadata(slug);
228
+ const templateId = meta.definition?.template?.id;
229
+ if (!templateId)
230
+ throw new Error(`Server "${slug}" has no template ID — cannot start in proxy mode`);
231
+ const template = await getTemplate(templateId);
232
+ if (!template.server)
233
+ throw new Error(`Template "${templateId}" has no server run config`);
234
+ const credentials = await loadCredentials(slug);
235
+ const templateInputs = Object.fromEntries(Object.entries(meta.definition?.template?.inputs ?? {}).map(([k, v]) => [k, String(v)]));
236
+ const substitutions = { ...templateInputs, ...credentials };
237
+ const runConfig = interpolateRunConfig(template.server, substitutions);
238
+ // Log run config (redacted) for debugging
239
+ const hostLogPath = path.join(getServerDir(slug), 'host.log');
240
+ await fs.ensureFile(hostLogPath);
241
+ await fs.appendFile(hostLogPath, `\n--- ${new Date().toISOString()} proxy start ${slug} on :${port} ---\n cmd: ${runConfig.command} ${runConfig.args.join(' ')}\n`);
242
+ // ── Spawn child stdio server ─────────────────────────────────────────────────
243
+ const proxy = new StdioJsonRpcProxy(runConfig.command, runConfig.args, runConfig.env ?? {});
244
+ await proxy.start();
245
+ logger.info(`Proxy child started (pid=${proxy.childPid ?? 'unknown'}, template=${templateId})`);
246
+ // ── Rate limiter (matches host.ts exactly) ─────────────────────────────────
247
+ const RATE_LIMIT = Math.max(1, parseInt(process.env.MCP_RATE_LIMIT || '120', 10));
248
+ const RATE_WINDOW_MS = Math.max(1000, parseInt(process.env.MCP_RATE_WINDOW_SEC || '60', 10) * 1000);
249
+ const rateStatePath = path.join(getServerDataDir(slug), 'rate-state.json');
250
+ let reqCount = 0;
251
+ let windowStart = Date.now();
252
+ try {
253
+ const state = await fs.readJson(rateStatePath);
254
+ if (typeof state.windowStart === 'number' && typeof state.reqCount === 'number') {
255
+ reqCount = state.reqCount;
256
+ windowStart = state.windowStart;
257
+ }
258
+ }
259
+ catch { }
260
+ async function saveRateState() {
261
+ await fs.writeJson(rateStatePath, { windowStart, reqCount, limit: RATE_LIMIT, windowMs: RATE_WINDOW_MS }).catch(() => { });
262
+ }
263
+ async function checkRateLimit() {
264
+ const now = Date.now();
265
+ if (now - windowStart > RATE_WINDOW_MS) {
266
+ reqCount = 0;
267
+ windowStart = now;
268
+ }
269
+ reqCount += 1;
270
+ await saveRateState();
271
+ return reqCount <= RATE_LIMIT;
272
+ }
273
+ // ── Audit (matches host.ts exactly) ─────────────────────────────────────────
274
+ const auditPath = path.join(getServerDataDir(slug), 'audit.log');
275
+ const MAX_AUDIT_LINES = 5000;
276
+ async function audit(tool, details) {
277
+ try {
278
+ const line = JSON.stringify({ ts: new Date().toISOString(), tool, transport: 'proxy', ...details }) + '\n';
279
+ await fs.appendFile(auditPath, line).catch(() => { });
280
+ try {
281
+ const content = await fs.readFile(auditPath, 'utf8').catch(() => '');
282
+ const lines = content.split('\n').filter(Boolean);
283
+ if (lines.length > MAX_AUDIT_LINES) {
284
+ await fs.writeFile(auditPath, lines.slice(-Math.floor(MAX_AUDIT_LINES * 0.8)).join('\n') + '\n').catch(() => { });
285
+ }
286
+ }
287
+ catch { }
288
+ }
289
+ catch { }
290
+ }
291
+ // ── Hono HTTP server ─────────────────────────────────────────────────────────
292
+ const app = new Hono();
293
+ app.get('/health', (c) => {
294
+ return c.json({
295
+ status: proxy.isAlive ? 'ok' : 'degraded',
296
+ server: slug,
297
+ mode: 'proxy',
298
+ template: templateId,
299
+ restarts: proxy.restartCount ?? 0,
300
+ });
301
+ });
302
+ // Auth + rate-limit middleware
303
+ app.use('/mcp', async (c, next) => {
304
+ const authHeader = c.req.header('Authorization');
305
+ const headerKey = authHeader?.startsWith('Bearer ') || authHeader?.startsWith('bearer ')
306
+ ? authHeader.replace(/^Bearer\s+/i, '')
307
+ : c.req.header('X-MCP-Key');
308
+ if (!headerKey || headerKey !== authKey) {
309
+ return c.json({ error: 'Unauthorized. Provide valid Authorization: Bearer <key> or X-MCP-Key header.' }, 401);
310
+ }
311
+ if (!(await checkRateLimit())) {
312
+ await audit('rate_limited', { limit: RATE_LIMIT, windowSec: Math.floor(RATE_WINDOW_MS / 1000) });
313
+ c.header('Retry-After', String(Math.ceil(RATE_WINDOW_MS / 1000)));
314
+ return c.json({ error: 'Rate limit exceeded. Try again later.' }, 429);
315
+ }
316
+ await next();
317
+ return;
318
+ });
319
+ app.all('/mcp', async (c) => {
320
+ if (!proxy.isAlive) {
321
+ return c.json({ jsonrpc: '2.0', id: null, error: { code: -32000, message: `Proxy child for "${slug}" is not running` } }, 503);
322
+ }
323
+ let body;
324
+ try {
325
+ body = await c.req.json();
326
+ }
327
+ catch {
328
+ return c.json({ jsonrpc: '2.0', id: null, error: { code: -32700, message: 'Parse error — invalid JSON body' } }, 400);
329
+ }
330
+ // Detect SSE preference (Streamable HTTP spec: client may send Accept: text/event-stream)
331
+ const acceptHeader = c.req.header('Accept') ?? '';
332
+ const preferSSE = acceptHeader.includes('text/event-stream');
333
+ try {
334
+ if (Array.isArray(body)) {
335
+ const responses = await Promise.all(body.map(async (req) => {
336
+ await audit('proxy_request', { method: req?.method, id: req?.id });
337
+ return proxy.send(req);
338
+ }));
339
+ const filtered = responses.filter((r) => r !== null);
340
+ if (preferSSE)
341
+ return jsonRpcToSSE(filtered);
342
+ return c.json(filtered);
343
+ }
344
+ const req = body;
345
+ await audit('proxy_request', { method: req?.method, id: req?.id });
346
+ const response = await proxy.send(req);
347
+ if (response === null)
348
+ return new Response(null, { status: 204 });
349
+ if (preferSSE)
350
+ return jsonRpcToSSE(response);
351
+ return c.json(response);
352
+ }
353
+ catch (e) {
354
+ await audit('proxy_error', { reason: e?.message || String(e) });
355
+ const errResponse = {
356
+ jsonrpc: '2.0',
357
+ id: body?.id ?? null,
358
+ error: { code: -32603, message: e?.message || 'Internal proxy error' },
359
+ };
360
+ if (preferSSE)
361
+ return jsonRpcToSSE(errResponse);
362
+ return c.json(errResponse, 500);
363
+ }
364
+ });
365
+ // ── Runtime marker (same format as host.ts + extra proxy fields) ─────────────
366
+ const runtimePath = getServerRuntimePath(slug);
367
+ await fs.writeJson(runtimePath, {
368
+ pid: process.pid,
369
+ port,
370
+ startedAt: new Date().toISOString(),
371
+ status: 'running',
372
+ mode: 'proxy',
373
+ childPid: proxy.childPid,
374
+ template: templateId,
375
+ }, { spaces: 2 });
376
+ // ── Graceful shutdown ─────────────────────────────────────────────────────────
377
+ const shutdown = async () => {
378
+ logger.info(`Shutting down proxy host for "${slug}"…`);
379
+ proxy.kill();
380
+ try {
381
+ await fs.remove(runtimePath);
382
+ }
383
+ catch { }
384
+ process.exit(0);
385
+ };
386
+ process.on('SIGTERM', shutdown);
387
+ process.on('SIGINT', shutdown);
388
+ logger.info(`Proxy host ready at http://${bindHost}:${port}/mcp (template: ${templateId})`);
389
+ logger.info(`Auth header required: Authorization: Bearer ${maskSecret(authKey)}`);
390
+ logger.info(`Auto-restart enabled: max ${MAX_RESTARTS} attempts with exponential backoff`);
391
+ serve({ fetch: app.fetch, port, hostname: bindHost });
392
+ }
393
+ //# sourceMappingURL=proxy-host.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy-host.js","sourceRoot":"","sources":["../../src/mcp/proxy-host.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * MCP Server Host — stdio transport.
3
+ *
4
+ * Runs a fully functional MCP server over stdin/stdout for MCP clients that
5
+ * prefer the stdio transport (Claude Desktop, VS Code extensions, etc.).
6
+ *
7
+ * This module is called directly by cmdStart when --transport stdio is detected.
8
+ * It runs in the foreground (the process stays alive with stdin open) — which is
9
+ * exactly how stdio MCP servers are supposed to work: the MCP client spawns the
10
+ * process and communicates over stdio.
11
+ *
12
+ * No HTTP, no auth key, no port, no rate limiting — the trust boundary is the
13
+ * OS process ownership (only the client that spawned us talks to us).
14
+ * Audit logging is preserved so usage is still observable via `hoolix audit`.
15
+ *
16
+ * See AGENTS.md "Host Execution Model" for the binary invariants.
17
+ */
18
+ export declare function startStdioServer(slug: string): Promise<void>;
19
+ //# sourceMappingURL=stdio-host.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stdio-host.d.ts","sourceRoot":"","sources":["../../src/mcp/stdio-host.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AA0DH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA+HlE"}
@@ -0,0 +1,175 @@
1
+ /**
2
+ * MCP Server Host — stdio transport.
3
+ *
4
+ * Runs a fully functional MCP server over stdin/stdout for MCP clients that
5
+ * prefer the stdio transport (Claude Desktop, VS Code extensions, etc.).
6
+ *
7
+ * This module is called directly by cmdStart when --transport stdio is detected.
8
+ * It runs in the foreground (the process stays alive with stdin open) — which is
9
+ * exactly how stdio MCP servers are supposed to work: the MCP client spawns the
10
+ * process and communicates over stdio.
11
+ *
12
+ * No HTTP, no auth key, no port, no rate limiting — the trust boundary is the
13
+ * OS process ownership (only the client that spawned us talks to us).
14
+ * Audit logging is preserved so usage is still observable via `hoolix audit`.
15
+ *
16
+ * See AGENTS.md "Host Execution Model" for the binary invariants.
17
+ */
18
+ import { McpServer, StdioServerTransport } from '@modelcontextprotocol/server';
19
+ import * as z from 'zod';
20
+ import fs from 'fs-extra';
21
+ import path from 'node:path';
22
+ import { createRAGForServer } from '../rag/store.js';
23
+ import { logger } from '../core/logger.js';
24
+ import { getServerDataDir } from '../core/paths.js';
25
+ import { getServerMetadata } from '../core/registry.js';
26
+ const DEFAULT_TOOL_TIMEOUT_MS = 15_000;
27
+ function getToolTimeoutMs() {
28
+ const parsed = parseInt(process.env.MCP_TOOL_TIMEOUT_MS || '', 10);
29
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_TOOL_TIMEOUT_MS;
30
+ }
31
+ async function withToolTimeout(tool, op) {
32
+ const timeoutMs = getToolTimeoutMs();
33
+ let timer;
34
+ const timeout = new Promise((_, reject) => {
35
+ timer = setTimeout(() => reject(new Error(`${tool} timed out after ${timeoutMs}ms. Next: retry with a narrower query or lower limit.`)), timeoutMs);
36
+ });
37
+ try {
38
+ return await Promise.race([op, timeout]);
39
+ }
40
+ finally {
41
+ if (timer)
42
+ clearTimeout(timer);
43
+ }
44
+ }
45
+ function toolErrorResponse(message) {
46
+ return { content: [{ type: 'text', text: message }] };
47
+ }
48
+ function formatResultSource(metadata) {
49
+ const prefix = metadata.sourceLabel ? `Source (${metadata.sourceLabel})` : 'Source';
50
+ const type = metadata.sourceType ? ` [${metadata.sourceType}]` : '';
51
+ return `${prefix}${type}: ${metadata.url}`;
52
+ }
53
+ function tokenBudget(args, fallbackTokens) {
54
+ const maxTokens = Number(args?.maxTokens || 0);
55
+ const contextWindowTokens = Number(args?.contextWindowTokens || 0);
56
+ const fromContext = contextWindowTokens > 0 ? Math.floor(contextWindowTokens * 0.25) : fallbackTokens;
57
+ const budget = maxTokens > 0 ? Math.min(maxTokens, fromContext) : fromContext;
58
+ return Math.max(500, Math.min(12000, budget));
59
+ }
60
+ function truncateToTokenBudget(text, budgetTokens) {
61
+ const maxChars = budgetTokens * 4;
62
+ if (text.length <= maxChars)
63
+ return text;
64
+ return text.slice(0, maxChars) + `\n... (truncated to ~${budgetTokens} tokens; pass maxTokens or use read_documentation_page for more)`;
65
+ }
66
+ export async function startStdioServer(slug) {
67
+ logger.info(`Starting stdio MCP server for "${slug}"`);
68
+ const rag = await createRAGForServer(slug);
69
+ const meta = await getServerMetadata(slug).catch(() => null);
70
+ const auditPath = path.join(getServerDataDir(slug), 'audit.log');
71
+ const MAX_AUDIT_LINES = 5000;
72
+ async function audit(tool, details) {
73
+ try {
74
+ const line = JSON.stringify({ ts: new Date().toISOString(), tool, transport: 'stdio', ...details }) + '\n';
75
+ await fs.appendFile(auditPath, line).catch(() => { });
76
+ try {
77
+ const content = await fs.readFile(auditPath, 'utf8').catch(() => '');
78
+ const lines = content.split('\n').filter(Boolean);
79
+ if (lines.length > MAX_AUDIT_LINES) {
80
+ await fs.writeFile(auditPath, lines.slice(-Math.floor(MAX_AUDIT_LINES * 0.8)).join('\n') + '\n').catch(() => { });
81
+ }
82
+ }
83
+ catch { }
84
+ }
85
+ catch { }
86
+ }
87
+ const server = new McpServer({ name: `hoolix-${slug}`, version: '1.0.0' });
88
+ // ── search_documentation ─────────────────────────────────────────────────
89
+ server.registerTool('search_documentation', {
90
+ description: 'Search the docs (keyword + optional hybrid semantic via BGE). Supports mode (keyword|semantic|hybrid), plus advanced tuning (alpha, reranker=rrf). Always includes Source URLs.',
91
+ inputSchema: z.object({
92
+ query: z.string().min(2).describe('Natural language or keyword query'),
93
+ limit: z.number().int().min(1).max(20).default(8),
94
+ mode: z.enum(['semantic', 'keyword', 'hybrid']).default('hybrid'),
95
+ maxTokens: z.number().int().min(500).max(12000).optional(),
96
+ contextWindowTokens: z.number().int().min(1000).max(1000000).optional(),
97
+ }),
98
+ }, async (args) => {
99
+ const { query, limit, mode } = args || {};
100
+ try {
101
+ return await withToolTimeout('search_documentation', (async () => {
102
+ const results = await rag.search(query, { limit, mode });
103
+ await audit('search_documentation', { query: String(query).slice(0, 120), limit, mode, hits: results.length });
104
+ let formatted = results
105
+ .map((r, i) => `[${i + 1}] ${r.metadata.title || r.metadata.url}\n${r.content}\n${formatResultSource(r.metadata)}\n`)
106
+ .join('\n---\n');
107
+ formatted = truncateToTokenBudget(formatted, tokenBudget(args, 4500));
108
+ return { content: [{ type: 'text', text: formatted || 'No relevant documentation found.' }] };
109
+ })());
110
+ }
111
+ catch (e) {
112
+ await audit('tool_error', { toolName: 'search_documentation', reason: e?.message || String(e) });
113
+ return toolErrorResponse(e?.message || 'search_documentation failed. Next: retry with a narrower query.');
114
+ }
115
+ });
116
+ // ── read_documentation_page ──────────────────────────────────────────────
117
+ server.registerTool('read_documentation_page', {
118
+ description: 'Retrieve the full content of a specific documentation page by its URL or path.',
119
+ inputSchema: z.object({
120
+ urlOrPath: z.string().describe('URL or path fragment to read'),
121
+ maxChunks: z.number().int().min(1).max(30).default(15),
122
+ maxTokens: z.number().int().min(500).max(20000).optional(),
123
+ contextWindowTokens: z.number().int().min(1000).max(1000000).optional(),
124
+ }),
125
+ }, async (args) => {
126
+ const { urlOrPath, maxChunks } = args || {};
127
+ try {
128
+ return await withToolTimeout('read_documentation_page', (async () => {
129
+ const page = await rag.readPage(urlOrPath, maxChunks);
130
+ if (!page) {
131
+ await audit('read_documentation_page', { urlOrPath: String(urlOrPath).slice(0, 200), found: false });
132
+ return { content: [{ type: 'text', text: `Page not found: ${urlOrPath}` }] };
133
+ }
134
+ await audit('read_documentation_page', { urlOrPath: String(urlOrPath).slice(0, 200), found: true, chunks: page.chunks?.length || 0 });
135
+ const text = `# ${page.title}\n\nSource: ${page.url}${meta?.definition?.template ? `\nTemplate: ${meta.definition.template.name}` : ''}\n\n${page.content}`;
136
+ return { content: [{ type: 'text', text: truncateToTokenBudget(text, tokenBudget(args, 7000)) }] };
137
+ })());
138
+ }
139
+ catch (e) {
140
+ await audit('tool_error', { toolName: 'read_documentation_page', reason: e?.message || String(e) });
141
+ return toolErrorResponse(e?.message || 'read_documentation_page failed. Next: retry with a smaller maxChunks value.');
142
+ }
143
+ });
144
+ // ── get_table_of_contents ────────────────────────────────────────────────
145
+ server.registerTool('get_table_of_contents', { description: 'Returns a reconstructed table of contents / outline of the entire documentation set.' }, async () => {
146
+ try {
147
+ return await withToolTimeout('get_table_of_contents', (async () => {
148
+ const toc = await rag.getTableOfContents();
149
+ await audit('get_table_of_contents', { entries: toc.length });
150
+ const text = toc
151
+ .map((item) => `${' '.repeat(item.level - 1)}- ${item.title}${item.url ? `\n${' '.repeat(item.level)}Source: ${item.url}` : ''}`)
152
+ .join('\n');
153
+ return { content: [{ type: 'text', text: text || 'No table of contents available.' }] };
154
+ })());
155
+ }
156
+ catch (e) {
157
+ await audit('tool_error', { toolName: 'get_table_of_contents', reason: e?.message || String(e) });
158
+ return toolErrorResponse(e?.message || 'get_table_of_contents failed. Next: retry after reindexing this server.');
159
+ }
160
+ });
161
+ const transport = new StdioServerTransport();
162
+ await server.connect(transport);
163
+ // Graceful shutdown
164
+ const shutdown = () => {
165
+ logger.info(`stdio MCP server for "${slug}" shutting down`);
166
+ process.exit(0);
167
+ };
168
+ process.on('SIGTERM', shutdown);
169
+ process.on('SIGINT', shutdown);
170
+ logger.info(`stdio MCP server ready for "${slug}" — waiting for client on stdin`);
171
+ // Keep the process alive by holding open stdin (the transport manages stdin internally,
172
+ // but we need to prevent Node from exiting when there's no other work).
173
+ await new Promise(() => { });
174
+ }
175
+ //# sourceMappingURL=stdio-host.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stdio-host.js","sourceRoot":"","sources":["../../src/mcp/stdio-host.ts"],"names":[],"mappings":"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"}