playwright 1.55.0 → 1.56.0-alpha-2025-08-21

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 (35) hide show
  1. package/lib/index.js +45 -4
  2. package/lib/isomorphic/testServerConnection.js +0 -7
  3. package/lib/matchers/expect.js +7 -19
  4. package/lib/matchers/toBeTruthy.js +2 -0
  5. package/lib/matchers/toEqual.js +2 -0
  6. package/lib/matchers/toMatchText.js +3 -0
  7. package/lib/mcp/browser/backend.js +88 -0
  8. package/lib/mcp/browser/tool.js +30 -0
  9. package/lib/mcp/browser/tools.js +132 -0
  10. package/lib/mcp/{bundle.js → sdk/bundle.js} +5 -2
  11. package/lib/mcp/sdk/call.js +49 -0
  12. package/lib/mcp/{exports.js → sdk/exports.js} +12 -10
  13. package/lib/mcp/{transport.js → sdk/http.js} +51 -68
  14. package/lib/mcp/sdk/mdb.js +195 -0
  15. package/lib/mcp/{proxyBackend.js → sdk/proxyBackend.js} +8 -10
  16. package/lib/mcp/{server.js → sdk/server.js} +43 -14
  17. package/lib/mcp/{tool.js → sdk/tool.js} +6 -1
  18. package/lib/mcp/test/backend.js +68 -0
  19. package/lib/mcp/test/context.js +43 -0
  20. package/lib/mcp/test/listTests.js +88 -0
  21. package/lib/mcp/test/program.js +42 -0
  22. package/lib/mcp/test/runTests.js +82 -0
  23. package/lib/mcp/test/streams.js +41 -0
  24. package/lib/mcp/test/tool.js +30 -0
  25. package/lib/mcpBundleImpl.js +17 -13
  26. package/lib/runner/dispatcher.js +1 -22
  27. package/lib/runner/failureTracker.js +0 -14
  28. package/lib/runner/testRunner.js +2 -25
  29. package/lib/runner/testServer.js +2 -8
  30. package/lib/runner/watchMode.js +1 -53
  31. package/lib/runner/workerHost.js +2 -6
  32. package/lib/worker/testInfo.js +1 -24
  33. package/lib/worker/workerMain.js +0 -5
  34. package/package.json +3 -3
  35. /package/lib/mcp/{inProcessTransport.js → sdk/inProcessTransport.js} +0 -0
@@ -26,29 +26,57 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
26
26
  mod
27
27
  ));
