@darbotlabs/darbot-browser-mcp 0.2.0 → 1.3.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 +1 -1
- package/README.md +222 -161
- package/cli.js +1 -1
- package/config.d.ts +77 -1
- package/index.d.ts +1 -1
- package/index.js +1 -1
- package/lib/ai/context.js +150 -0
- package/lib/ai/guardrails.js +382 -0
- package/lib/ai/integration.js +397 -0
- package/lib/ai/intent.js +237 -0
- package/lib/ai/manualPromise.js +111 -0
- package/lib/ai/memory.js +273 -0
- package/lib/ai/ml-scorer.js +265 -0
- package/lib/ai/orchestrator-tools.js +292 -0
- package/lib/ai/orchestrator.js +473 -0
- package/lib/ai/planner.js +300 -0
- package/lib/ai/reporter.js +493 -0
- package/lib/ai/workflow.js +407 -0
- package/lib/auth/apiKeyAuth.js +46 -0
- package/lib/auth/entraAuth.js +110 -0
- package/lib/auth/entraJwtVerifier.js +117 -0
- package/lib/auth/index.js +210 -0
- package/lib/auth/managedIdentityAuth.js +175 -0
- package/lib/auth/mcpOAuthProvider.js +186 -0
- package/lib/auth/tunnelAuth.js +120 -0
- package/lib/browserContextFactory.js +1 -1
- package/lib/browserServer.js +1 -1
- package/lib/cdpRelay.js +2 -2
- package/lib/common.js +68 -0
- package/lib/config.js +62 -3
- package/lib/connection.js +1 -1
- package/lib/context.js +1 -1
- package/lib/fileUtils.js +1 -1
- package/lib/guardrails.js +382 -0
- package/lib/health.js +178 -0
- package/lib/httpServer.js +1 -1
- package/lib/index.js +1 -1
- package/lib/javascript.js +1 -1
- package/lib/manualPromise.js +1 -1
- package/lib/memory.js +273 -0
- package/lib/openapi.js +373 -0
- package/lib/orchestrator.js +473 -0
- package/lib/package.js +1 -1
- package/lib/pageSnapshot.js +17 -2
- package/lib/planner.js +302 -0
- package/lib/program.js +17 -5
- package/lib/reporter.js +493 -0
- package/lib/resources/resource.js +1 -1
- package/lib/server.js +5 -3
- package/lib/tab.js +1 -1
- package/lib/tools/ai-native.js +298 -0
- package/lib/tools/autonomous.js +147 -0
- package/lib/tools/clock.js +183 -0
- package/lib/tools/common.js +1 -1
- package/lib/tools/console.js +1 -1
- package/lib/tools/diagnostics.js +132 -0
- package/lib/tools/dialogs.js +1 -1
- package/lib/tools/emulation.js +155 -0
- package/lib/tools/files.js +1 -1
- package/lib/tools/install.js +1 -1
- package/lib/tools/keyboard.js +1 -1
- package/lib/tools/navigate.js +1 -1
- package/lib/tools/network.js +1 -1
- package/lib/tools/pageSnapshot.js +58 -0
- package/lib/tools/pdf.js +1 -1
- package/lib/tools/profiles.js +76 -25
- package/lib/tools/screenshot.js +1 -1
- package/lib/tools/scroll.js +93 -0
- package/lib/tools/snapshot.js +1 -1
- package/lib/tools/storage.js +328 -0
- package/lib/tools/tab.js +16 -0
- package/lib/tools/tabs.js +1 -1
- package/lib/tools/testing.js +1 -1
- package/lib/tools/tool.js +1 -1
- package/lib/tools/utils.js +1 -1
- package/lib/tools/vision.js +1 -1
- package/lib/tools/wait.js +1 -1
- package/lib/tools.js +22 -1
- package/lib/transport.js +251 -31
- package/package.json +28 -22
package/lib/transport.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Copyright (c)
|
|
2
|
+
* Copyright (c) DarbotLabs.
|
|
3
3
|
*
|
|
4
4
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
* you may not use this file except in compliance with the License.
|
|
@@ -16,10 +16,15 @@
|
|
|
16
16
|
import http from 'node:http';
|
|
17
17
|
import assert from 'node:assert';
|
|
18
18
|
import crypto from 'node:crypto';
|
|
19
|
+
import { execSync } from 'node:child_process';
|
|
19
20
|
import debug from 'debug';
|
|
21
|
+
import express from 'express';
|
|
20
22
|
import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
|
|
21
23
|
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
22
24
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
25
|
+
import { mcpAuthRouter } from '@modelcontextprotocol/sdk/server/auth/router.js';
|
|
26
|
+
import { createUnifiedAuthenticator } from './auth/index.js';
|
|
27
|
+
import { createMcpOAuthProvider, getOAuthConfig, isOAuthConfigured } from './auth/mcpOAuthProvider.js';
|
|
23
28
|
export async function startStdioTransport(server) {
|
|
24
29
|
await server.createConnection(new StdioServerTransport());
|
|
25
30
|
}
|
|
@@ -56,67 +61,282 @@ async function handleSSE(server, req, res, url, sessions) {
|
|
|
56
61
|
}
|
|
57
62
|
async function handleStreamable(server, req, res, sessions) {
|
|
58
63
|
const sessionId = req.headers['mcp-session-id'];
|
|
64
|
+
// If session ID provided, try to use existing session
|
|
59
65
|
if (sessionId) {
|
|
60
|
-
const
|
|
61
|
-
if (
|
|
62
|
-
|
|
63
|
-
res.end('Session not found');
|
|
64
|
-
return;
|
|
66
|
+
const existingTransport = sessions.get(sessionId);
|
|
67
|
+
if (existingTransport) {
|
|
68
|
+
return await existingTransport.handleRequest(req, res);
|
|
65
69
|
}
|
|
66
|
-
|
|
70
|
+
// Session not found (server may have restarted) - create new session for POST requests
|
|
71
|
+
// eslint-disable-next-line no-console
|
|
72
|
+
console.error(`[MCP] Session ${sessionId} not found, will create new session if POST request`);
|
|
67
73
|
}
|
|
74
|
+
// Handle POST requests - create new session (or recreate if old session expired)
|
|
68
75
|
if (req.method === 'POST') {
|
|
69
76
|
const transport = new StreamableHTTPServerTransport({
|
|
70
77
|
sessionIdGenerator: () => crypto.randomUUID(),
|
|
71
|
-
onsessioninitialized:
|
|
72
|
-
sessions.set(
|
|
78
|
+
onsessioninitialized: newSessionId => {
|
|
79
|
+
sessions.set(newSessionId, transport);
|
|
80
|
+
// eslint-disable-next-line no-console
|
|
81
|
+
console.error(`[MCP] New session created: ${newSessionId}`);
|
|
73
82
|
}
|
|
74
83
|
});
|
|
75
84
|
transport.onclose = () => {
|
|
76
|
-
if (transport.sessionId)
|
|
85
|
+
if (transport.sessionId) {
|
|
77
86
|
sessions.delete(transport.sessionId);
|
|
87
|
+
// eslint-disable-next-line no-console
|
|
88
|
+
console.error(`[MCP] Session closed: ${transport.sessionId}`);
|
|
89
|
+
}
|
|
78
90
|
};
|
|
79
91
|
await server.createConnection(transport);
|
|
80
92
|
await transport.handleRequest(req, res);
|
|
81
93
|
return;
|
|
82
94
|
}
|
|
83
|
-
|
|
84
|
-
|
|
95
|
+
// GET requests without valid session
|
|
96
|
+
if (req.method === 'GET') {
|
|
97
|
+
res.statusCode = 400;
|
|
98
|
+
res.setHeader('Content-Type', 'application/json');
|
|
99
|
+
res.end(JSON.stringify({
|
|
100
|
+
error: 'invalid_request',
|
|
101
|
+
message: 'GET requests require a valid session. Send a POST to /mcp first to initialize.',
|
|
102
|
+
}));
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
res.statusCode = 405;
|
|
106
|
+
res.setHeader('Content-Type', 'application/json');
|
|
107
|
+
res.end(JSON.stringify({
|
|
108
|
+
error: 'method_not_allowed',
|
|
109
|
+
message: 'Use POST to send MCP messages',
|
|
110
|
+
}));
|
|
111
|
+
}
|
|
112
|
+
async function killProcessOnPort(port) {
|
|
113
|
+
const isWindows = process.platform === 'win32';
|
|
114
|
+
try {
|
|
115
|
+
if (isWindows) {
|
|
116
|
+
// Find and kill process on Windows
|
|
117
|
+
const result = execSync(`netstat -ano | findstr ":${port}"`, { encoding: 'utf8' });
|
|
118
|
+
const lines = result.split('\n').filter(line => line.includes('LISTENING'));
|
|
119
|
+
const pidsToKill = new Set();
|
|
120
|
+
for (const line of lines) {
|
|
121
|
+
const parts = line.trim().split(/\s+/);
|
|
122
|
+
const pid = parts[parts.length - 1];
|
|
123
|
+
if (pid && /^\d+$/.test(pid) && pid !== '0')
|
|
124
|
+
pidsToKill.add(pid);
|
|
125
|
+
}
|
|
126
|
+
for (const pid of pidsToKill) {
|
|
127
|
+
// eslint-disable-next-line no-console
|
|
128
|
+
console.error(`Killing process ${pid} using port ${port}...`);
|
|
129
|
+
try {
|
|
130
|
+
execSync(`taskkill /F /PID ${pid}`, { stdio: 'pipe' });
|
|
131
|
+
}
|
|
132
|
+
catch (e) {
|
|
133
|
+
// Process may have already exited
|
|
134
|
+
if (!e.message?.includes('not found'))
|
|
135
|
+
throw e;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
// Find and kill process on Unix-like systems
|
|
141
|
+
const result = execSync(`lsof -ti:${port}`, { encoding: 'utf8' });
|
|
142
|
+
const pids = result.trim().split('\n').filter(Boolean);
|
|
143
|
+
for (const pid of pids) {
|
|
144
|
+
// eslint-disable-next-line no-console
|
|
145
|
+
console.error(`Killing process ${pid} using port ${port}...`);
|
|
146
|
+
try {
|
|
147
|
+
execSync(`kill -9 ${pid}`, { stdio: 'pipe' });
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
// Process may have already exited
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
// Wait for port to be released
|
|
155
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
85
161
|
}
|
|
86
162
|
export async function startHttpServer(config) {
|
|
87
163
|
const { host, port } = config;
|
|
88
|
-
|
|
89
|
-
|
|
164
|
+
// Create Express app
|
|
165
|
+
const app = express();
|
|
166
|
+
// Trust proxy for Azure App Service
|
|
167
|
+
app.set('trust proxy', 1);
|
|
168
|
+
// CORS middleware - must come before body parsers
|
|
169
|
+
app.use((req, res, next) => {
|
|
170
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
171
|
+
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, DELETE');
|
|
172
|
+
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-API-Key, Mcp-Session-Id, Accept');
|
|
173
|
+
if (req.method === 'OPTIONS') {
|
|
174
|
+
res.status(200).end();
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
next();
|
|
178
|
+
});
|
|
179
|
+
// Parse JSON bodies - but NOT for /mcp and /sse endpoints (MCP SDK handles its own body parsing)
|
|
180
|
+
app.use((req, res, next) => {
|
|
181
|
+
if (req.path === '/mcp' || req.path === '/sse') {
|
|
182
|
+
return next();
|
|
183
|
+
}
|
|
184
|
+
return express.json()(req, res, next);
|
|
185
|
+
});
|
|
186
|
+
// Setup OAuth router if configured
|
|
187
|
+
const oauthConfig = getOAuthConfig();
|
|
188
|
+
if (isOAuthConfigured() && oauthConfig) {
|
|
189
|
+
try {
|
|
190
|
+
const provider = createMcpOAuthProvider(oauthConfig);
|
|
191
|
+
const serverUrl = new URL(oauthConfig.serverBaseUrl);
|
|
192
|
+
const authRouter = mcpAuthRouter({
|
|
193
|
+
provider,
|
|
194
|
+
issuerUrl: serverUrl,
|
|
195
|
+
baseUrl: serverUrl,
|
|
196
|
+
serviceDocumentationUrl: new URL('https://github.com/AugustinMauworworworwy/darbot-browser-mcp'),
|
|
197
|
+
scopesSupported: ['openid', 'profile', 'email', 'User.Read'],
|
|
198
|
+
resourceName: 'Darbot Browser MCP',
|
|
199
|
+
});
|
|
200
|
+
// Mount OAuth router at root (handles /.well-known/*, /authorize, /token, /register)
|
|
201
|
+
app.use(authRouter);
|
|
202
|
+
// eslint-disable-next-line no-console
|
|
203
|
+
console.error('[OAuth] MCP OAuth router configured with Entra ID proxy');
|
|
204
|
+
}
|
|
205
|
+
catch (error) {
|
|
206
|
+
// eslint-disable-next-line no-console
|
|
207
|
+
console.error('[OAuth] Failed to setup OAuth router:', error);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
// Create HTTP server from Express app
|
|
211
|
+
const httpServer = http.createServer(app);
|
|
212
|
+
const tryListen = () => new Promise((resolve, reject) => {
|
|
90
213
|
httpServer.on('error', reject);
|
|
91
214
|
httpServer.listen(port, host, () => {
|
|
92
215
|
resolve();
|
|
93
216
|
httpServer.removeListener('error', reject);
|
|
94
217
|
});
|
|
95
218
|
});
|
|
96
|
-
|
|
219
|
+
try {
|
|
220
|
+
await tryListen();
|
|
221
|
+
}
|
|
222
|
+
catch (error) {
|
|
223
|
+
if (error.code === 'EADDRINUSE' && port !== undefined) {
|
|
224
|
+
// eslint-disable-next-line no-console
|
|
225
|
+
console.error(`Port ${port} is in use. Attempting to terminate conflicting service...`);
|
|
226
|
+
const killed = await killProcessOnPort(port);
|
|
227
|
+
if (killed) {
|
|
228
|
+
// Retry after killing
|
|
229
|
+
await tryListen();
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
throw new Error(`Port ${port} is already in use and could not terminate the conflicting process. Please free the port manually or use a different port.`);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
throw error;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
return { httpServer, app };
|
|
97
240
|
}
|
|
98
|
-
export function startHttpTransport(httpServer, mcpServer) {
|
|
241
|
+
export function startHttpTransport(httpServer, mcpServer, app) {
|
|
99
242
|
const sseSessions = new Map();
|
|
100
243
|
const streamableSessions = new Map();
|
|
101
|
-
|
|
244
|
+
// Use unified authenticator that supports multiple auth methods
|
|
245
|
+
const authenticator = createUnifiedAuthenticator();
|
|
246
|
+
// Initialize async auth providers (Managed Identity, Key Vault)
|
|
247
|
+
void authenticator.initialize().catch(err => {
|
|
248
|
+
// eslint-disable-next-line no-console
|
|
249
|
+
console.error('[Auth] Failed to initialize async auth providers:', err);
|
|
250
|
+
});
|
|
251
|
+
const enforceAuthIfEnabled = async (req, res) => {
|
|
252
|
+
// Check if any auth method is configured
|
|
253
|
+
if (!authenticator.isAuthEnabled())
|
|
254
|
+
return true;
|
|
255
|
+
const result = await authenticator.authenticate(req);
|
|
256
|
+
if (result.authenticated) {
|
|
257
|
+
// Attach user info to request
|
|
258
|
+
req.auth = result;
|
|
259
|
+
req.user = result.user;
|
|
260
|
+
return true;
|
|
261
|
+
}
|
|
262
|
+
// Return 401 with helpful error message
|
|
263
|
+
res.status(401).json({
|
|
264
|
+
error: 'unauthorized',
|
|
265
|
+
message: result.error || 'Valid authentication required.',
|
|
266
|
+
hint: 'Use Entra ID OAuth, VS Code tunnel, or Azure Managed Identity.',
|
|
267
|
+
});
|
|
268
|
+
return false;
|
|
269
|
+
};
|
|
270
|
+
// MCP Streamable HTTP endpoint - must be registered as Express route
|
|
271
|
+
// Cast to http types since Express extends them and MCP SDK needs the base types
|
|
272
|
+
app.all('/mcp', async (req, res) => {
|
|
273
|
+
if (!(await enforceAuthIfEnabled(req, res)))
|
|
274
|
+
return;
|
|
275
|
+
await handleStreamable(mcpServer, req, res, streamableSessions);
|
|
276
|
+
});
|
|
277
|
+
// SSE endpoint (legacy MCP transport)
|
|
278
|
+
app.all('/sse', async (req, res) => {
|
|
279
|
+
if (!(await enforceAuthIfEnabled(req, res)))
|
|
280
|
+
return;
|
|
102
281
|
const url = new URL(`http://localhost${req.url}`);
|
|
103
|
-
|
|
104
|
-
await handleStreamable(mcpServer, req, res, streamableSessions);
|
|
105
|
-
else
|
|
106
|
-
await handleSSE(mcpServer, req, res, url, sseSessions);
|
|
282
|
+
await handleSSE(mcpServer, req, res, url, sseSessions);
|
|
107
283
|
});
|
|
284
|
+
// Health check endpoints
|
|
285
|
+
app.get('/health', async (req, res) => {
|
|
286
|
+
try {
|
|
287
|
+
const { createHealthCheckService } = await import('./health.js');
|
|
288
|
+
const healthService = createHealthCheckService();
|
|
289
|
+
await healthService.handleHealthCheck(req, res);
|
|
290
|
+
}
|
|
291
|
+
catch {
|
|
292
|
+
res.status(500).send('Health check service unavailable');
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
app.get('/ready', async (req, res) => {
|
|
296
|
+
try {
|
|
297
|
+
const { createHealthCheckService } = await import('./health.js');
|
|
298
|
+
const healthService = createHealthCheckService();
|
|
299
|
+
await healthService.handleReadinessCheck(req, res);
|
|
300
|
+
}
|
|
301
|
+
catch {
|
|
302
|
+
res.status(503).send('Service unavailable');
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
app.get('/live', async (req, res) => {
|
|
306
|
+
try {
|
|
307
|
+
const { createHealthCheckService } = await import('./health.js');
|
|
308
|
+
const healthService = createHealthCheckService();
|
|
309
|
+
await healthService.handleLivenessCheck(req, res);
|
|
310
|
+
}
|
|
311
|
+
catch {
|
|
312
|
+
res.status(503).send('Service unavailable');
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
// OpenAPI specification endpoint
|
|
316
|
+
app.get(['/openapi.json', '/swagger.json'], async (req, res) => {
|
|
317
|
+
try {
|
|
318
|
+
const { createOpenAPIGenerator } = await import('./openapi.js');
|
|
319
|
+
const { snapshotTools } = await import('./tools.js');
|
|
320
|
+
const openApiGenerator = createOpenAPIGenerator(snapshotTools);
|
|
321
|
+
openApiGenerator.handleOpenAPISpec(req, res);
|
|
322
|
+
}
|
|
323
|
+
catch (error) {
|
|
324
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
325
|
+
res.status(500).json({ error: 'Failed to generate OpenAPI spec', message: errorMessage });
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
// Log server info
|
|
108
329
|
const url = httpAddressToString(httpServer.address());
|
|
109
330
|
const message = [
|
|
110
|
-
`
|
|
111
|
-
'
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
}
|
|
119
|
-
'If your client supports streamable HTTP, you can use the /mcp endpoint instead.',
|
|
331
|
+
`Darbot Browser MCP Server listening on ${url}`,
|
|
332
|
+
'',
|
|
333
|
+
'Available endpoints:',
|
|
334
|
+
` Health Check: ${url}/health`,
|
|
335
|
+
` Readiness: ${url}/ready`,
|
|
336
|
+
` Liveness: ${url}/live`,
|
|
337
|
+
` OpenAPI: ${url}/openapi.json`,
|
|
338
|
+
` MCP: ${url}/mcp`,
|
|
339
|
+
` SSE: ${url}/sse`,
|
|
120
340
|
].join('\n');
|
|
121
341
|
// eslint-disable-next-line no-console
|
|
122
342
|
console.error(message);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@darbotlabs/darbot-browser-mcp",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.3.0",
|
|
4
|
+
"description": "Darbot Browser - framework for 52 AI-driven browser tools with session state support and VS Code GitHub Copilot agent mode integration",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"browser",
|
|
14
14
|
"autonomous",
|
|
15
15
|
"darbot",
|
|
16
|
-
"automation",
|
|
16
|
+
"automation",
|
|
17
17
|
"testing",
|
|
18
18
|
"screenshot",
|
|
19
19
|
"copilot",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"selenium-alternative",
|
|
26
26
|
"browser-testing",
|
|
27
27
|
"accessibility",
|
|
28
|
-
"
|
|
28
|
+
"session-states",
|
|
29
29
|
"session-management",
|
|
30
30
|
"github-copilot",
|
|
31
31
|
"model-context-protocol",
|
|
@@ -34,10 +34,10 @@
|
|
|
34
34
|
"copilot-integration"
|
|
35
35
|
],
|
|
36
36
|
"engines": {
|
|
37
|
-
"node": ">=
|
|
37
|
+
"node": ">=23"
|
|
38
38
|
},
|
|
39
39
|
"author": {
|
|
40
|
-
"name": "
|
|
40
|
+
"name": "DarbotLabs"
|
|
41
41
|
},
|
|
42
42
|
"license": "Apache-2.0",
|
|
43
43
|
"scripts": {
|
|
@@ -45,8 +45,8 @@
|
|
|
45
45
|
"lint": "npm run update-readme && eslint . && tsc --noEmit",
|
|
46
46
|
"update-readme": "node utils/update-readme.js",
|
|
47
47
|
"watch": "tsc --watch",
|
|
48
|
-
"test": "npx
|
|
49
|
-
"test:msedge": "npx
|
|
48
|
+
"test": "npx playwright test",
|
|
49
|
+
"test:msedge": "npx playwright test --project=msedge",
|
|
50
50
|
"run-server": "node cli.js",
|
|
51
51
|
"run-darbot": "node cli.js",
|
|
52
52
|
"clean": "rmdir /s /q lib 2>nul || echo Clean completed",
|
|
@@ -62,31 +62,37 @@
|
|
|
62
62
|
}
|
|
63
63
|
},
|
|
64
64
|
"dependencies": {
|
|
65
|
-
"@
|
|
65
|
+
"@azure/identity": "^4.5.0",
|
|
66
|
+
"@azure/keyvault-secrets": "^4.9.0",
|
|
67
|
+
"@azure/msal-node": "^5.0.2",
|
|
68
|
+
"@modelcontextprotocol/sdk": "^1.25.3",
|
|
66
69
|
"commander": "^13.1.0",
|
|
67
|
-
"debug": "^4.4.
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
"playwright
|
|
71
|
-
"
|
|
72
|
-
"
|
|
70
|
+
"debug": "^4.4.3",
|
|
71
|
+
"express": "^4.21.2",
|
|
72
|
+
"mime": "^4.1.0",
|
|
73
|
+
"playwright": "^1.57.0",
|
|
74
|
+
"playwright-core": "^1.57.0",
|
|
75
|
+
"ws": "^8.19.0",
|
|
76
|
+
"zod": "^3.25.76",
|
|
77
|
+
"zod-to-json-schema": "^3.25.1"
|
|
73
78
|
},
|
|
74
79
|
"devDependencies": {
|
|
75
80
|
"@eslint/eslintrc": "^3.2.0",
|
|
76
|
-
"@eslint/js": "^9.
|
|
77
|
-
"@playwright/test": "1.
|
|
81
|
+
"@eslint/js": "^9.39.2",
|
|
82
|
+
"@playwright/test": "^1.57.0",
|
|
78
83
|
"@stylistic/eslint-plugin": "^3.0.1",
|
|
79
84
|
"@types/chrome": "^0.0.315",
|
|
80
85
|
"@types/debug": "^4.1.12",
|
|
81
|
-
"@types/
|
|
86
|
+
"@types/express": "^5.0.0",
|
|
87
|
+
"@types/node": "^25.0.10",
|
|
82
88
|
"@types/ws": "^8.18.1",
|
|
83
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
84
|
-
"@typescript-eslint/parser": "^8.
|
|
89
|
+
"@typescript-eslint/eslint-plugin": "^8.53.1",
|
|
90
|
+
"@typescript-eslint/parser": "^8.53.1",
|
|
85
91
|
"@typescript-eslint/utils": "^8.26.1",
|
|
86
|
-
"eslint": "^9.
|
|
92
|
+
"eslint": "^9.39.2",
|
|
87
93
|
"eslint-plugin-import": "^2.31.0",
|
|
88
94
|
"eslint-plugin-notice": "^1.0.0",
|
|
89
|
-
"typescript": "^5.
|
|
95
|
+
"typescript": "^5.9.3"
|
|
90
96
|
},
|
|
91
97
|
"bin": {
|
|
92
98
|
"darbot-browser-mcp": "cli.js"
|