@kiro-paradigm/browser 0.1.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 +21 -0
- package/README.md +56 -0
- package/dist/cdp-client.d.ts +57 -0
- package/dist/cdp-client.js +150 -0
- package/dist/cdp-client.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +126 -0
- package/dist/index.js.map +1 -0
- package/package.json +54 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Frank Ren
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Browser Power for Kiro
|
|
2
|
+
|
|
3
|
+
A [Kiro](https://kiro.dev) power providing browser automation with a CDP fallback MCP server.
|
|
4
|
+
|
|
5
|
+
## What's Included
|
|
6
|
+
|
|
7
|
+
| Component | Purpose |
|
|
8
|
+
|-----------|---------|
|
|
9
|
+
| `.kiro/powers/browser/` | Kiro power (Playwright + CDP + Chrome DevTools MCP servers) |
|
|
10
|
+
| `src/` | CDP fallback MCP server (`@renfeng/kiro-browser-alternative`) |
|
|
11
|
+
|
|
12
|
+
## MCP Servers
|
|
13
|
+
|
|
14
|
+
- **Playwright** (enabled) — Full browser automation via `@playwright/mcp`
|
|
15
|
+
- **alternative** (enabled) — Fallback for when Chrome is already running with the same user data directory
|
|
16
|
+
- **Chrome DevTools** (disabled) — Alternative via `chrome-devtools-mcp`
|
|
17
|
+
|
|
18
|
+
## Quick Start
|
|
19
|
+
|
|
20
|
+
### As a Kiro Power
|
|
21
|
+
|
|
22
|
+
1. Clone this repo
|
|
23
|
+
2. In Kiro, open Command Palette → "Powers" → "Add power from Local Path"
|
|
24
|
+
3. Select the `.kiro/powers/browser` directory
|
|
25
|
+
|
|
26
|
+
### As a Workspace Root
|
|
27
|
+
|
|
28
|
+
Add to your `.code-workspace`:
|
|
29
|
+
|
|
30
|
+
```json
|
|
31
|
+
{ "name": "browser", "path": "../browser-kirospace" }
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The power at `.kiro/powers/browser/` is auto-discovered.
|
|
35
|
+
|
|
36
|
+
## CDP Fallback
|
|
37
|
+
|
|
38
|
+
When Playwright fails with "Opening in existing browser session", the `alternative` server auto-discovers the running Chrome's CDP port and connects directly. Tools:
|
|
39
|
+
|
|
40
|
+
- `cdp_list_tabs` — List open tabs
|
|
41
|
+
- `cdp_navigate` — Navigate a tab to a URL
|
|
42
|
+
- `cdp_screenshot` — Capture viewport as PNG
|
|
43
|
+
- `cdp_evaluate` — Run JavaScript in a tab
|
|
44
|
+
- `cdp_reload` — Reload a tab
|
|
45
|
+
|
|
46
|
+
## Development
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
npm install
|
|
50
|
+
npm run build
|
|
51
|
+
npm test
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## License
|
|
55
|
+
|
|
56
|
+
MIT
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CDP Client — low-level Chrome DevTools Protocol communication.
|
|
3
|
+
*
|
|
4
|
+
* Discovers the CDP port from running Chrome processes, lists tabs,
|
|
5
|
+
* and sends CDP commands over websockets.
|
|
6
|
+
*/
|
|
7
|
+
interface CdpTab {
|
|
8
|
+
id: string;
|
|
9
|
+
type: string;
|
|
10
|
+
title?: string;
|
|
11
|
+
url?: string;
|
|
12
|
+
webSocketDebuggerUrl?: string;
|
|
13
|
+
}
|
|
14
|
+
interface CdpResponse {
|
|
15
|
+
id?: number;
|
|
16
|
+
result?: Record<string, unknown>;
|
|
17
|
+
error?: {
|
|
18
|
+
code: number;
|
|
19
|
+
message: string;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export interface CdpEvalResult {
|
|
23
|
+
type?: string;
|
|
24
|
+
subtype?: string;
|
|
25
|
+
value?: unknown;
|
|
26
|
+
description?: string;
|
|
27
|
+
}
|
|
28
|
+
export declare class CdpClient {
|
|
29
|
+
private cachedPort;
|
|
30
|
+
private readonly cwd;
|
|
31
|
+
constructor(cwd?: string);
|
|
32
|
+
/**
|
|
33
|
+
* Auto-discover the CDP port from running Chrome processes.
|
|
34
|
+
*
|
|
35
|
+
* Convention: looks for a Chrome process whose --user-data-dir ends with
|
|
36
|
+
* `.playwright-data` and matches the working directory of this process.
|
|
37
|
+
* This ensures the CDP fallback connects to the same Chrome instance that
|
|
38
|
+
* Playwright launched for the current workspace.
|
|
39
|
+
*
|
|
40
|
+
* Falls back to the first discovered port if no workspace match is found.
|
|
41
|
+
*/
|
|
42
|
+
discoverPort(): Promise<number>;
|
|
43
|
+
/**
|
|
44
|
+
* List open tabs on the given CDP port.
|
|
45
|
+
*/
|
|
46
|
+
listTabs(port: number): Promise<CdpTab[]>;
|
|
47
|
+
/**
|
|
48
|
+
* Get the websocket URL for a tab by index.
|
|
49
|
+
*/
|
|
50
|
+
getTabWsUrl(port: number, tabIndex: number): Promise<string>;
|
|
51
|
+
/**
|
|
52
|
+
* Send a CDP command and return the response.
|
|
53
|
+
*/
|
|
54
|
+
send(wsUrl: string, method: string, params?: Record<string, unknown>, timeout?: number): Promise<CdpResponse>;
|
|
55
|
+
private httpGet;
|
|
56
|
+
}
|
|
57
|
+
export {};
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CDP Client — low-level Chrome DevTools Protocol communication.
|
|
3
|
+
*
|
|
4
|
+
* Discovers the CDP port from running Chrome processes, lists tabs,
|
|
5
|
+
* and sends CDP commands over websockets.
|
|
6
|
+
*/
|
|
7
|
+
import { execFile } from 'node:child_process';
|
|
8
|
+
import { promisify } from 'node:util';
|
|
9
|
+
import http from 'node:http';
|
|
10
|
+
import WebSocket from 'ws';
|
|
11
|
+
const execFileAsync = promisify(execFile);
|
|
12
|
+
export class CdpClient {
|
|
13
|
+
cachedPort = null;
|
|
14
|
+
cwd;
|
|
15
|
+
constructor(cwd) {
|
|
16
|
+
this.cwd = cwd ?? process.cwd();
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Auto-discover the CDP port from running Chrome processes.
|
|
20
|
+
*
|
|
21
|
+
* Convention: looks for a Chrome process whose --user-data-dir ends with
|
|
22
|
+
* `.playwright-data` and matches the working directory of this process.
|
|
23
|
+
* This ensures the CDP fallback connects to the same Chrome instance that
|
|
24
|
+
* Playwright launched for the current workspace.
|
|
25
|
+
*
|
|
26
|
+
* Falls back to the first discovered port if no workspace match is found.
|
|
27
|
+
*/
|
|
28
|
+
async discoverPort() {
|
|
29
|
+
if (this.cachedPort) {
|
|
30
|
+
try {
|
|
31
|
+
await this.httpGet(`http://localhost:${this.cachedPort}/json/version`);
|
|
32
|
+
return this.cachedPort;
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
this.cachedPort = null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
// Convention: match the .playwright-data dir under the current working directory
|
|
40
|
+
const expectedDataDir = `${this.cwd}/.playwright-data`;
|
|
41
|
+
// Try workspace-specific match first (own try/catch so failure falls through to generic)
|
|
42
|
+
try {
|
|
43
|
+
// Run ps aux and match in Node.js to avoid shell escaping and prefix-collision issues.
|
|
44
|
+
// grep -F with env var narrows to candidate lines; JS does exact boundary matching.
|
|
45
|
+
const { stdout: specificOut } = await execFileAsync('bash', [
|
|
46
|
+
'-c',
|
|
47
|
+
`ps aux | grep -v grep | grep -F "user-data-dir=$EXPECTED_DIR"`,
|
|
48
|
+
], { env: { ...process.env, EXPECTED_DIR: expectedDataDir } });
|
|
49
|
+
// Exact boundary match: the path must be followed by a space, quote, or end-of-line
|
|
50
|
+
const portPattern = /remote-debugging-port=(\d+)/;
|
|
51
|
+
const exactPattern = `user-data-dir=${expectedDataDir}`;
|
|
52
|
+
const matchedLine = specificOut.split('\n').find(line => {
|
|
53
|
+
const idx = line.indexOf(exactPattern);
|
|
54
|
+
if (idx === -1)
|
|
55
|
+
return false;
|
|
56
|
+
const afterChar = line[idx + exactPattern.length];
|
|
57
|
+
return afterChar === undefined || afterChar === ' ' || afterChar === '"' || afterChar === "'" || afterChar === '/';
|
|
58
|
+
});
|
|
59
|
+
const specificMatch = matchedLine?.match(portPattern);
|
|
60
|
+
if (specificMatch) {
|
|
61
|
+
const port = parseInt(specificMatch[1], 10);
|
|
62
|
+
await this.httpGet(`http://localhost:${port}/json/version`);
|
|
63
|
+
this.cachedPort = port;
|
|
64
|
+
return port;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
// Workspace-specific discovery failed — fall through to generic.
|
|
69
|
+
// Intentionally silent: the generic path will either succeed or the
|
|
70
|
+
// outer catch will surface a meaningful error message.
|
|
71
|
+
}
|
|
72
|
+
// Fall back to any Chrome with remote-debugging-port
|
|
73
|
+
const { stdout } = await execFileAsync('bash', [
|
|
74
|
+
'-c',
|
|
75
|
+
'ps aux | grep -v grep | grep -o "remote-debugging-port=[0-9]*" | head -1',
|
|
76
|
+
]);
|
|
77
|
+
const match = stdout.trim().match(/remote-debugging-port=(\d+)/);
|
|
78
|
+
if (match) {
|
|
79
|
+
const port = parseInt(match[1], 10);
|
|
80
|
+
await this.httpGet(`http://localhost:${port}/json/version`);
|
|
81
|
+
this.cachedPort = port;
|
|
82
|
+
return port;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
// fall through
|
|
87
|
+
}
|
|
88
|
+
throw new Error('Cannot find a running Chrome with --remote-debugging-port. ' +
|
|
89
|
+
'Start Chrome with --remote-debugging-port=PORT or let Playwright MCP launch it first.');
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* List open tabs on the given CDP port.
|
|
93
|
+
*/
|
|
94
|
+
async listTabs(port) {
|
|
95
|
+
const body = await this.httpGet(`http://localhost:${port}/json/list`);
|
|
96
|
+
return JSON.parse(body);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Get the websocket URL for a tab by index.
|
|
100
|
+
*/
|
|
101
|
+
async getTabWsUrl(port, tabIndex) {
|
|
102
|
+
const tabs = await this.listTabs(port);
|
|
103
|
+
if (tabIndex < 0 || tabIndex >= tabs.length) {
|
|
104
|
+
throw new Error(`Tab index ${tabIndex} out of range (0-${tabs.length - 1})`);
|
|
105
|
+
}
|
|
106
|
+
const wsUrl = tabs[tabIndex].webSocketDebuggerUrl;
|
|
107
|
+
if (!wsUrl) {
|
|
108
|
+
throw new Error(`Tab ${tabIndex} has no webSocketDebuggerUrl (type: ${tabs[tabIndex].type})`);
|
|
109
|
+
}
|
|
110
|
+
return wsUrl;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Send a CDP command and return the response.
|
|
114
|
+
*/
|
|
115
|
+
async send(wsUrl, method, params = {}, timeout = 30000) {
|
|
116
|
+
return new Promise((resolve, reject) => {
|
|
117
|
+
const ws = new WebSocket(wsUrl, { maxPayload: 50 * 1024 * 1024 });
|
|
118
|
+
const timer = setTimeout(() => {
|
|
119
|
+
ws.close();
|
|
120
|
+
reject(new Error(`Timeout waiting for CDP response to ${method}`));
|
|
121
|
+
}, timeout);
|
|
122
|
+
ws.on('open', () => {
|
|
123
|
+
ws.send(JSON.stringify({ id: 1, method, params }));
|
|
124
|
+
});
|
|
125
|
+
ws.on('message', (data) => {
|
|
126
|
+
const msg = JSON.parse(data.toString());
|
|
127
|
+
if (msg.id === 1) {
|
|
128
|
+
clearTimeout(timer);
|
|
129
|
+
ws.close();
|
|
130
|
+
resolve(msg);
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
ws.on('error', (err) => {
|
|
134
|
+
clearTimeout(timer);
|
|
135
|
+
reject(err);
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
httpGet(url) {
|
|
140
|
+
return new Promise((resolve, reject) => {
|
|
141
|
+
http.get(url, { timeout: 5000 }, (res) => {
|
|
142
|
+
let body = '';
|
|
143
|
+
res.on('data', (chunk) => { body += chunk.toString(); });
|
|
144
|
+
res.on('end', () => resolve(body));
|
|
145
|
+
res.on('error', reject);
|
|
146
|
+
}).on('error', reject);
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
//# sourceMappingURL=cdp-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cdp-client.js","sourceRoot":"","sources":["../src/cdp-client.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* CDP Browser MCP Server — connects to an already-running Chrome instance
|
|
4
|
+
* via Chrome DevTools Protocol when Playwright MCP cannot launch.
|
|
5
|
+
*
|
|
6
|
+
* Auto-discovers the CDP port from running Chrome processes.
|
|
7
|
+
*/
|
|
8
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
9
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
10
|
+
import { z } from 'zod';
|
|
11
|
+
import { CdpClient } from './cdp-client.js';
|
|
12
|
+
const server = new McpServer({
|
|
13
|
+
name: 'alternative',
|
|
14
|
+
version: '0.1.0',
|
|
15
|
+
});
|
|
16
|
+
// Workspace-specific port discovery relies on process.cwd() being the workspace
|
|
17
|
+
// folder at startup. Kiro sets cwd to the workspace folder when launching MCP
|
|
18
|
+
// servers, so the default (no explicit cwd) is correct for production use.
|
|
19
|
+
const cdp = new CdpClient();
|
|
20
|
+
// --- Tool: cdp_list_tabs ---
|
|
21
|
+
server.tool('cdp_list_tabs', 'List open browser tabs. Auto-discovers the CDP port from running Chrome processes.', { port: z.number().optional().describe('CDP port (auto-detected if omitted)') }, async ({ port }) => {
|
|
22
|
+
const resolvedPort = port ?? await cdp.discoverPort();
|
|
23
|
+
const tabs = await cdp.listTabs(resolvedPort);
|
|
24
|
+
const pages = tabs
|
|
25
|
+
.filter((t) => t.type === 'page')
|
|
26
|
+
.map((t, i) => `${i}: ${t.title ?? '(no title)'}\n ${t.url ?? ''}`);
|
|
27
|
+
return { content: [{ type: 'text', text: pages.join('\n\n') || '(no page tabs open)' }] };
|
|
28
|
+
});
|
|
29
|
+
// --- Tool: cdp_navigate ---
|
|
30
|
+
server.tool('cdp_navigate', 'Navigate a browser tab to a URL.', {
|
|
31
|
+
tab: z.number().describe('Tab index from cdp_list_tabs'),
|
|
32
|
+
url: z.string().describe('URL to navigate to'),
|
|
33
|
+
wait: z.number().optional().default(3).describe('Seconds to wait after navigation (default: 3)'),
|
|
34
|
+
port: z.number().optional().describe('CDP port (auto-detected if omitted)'),
|
|
35
|
+
}, async ({ tab, url, wait, port }) => {
|
|
36
|
+
const resolvedPort = port ?? await cdp.discoverPort();
|
|
37
|
+
const wsUrl = await cdp.getTabWsUrl(resolvedPort, tab);
|
|
38
|
+
const result = await cdp.send(wsUrl, 'Page.navigate', { url });
|
|
39
|
+
if (result.error) {
|
|
40
|
+
return { content: [{ type: 'text', text: `Error: ${JSON.stringify(result.error)}` }], isError: true };
|
|
41
|
+
}
|
|
42
|
+
if (wait > 0)
|
|
43
|
+
await sleep(wait * 1000);
|
|
44
|
+
return { content: [{ type: 'text', text: `Navigated to ${url}` }] };
|
|
45
|
+
});
|
|
46
|
+
// --- Tool: cdp_screenshot ---
|
|
47
|
+
server.tool('cdp_screenshot', 'Take a screenshot of a browser tab. Returns the image as base64-encoded PNG.', {
|
|
48
|
+
tab: z.number().describe('Tab index from cdp_list_tabs'),
|
|
49
|
+
wait: z.number().optional().default(0).describe('Seconds to wait before screenshot (default: 0)'),
|
|
50
|
+
port: z.number().optional().describe('CDP port (auto-detected if omitted)'),
|
|
51
|
+
}, async ({ tab, wait, port }) => {
|
|
52
|
+
const resolvedPort = port ?? await cdp.discoverPort();
|
|
53
|
+
const wsUrl = await cdp.getTabWsUrl(resolvedPort, tab);
|
|
54
|
+
if (wait > 0)
|
|
55
|
+
await sleep(wait * 1000);
|
|
56
|
+
const result = await cdp.send(wsUrl, 'Page.captureScreenshot', { format: 'png' });
|
|
57
|
+
if (result.error) {
|
|
58
|
+
return { content: [{ type: 'text', text: `Error: ${JSON.stringify(result.error)}` }], isError: true };
|
|
59
|
+
}
|
|
60
|
+
const data = result.result?.data;
|
|
61
|
+
if (typeof data !== 'string') {
|
|
62
|
+
return { content: [{ type: 'text', text: 'Error: no screenshot data returned' }], isError: true };
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
content: [{
|
|
66
|
+
type: 'image',
|
|
67
|
+
data,
|
|
68
|
+
mimeType: 'image/png',
|
|
69
|
+
}],
|
|
70
|
+
};
|
|
71
|
+
});
|
|
72
|
+
// --- Tool: cdp_evaluate ---
|
|
73
|
+
server.tool('cdp_evaluate', 'Evaluate a JavaScript expression in a browser tab and return the result.', {
|
|
74
|
+
tab: z.number().describe('Tab index from cdp_list_tabs'),
|
|
75
|
+
expression: z.string().describe('JavaScript expression to evaluate'),
|
|
76
|
+
port: z.number().optional().describe('CDP port (auto-detected if omitted)'),
|
|
77
|
+
}, async ({ tab, expression, port }) => {
|
|
78
|
+
const resolvedPort = port ?? await cdp.discoverPort();
|
|
79
|
+
const wsUrl = await cdp.getTabWsUrl(resolvedPort, tab);
|
|
80
|
+
const result = await cdp.send(wsUrl, 'Runtime.evaluate', {
|
|
81
|
+
expression,
|
|
82
|
+
returnByValue: true,
|
|
83
|
+
});
|
|
84
|
+
if (result.error) {
|
|
85
|
+
return { content: [{ type: 'text', text: `Error: ${JSON.stringify(result.error)}` }], isError: true };
|
|
86
|
+
}
|
|
87
|
+
const evalResult = result.result?.result;
|
|
88
|
+
if (!evalResult) {
|
|
89
|
+
return { content: [{ type: 'text', text: '(no result)' }] };
|
|
90
|
+
}
|
|
91
|
+
if (evalResult.type === 'undefined') {
|
|
92
|
+
return { content: [{ type: 'text', text: '(undefined)' }] };
|
|
93
|
+
}
|
|
94
|
+
if (evalResult.subtype === 'error') {
|
|
95
|
+
return { content: [{ type: 'text', text: `Error: ${evalResult.description ?? evalResult.value}` }], isError: true };
|
|
96
|
+
}
|
|
97
|
+
const value = evalResult.value;
|
|
98
|
+
const text = typeof value === 'string' ? value : JSON.stringify(value, null, 2);
|
|
99
|
+
return { content: [{ type: 'text', text }] };
|
|
100
|
+
});
|
|
101
|
+
// --- Tool: cdp_reload ---
|
|
102
|
+
server.tool('cdp_reload', 'Reload a browser tab.', {
|
|
103
|
+
tab: z.number().describe('Tab index from cdp_list_tabs'),
|
|
104
|
+
wait: z.number().optional().default(3).describe('Seconds to wait after reload (default: 3)'),
|
|
105
|
+
port: z.number().optional().describe('CDP port (auto-detected if omitted)'),
|
|
106
|
+
}, async ({ tab, wait, port }) => {
|
|
107
|
+
const resolvedPort = port ?? await cdp.discoverPort();
|
|
108
|
+
const wsUrl = await cdp.getTabWsUrl(resolvedPort, tab);
|
|
109
|
+
await cdp.send(wsUrl, 'Page.reload', {});
|
|
110
|
+
if (wait > 0)
|
|
111
|
+
await sleep(wait * 1000);
|
|
112
|
+
return { content: [{ type: 'text', text: 'Page reloaded' }] };
|
|
113
|
+
});
|
|
114
|
+
function sleep(ms) {
|
|
115
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
116
|
+
}
|
|
117
|
+
// --- Start ---
|
|
118
|
+
async function main() {
|
|
119
|
+
const transport = new StdioServerTransport();
|
|
120
|
+
await server.connect(transport);
|
|
121
|
+
}
|
|
122
|
+
main().catch((err) => {
|
|
123
|
+
console.error('Fatal:', err);
|
|
124
|
+
process.exit(1);
|
|
125
|
+
});
|
|
126
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kiro-paradigm/browser",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP server providing Chrome DevTools Protocol (CDP) browser automation — connects to an already-running Chrome instance when Playwright MCP cannot launch",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"browser-cdp-mcp": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"keywords": [
|
|
11
|
+
"mcp",
|
|
12
|
+
"model-context-protocol",
|
|
13
|
+
"browser",
|
|
14
|
+
"chrome",
|
|
15
|
+
"cdp",
|
|
16
|
+
"devtools",
|
|
17
|
+
"automation",
|
|
18
|
+
"kiro"
|
|
19
|
+
],
|
|
20
|
+
"author": "Frank Ren",
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "https://gitlab.com/kiro-paradigm/browser-kirospace.git"
|
|
25
|
+
},
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=18.0.0"
|
|
28
|
+
},
|
|
29
|
+
"publishConfig": {
|
|
30
|
+
"registry": "https://registry.npmjs.org"
|
|
31
|
+
},
|
|
32
|
+
"files": [
|
|
33
|
+
"dist/",
|
|
34
|
+
"README.md",
|
|
35
|
+
"LICENSE"
|
|
36
|
+
],
|
|
37
|
+
"scripts": {
|
|
38
|
+
"build": "tsc",
|
|
39
|
+
"prepublishOnly": "npm run build",
|
|
40
|
+
"type-check": "tsc --noEmit",
|
|
41
|
+
"test": "vitest --run",
|
|
42
|
+
"test:watch": "vitest"
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"@modelcontextprotocol/sdk": "^1.25.1",
|
|
46
|
+
"ws": "^8.18.0"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@types/node": "^20.0.0",
|
|
50
|
+
"@types/ws": "^8.5.0",
|
|
51
|
+
"typescript": "^5.0.0",
|
|
52
|
+
"vitest": "^4.1.0"
|
|
53
|
+
}
|
|
54
|
+
}
|