28
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
- var transport_exports = {};
30
- __export(transport_exports, {
31
- start: () => start
29
+ var http_exports = {};
30
+ __export(http_exports, {
31
+ httpAddressToString: () => httpAddressToString,
32
+ installHttpTransport: () => installHttpTransport,
33
+ startHttpServer: () => startHttpServer
32
34
  });
33
- module.exports = __toCommonJS(transport_exports);
35
+ module.exports = __toCommonJS(http_exports);
34
36
  var import_assert = __toESM(require("assert"));
35
37
  var import_http = __toESM(require("http"));
36
38
  var import_crypto = __toESM(require("crypto"));
37
39
  var import_utilsBundle = require("playwright-core/lib/utilsBundle");
38
- var mcpBundle = __toESM(require("./bundle"));
39
- var mcpServer = __toESM(require("./server"));
40
- async function start(serverBackendFactory, options) {
41
- if (options.port !== void 0) {
42
- const httpServer = await startHttpServer(options);
43
- startHttpTransport(httpServer, serverBackendFactory);
44
- } else {
45
- await startStdioTransport(serverBackendFactory);
46
- }
40
+ var mcp = __toESM(require("./bundle"));
41
+ var import_server = require("./server");
42
+ const testDebug = (0, import_utilsBundle.debug)("pw:mcp:test");
43
+ async function startHttpServer(config, abortSignal) {
44
+ const { host, port } = config;
45
+ const httpServer = import_http.default.createServer();
46
+ await new Promise((resolve, reject) => {
47
+ httpServer.on("error", reject);
48
+ abortSignal?.addEventListener("abort", () => {
49
+ httpServer.close();
50
+ reject(new Error("Aborted"));
51
+ });
52
+ httpServer.listen(port, host, () => {
53
+ resolve();
54
+ httpServer.removeListener("error", reject);
55
+ });
56
+ });
57
+ return httpServer;
58
+ }
59
+ function httpAddressToString(address) {
60
+ (0, import_assert.default)(address, "Could not bind server socket");
61
+ if (typeof address === "string")
62
+ return address;
63
+ const resolvedPort = address.port;
64
+ let resolvedHost = address.family === "IPv4" ? address.address : `[${address.address}]`;
65
+ if (resolvedHost === "0.0.0.0" || resolvedHost === "[::]")
66
+ resolvedHost = "localhost";
67
+ return `http://${resolvedHost}:${resolvedPort}`;
47
68
  }
48
- async function startStdioTransport(serverBackendFactory) {
49
- await mcpServer.connect(serverBackendFactory, new mcpBundle.StdioServerTransport(), false);
69
+ async function installHttpTransport(httpServer, serverBackendFactory) {
70
+ const sseSessions = /* @__PURE__ */ new Map();
71
+ const streamableSessions = /* @__PURE__ */ new Map();
72
+ httpServer.on("request", async (req, res) => {
73
+ const url = new URL(`http://localhost${req.url}`);
74
+ if (url.pathname.startsWith("/sse"))
75
+ await handleSSE(serverBackendFactory, req, res, url, sseSessions);
76
+ else
77
+ await handleStreamable(serverBackendFactory, req, res, streamableSessions);
78
+ });
50
79
  }
51
- const testDebug = (0, import_utilsBundle.debug)("pw:mcp:test");
52
80
  async function handleSSE(serverBackendFactory, req, res, url, sessions) {
53
81
  if (req.method === "POST") {
54
82
  const sessionId = url.searchParams.get("sessionId");
@@ -63,10 +91,10 @@ async function handleSSE(serverBackendFactory, req, res, url, sessions) {
63
91
  }
64
92
  return await transport.handlePostMessage(req, res);
65
93
  } else if (req.method === "GET") {
66
- const transport = new mcpBundle.SSEServerTransport("/sse", res);
94
+ const transport = new mcp.SSEServerTransport("/sse", res);
67
95
  sessions.set(transport.sessionId, transport);
68
96
  testDebug(`create SSE session: ${transport.sessionId}`);
69
- await mcpServer.connect(serverBackendFactory, transport, false);
97
+ await (0, import_server.connect)(serverBackendFactory, transport, false);
70
98
  res.on("close", () => {
71
99
  testDebug(`delete SSE session: ${transport.sessionId}`);
72
100
  sessions.delete(transport.sessionId);
@@ -88,11 +116,11 @@ async function handleStreamable(serverBackendFactory, req, res, sessions) {
88
116
  return await transport.handleRequest(req, res);
89
117
  }
90
118
  if (req.method === "POST") {
91
- const transport = new mcpBundle.StreamableHTTPServerTransport({
119
+ const transport = new mcp.StreamableHTTPServerTransport({
92
120
  sessionIdGenerator: () => import_crypto.default.randomUUID(),
93
121
  onsessioninitialized: async (sessionId2) => {
94
122
  testDebug(`create http session: ${transport.sessionId}`);
95
- await mcpServer.connect(serverBackendFactory, transport, true);
123
+ await (0, import_server.connect)(serverBackendFactory, transport, true);
96
124
  sessions.set(sessionId2, transport);
97
125
  }
98
126
  });
@@ -108,54 +136,9 @@ async function handleStreamable(serverBackendFactory, req, res, sessions) {
108
136
  res.statusCode = 400;
109
137
  res.end("Invalid request");
110
138
  }
111
- function startHttpTransport(httpServer, serverBackendFactory) {
112
- const sseSessions = /* @__PURE__ */ new Map();
113
- const streamableSessions = /* @__PURE__ */ new Map();
114
- httpServer.on("request", async (req, res) => {
115
- const url2 = new URL(`http://localhost${req.url}`);
116
- if (url2.pathname.startsWith("/sse"))
117
- await handleSSE(serverBackendFactory, req, res, url2, sseSessions);
118
- else
119
- await handleStreamable(serverBackendFactory, req, res, streamableSessions);
120
- });
121
- const url = httpAddressToString(httpServer.address());
122
- const message = [
123
- `Listening on ${url}`,
124
- "Put this in your client config:",
125
- JSON.stringify({
126
- "mcpServers": {
127
- "playwright": {
128
- "url": `${url}/mcp`
129
- }
130
- }
131
- }, void 0, 2),
132
- "For legacy SSE transport support, you can use the /sse endpoint instead."
133
- ].join("\n");
134
- console.error(message);
135
- }
136
- async function startHttpServer(config) {
137
- const { host, port } = config;
138
- const httpServer = import_http.default.createServer();
139
- await new Promise((resolve, reject) => {
140
- httpServer.on("error", reject);
141
- httpServer.listen(port, host, () => {
142
- resolve();
143
- httpServer.removeListener("error", reject);
144
- });
145
- });
146
- return httpServer;
147
- }
148
- function httpAddressToString(address) {
149
- (0, import_assert.default)(address, "Could not bind server socket");
150
- if (typeof address === "string")
151
- return address;
152
- const resolvedPort = address.port;
153
- let resolvedHost = address.family === "IPv4" ? address.address : `[${address.address}]`;
154
- if (resolvedHost === "0.0.0.0" || resolvedHost === "[::]")
155
- resolvedHost = "localhost";
156
- return `http://${resolvedHost}:${resolvedPort}`;
157
- }
158
139
  // Annotate the CommonJS export names for ESM import in node:
159
140
  0 && (module.exports = {
160
- start
141
+ httpAddressToString,
142
+ installHttpTransport,
143
+ startHttpServer
161
144
  });
@@ -0,0 +1,195 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var mdb_exports = {};
30
+ __export(mdb_exports, {
31
+ MDBBackend: () => MDBBackend,
32
+ runOnPauseBackendLoop: () => runOnPauseBackendLoop,
33
+ runToolsBackend: () => runToolsBackend
34
+ });
35
+ module.exports = __toCommonJS(mdb_exports);
36
+ var import_utilsBundle = require("playwright-core/lib/utilsBundle");
37
+ var import_utils = require("playwright-core/lib/utils");
38
+ var import_bundle = require("./bundle.js");
39
+ var import_bundle2 = require("./bundle.js");
40
+ var mcpBundle = __toESM(require("./bundle.js"));
41
+ var import_tool = require("./tool.js");
42
+ var mcpHttp = __toESM(require("./http.js"));
43
+ var import_call = require("./call.js");
44
+ const errorsDebug = (0, import_utilsBundle.debug)("pw:mcp:errors");
45
+ class MDBBackend {
46
+ constructor() {
47
+ this._stack = [];
48
+ }
49
+ async initialize(server) {
50
+ this._server = server;
51
+ }
52
+ async listTools() {
53
+ const response = await this._client().listTools();
54
+ return response.tools;
55
+ }
56
+ async callTool(name, args) {
57
+ if (name === pushToolsSchema.name)
58
+ return await this._pushTools(pushToolsSchema.inputSchema.parse(args || {}));
59
+ this._interruptPromise = new import_utils.ManualPromise();
60
+ let [entry] = this._stack;
61
+ while (entry && !entry.toolNames.includes(name)) {
62
+ this._stack.shift();
63
+ await entry.client.close();
64
+ entry = this._stack[0];
65
+ }
66
+ const resultPromise = new import_utils.ManualPromise();
67
+ entry.resultPromise = resultPromise;
68
+ this._client().callTool({
69
+ name,
70
+ arguments: args
71
+ }).then((result) => {
72
+ resultPromise.resolve(result);
73
+ }).catch((e) => {
74
+ if (this._stack.length < 2)
75
+ throw e;
76
+ this._stack.shift();
77
+ const prevEntry = this._stack[0];
78
+ void prevEntry.resultPromise.then((result) => resultPromise.resolve(result));
79
+ });
80
+ return await Promise.race([this._interruptPromise, resultPromise]);
81
+ }
82
+ _client() {
83
+ const [entry] = this._stack;
84
+ if (!entry)
85
+ throw new Error("No debugging backend available");
86
+ return entry.client;
87
+ }
88
+ async _pushTools(params) {
89
+ const client = new mcpBundle.Client({ name: "Internal client", version: "0.0.0" });
90
+ client.setRequestHandler(import_bundle.PingRequestSchema, () => ({}));
91
+ const transport = new import_bundle2.StreamableHTTPClientTransport(new URL(params.mcpUrl));
92
+ await client.connect(transport);
93
+ this._interruptPromise?.resolve({
94
+ content: [{
95
+ type: "text",
96
+ text: params.introMessage || ""
97
+ }]
98
+ });
99
+ this._interruptPromise = void 0;
100
+ const { tools } = await client.listTools();
101
+ this._stack.unshift({ client, toolNames: tools.map((tool) => tool.name), resultPromise: void 0 });
102
+ await this._server.notification({
103
+ method: "notifications/tools/list_changed"
104
+ });
105
+ return { content: [{ type: "text", text: "Tools pushed" }] };
106
+ }
107
+ }
108
+ const pushToolsSchema = (0, import_tool.defineToolSchema)({
109
+ name: "mdb_push_tools",
110
+ title: "Push MCP tools to the tools stack",
111
+ description: "Push MCP tools to the tools stack",
112
+ inputSchema: import_bundle.z.object({
113
+ mcpUrl: import_bundle.z.string(),
114
+ introMessage: import_bundle.z.string().optional()
115
+ }),
116
+ type: "readOnly"
117
+ });
118
+ async function runToolsBackend(backendFactory, options) {
119
+ const mdbBackend = new MDBBackend();
120
+ const mdbBackendFactory = {
121
+ name: "Playwright MDB",
122
+ nameInConfig: "playwright-mdb",
123
+ version: "0.0.0",
124
+ create: () => mdbBackend
125
+ };
126
+ const mdbUrl = await startAsHttp(mdbBackendFactory, options);
127
+ const backendUrl = await startAsHttp(backendFactory, { port: 0 });
128
+ const result = await (0, import_call.callTool)(mdbUrl, pushToolsSchema.name, { mcpUrl: backendUrl });
129
+ if (result.isError)
130
+ errorsDebug("Failed to push tools", result.content);
131
+ return mdbUrl;
132
+ }
133
+ async function runOnPauseBackendLoop(mdbUrl, backend, introMessage) {
134
+ const wrappedBackend = new OnceTimeServerBackendWrapper(backend);
135
+ const factory = {
136
+ name: "on-pause-backend",
137
+ nameInConfig: "on-pause-backend",
138
+ version: "0.0.0",
139
+ create: () => wrappedBackend
140
+ };
141
+ const httpServer = await mcpHttp.startHttpServer({ port: 0 });
142
+ await mcpHttp.installHttpTransport(httpServer, factory);
143
+ const url = mcpHttp.httpAddressToString(httpServer.address());
144
+ const client = new mcpBundle.Client({ name: "Internal client", version: "0.0.0" });
145
+ client.setRequestHandler(import_bundle.PingRequestSchema, () => ({}));
146
+ const transport = new import_bundle2.StreamableHTTPClientTransport(new URL(mdbUrl));
147
+ await client.connect(transport);
148
+ const pushToolsResult = await client.callTool({
149
+ name: pushToolsSchema.name,
150
+ arguments: {
151
+ mcpUrl: url,
152
+ introMessage
153
+ }
154
+ });
155
+ if (pushToolsResult.isError)
156
+ errorsDebug("Failed to push tools", pushToolsResult.content);
157
+ await transport.terminateSession();
158
+ await client.close();
159
+ await wrappedBackend.waitForClosed();
160
+ httpServer.close();
161
+ }
162
+ async function startAsHttp(backendFactory, options) {
163
+ const httpServer = await mcpHttp.startHttpServer(options);
164
+ await mcpHttp.installHttpTransport(httpServer, backendFactory);
165
+ return mcpHttp.httpAddressToString(httpServer.address());
166
+ }
167
+ class OnceTimeServerBackendWrapper {
168
+ constructor(backend) {
169
+ this._selfDestructPromise = new import_utils.ManualPromise();
170
+ this._backend = backend;
171
+ this._backend.requestSelfDestruct = () => this._selfDestructPromise.resolve();
172
+ }
173
+ async initialize(server, clientVersion, roots) {
174
+ await this._backend.initialize?.(server, clientVersion, roots);
175
+ }
176
+ async listTools() {
177
+ return this._backend.listTools();
178
+ }
179
+ async callTool(name, args) {
180
+ return this._backend.callTool(name, args);
181
+ }
182
+ serverClosed() {
183
+ this._backend.serverClosed?.();
184
+ this._selfDestructPromise.resolve();
185
+ }
186
+ async waitForClosed() {
187
+ await this._selfDestructPromise;
188
+ }
189
+ }
190
+ // Annotate the CommonJS export names for ESM import in node:
191
+ 0 && (module.exports = {
192
+ MDBBackend,
193
+ runOnPauseBackendLoop,
194
+ runToolsBackend
195
+ });
@@ -32,17 +32,15 @@ __export(proxyBackend_exports, {
32
32
  });
33
33
  module.exports = __toCommonJS(proxyBackend_exports);
34
34
  var import_utilsBundle = require("playwright-core/lib/utilsBundle");
35
- var mcpBundle = __toESM(require("./bundle"));
35
+ var mcp = __toESM(require("./bundle"));
36
36
  const errorsDebug = (0, import_utilsBundle.debug)("pw:mcp:errors");
37
37
  class ProxyBackend {
38
- constructor(name, version, mcpProviders) {
38
+ constructor(mcpProviders) {
39
39
  this._roots = [];
40
- this.name = name;
41
- this.version = version;
42
40
  this._mcpProviders = mcpProviders;
43
41
  this._contextSwitchTool = this._defineContextSwitchTool();
44
42
  }
45
- async initialize(clientVersion, roots) {
43
+ async initialize(server, clientVersion, roots) {
46
44
  this._roots = roots;
47
45
  await this._setCurrentClient(this._mcpProviders[0]);
48
46
  }
@@ -91,8 +89,8 @@ Error: ${error}
91
89
  "Connect to a browser using one of the available methods:",
92
90
  ...this._mcpProviders.map((factory) => `- "${factory.name}": ${factory.description}`)
93
91
  ].join("\n"),
94
- inputSchema: mcpBundle.zodToJsonSchema(mcpBundle.z.object({
95
- name: mcpBundle.z.enum(this._mcpProviders.map((factory) => factory.name)).default(this._mcpProviders[0].name).describe("The method to use to connect to the browser")
92
+ inputSchema: mcp.zodToJsonSchema(mcp.z.object({
93
+ name: mcp.z.enum(this._mcpProviders.map((factory) => factory.name)).default(this._mcpProviders[0].name).describe("The method to use to connect to the browser")
96
94
  }), { strictUnions: true }),
97
95
  annotations: {
98
96
  title: "Connect to a browser context",
@@ -104,14 +102,14 @@ Error: ${error}
104
102
  async _setCurrentClient(factory) {
105
103
  await this._currentClient?.close();
106
104
  this._currentClient = void 0;
107
- const client = new mcpBundle.Client({ name: this.name, version: this.version });
105
+ const client = new mcp.Client({ name: "Playwright MCP Proxy", version: "0.0.0" });
108
106
  client.registerCapabilities({
109
107
  roots: {
110
108
  listRoots: true
111
109
  }
112
110
  });
113
- client.setRequestHandler(mcpBundle.ListRootsRequestSchema, () => ({ roots: this._roots }));
114
- client.setRequestHandler(mcpBundle.PingRequestSchema, () => ({}));
111
+ client.setRequestHandler(mcp.ListRootsRequestSchema, () => ({ roots: this._roots }));
112
+ client.setRequestHandler(mcp.PingRequestSchema, () => ({}));
115
113
  const transport = await factory.connect();
116
114
  await client.connect(transport);
117
115
  this._currentClient = client;
@@ -29,35 +29,42 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
29
29
  var server_exports = {};
30
30
  __export(server_exports, {
31
31
  connect: () => connect,
32
- createServer: () => createServer
32
+ createServer: () => createServer,
33
+ start: () => start,
34
+ wrapInProcess: () => wrapInProcess
33
35
  });
34
36
  module.exports = __toCommonJS(server_exports);
35
37
  var import_utilsBundle = require("playwright-core/lib/utilsBundle");
36
- var mcpBundle = __toESM(require("./bundle"));
38
+ var mcp = __toESM(require("./bundle"));
39
+ var import_inProcessTransport = require("./inProcessTransport");
40
+ var import_http = require("./http");
37
41
  const serverDebug = (0, import_utilsBundle.debug)("pw:mcp:server");
38
42
  const errorsDebug = (0, import_utilsBundle.debug)("pw:mcp:errors");
39
- async function connect(serverBackendFactory, transport, runHeartbeat) {
40
- const backend = serverBackendFactory();
41
- const server = createServer(backend, runHeartbeat);
43
+ async function connect(factory, transport, runHeartbeat) {
44
+ const server = createServer(factory.name, factory.version, factory.create(), runHeartbeat);
42
45
  await server.connect(transport);
43
46
  }
44
- function createServer(backend, runHeartbeat) {
45
- let initializedCallback = () => {
47
+ async function wrapInProcess(backend) {
48
+ const server = createServer("Internal", "0.0.0", backend, false);
49
+ return new import_inProcessTransport.InProcessTransport(server);
50
+ }
51
+ function createServer(name, version, backend, runHeartbeat) {
52
+ let initializedPromiseResolve = () => {
46
53
  };
47
- const initializedPromise = new Promise((resolve) => initializedCallback = resolve);
48
- const server = new mcpBundle.Server({ name: backend.name, version: backend.version }, {
54
+ const initializedPromise = new Promise((resolve) => initializedPromiseResolve = resolve);
55
+ const server = new mcp.Server({ name, version }, {
49
56
  capabilities: {
50
57
  tools: {}
51
58
  }
52
59
  });
53
- server.setRequestHandler(mcpBundle.ListToolsRequestSchema, async () => {
60
+ server.setRequestHandler(mcp.ListToolsRequestSchema, async () => {
54
61
  serverDebug("listTools");
55
62
  await initializedPromise;
56
63
  const tools = await backend.listTools();
57
64
  return { tools };
58
65
  });
59
66
  let heartbeatRunning = false;
60
- server.setRequestHandler(mcpBundle.CallToolRequestSchema, async (request) => {
67
+ server.setRequestHandler(mcp.CallToolRequestSchema, async (request) => {
61
68
  serverDebug("callTool", request);
62
69
  await initializedPromise;
63
70
  if (runHeartbeat && !heartbeatRunning) {
@@ -82,8 +89,8 @@ function createServer(backend, runHeartbeat) {
82
89
  clientRoots = roots;
83
90
  }
84
91
  const clientVersion = server.getClientVersion() ?? { name: "unknown", version: "unknown" };
85
- await backend.initialize?.(clientVersion, clientRoots);
86
- initializedCallback();
92
+ await backend.initialize?.(server, clientVersion, clientRoots);
93
+ initializedPromiseResolve();
87
94
  } catch (e) {
88
95
  errorsDebug(e);
89
96
  }
@@ -111,8 +118,30 @@ function addServerListener(server, event, listener) {
111
118
  listener();
112
119
  };
113
120
  }
121
+ async function start(serverBackendFactory, options) {
122
+ if (options.port === void 0) {
123
+ await connect(serverBackendFactory, new mcp.StdioServerTransport(), false);
124
+ return;
125
+ }
126
+ const httpServer = await (0, import_http.startHttpServer)(options);
127
+ await (0, import_http.installHttpTransport)(httpServer, serverBackendFactory);
128
+ const url = (0, import_http.httpAddressToString)(httpServer.address());
129
+ const mcpConfig = { mcpServers: {} };
130
+ mcpConfig.mcpServers[serverBackendFactory.nameInConfig] = {
131
+ url: `${url}/mcp`
132
+ };
133
+ const message = [
134
+ `Listening on ${url}`,
135
+ "Put this in your client config:",
136
+ JSON.stringify(mcpConfig, void 0, 2),
137
+ "For legacy SSE transport support, you can use the /sse endpoint instead."
138
+ ].join("\n");
139
+ console.error(message);
140
+ }
114
141
  // Annotate the CommonJS export names for ESM import in node:
115
142
  0 && (module.exports = {
116
143
  connect,
117
- createServer
144
+ createServer,
145
+ start,
146
+ wrapInProcess
118
147
  });
@@ -18,10 +18,11 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var tool_exports = {};
20
20
  __export(tool_exports, {
21
+ defineToolSchema: () => defineToolSchema,
21
22
  toMcpTool: () => toMcpTool
22
23
  });
23
24
  module.exports = __toCommonJS(tool_exports);
24
- var import_bundle = require("./bundle");
25
+ var import_bundle = require("./bundle.js");
25
26
  function toMcpTool(tool) {
26
27
  return {
27
28
  name: tool.name,
@@ -35,7 +36,11 @@ function toMcpTool(tool) {
35
36
  }
36
37
  };
37
38
  }
39
+ function defineToolSchema(tool) {
40
+ return tool;
41
+ }
38
42
  // Annotate the CommonJS export names for ESM import in node:
39
43
  0 && (module.exports = {
44
+ defineToolSchema,
40
45
  toMcpTool
41
46
  });
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var backend_exports = {};
30
+ __export(backend_exports, {
31
+ TestServerBackend: () => TestServerBackend
32
+ });
33
+ module.exports = __toCommonJS(backend_exports);
34
+ var mcp = __toESM(require("../sdk/exports.js"));
35
+ var import_context = require("./context");
36
+ var import_listTests = require("./listTests");
37
+ var import_runTests = require("./runTests");
38
+ var import_tools = require("../browser/tools");
39
+ class TestServerBackend {
40
+ constructor(resolvedLocation) {
41
+ this.name = "Playwright";
42
+ this.version = "0.0.1";
43
+ this._tools = [import_listTests.listTests, import_runTests.runTests];
44
+ this._context = new import_context.Context(resolvedLocation);
45
+ }
46
+ async listTools() {
47
+ return [
48
+ ...this._tools.map((tool) => mcp.toMcpTool(tool.schema)),
49
+ mcp.toMcpTool(import_tools.snapshot.schema),
50
+ mcp.toMcpTool(import_tools.pickLocator.schema),
51
+ mcp.toMcpTool(import_tools.evaluate.schema)
52
+ ];
53
+ }
54
+ async callTool(name, args) {
55
+ const tool = this._tools.find((tool2) => tool2.schema.name === name);
56
+ if (!tool)
57
+ throw new Error(`Tool not found: ${name}. Available tools: ${this._tools.map((tool2) => tool2.schema.name).join(", ")}`);
58
+ const parsedArguments = tool.schema.inputSchema.parse(args || {});
59
+ return await tool.handle(this._context, parsedArguments);
60
+ }
61
+ serverClosed() {
62
+ void this._context.close();
63
+ }
64
+ }
65
+ // Annotate the CommonJS export names for ESM import in node:
66
+ 0 && (module.exports = {
67
+ TestServerBackend
68
+ });
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var context_exports = {};
20
+ __export(context_exports, {
21
+ Context: () => Context
22
+ });
23
+ module.exports = __toCommonJS(context_exports);
24
+ var import_testRunner = require("../../runner/testRunner");
25
+ class Context {
26
+ constructor(configLocation) {
27
+ this.configLocation = configLocation;
28
+ }
29
+ async createTestRunner() {
30
+ if (this._testRunner)
31
+ await this._testRunner.stopTests();
32
+ const testRunner = new import_testRunner.TestRunner(this.configLocation, {});
33
+ await testRunner.initialize({});
34
+ this._testRunner = testRunner;
35
+ return testRunner;
36
+ }
37
+ async close() {
38
+ }
39
+ }
40
+ // Annotate the CommonJS export names for ESM import in node:
41
+ 0 && (module.exports = {
42
+ Context
43
+ });