browser-devtools-mcp 0.1.7 → 0.2.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.
- package/LICENSE +93 -21
- package/README.md +93 -16
- package/dist/cli.js +53 -1721
- package/dist/core.js +764 -0
- package/dist/daemon-server.js +1 -338
- package/dist/index.d.ts +2 -0
- package/dist/index.js +210 -80
- package/dist/otel/otel-initializer.bundle.js +0 -1
- package/dist/tools/a11y/index.d.ts +2 -0
- package/dist/tools/content/index.d.ts +2 -0
- package/dist/tools/debug/index.d.ts +2 -0
- package/dist/tools/figma/compare/index.d.ts +56 -0
- package/dist/tools/figma/compare/types.d.ts +15 -0
- package/dist/tools/figma/index.d.ts +2 -0
- package/dist/tools/index.d.ts +4 -0
- package/dist/tools/interaction/index.d.ts +2 -0
- package/dist/tools/navigation/index.d.ts +2 -0
- package/dist/tools/o11y/index.d.ts +2 -0
- package/dist/tools/react/index.d.ts +2 -0
- package/dist/tools/run/index.d.ts +2 -0
- package/dist/tools/stub/index.d.ts +2 -0
- package/dist/tools/sync/index.d.ts +2 -0
- package/dist/tools/types.d.ts +21 -0
- package/dist/types.d.ts +78 -0
- package/package.json +11 -11
- package/dist/browser.js +0 -213
- package/dist/browser.js.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/config.js +0 -96
- package/dist/config.js.map +0 -1
- package/dist/context.js +0 -298
- package/dist/context.js.map +0 -1
- package/dist/daemon-server.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/logger.js +0 -97
- package/dist/logger.js.map +0 -1
- package/dist/mcp-server.js +0 -401
- package/dist/mcp-server.js.map +0 -1
- package/dist/otel/otel-controller.js +0 -323
- package/dist/otel/otel-controller.js.map +0 -1
- package/dist/otel/otel-initializer.bundle.js.map +0 -7
- package/dist/otel/otel-proxy.js +0 -407
- package/dist/otel/otel-proxy.js.map +0 -1
- package/dist/server-info.js +0 -186
- package/dist/server-info.js.map +0 -1
- package/dist/tools/a11y/index.js +0 -7
- package/dist/tools/a11y/index.js.map +0 -1
- package/dist/tools/a11y/take-aria-snapshot.js +0 -54
- package/dist/tools/a11y/take-aria-snapshot.js.map +0 -1
- package/dist/tools/a11y/take-ax-tree-snapshot.js +0 -850
- package/dist/tools/a11y/take-ax-tree-snapshot.js.map +0 -1
- package/dist/tools/content/get-as-html.js +0 -164
- package/dist/tools/content/get-as-html.js.map +0 -1
- package/dist/tools/content/get-as-text.js +0 -76
- package/dist/tools/content/get-as-text.js.map +0 -1
- package/dist/tools/content/index.js +0 -14
- package/dist/tools/content/index.js.map +0 -1
- package/dist/tools/content/save-as-pdf.js +0 -119
- package/dist/tools/content/save-as-pdf.js.map +0 -1
- package/dist/tools/content/take-screenshot.js +0 -297
- package/dist/tools/content/take-screenshot.js.map +0 -1
- package/dist/tools/figma/compare/compare-image-embedding.js +0 -159
- package/dist/tools/figma/compare/compare-image-embedding.js.map +0 -1
- package/dist/tools/figma/compare/compare-mssim.js +0 -98
- package/dist/tools/figma/compare/compare-mssim.js.map +0 -1
- package/dist/tools/figma/compare/compare-text-embedding.js +0 -291
- package/dist/tools/figma/compare/compare-text-embedding.js.map +0 -1
- package/dist/tools/figma/compare/index.js +0 -139
- package/dist/tools/figma/compare/index.js.map +0 -1
- package/dist/tools/figma/compare/types.js +0 -3
- package/dist/tools/figma/compare/types.js.map +0 -1
- package/dist/tools/figma/compare/vector.js +0 -46
- package/dist/tools/figma/compare/vector.js.map +0 -1
- package/dist/tools/figma/compare-page-with-design.js +0 -240
- package/dist/tools/figma/compare-page-with-design.js.map +0 -1
- package/dist/tools/figma/figma-service.js +0 -134
- package/dist/tools/figma/figma-service.js.map +0 -1
- package/dist/tools/figma/index.js +0 -6
- package/dist/tools/figma/index.js.map +0 -1
- package/dist/tools/index.js +0 -41
- package/dist/tools/index.js.map +0 -1
- package/dist/tools/interaction/click.js +0 -29
- package/dist/tools/interaction/click.js.map +0 -1
- package/dist/tools/interaction/drag.js +0 -41
- package/dist/tools/interaction/drag.js.map +0 -1
- package/dist/tools/interaction/fill.js +0 -28
- package/dist/tools/interaction/fill.js.map +0 -1
- package/dist/tools/interaction/hover.js +0 -29
- package/dist/tools/interaction/hover.js.map +0 -1
- package/dist/tools/interaction/index.js +0 -24
- package/dist/tools/interaction/index.js.map +0 -1
- package/dist/tools/interaction/press-key.js +0 -99
- package/dist/tools/interaction/press-key.js.map +0 -1
- package/dist/tools/interaction/resize-viewport.js +0 -110
- package/dist/tools/interaction/resize-viewport.js.map +0 -1
- package/dist/tools/interaction/resize-window.js +0 -261
- package/dist/tools/interaction/resize-window.js.map +0 -1
- package/dist/tools/interaction/scroll.js +0 -304
- package/dist/tools/interaction/scroll.js.map +0 -1
- package/dist/tools/interaction/select.js +0 -30
- package/dist/tools/interaction/select.js.map +0 -1
- package/dist/tools/navigation/go-back.js +0 -76
- package/dist/tools/navigation/go-back.js.map +0 -1
- package/dist/tools/navigation/go-forward.js +0 -76
- package/dist/tools/navigation/go-forward.js.map +0 -1
- package/dist/tools/navigation/go-to.js +0 -80
- package/dist/tools/navigation/go-to.js.map +0 -1
- package/dist/tools/navigation/index.js +0 -14
- package/dist/tools/navigation/index.js.map +0 -1
- package/dist/tools/navigation/reload.js +0 -76
- package/dist/tools/navigation/reload.js.map +0 -1
- package/dist/tools/o11y/get-console-messages.js +0 -151
- package/dist/tools/o11y/get-console-messages.js.map +0 -1
- package/dist/tools/o11y/get-http-requests.js +0 -216
- package/dist/tools/o11y/get-http-requests.js.map +0 -1
- package/dist/tools/o11y/get-trace-id.js +0 -30
- package/dist/tools/o11y/get-trace-id.js.map +0 -1
- package/dist/tools/o11y/get-web-vitals.js +0 -595
- package/dist/tools/o11y/get-web-vitals.js.map +0 -1
- package/dist/tools/o11y/index.js +0 -18
- package/dist/tools/o11y/index.js.map +0 -1
- package/dist/tools/o11y/new-trace-id.js +0 -32
- package/dist/tools/o11y/new-trace-id.js.map +0 -1
- package/dist/tools/o11y/set-trace-id.js +0 -28
- package/dist/tools/o11y/set-trace-id.js.map +0 -1
- package/dist/tools/react/get-component-for-element.js +0 -941
- package/dist/tools/react/get-component-for-element.js.map +0 -1
- package/dist/tools/react/get-element-for-component.js +0 -1190
- package/dist/tools/react/get-element-for-component.js.map +0 -1
- package/dist/tools/react/index.js +0 -10
- package/dist/tools/react/index.js.map +0 -1
- package/dist/tools/run/index.js +0 -7
- package/dist/tools/run/index.js.map +0 -1
- package/dist/tools/run/js-in-browser.js +0 -51
- package/dist/tools/run/js-in-browser.js.map +0 -1
- package/dist/tools/run/js-in-sandbox.js +0 -175
- package/dist/tools/run/js-in-sandbox.js.map +0 -1
- package/dist/tools/stub/clear.js +0 -41
- package/dist/tools/stub/clear.js.map +0 -1
- package/dist/tools/stub/index.js +0 -14
- package/dist/tools/stub/index.js.map +0 -1
- package/dist/tools/stub/intercept-http-request.js +0 -112
- package/dist/tools/stub/intercept-http-request.js.map +0 -1
- package/dist/tools/stub/list.js +0 -75
- package/dist/tools/stub/list.js.map +0 -1
- package/dist/tools/stub/mock-http-response.js +0 -152
- package/dist/tools/stub/mock-http-response.js.map +0 -1
- package/dist/tools/stub/stub-controller.js +0 -284
- package/dist/tools/stub/stub-controller.js.map +0 -1
- package/dist/tools/sync/index.js +0 -6
- package/dist/tools/sync/index.js.map +0 -1
- package/dist/tools/sync/wait-for-network-idle.js +0 -152
- package/dist/tools/sync/wait-for-network-idle.js.map +0 -1
- package/dist/tools/tool-executor.js +0 -79
- package/dist/tools/tool-executor.js.map +0 -1
- package/dist/tools/types.js +0 -3
- package/dist/tools/types.js.map +0 -1
- package/dist/types.js +0 -55
- package/dist/types.js.map +0 -1
- package/dist/utils/cli-utils.js +0 -253
- package/dist/utils/cli-utils.js.map +0 -1
- package/dist/utils.js +0 -85
- package/dist/utils.js.map +0 -1
package/dist/daemon-server.js
CHANGED
|
@@ -1,338 +1 @@
|
|
|
1
|
-
"use
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.startDaemonHTTPServer = startDaemonHTTPServer;
|
|
37
|
-
const config = __importStar(require("./config"));
|
|
38
|
-
const logger = __importStar(require("./logger"));
|
|
39
|
-
const tools_1 = require("./tools");
|
|
40
|
-
const node_server_1 = require("@hono/node-server");
|
|
41
|
-
const hono_1 = require("hono");
|
|
42
|
-
const cors_1 = require("hono/cors");
|
|
43
|
-
const zod_1 = require("zod");
|
|
44
|
-
let daemonStartTime = 0;
|
|
45
|
-
let daemonPort = 0;
|
|
46
|
-
const app = new hono_1.Hono();
|
|
47
|
-
const sessions = new Map();
|
|
48
|
-
const DEFAULT_SESSION_ID = '#default';
|
|
49
|
-
const ERRORS = {
|
|
50
|
-
get sessionNotFound() {
|
|
51
|
-
return _buildErrorResponse(404, 'Session Not Found');
|
|
52
|
-
},
|
|
53
|
-
get toolNotFound() {
|
|
54
|
-
return _buildErrorResponse(404, 'Tool Not Found');
|
|
55
|
-
},
|
|
56
|
-
get internalServerError() {
|
|
57
|
-
return _buildErrorResponse(500, 'Internal Server Error');
|
|
58
|
-
},
|
|
59
|
-
};
|
|
60
|
-
function _buildErrorResponse(code, message) {
|
|
61
|
-
return {
|
|
62
|
-
error: {
|
|
63
|
-
code: code,
|
|
64
|
-
message: message,
|
|
65
|
-
},
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
async function _closeSession(session) {
|
|
69
|
-
session.closed = true;
|
|
70
|
-
if (session.context) {
|
|
71
|
-
try {
|
|
72
|
-
await session.context.close();
|
|
73
|
-
logger.debug('Closed MCP session context');
|
|
74
|
-
}
|
|
75
|
-
catch (err) {
|
|
76
|
-
logger.error('Error occurred while closing MCP session context', err);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
sessions.delete(session.id);
|
|
80
|
-
}
|
|
81
|
-
function _createSession(ctx, sessionId) {
|
|
82
|
-
const now = Date.now();
|
|
83
|
-
const session = {
|
|
84
|
-
id: sessionId,
|
|
85
|
-
toolExecutor: new tools_1.ToolExecutor(() => sessionId),
|
|
86
|
-
closed: false,
|
|
87
|
-
createdAt: now,
|
|
88
|
-
lastActiveAt: now,
|
|
89
|
-
};
|
|
90
|
-
logger.debug(`Created session with id ${sessionId}`);
|
|
91
|
-
return session;
|
|
92
|
-
}
|
|
93
|
-
function _getSessionInfo(session) {
|
|
94
|
-
const now = Date.now();
|
|
95
|
-
return {
|
|
96
|
-
id: session.id,
|
|
97
|
-
createdAt: session.createdAt,
|
|
98
|
-
lastActiveAt: session.lastActiveAt,
|
|
99
|
-
idleSeconds: Math.floor((now - session.lastActiveAt) / 1000),
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
async function _getSession(ctx) {
|
|
103
|
-
const sessionId = ctx.req.header('session-id') || DEFAULT_SESSION_ID;
|
|
104
|
-
return sessions.get(sessionId);
|
|
105
|
-
}
|
|
106
|
-
async function _getOrCreateSession(ctx) {
|
|
107
|
-
const sessionId = ctx.req.header('session-id') || DEFAULT_SESSION_ID;
|
|
108
|
-
let session = sessions.get(sessionId);
|
|
109
|
-
if (session) {
|
|
110
|
-
logger.debug(`Reusing session with id ${sessionId}`);
|
|
111
|
-
}
|
|
112
|
-
else {
|
|
113
|
-
logger.debug(`No session could be found with id ${sessionId}`);
|
|
114
|
-
session = _createSession(ctx, sessionId);
|
|
115
|
-
sessions.set(sessionId, session);
|
|
116
|
-
}
|
|
117
|
-
return session;
|
|
118
|
-
}
|
|
119
|
-
function _scheduleIdleSessionCheck() {
|
|
120
|
-
let noActiveSession = false;
|
|
121
|
-
const sessionCheck = () => {
|
|
122
|
-
const currentTime = Date.now();
|
|
123
|
-
if (noActiveSession && sessions.size === 0) {
|
|
124
|
-
// There is no active session from last check and still there is no active session
|
|
125
|
-
logger.info('No active session found, so terminating daemon server');
|
|
126
|
-
process.exit(0);
|
|
127
|
-
}
|
|
128
|
-
for (const [sessionId, session] of sessions) {
|
|
129
|
-
logger.debug(`Checking whether session with id ${sessionId} is idle or not ...`);
|
|
130
|
-
if (currentTime - session.lastActiveAt >
|
|
131
|
-
config.DAEMON_SESSION_IDLE_SECONDS * 1000) {
|
|
132
|
-
logger.debug(`Session with id ${sessionId} is idle, so it will be closing ...`);
|
|
133
|
-
_closeSession(session)
|
|
134
|
-
.then(() => {
|
|
135
|
-
logger.debug(`Session with id ${sessionId} was idle, so it has been closed`);
|
|
136
|
-
})
|
|
137
|
-
.catch((err) => {
|
|
138
|
-
logger.error(`Unable to delete idle session with id ${sessionId}`, err);
|
|
139
|
-
});
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
noActiveSession = sessions.size === 0;
|
|
143
|
-
};
|
|
144
|
-
setInterval(sessionCheck, config.DAEMON_SESSION_IDLE_CHECK_SECONDS * 1000);
|
|
145
|
-
}
|
|
146
|
-
async function _logRequest(ctx) {
|
|
147
|
-
const reqClone = ctx.req.raw.clone();
|
|
148
|
-
logger.debug(`Got request: ${await reqClone.json()}`);
|
|
149
|
-
}
|
|
150
|
-
async function startDaemonHTTPServer(port) {
|
|
151
|
-
const toolMap = Object.fromEntries(tools_1.tools.map((tool) => [tool.name(), tool]));
|
|
152
|
-
// Global CORS
|
|
153
|
-
app.use('*', (0, cors_1.cors)({
|
|
154
|
-
origin: '*',
|
|
155
|
-
allowMethods: ['GET', 'POST', 'DELETE', 'OPTIONS'],
|
|
156
|
-
allowHeaders: ['Content-Type', 'Authorization', 'session-id'],
|
|
157
|
-
}));
|
|
158
|
-
// Store daemon port and start time
|
|
159
|
-
daemonPort = port;
|
|
160
|
-
daemonStartTime = Date.now();
|
|
161
|
-
// Graceful shutdown handler
|
|
162
|
-
const gracefulShutdown = async (signal) => {
|
|
163
|
-
logger.info(`Received ${signal}, initiating graceful shutdown...`);
|
|
164
|
-
// Close all sessions
|
|
165
|
-
const closePromises = [];
|
|
166
|
-
for (const session of sessions.values()) {
|
|
167
|
-
closePromises.push(_closeSession(session));
|
|
168
|
-
}
|
|
169
|
-
await Promise.allSettled(closePromises);
|
|
170
|
-
logger.info('All sessions closed, exiting...');
|
|
171
|
-
process.exit(0);
|
|
172
|
-
};
|
|
173
|
-
process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
|
|
174
|
-
process.on('SIGINT', () => gracefulShutdown('SIGINT'));
|
|
175
|
-
// Handle uncaught errors to prevent crashes
|
|
176
|
-
process.on('uncaughtException', (err) => {
|
|
177
|
-
logger.error('Uncaught exception', err);
|
|
178
|
-
});
|
|
179
|
-
process.on('unhandledRejection', (reason) => {
|
|
180
|
-
logger.error('Unhandled rejection', reason);
|
|
181
|
-
});
|
|
182
|
-
// MCP Health
|
|
183
|
-
app.get('/health', (ctx) => ctx.json({ status: 'ok' }));
|
|
184
|
-
// Daemon info
|
|
185
|
-
app.get('/info', (ctx) => {
|
|
186
|
-
const info = {
|
|
187
|
-
version: require('../package.json').version,
|
|
188
|
-
uptime: Math.floor((Date.now() - daemonStartTime) / 1000),
|
|
189
|
-
sessionCount: sessions.size,
|
|
190
|
-
port: daemonPort,
|
|
191
|
-
};
|
|
192
|
-
return ctx.json(info);
|
|
193
|
-
});
|
|
194
|
-
// List all sessions
|
|
195
|
-
app.get('/sessions', (ctx) => {
|
|
196
|
-
const sessionList = [];
|
|
197
|
-
for (const session of sessions.values()) {
|
|
198
|
-
sessionList.push(_getSessionInfo(session));
|
|
199
|
-
}
|
|
200
|
-
return ctx.json({ sessions: sessionList });
|
|
201
|
-
});
|
|
202
|
-
// Get session info
|
|
203
|
-
app.get('/session', async (ctx) => {
|
|
204
|
-
const session = await _getSession(ctx);
|
|
205
|
-
if (!session) {
|
|
206
|
-
return ctx.json(ERRORS.sessionNotFound, 404);
|
|
207
|
-
}
|
|
208
|
-
return ctx.json(_getSessionInfo(session));
|
|
209
|
-
});
|
|
210
|
-
// Shutdown daemon server
|
|
211
|
-
app.post('/shutdown', async (ctx) => {
|
|
212
|
-
logger.info('Shutdown request received, closing all sessions...');
|
|
213
|
-
// Close all sessions
|
|
214
|
-
const closePromises = [];
|
|
215
|
-
for (const session of sessions.values()) {
|
|
216
|
-
closePromises.push(_closeSession(session));
|
|
217
|
-
}
|
|
218
|
-
await Promise.allSettled(closePromises);
|
|
219
|
-
logger.info('All sessions closed, shutting down daemon server...');
|
|
220
|
-
// Schedule process exit after response is sent
|
|
221
|
-
setTimeout(() => {
|
|
222
|
-
process.exit(0);
|
|
223
|
-
}, 500);
|
|
224
|
-
return ctx.json({ status: 'shutting_down' }, 200);
|
|
225
|
-
});
|
|
226
|
-
// Call message
|
|
227
|
-
app.post('/call', async (ctx) => {
|
|
228
|
-
try {
|
|
229
|
-
if (logger.isDebugEnabled()) {
|
|
230
|
-
await _logRequest(ctx);
|
|
231
|
-
}
|
|
232
|
-
const session = await _getOrCreateSession(ctx);
|
|
233
|
-
session.lastActiveAt = Date.now();
|
|
234
|
-
const toolCallRequest = (await ctx.req.json());
|
|
235
|
-
const tool = toolMap[toolCallRequest.toolName];
|
|
236
|
-
if (!tool) {
|
|
237
|
-
return ctx.json(ERRORS.toolNotFound, 404);
|
|
238
|
-
}
|
|
239
|
-
let toolInput;
|
|
240
|
-
try {
|
|
241
|
-
const schema = zod_1.z.object(tool.inputSchema());
|
|
242
|
-
toolInput = schema.parse(toolCallRequest.toolInput);
|
|
243
|
-
}
|
|
244
|
-
catch (err) {
|
|
245
|
-
// Return validation error with details
|
|
246
|
-
const errorMessage = err.errors && Array.isArray(err.errors)
|
|
247
|
-
? err.errors
|
|
248
|
-
.map((e) => `${e.path?.join('.') || 'input'}: ${e.message}`)
|
|
249
|
-
.join('; ')
|
|
250
|
-
: 'Invalid tool input';
|
|
251
|
-
return ctx.json(_buildErrorResponse(400, `Invalid Tool Request: ${errorMessage}`), 400);
|
|
252
|
-
}
|
|
253
|
-
try {
|
|
254
|
-
const toolOutput = await session.toolExecutor.executeTool(tool, toolInput);
|
|
255
|
-
const toolCallResponse = {
|
|
256
|
-
toolOutput,
|
|
257
|
-
};
|
|
258
|
-
return ctx.json(toolCallResponse, 200);
|
|
259
|
-
}
|
|
260
|
-
catch (err) {
|
|
261
|
-
const toolCallResponse = {
|
|
262
|
-
toolError: {
|
|
263
|
-
code: err.code,
|
|
264
|
-
message: err.message,
|
|
265
|
-
},
|
|
266
|
-
};
|
|
267
|
-
return ctx.json(toolCallResponse, 500);
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
catch (err) {
|
|
271
|
-
logger.error('Error occurred while handling tool call request', err);
|
|
272
|
-
return ctx.json(ERRORS.internalServerError, 500);
|
|
273
|
-
}
|
|
274
|
-
});
|
|
275
|
-
// Delete session
|
|
276
|
-
app.delete('/session', async (ctx) => {
|
|
277
|
-
try {
|
|
278
|
-
const session = await _getSession(ctx);
|
|
279
|
-
if (!session) {
|
|
280
|
-
return ctx.json(ERRORS.sessionNotFound, 404);
|
|
281
|
-
}
|
|
282
|
-
await _closeSession(session);
|
|
283
|
-
return ctx.json({ ok: true }, 200);
|
|
284
|
-
}
|
|
285
|
-
catch (err) {
|
|
286
|
-
logger.error('Error occurred while deleting session', err);
|
|
287
|
-
return ctx.json(ERRORS.internalServerError, 500);
|
|
288
|
-
}
|
|
289
|
-
});
|
|
290
|
-
// Global error handler
|
|
291
|
-
app.onError((err, ctx) => {
|
|
292
|
-
logger.error('Unhandled error in request handler', err);
|
|
293
|
-
return ctx.json({
|
|
294
|
-
error: {
|
|
295
|
-
code: 500,
|
|
296
|
-
message: 'Internal Server Error',
|
|
297
|
-
},
|
|
298
|
-
}, 500);
|
|
299
|
-
});
|
|
300
|
-
// 404
|
|
301
|
-
app.notFound((ctx) => ctx.json({ error: 'Not Found', status: 404 }, 404));
|
|
302
|
-
// Listener for Node
|
|
303
|
-
(0, node_server_1.serve)({
|
|
304
|
-
fetch: app.fetch,
|
|
305
|
-
port,
|
|
306
|
-
}, () => logger.info(`Listening on port ${port}`));
|
|
307
|
-
// Schedule background task to check (and remove) idle sessions
|
|
308
|
-
_scheduleIdleSessionCheck();
|
|
309
|
-
}
|
|
310
|
-
// Main entry point when run directly
|
|
311
|
-
if (require.main === module) {
|
|
312
|
-
const { Command, InvalidOptionArgumentError, Option, } = require('commander');
|
|
313
|
-
function parsePort(value) {
|
|
314
|
-
const n = Number(value);
|
|
315
|
-
if (!Number.isInteger(n) || n < 1 || n > 65535) {
|
|
316
|
-
throw new InvalidOptionArgumentError('port must be an integer between 1 and 65535');
|
|
317
|
-
}
|
|
318
|
-
return n;
|
|
319
|
-
}
|
|
320
|
-
const program = new Command()
|
|
321
|
-
.addOption(new Option('--port <number>', 'port for daemon HTTP server')
|
|
322
|
-
.argParser(parsePort)
|
|
323
|
-
.default(config.DAEMON_PORT))
|
|
324
|
-
.allowUnknownOption()
|
|
325
|
-
.parse(process.argv);
|
|
326
|
-
const options = program.opts();
|
|
327
|
-
logger.enable();
|
|
328
|
-
logger.info('Starting daemon HTTP server...');
|
|
329
|
-
startDaemonHTTPServer(options.port)
|
|
330
|
-
.then(() => {
|
|
331
|
-
logger.info('Daemon HTTP server started');
|
|
332
|
-
})
|
|
333
|
-
.catch((err) => {
|
|
334
|
-
logger.error('Failed to start daemon HTTP server', err);
|
|
335
|
-
process.exit(1);
|
|
336
|
-
});
|
|
337
|
-
}
|
|
338
|
-
//# sourceMappingURL=daemon-server.js.map
|
|
1
|
+
import{A as C,C as y,D as u,E as c,F as d,G as I,H as D,a as t,x as T,y as b,z as E}from"./core.js";import{createRequire as N}from"module";import{Command as x,Option as _,InvalidOptionArgumentError as q}from"commander";import{serve as M}from"@hono/node-server";import{Hono as $}from"hono";import{cors as F}from"hono/cors";import{z as k}from"zod";var H=N(import.meta.url),A=0,R=0,i=new $,a=new Map,P="#default",p={get sessionNotFound(){return f(404,"Session Not Found")},get toolNotFound(){return f(404,"Tool Not Found")},get internalServerError(){return f(500,"Internal Server Error")}};function f(n,r){return{error:{code:n,message:r}}}t(f,"_buildErrorResponse");async function S(n){if(n.closed=!0,n.context)try{await n.context.close(),u("Closed MCP session context")}catch(r){d("Error occurred while closing MCP session context",r)}a.delete(n.id)}t(S,"_closeSession");function G(n,r){let s=Date.now(),e={id:r,toolExecutor:new I(()=>r),closed:!1,createdAt:s,lastActiveAt:s};return u(`Created session with id ${r}`),e}t(G,"_createSession");function j(n){let r=Date.now();return{id:n.id,createdAt:n.createdAt,lastActiveAt:n.lastActiveAt,idleSeconds:Math.floor((r-n.lastActiveAt)/1e3)}}t(j,"_getSessionInfo");async function O(n){let r=n.req.header("session-id")||P;return a.get(r)}t(O,"_getSession");async function L(n){let r=n.req.header("session-id")||P,s=a.get(r);return s?u(`Reusing session with id ${r}`):(u(`No session could be found with id ${r}`),s=G(n,r),a.set(r,s)),s}t(L,"_getOrCreateSession");function U(){let n=!1;setInterval(t(()=>{let s=Date.now();n&&a.size===0&&(c("No active session found, so terminating daemon server"),process.exit(0));for(let[e,o]of a)u(`Checking whether session with id ${e} is idle or not ...`),s-o.lastActiveAt>b*1e3&&(u(`Session with id ${e} is idle, so it will be closing ...`),S(o).then(()=>{u(`Session with id ${e} was idle, so it has been closed`)}).catch(l=>{d(`Unable to delete idle session with id ${e}`,l)}));n=a.size===0},"sessionCheck"),E*1e3)}t(U,"_scheduleIdleSessionCheck");async function z(n){let r=n.req.raw.clone();u(`Got request: ${await r.json()}`)}t(z,"_logRequest");async function W(n){let r=Object.fromEntries(D.map(e=>[e.name(),e]));i.use("*",F({origin:"*",allowMethods:["GET","POST","DELETE","OPTIONS"],allowHeaders:["Content-Type","Authorization","session-id"]})),R=n,A=Date.now();let s=t(async e=>{c(`Received ${e}, initiating graceful shutdown...`);let o=[];for(let l of a.values())o.push(S(l));await Promise.allSettled(o),c("All sessions closed, exiting..."),process.exit(0)},"gracefulShutdown");process.on("SIGTERM",()=>s("SIGTERM")),process.on("SIGINT",()=>s("SIGINT")),process.on("uncaughtException",e=>{d("Uncaught exception",e)}),process.on("unhandledRejection",e=>{d("Unhandled rejection",e)}),i.get("/health",e=>e.json({status:"ok"})),i.get("/info",e=>{let o={version:H("../package.json").version,uptime:Math.floor((Date.now()-A)/1e3),sessionCount:a.size,port:R};return e.json(o)}),i.get("/sessions",e=>{let o=[];for(let l of a.values())o.push(j(l));return e.json({sessions:o})}),i.get("/session",async e=>{let o=await O(e);return o?e.json(j(o)):e.json(p.sessionNotFound,404)}),i.post("/shutdown",async e=>{c("Shutdown request received, closing all sessions...");let o=[];for(let l of a.values())o.push(S(l));return await Promise.allSettled(o),c("All sessions closed, shutting down daemon server..."),setTimeout(()=>{process.exit(0)},500),e.json({status:"shutting_down"},200)}),i.post("/call",async e=>{try{y()&&await z(e);let o=await L(e);o.lastActiveAt=Date.now();let l=await e.req.json(),v=r[l.toolName];if(!v)return e.json(p.toolNotFound,404);let h;try{h=k.object(v.inputSchema()).parse(l.toolInput)}catch(g){let m=g.errors&&Array.isArray(g.errors)?g.errors.map(w=>`${w.path?.join(".")||"input"}: ${w.message}`).join("; "):"Invalid tool input";return e.json(f(400,`Invalid Tool Request: ${m}`),400)}try{let m={toolOutput:await o.toolExecutor.executeTool(v,h)};return e.json(m,200)}catch(g){let m={toolError:{code:g.code,message:g.message}};return e.json(m,500)}}catch(o){return d("Error occurred while handling tool call request",o),e.json(p.internalServerError,500)}}),i.delete("/session",async e=>{try{let o=await O(e);return o?(await S(o),e.json({ok:!0},200)):e.json(p.sessionNotFound,404)}catch(o){return d("Error occurred while deleting session",o),e.json(p.internalServerError,500)}}),i.onError((e,o)=>(d("Unhandled error in request handler",e),o.json({error:{code:500,message:"Internal Server Error"}},500))),i.notFound(e=>e.json({error:"Not Found",status:404},404)),M({fetch:i.fetch,port:n},()=>c(`Listening on port ${n}`)),U()}t(W,"startDaemonHTTPServer");var Z=import.meta.url===`file://${process.argv[1]}`||import.meta.url===`file://${process.argv[1]}.mjs`||process.argv[1]?.endsWith("daemon-server.js")||process.argv[1]?.endsWith("daemon-server.mjs");if(Z){let n=function(e){let o=Number(e);if(!Number.isInteger(o)||o<1||o>65535)throw new q("port must be an integer between 1 and 65535");return o};K=n,t(n,"parsePort");let s=new x().addOption(new _("--port <number>","port for daemon HTTP server").argParser(n).default(T)).allowUnknownOption().parse(process.argv).opts();C(),c("Starting daemon HTTP server..."),W(s.port).then(()=>{c("Daemon HTTP server started")}).catch(e=>{d("Failed to start daemon HTTP server",e),process.exit(1)})}var K;export{W as startDaemonHTTPServer};
|
package/dist/index.d.ts
ADDED