mcp-accessibility-scanner 3.0.1 → 3.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/README.md +265 -12
- package/index.d.ts +1 -1
- package/lib/browserContextFactory.js +1161 -94
- package/lib/browserContextFactory.js.map +1 -1
- package/lib/browserServerBackend.js +199 -22
- package/lib/browserServerBackend.js.map +1 -1
- package/lib/browserSessions.js +172 -0
- package/lib/browserSessions.js.map +1 -0
- package/lib/config.js +48 -7
- package/lib/config.js.map +1 -1
- package/lib/context.js +321 -71
- package/lib/context.js.map +1 -1
- package/lib/extension/cdpRelay.js +5 -0
- package/lib/extension/cdpRelay.js.map +1 -1
- package/lib/extension/extensionContextFactory.js +12 -1
- package/lib/extension/extensionContextFactory.js.map +1 -1
- package/lib/index.js +5 -1
- package/lib/index.js.map +1 -1
- package/lib/mcp/http.js +194 -44
- package/lib/mcp/http.js.map +1 -1
- package/lib/mcp/inProcessTransport.js.map +1 -1
- package/lib/mcp/mdb.js +7 -9
- package/lib/mcp/mdb.js.map +1 -1
- package/lib/mcp/proxyBackend.js +76 -18
- package/lib/mcp/proxyBackend.js.map +1 -1
- package/lib/mcp/server.js +70 -41
- package/lib/mcp/server.js.map +1 -1
- package/lib/mcp/sharedClientSlot.js +134 -0
- package/lib/mcp/sharedClientSlot.js.map +1 -0
- package/lib/mcp/tool.js +3 -0
- package/lib/mcp/tool.js.map +1 -1
- package/lib/networkPolicy.js +73 -0
- package/lib/networkPolicy.js.map +1 -0
- package/lib/program.js +91 -12
- package/lib/program.js.map +1 -1
- package/lib/response.js +16 -3
- package/lib/response.js.map +1 -1
- package/lib/sessionLog.js +36 -6
- package/lib/sessionLog.js.map +1 -1
- package/lib/tab.js +149 -18
- package/lib/tab.js.map +1 -1
- package/lib/tools/auditKeyboard.js +204 -4
- package/lib/tools/auditKeyboard.js.map +1 -1
- package/lib/tools/auditScreenReader.js +823 -0
- package/lib/tools/auditScreenReader.js.map +1 -0
- package/lib/tools/auditSite.js +268 -90
- package/lib/tools/auditSite.js.map +1 -1
- package/lib/tools/axe.js +479 -21
- package/lib/tools/axe.js.map +1 -1
- package/lib/tools/dialogs.js +18 -4
- package/lib/tools/dialogs.js.map +1 -1
- package/lib/tools/evaluate.js +34 -5
- package/lib/tools/evaluate.js.map +1 -1
- package/lib/tools/network.js +136 -8
- package/lib/tools/network.js.map +1 -1
- package/lib/tools/pdf.js +5 -2
- package/lib/tools/pdf.js.map +1 -1
- package/lib/tools/scanPageMatrix.js +135 -47
- package/lib/tools/scanPageMatrix.js.map +1 -1
- package/lib/tools/screenshot.js +8 -4
- package/lib/tools/screenshot.js.map +1 -1
- package/lib/tools/session.js +53 -0
- package/lib/tools/session.js.map +1 -0
- package/lib/tools/snapshot.js +266 -8
- package/lib/tools/snapshot.js.map +1 -1
- package/lib/tools/tool.js.map +1 -1
- package/lib/tools/utils.js +62 -6
- package/lib/tools/utils.js.map +1 -1
- package/lib/tools.js +11 -2
- package/lib/tools.js.map +1 -1
- package/lib/utils/dataUrl.js +58 -35
- package/lib/utils/dataUrl.js.map +1 -1
- package/lib/utils/fileUtils.js +35 -0
- package/lib/utils/fileUtils.js.map +1 -1
- package/lib/utils/guid.js +8 -0
- package/lib/utils/guid.js.map +1 -1
- package/lib/utils/jsSource.js +187 -0
- package/lib/utils/jsSource.js.map +1 -0
- package/lib/vscode/browserContextFactory.js +87 -0
- package/lib/vscode/browserContextFactory.js.map +1 -0
- package/lib/vscode/host.js +189 -33
- package/lib/vscode/host.js.map +1 -1
- package/lib/vscode/main.js +3 -35
- package/lib/vscode/main.js.map +1 -1
- package/package.json +13 -9
package/lib/mcp/mdb.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mdb.js","sourceRoot":"","sources":["../../src/mcp/mdb.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"mdb.js","sourceRoot":"","sources":["../../src/mcp/mdb.ts"],"names":[],"mappings":"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"}
|
package/lib/mcp/proxyBackend.js
CHANGED
|
@@ -15,23 +15,38 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import debug from 'debug';
|
|
17
17
|
import { z } from 'zod';
|
|
18
|
-
import { Client } from '@modelcontextprotocol/
|
|
19
|
-
import { ListRootsRequestSchema, PingRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
18
|
+
import { Client } from '@modelcontextprotocol/client';
|
|
20
19
|
import { notifyToolListChanged } from './toolListChanged.js';
|
|
21
20
|
const errorsDebug = debug('pw:mcp:errors');
|
|
22
21
|
export class ProxyBackend {
|
|
23
22
|
_mcpProviders;
|
|
24
23
|
_currentClient;
|
|
24
|
+
// False when _currentClient is adopted from the shared slot: response
|
|
25
|
+
// cleanup (serverClosed) must not tear down a process-scoped client that
|
|
26
|
+
// later requests still route through.
|
|
27
|
+
_ownsCurrentClient = true;
|
|
25
28
|
_contextSwitchTool;
|
|
26
|
-
_roots = [];
|
|
27
29
|
_backendContext;
|
|
28
|
-
|
|
30
|
+
_sharedSelection;
|
|
31
|
+
constructor(mcpProviders, sharedSelection) {
|
|
29
32
|
this._mcpProviders = mcpProviders;
|
|
33
|
+
this._sharedSelection = sharedSelection;
|
|
30
34
|
this._contextSwitchTool = this._defineContextSwitchTool();
|
|
31
35
|
}
|
|
32
|
-
async initialize(context,
|
|
36
|
+
async initialize(context, _clientVersion) {
|
|
33
37
|
this._backendContext = context;
|
|
34
|
-
|
|
38
|
+
// A process-scoped browser_connect switch is in effect: adopt it instead
|
|
39
|
+
// of connecting the default provider, so the selection made in an earlier
|
|
40
|
+
// handshake-free request keeps governing this one. The adoption holds a
|
|
41
|
+
// lease on the shared client (released in serverClosed, or earlier when
|
|
42
|
+
// this request switches away), so a concurrent switch cannot close it
|
|
43
|
+
// under this request's in-flight calls.
|
|
44
|
+
const shared = this._sharedSelection?.slot.acquire();
|
|
45
|
+
if (shared) {
|
|
46
|
+
this._currentClient = shared;
|
|
47
|
+
this._ownsCurrentClient = false;
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
35
50
|
await this._setCurrentClient(this._mcpProviders[0], false);
|
|
36
51
|
}
|
|
37
52
|
async listTools() {
|
|
@@ -51,21 +66,30 @@ export class ProxyBackend {
|
|
|
51
66
|
name,
|
|
52
67
|
arguments: args,
|
|
53
68
|
_meta: requestContext?._meta,
|
|
54
|
-
},
|
|
69
|
+
}, progressToken === undefined ? undefined : {
|
|
55
70
|
onprogress: params => {
|
|
56
71
|
void this._forwardProgressNotification(requestContext, progressToken, params);
|
|
57
72
|
},
|
|
58
73
|
});
|
|
59
74
|
}
|
|
60
75
|
serverClosed() {
|
|
61
|
-
|
|
76
|
+
if (this._ownsCurrentClient)
|
|
77
|
+
void this._currentClient?.close().catch(errorsDebug);
|
|
78
|
+
else if (this._currentClient)
|
|
79
|
+
// Adopted from the shared slot: release the lease instead of closing —
|
|
80
|
+
// the slot closes the client once it is retired and fully drained.
|
|
81
|
+
void this._sharedSelection?.slot.release(this._currentClient);
|
|
62
82
|
}
|
|
63
83
|
async _callContextSwitchTool(params) {
|
|
64
84
|
try {
|
|
65
85
|
const factory = this._mcpProviders.find(factory => factory.name === params.name);
|
|
66
86
|
if (!factory)
|
|
67
87
|
throw new Error('Unknown connection method: ' + params.name);
|
|
68
|
-
|
|
88
|
+
factory.validate?.();
|
|
89
|
+
if (this._sharedSelection)
|
|
90
|
+
await this._switchSharedClient(factory.name);
|
|
91
|
+
else
|
|
92
|
+
await this._setCurrentClient(factory, true);
|
|
69
93
|
return {
|
|
70
94
|
content: [{ type: 'text', text: '### Result\nSuccessfully changed connection method.\n' }],
|
|
71
95
|
};
|
|
@@ -77,6 +101,41 @@ export class ProxyBackend {
|
|
|
77
101
|
};
|
|
78
102
|
}
|
|
79
103
|
}
|
|
104
|
+
// Stateless serving: publish the switch through the process-scoped slot so
|
|
105
|
+
// later per-request backends adopt it. The slot closes the previously
|
|
106
|
+
// shared client itself (exactly once, after the swap, once every adopting
|
|
107
|
+
// request has released it); only a client this request owned — its
|
|
108
|
+
// per-request default — is closed here.
|
|
109
|
+
async _switchSharedClient(name) {
|
|
110
|
+
const { slot, providers } = this._sharedSelection;
|
|
111
|
+
// The stateful-flavored list mirrors this._mcpProviders name-for-name;
|
|
112
|
+
// the name was already resolved and validated against the latter.
|
|
113
|
+
const provider = providers.find(factory => factory.name === name);
|
|
114
|
+
if (!provider)
|
|
115
|
+
throw new Error('Unknown connection method: ' + name);
|
|
116
|
+
const previousTools = await this._getExposedTools(this._currentClient).catch(() => undefined);
|
|
117
|
+
const previousOwned = this._ownsCurrentClient ? this._currentClient : undefined;
|
|
118
|
+
const previousShared = this._ownsCurrentClient ? undefined : this._currentClient;
|
|
119
|
+
const shared = await slot.replace(provider === providers[0] ? undefined : () => this._connectClient(provider));
|
|
120
|
+
if (shared) {
|
|
121
|
+
this._currentClient = shared;
|
|
122
|
+
this._ownsCurrentClient = false;
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
// Back to the default provider, which stateless serving runs
|
|
126
|
+
// per-request: finish this exchange on an owned per-request client.
|
|
127
|
+
this._currentClient = await this._connectClient(this._mcpProviders[0]);
|
|
128
|
+
this._ownsCurrentClient = true;
|
|
129
|
+
}
|
|
130
|
+
// This request no longer routes through the shared client it adopted;
|
|
131
|
+
// when it was the retiring client's last adopter, this runs the close
|
|
132
|
+
// the replace deferred. Only on success — a failed replace threw above,
|
|
133
|
+
// and the request keeps using its adopted client.
|
|
134
|
+
if (previousShared)
|
|
135
|
+
await slot.release(previousShared);
|
|
136
|
+
await previousOwned?.close().catch(errorsDebug);
|
|
137
|
+
await notifyToolListChanged(this._backendContext, previousTools, await this._getExposedTools(this._currentClient));
|
|
138
|
+
}
|
|
80
139
|
async _forwardProgressNotification(requestContext, progressToken, params) {
|
|
81
140
|
try {
|
|
82
141
|
await requestContext?.sendNotification({
|
|
@@ -112,18 +171,17 @@ export class ProxyBackend {
|
|
|
112
171
|
const previousTools = notifyOnChange ? await this._getExposedTools(this._currentClient).catch(() => undefined) : undefined;
|
|
113
172
|
await this._currentClient?.close();
|
|
114
173
|
this._currentClient = undefined;
|
|
174
|
+
const client = await this._connectClient(factory);
|
|
175
|
+
this._currentClient = client;
|
|
176
|
+
this._ownsCurrentClient = true;
|
|
177
|
+
await notifyToolListChanged(this._backendContext, previousTools, await this._getExposedTools(client));
|
|
178
|
+
}
|
|
179
|
+
async _connectClient(factory) {
|
|
115
180
|
const client = new Client({ name: 'Playwright MCP Proxy', version: '0.0.0' });
|
|
116
|
-
client.
|
|
117
|
-
roots: {
|
|
118
|
-
listChanged: true,
|
|
119
|
-
},
|
|
120
|
-
});
|
|
121
|
-
client.setRequestHandler(ListRootsRequestSchema, () => ({ roots: this._roots }));
|
|
122
|
-
client.setRequestHandler(PingRequestSchema, () => ({}));
|
|
181
|
+
client.setRequestHandler('ping', () => ({}));
|
|
123
182
|
const transport = await factory.connect();
|
|
124
183
|
await client.connect(transport);
|
|
125
|
-
|
|
126
|
-
await notifyToolListChanged(this._backendContext, previousTools, await this._getExposedTools(client));
|
|
184
|
+
return client;
|
|
127
185
|
}
|
|
128
186
|
async _getExposedTools(client) {
|
|
129
187
|
if (!client)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"proxyBackend.js","sourceRoot":"","sources":["../../src/mcp/proxyBackend.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,MAAM,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"proxyBackend.js","sourceRoot":"","sources":["../../src/mcp/proxyBackend.ts"],"names":[],"mappings":"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"}
|
package/lib/mcp/server.js
CHANGED
|
@@ -14,24 +14,21 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
import debug from 'debug';
|
|
17
|
-
import { Server } from '@modelcontextprotocol/
|
|
18
|
-
import {
|
|
19
|
-
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
17
|
+
import { ProtocolError, ProtocolErrorCode, Server } from '@modelcontextprotocol/server';
|
|
18
|
+
import { StdioServerTransport } from '@modelcontextprotocol/server/stdio';
|
|
20
19
|
import { httpAddressToString, installHttpTransport, startHttpServer } from './http.js';
|
|
21
20
|
import { InProcessTransport } from './inProcessTransport.js';
|
|
22
21
|
const serverDebug = debug('pw:mcp:server');
|
|
23
22
|
const errorsDebug = debug('pw:mcp:errors');
|
|
24
|
-
export async function connect(factory, transport,
|
|
25
|
-
const server = createServer(factory.name, factory.version, factory.create(),
|
|
23
|
+
export async function connect(factory, transport, runHeartbeat) {
|
|
24
|
+
const server = createServer(factory.name, factory.version, factory.create(), runHeartbeat, factory);
|
|
26
25
|
await server.connect(transport);
|
|
27
26
|
}
|
|
28
27
|
export async function wrapInProcess(backend) {
|
|
29
|
-
const server = createServer('Internal', '0.0.0', backend,
|
|
28
|
+
const server = createServer('Internal', '0.0.0', backend, false);
|
|
30
29
|
return new InProcessTransport(server);
|
|
31
30
|
}
|
|
32
|
-
export function createServer(name, version, backend,
|
|
33
|
-
let initializedPromiseResolve = () => { };
|
|
34
|
-
const initializedPromise = new Promise(resolve => initializedPromiseResolve = resolve);
|
|
31
|
+
export function createServer(name, version, backend, runHeartbeat, metadata) {
|
|
35
32
|
const server = new Server({ name, version, title: metadata?.title }, {
|
|
36
33
|
capabilities: {
|
|
37
34
|
tools: {
|
|
@@ -39,28 +36,73 @@ export function createServer(name, version, backend, transportInitialized, runHe
|
|
|
39
36
|
},
|
|
40
37
|
},
|
|
41
38
|
instructions: metadata?.instructions,
|
|
39
|
+
...(metadata?.toolListCacheHint ? { cacheHints: { 'tools/list': metadata.toolListCacheHint } } : {}),
|
|
42
40
|
});
|
|
43
|
-
|
|
41
|
+
// Idempotent backend initialization shared by the handshake path and the
|
|
42
|
+
// lazy per-request path. The `initialized` notification remains the
|
|
43
|
+
// preferred entry point (it carries the client's identity), but the MCP
|
|
44
|
+
// 2026-07-28 revision removes the initialize/initialized handshake entirely,
|
|
45
|
+
// so a request arriving without one must trigger initialization on demand
|
|
46
|
+
// instead of hanging forever. Whichever path runs first wins; concurrent
|
|
47
|
+
// callers await the same in-flight promise. Refs #165.
|
|
48
|
+
// Roots are deprecated in MCP 2026-07-28 (SEP-2577) and are no longer
|
|
49
|
+
// fetched here — output directories come from server configuration
|
|
50
|
+
// (`--output-dir` / `outputDir`) instead of a client-supplied root, which
|
|
51
|
+
// also drops a blocking listRoots round-trip from startup. Refs #169.
|
|
52
|
+
let backendInitialized;
|
|
53
|
+
const ensureInitialized = () => {
|
|
54
|
+
if (!backendInitialized) {
|
|
55
|
+
const initialization = (async () => {
|
|
56
|
+
// Pre-handshake there is no client info yet.
|
|
57
|
+
const clientVersion = server.getClientVersion() ?? { name: 'unknown', version: 'unknown' };
|
|
58
|
+
const context = {
|
|
59
|
+
notifyToolListChanged: () => server.sendToolListChanged(),
|
|
60
|
+
};
|
|
61
|
+
await backend.initialize?.(context, clientVersion);
|
|
62
|
+
})();
|
|
63
|
+
// Memoize success only: a rejected attempt clears the memo so the next
|
|
64
|
+
// request retries instead of replaying the same failure forever (e.g. a
|
|
65
|
+
// long-lived stdio process whose backend hit a transient error). Callers
|
|
66
|
+
// already awaiting this attempt still observe its rejection — they hold
|
|
67
|
+
// the promise before this handler clears the memo.
|
|
68
|
+
initialization.catch(() => {
|
|
69
|
+
if (backendInitialized === initialization)
|
|
70
|
+
backendInitialized = undefined;
|
|
71
|
+
});
|
|
72
|
+
backendInitialized = initialization;
|
|
73
|
+
}
|
|
74
|
+
return backendInitialized;
|
|
75
|
+
};
|
|
76
|
+
server.setRequestHandler('tools/list', async () => {
|
|
44
77
|
serverDebug('listTools');
|
|
45
|
-
await
|
|
78
|
+
await ensureInitialized();
|
|
46
79
|
const tools = await backend.listTools();
|
|
47
80
|
return { tools };
|
|
48
81
|
});
|
|
49
82
|
let heartbeatRunning = false;
|
|
50
|
-
server.setRequestHandler(
|
|
83
|
+
server.setRequestHandler('tools/call', async (request, ctx) => {
|
|
51
84
|
serverDebug('callTool', request);
|
|
52
|
-
await
|
|
85
|
+
await ensureInitialized();
|
|
53
86
|
if (runHeartbeat && !heartbeatRunning) {
|
|
54
87
|
heartbeatRunning = true;
|
|
55
88
|
startHeartbeat(server);
|
|
56
89
|
}
|
|
90
|
+
const requestContext = {
|
|
91
|
+
signal: ctx.mcpReq.signal,
|
|
92
|
+
requestId: ctx.mcpReq.id,
|
|
93
|
+
sendNotification: notification => ctx.mcpReq.notify(notification),
|
|
94
|
+
_meta: ctx.mcpReq._meta,
|
|
95
|
+
};
|
|
57
96
|
try {
|
|
58
|
-
return await backend.callTool(request.params.name, request.params.arguments || {},
|
|
97
|
+
return await backend.callTool(request.params.name, request.params.arguments || {}, requestContext);
|
|
59
98
|
}
|
|
60
99
|
catch (error) {
|
|
61
100
|
// Protocol-level failures (e.g. unknown tool) surface as JSON-RPC
|
|
62
101
|
// errors; only tool execution failures become isError results.
|
|
63
|
-
|
|
102
|
+
// `isInstance` brand-matches, so a `ProtocolError` constructed by
|
|
103
|
+
// another bundled SDK copy (e.g. the client package in-process) is
|
|
104
|
+
// recognized too.
|
|
105
|
+
if (ProtocolError.isInstance(error))
|
|
64
106
|
throw error;
|
|
65
107
|
return {
|
|
66
108
|
content: [{ type: 'text', text: '### Result\n' + String(error) }],
|
|
@@ -68,29 +110,8 @@ export function createServer(name, version, backend, transportInitialized, runHe
|
|
|
68
110
|
};
|
|
69
111
|
}
|
|
70
112
|
});
|
|
71
|
-
addServerListener(server, 'initialized',
|
|
72
|
-
|
|
73
|
-
const capabilities = server.getClientCapabilities();
|
|
74
|
-
let clientRoots = [];
|
|
75
|
-
if (capabilities?.roots) {
|
|
76
|
-
const { roots } = await transportInitialized
|
|
77
|
-
.then(() => server.listRoots(undefined, { timeout: 2_000 }))
|
|
78
|
-
.catch(e => {
|
|
79
|
-
serverDebug(e);
|
|
80
|
-
return { roots: [] };
|
|
81
|
-
});
|
|
82
|
-
clientRoots = roots;
|
|
83
|
-
}
|
|
84
|
-
const clientVersion = server.getClientVersion() ?? { name: 'unknown', version: 'unknown' };
|
|
85
|
-
const context = {
|
|
86
|
-
notifyToolListChanged: () => server.sendToolListChanged(),
|
|
87
|
-
};
|
|
88
|
-
await backend.initialize?.(context, clientVersion, clientRoots);
|
|
89
|
-
initializedPromiseResolve();
|
|
90
|
-
}
|
|
91
|
-
catch (e) {
|
|
92
|
-
errorsDebug(e);
|
|
93
|
-
}
|
|
113
|
+
addServerListener(server, 'initialized', () => {
|
|
114
|
+
ensureInitialized().catch(e => errorsDebug(e));
|
|
94
115
|
});
|
|
95
116
|
addServerListener(server, 'close', () => backend.serverClosed?.());
|
|
96
117
|
return server;
|
|
@@ -101,7 +122,7 @@ const startHeartbeat = (server) => {
|
|
|
101
122
|
return;
|
|
102
123
|
const beat = () => {
|
|
103
124
|
let timeoutId;
|
|
104
|
-
const ping = server.request({ method: 'ping' },
|
|
125
|
+
const ping = server.request({ method: 'ping' }, { timeout }).finally(() => {
|
|
105
126
|
if (timeoutId)
|
|
106
127
|
clearTimeout(timeoutId);
|
|
107
128
|
});
|
|
@@ -112,7 +133,15 @@ const startHeartbeat = (server) => {
|
|
|
112
133
|
}),
|
|
113
134
|
]).then(() => {
|
|
114
135
|
setTimeout(beat, 3000);
|
|
115
|
-
}).catch(
|
|
136
|
+
}).catch(error => {
|
|
137
|
+
// A "method not found" reply proves the peer is alive — it answered.
|
|
138
|
+
// MCP 2026-07-28 clients reject `ping` as an unknown method, so stop
|
|
139
|
+
// heartbeating this connection for good instead of killing it. Only a
|
|
140
|
+
// timeout or transport-level failure still closes the server. Refs #168.
|
|
141
|
+
// Brand-matched check: the error may be constructed by the client
|
|
142
|
+
// package's bundled SDK copy when both run in-process.
|
|
143
|
+
if (ProtocolError.isInstance(error) && error.code === ProtocolErrorCode.MethodNotFound)
|
|
144
|
+
return;
|
|
116
145
|
void server.close();
|
|
117
146
|
});
|
|
118
147
|
};
|
|
@@ -140,7 +169,7 @@ function addServerListener(server, event, listener) {
|
|
|
140
169
|
}
|
|
141
170
|
export async function start(serverBackendFactory, options) {
|
|
142
171
|
if (options.port === undefined) {
|
|
143
|
-
await connect(serverBackendFactory, new StdioServerTransport(),
|
|
172
|
+
await connect(serverBackendFactory, new StdioServerTransport(), false);
|
|
144
173
|
return;
|
|
145
174
|
}
|
|
146
175
|
const httpServer = await startHttpServer(options);
|
package/lib/mcp/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Microsoft Corporation.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
import debug from 'debug';
|
|
17
|
+
const errorsDebug = debug('pw:mcp:errors');
|
|
18
|
+
/**
|
|
19
|
+
* Process-scoped holder for a proxy backend's switched downstream client.
|
|
20
|
+
*
|
|
21
|
+
* Stateless HTTP serving builds a fresh proxy backend per request and closes
|
|
22
|
+
* it with the response, so a `browser_connect` switch stored only on that
|
|
23
|
+
* backend would evaporate as soon as its response ended: the switch reported
|
|
24
|
+
* success, yet the next handshake-free request initialized a new proxy on the
|
|
25
|
+
* default provider again. This slot hoists the switched client — and the live
|
|
26
|
+
* connection behind it (in-process backend or spawned child) — to the server
|
|
27
|
+
* factory's scope: per-request backends adopt whatever the slot holds at
|
|
28
|
+
* initialize() and must not close an adopted client with their response.
|
|
29
|
+
*
|
|
30
|
+
* Adoptions are leased: acquire() hands out the published client with its
|
|
31
|
+
* adopter count raised, and release() lowers it when the adopting request is
|
|
32
|
+
* done with the client (its response closed, or it switched away). A
|
|
33
|
+
* replace() that retires a client whose count has not drained defers the
|
|
34
|
+
* close to the last release — a request mid-listTools/callTool on the old
|
|
35
|
+
* client must finish on a live transport, not fail because a sibling request
|
|
36
|
+
* switched providers underneath it.
|
|
37
|
+
*
|
|
38
|
+
* replace() serializes switches: the next client is fully connected before it
|
|
39
|
+
* is published, and the previously published client is closed exactly once —
|
|
40
|
+
* only after the swap, and only once every adopter has released it — so a
|
|
41
|
+
* concurrent request reading the slot observes either the old client still
|
|
42
|
+
* live or the new one ready, never a half-open one. A failed connect leaves
|
|
43
|
+
* the previous selection in place.
|
|
44
|
+
*/
|
|
45
|
+
export class SharedClientSlot {
|
|
46
|
+
_current;
|
|
47
|
+
_chain = Promise.resolve();
|
|
48
|
+
// Adopter count and retirement flag per client this slot has published. An
|
|
49
|
+
// entry leaves the map exactly when its client is closed (drained after
|
|
50
|
+
// retirement, closed inline by replace(), or swept by dispose()), so a
|
|
51
|
+
// straggling release can never double-close.
|
|
52
|
+
_leases = new Map();
|
|
53
|
+
/**
|
|
54
|
+
* Adopts the process-scoped switched client for one request, raising its
|
|
55
|
+
* adopter count; undefined while the default (per-request) provider is
|
|
56
|
+
* selected. Every acquired client must be released exactly once — on
|
|
57
|
+
* serverClosed(), or earlier when the request switches away from it.
|
|
58
|
+
*/
|
|
59
|
+
acquire() {
|
|
60
|
+
if (!this._current)
|
|
61
|
+
return undefined;
|
|
62
|
+
const lease = this._leases.get(this._current);
|
|
63
|
+
if (lease)
|
|
64
|
+
lease.count++;
|
|
65
|
+
return this._current;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Releases one adoption of `client`. When the client has been retired by a
|
|
69
|
+
* replace() and this was its last adopter, the deferred close runs now; the
|
|
70
|
+
* returned promise settles once that close (if any) has finished. Unknown
|
|
71
|
+
* or already-closed clients are ignored.
|
|
72
|
+
*/
|
|
73
|
+
async release(client) {
|
|
74
|
+
const lease = this._leases.get(client);
|
|
75
|
+
if (!lease)
|
|
76
|
+
return;
|
|
77
|
+
lease.count = Math.max(0, lease.count - 1);
|
|
78
|
+
if (lease.retired && lease.count === 0) {
|
|
79
|
+
this._leases.delete(client);
|
|
80
|
+
await client.close().catch(errorsDebug);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Switches the slot to the client produced by `connect`, or back to the
|
|
85
|
+
* default selection (no shared client) when `connect` is undefined.
|
|
86
|
+
* Returns the newly published client — already carrying one adopter lease
|
|
87
|
+
* for the caller, so no concurrent replace can close it before the caller
|
|
88
|
+
* registers as its user — or undefined for the default selection.
|
|
89
|
+
*/
|
|
90
|
+
async replace(connect) {
|
|
91
|
+
const result = this._chain.then(async () => {
|
|
92
|
+
const next = connect ? await connect() : undefined;
|
|
93
|
+
const previous = this._current;
|
|
94
|
+
this._current = next;
|
|
95
|
+
if (next)
|
|
96
|
+
this._leases.set(next, { count: 1, retired: false });
|
|
97
|
+
if (previous) {
|
|
98
|
+
const lease = this._leases.get(previous);
|
|
99
|
+
if (lease && lease.count > 0) {
|
|
100
|
+
// An in-flight request still routes through the outgoing client;
|
|
101
|
+
// the last release closes it.
|
|
102
|
+
lease.retired = true;
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
this._leases.delete(previous);
|
|
106
|
+
await previous.close().catch(errorsDebug);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return next;
|
|
110
|
+
});
|
|
111
|
+
// A rejected switch (failed connect) must not poison later switches.
|
|
112
|
+
this._chain = result.catch(() => { });
|
|
113
|
+
return await result;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Process-shutdown cleanup: closes the published client and any retired
|
|
117
|
+
* clients still draining, WITHOUT waiting for their adopters — no request
|
|
118
|
+
* outlives the process, and waiting on a lease a hung request will never
|
|
119
|
+
* release would stall shutdown forever. Serialized behind in-flight
|
|
120
|
+
* switches so a client mid-connect is not orphaned half-open. Leases are
|
|
121
|
+
* swept before the closes, so a straggling release stays a no-op.
|
|
122
|
+
*/
|
|
123
|
+
async dispose() {
|
|
124
|
+
const result = this._chain.then(async () => {
|
|
125
|
+
const clients = [...this._leases.keys()];
|
|
126
|
+
this._leases.clear();
|
|
127
|
+
this._current = undefined;
|
|
128
|
+
await Promise.all(clients.map(client => client.close().catch(errorsDebug)));
|
|
129
|
+
});
|
|
130
|
+
this._chain = result.catch(() => { });
|
|
131
|
+
return await result;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=sharedClientSlot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sharedClientSlot.js","sourceRoot":"","sources":["../../src/mcp/sharedClientSlot.ts"],"names":[],"mappings":"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"}
|
package/lib/mcp/tool.js
CHANGED
|
@@ -26,6 +26,9 @@ export function toMcpTool(tool) {
|
|
|
26
26
|
title: tool.title,
|
|
27
27
|
readOnlyHint: tool.type === 'readOnly',
|
|
28
28
|
destructiveHint: tool.type === 'destructive',
|
|
29
|
+
// stateChanging tools are non-idempotent by nature (each call creates
|
|
30
|
+
// fresh state), so clients must not silently retry them.
|
|
31
|
+
...(tool.type === 'stateChanging' ? { idempotentHint: false } : {}),
|
|
29
32
|
openWorldHint: true,
|
|
30
33
|
},
|
|
31
34
|
};
|
package/lib/mcp/tool.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool.js","sourceRoot":"","sources":["../../src/mcp/tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"tool.js","sourceRoot":"","sources":["../../src/mcp/tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAexB,MAAM,UAAU,SAAS,CAAC,IAAqB;IAC7C,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,kEAAkE;QAClE,oEAAoE;QACpE,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,WAAW,EAAE,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,WAAW,CAAkC;QAC9E,WAAW,EAAE;YACX,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,YAAY,EAAE,IAAI,CAAC,IAAI,KAAK,UAAU;YACtC,eAAe,EAAE,IAAI,CAAC,IAAI,KAAK,aAAa;YAC5C,sEAAsE;YACtE,yDAAyD;YACzD,GAAG,CAAC,IAAI,CAAC,IAAI,KAAK,eAAe,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACnE,aAAa,EAAE,IAAI;SACpB;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAyB,IAAuB;IAC9E,OAAO,IAAI,CAAC;AACd,CAAC"}
|