@playwright/mcp 0.0.6 → 0.0.7

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/lib/program.js CHANGED
@@ -26,6 +26,7 @@ const commander_1 = require("commander");
26
26
  const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
27
27
  const sse_js_1 = require("@modelcontextprotocol/sdk/server/sse.js");
28
28
  const index_1 = require("./index");
29
+ const server_1 = require("./server");
29
30
  const assert_1 = __importDefault(require("assert"));
30
31
  const packageJSON = require('../package.json');
31
32
  commander_1.program
@@ -40,85 +41,30 @@ commander_1.program
40
41
  headless: !!options.headless,
41
42
  channel: 'chrome',
42
43
  };
43
- const server = (0, index_1.createServer)({
44
- userDataDir: options.userDataDir ?? await userDataDir(),
44
+ const userDataDir = options.userDataDir ?? await createUserDataDir();
45
+ const serverList = new server_1.ServerList(() => (0, index_1.createServer)({
46
+ userDataDir,
45
47
  launchOptions,
46
48
  vision: !!options.vision,
47
- });
48
- setupExitWatchdog(server);
49
+ }));
50
+ setupExitWatchdog(serverList);
49
51
  if (options.port) {
50
- const sessions = new Map();
51
- const httpServer = http_1.default.createServer(async (req, res) => {
52
- if (req.method === 'POST') {
53
- const host = req.headers.host ?? 'http://unknown';
54
- const sessionId = new URL(host + req.url).searchParams.get('sessionId');
55
- if (!sessionId) {
56
- res.statusCode = 400;
57
- res.end('Missing sessionId');
58
- return;
59
- }
60
- const transport = sessions.get(sessionId);
61
- if (!transport) {
62
- res.statusCode = 404;
63
- res.end('Session not found');
64
- return;
65
- }
66
- await transport.handlePostMessage(req, res);
67
- return;
68
- }
69
- else if (req.method === 'GET') {
70
- const transport = new sse_js_1.SSEServerTransport('/sse', res);
71
- sessions.set(transport.sessionId, transport);
72
- res.on('close', () => {
73
- sessions.delete(transport.sessionId);
74
- });
75
- await server.connect(transport);
76
- return;
77
- }
78
- else {
79
- res.statusCode = 405;
80
- res.end('Method not allowed');
81
- }
82
- });
83
- httpServer.listen(+options.port, () => {
84
- const address = httpServer.address();
85
- (0, assert_1.default)(address, 'Could not bind server socket');
86
- let urlPrefixHumanReadable;
87
- if (typeof address === 'string') {
88
- urlPrefixHumanReadable = address;
89
- }
90
- else {
91
- const port = address.port;
92
- let resolvedHost = address.family === 'IPv4' ? address.address : `[${address.address}]`;
93
- if (resolvedHost === '0.0.0.0' || resolvedHost === '[::]')
94
- resolvedHost = 'localhost';
95
- urlPrefixHumanReadable = `http://${resolvedHost}:${port}`;
96
- }
97
- console.log(`Listening on ${urlPrefixHumanReadable}`);
98
- console.log('Put this in your client config:');
99
- console.log(JSON.stringify({
100
- 'mcpServers': {
101
- 'playwright': {
102
- 'url': `${urlPrefixHumanReadable}/sse`
103
- }
104
- }
105
- }, undefined, 2));
106
- });
52
+ startSSEServer(+options.port, serverList);
107
53
  }
108
54
  else {
109
- const transport = new stdio_js_1.StdioServerTransport();
110
- await server.connect(transport);
55
+ const server = await serverList.create();
56
+ await server.connect(new stdio_js_1.StdioServerTransport());
111
57
  }
112
58
  });
113
- function setupExitWatchdog(server) {
59
+ function setupExitWatchdog(serverList) {
114
60
  process.stdin.on('close', async () => {
115
61
  setTimeout(() => process.exit(0), 15000);
116
- await server.close();
62
+ await serverList.closeAll();
117
63
  process.exit(0);
118
64
  });
119
65
  }
120
66
  commander_1.program.parse(process.argv);
121
- async function userDataDir() {
67
+ async function createUserDataDir() {
122
68
  let cacheDirectory;
123
69
  if (process.platform === 'linux')
124
70
  cacheDirectory = process.env.XDG_CACHE_HOME || path_1.default.join(os_1.default.homedir(), '.cache');
@@ -132,3 +78,64 @@ async function userDataDir() {
132
78
  await fs_1.default.promises.mkdir(result, { recursive: true });
133
79
  return result;
134
80
  }
81
+ async function startSSEServer(port, serverList) {
82
+ const sessions = new Map();
83
+ const httpServer = http_1.default.createServer(async (req, res) => {
84
+ if (req.method === 'POST') {
85
+ const searchParams = new URL(`http://localhost${req.url}`).searchParams;
86
+ const sessionId = searchParams.get('sessionId');
87
+ if (!sessionId) {
88
+ res.statusCode = 400;
89
+ res.end('Missing sessionId');
90
+ return;
91
+ }
92
+ const transport = sessions.get(sessionId);
93
+ if (!transport) {
94
+ res.statusCode = 404;
95
+ res.end('Session not found');
96
+ return;
97
+ }
98
+ await transport.handlePostMessage(req, res);
99
+ return;
100
+ }
101
+ else if (req.method === 'GET') {
102
+ const transport = new sse_js_1.SSEServerTransport('/sse', res);
103
+ sessions.set(transport.sessionId, transport);
104
+ const server = await serverList.create();
105
+ res.on('close', () => {
106
+ sessions.delete(transport.sessionId);
107
+ serverList.close(server).catch(e => console.error(e));
108
+ });
109
+ await server.connect(transport);
110
+ return;
111
+ }
112
+ else {
113
+ res.statusCode = 405;
114
+ res.end('Method not allowed');
115
+ }
116
+ });
117
+ httpServer.listen(port, () => {
118
+ const address = httpServer.address();
119
+ (0, assert_1.default)(address, 'Could not bind server socket');
120
+ let url;
121
+ if (typeof address === 'string') {
122
+ url = address;
123
+ }
124
+ else {
125
+ const resolvedPort = address.port;
126
+ let resolvedHost = address.family === 'IPv4' ? address.address : `[${address.address}]`;
127
+ if (resolvedHost === '0.0.0.0' || resolvedHost === '[::]')
128
+ resolvedHost = 'localhost';
129
+ url = `http://${resolvedHost}:${resolvedPort}`;
130
+ }
131
+ console.log(`Listening on ${url}`);
132
+ console.log('Put this in your client config:');
133
+ console.log(JSON.stringify({
134
+ 'mcpServers': {
135
+ 'playwright': {
136
+ 'url': `${url}/sse`
137
+ }
138
+ }
139
+ }, undefined, 2));
140
+ });
141
+ }
package/lib/server.js CHANGED
@@ -15,6 +15,7 @@
15
15
  * limitations under the License.
16
16
  */
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.ServerList = void 0;
18
19
  exports.createServerWithTools = createServerWithTools;
19
20
  const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
20
21
  const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
@@ -67,3 +68,25 @@ function createServerWithTools(options) {
67
68
  };
68
69
  return server;
69
70
  }
71
+ class ServerList {
72
+ _servers = [];
73
+ _serverFactory;
74
+ constructor(serverFactory) {
75
+ this._serverFactory = serverFactory;
76
+ }
77
+ async create() {
78
+ const server = this._serverFactory();
79
+ this._servers.push(server);
80
+ return server;
81
+ }
82
+ async close(server) {
83
+ const index = this._servers.indexOf(server);
84
+ if (index !== -1)
85
+ this._servers.splice(index, 1);
86
+ await server.close();
87
+ }
88
+ async closeAll() {
89
+ await Promise.all(this._servers.map(server => server.close()));
90
+ }
91
+ }
92
+ exports.ServerList = ServerList;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@playwright/mcp",
3
- "version": "0.0.6",
3
+ "version": "0.0.7",
4
4
  "description": "Playwright Tools for MCP",
5
5
  "repository": {
6
6
  "type": "git",
@@ -20,7 +20,7 @@
20
20
  "watch": "tsc --watch",
21
21
  "test": "playwright test",
22
22
  "clean": "rm -rf lib",
23
- "publish": "npm run clean && npm run build && npm run test && npm publish"
23
+ "npm-publish": "npm run clean && npm run build && npm run test && npm publish"
24
24
  },
25
25
  "exports": {
26
26
  "./package.json": "./package.json",