chrome-devtools-mcp-for-extension 0.25.8 → 0.26.1
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 +86 -3
- package/build/src/main.js +28 -28
- package/build/src/plugin-api.js +189 -0
- package/build/src/tools/core-tools.js +71 -0
- package/build/src/tools/optional-tools.js +68 -0
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -169,9 +169,12 @@ vim src/tools/extensions.ts
|
|
|
169
169
|
chrome-devtools-mcp/
|
|
170
170
|
├── src/
|
|
171
171
|
│ ├── tools/ # MCP tool definitions
|
|
172
|
-
│ │ ├──
|
|
172
|
+
│ │ ├── core-tools.ts # Core tool exports (v0.26.0)
|
|
173
|
+
│ │ ├── optional-tools.ts # Web-LLM tool exports (v0.26.0)
|
|
173
174
|
│ │ ├── chatgpt-web.ts # ChatGPT automation
|
|
175
|
+
│ │ ├── gemini-web.ts # Gemini automation
|
|
174
176
|
│ │ └── ...
|
|
177
|
+
│ ├── plugin-api.ts # Plugin architecture (v0.26.0)
|
|
175
178
|
│ ├── browser.ts # Browser/profile management
|
|
176
179
|
│ ├── main.ts # MCP server entry point
|
|
177
180
|
│ └── graceful.ts # Graceful shutdown
|
|
@@ -264,7 +267,8 @@ git push && git push --tags
|
|
|
264
267
|
- 🔧 **Browser Testing**: Test extensions in real user environments
|
|
265
268
|
- 🐛 **Advanced Debugging**: Service worker inspection, console monitoring
|
|
266
269
|
- 📸 **Screenshot Generation**: Auto-create store listing images
|
|
267
|
-
- 🤖 **ChatGPT Integration**: Automated
|
|
270
|
+
- 🤖 **ChatGPT/Gemini Integration**: Automated AI interactions for research
|
|
271
|
+
- 🔌 **Plugin Architecture** (v0.26.0): Extensible tool system with external plugins
|
|
268
272
|
|
|
269
273
|
---
|
|
270
274
|
|
|
@@ -376,6 +380,85 @@ pkill -f mcp-wrapper
|
|
|
376
380
|
|
|
377
381
|
---
|
|
378
382
|
|
|
383
|
+
## 🔌 Plugin Architecture (v0.26.0)
|
|
384
|
+
|
|
385
|
+
### Tool Categories
|
|
386
|
+
|
|
387
|
+
**Core Tools (18)** - Stable, site-independent:
|
|
388
|
+
- Input: click, hover, fill, drag, fill_form, upload_file
|
|
389
|
+
- Navigation: pages, navigate, resize_page, handle_dialog
|
|
390
|
+
- Debugging: list_console_messages, take_screenshot, evaluate_script, take_snapshot, wait_for
|
|
391
|
+
- Analysis: emulate, network, performance
|
|
392
|
+
|
|
393
|
+
**Optional Tools (2)** - Web-LLM, site-dependent (may break with UI changes):
|
|
394
|
+
- `ask_chatgpt_web` - ChatGPT browser automation
|
|
395
|
+
- `ask_gemini_web` - Gemini browser automation
|
|
396
|
+
|
|
397
|
+
### Disable Web-LLM Tools
|
|
398
|
+
|
|
399
|
+
If you don't need ChatGPT/Gemini integration:
|
|
400
|
+
|
|
401
|
+
```json
|
|
402
|
+
{
|
|
403
|
+
"mcpServers": {
|
|
404
|
+
"chrome-devtools-extension": {
|
|
405
|
+
"command": "npx",
|
|
406
|
+
"args": ["chrome-devtools-mcp-for-extension@latest"],
|
|
407
|
+
"env": {
|
|
408
|
+
"MCP_DISABLE_WEB_LLM": "true"
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
### External Plugins
|
|
416
|
+
|
|
417
|
+
Load custom plugins at startup:
|
|
418
|
+
|
|
419
|
+
```json
|
|
420
|
+
{
|
|
421
|
+
"mcpServers": {
|
|
422
|
+
"chrome-devtools-extension": {
|
|
423
|
+
"command": "npx",
|
|
424
|
+
"args": ["chrome-devtools-mcp-for-extension@latest"],
|
|
425
|
+
"env": {
|
|
426
|
+
"MCP_PLUGINS": "./my-plugin.js,@org/another-plugin"
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
**Plugin Interface:**
|
|
434
|
+
```typescript
|
|
435
|
+
// my-plugin.js
|
|
436
|
+
export default {
|
|
437
|
+
id: 'my-plugin',
|
|
438
|
+
name: 'My Custom Plugin',
|
|
439
|
+
version: '1.0.0',
|
|
440
|
+
|
|
441
|
+
async register(ctx) {
|
|
442
|
+
ctx.registry.register({
|
|
443
|
+
name: 'my_custom_tool',
|
|
444
|
+
description: 'Does something useful',
|
|
445
|
+
schema: { /* zod schema */ },
|
|
446
|
+
annotations: { category: 'automation' },
|
|
447
|
+
async handler(input, response, context) {
|
|
448
|
+
// Tool implementation
|
|
449
|
+
}
|
|
450
|
+
});
|
|
451
|
+
ctx.log('Plugin registered!');
|
|
452
|
+
},
|
|
453
|
+
|
|
454
|
+
async unload() {
|
|
455
|
+
// Cleanup if needed
|
|
456
|
+
}
|
|
457
|
+
};
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
---
|
|
461
|
+
|
|
379
462
|
## 🙏 Credits
|
|
380
463
|
|
|
381
464
|
This project is a fork of [Chrome DevTools MCP](https://github.com/ChromeDevTools/chrome-devtools-mcp) by Google LLC.
|
|
@@ -393,5 +476,5 @@ This project is a fork of [Chrome DevTools MCP](https://github.com/ChromeDevTool
|
|
|
393
476
|
|
|
394
477
|
Apache-2.0
|
|
395
478
|
|
|
396
|
-
**Version**: 0.
|
|
479
|
+
**Version**: 0.26.0
|
|
397
480
|
**Repository**: https://github.com/usedhonda/chrome-devtools-mcp
|
package/build/src/main.js
CHANGED
|
@@ -46,17 +46,9 @@ import { McpResponse } from './McpResponse.js';
|
|
|
46
46
|
import { Mutex } from './Mutex.js';
|
|
47
47
|
import { setProjectRoot } from './project-root-state.js';
|
|
48
48
|
import { resolveRoots } from './roots-manager.js';
|
|
49
|
-
import
|
|
50
|
-
import
|
|
51
|
-
import
|
|
52
|
-
import * as geminiWebTools from './tools/gemini-web.js';
|
|
53
|
-
import { click, fill, fillForm } from './tools/input.js';
|
|
54
|
-
import * as networkTools from './tools/network.js';
|
|
55
|
-
import { pages, navigate } from './tools/pages.js';
|
|
56
|
-
import * as performanceTools from './tools/performance.js';
|
|
57
|
-
import * as screenshotTools from './tools/screenshot.js';
|
|
58
|
-
import * as scriptTools from './tools/script.js';
|
|
59
|
-
import * as snapshotTools from './tools/snapshot.js';
|
|
49
|
+
import { ToolRegistry, PluginLoader } from './plugin-api.js';
|
|
50
|
+
import { registerCoreTools, getCoreToolCount } from './tools/core-tools.js';
|
|
51
|
+
import { registerOptionalTools, WEB_LLM_TOOLS_INFO } from './tools/optional-tools.js';
|
|
60
52
|
function readPackageJson() {
|
|
61
53
|
const currentDir = import.meta.dirname;
|
|
62
54
|
const packageJsonPath = path.join(currentDir, '..', '..', 'package.json');
|
|
@@ -237,25 +229,33 @@ function registerTool(tool) {
|
|
|
237
229
|
}
|
|
238
230
|
});
|
|
239
231
|
}
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
232
|
+
// v0.26.0: Use ToolRegistry for plugin architecture
|
|
233
|
+
const toolRegistry = new ToolRegistry();
|
|
234
|
+
// Register core tools (stable, site-independent)
|
|
235
|
+
registerCoreTools(toolRegistry);
|
|
236
|
+
logger(`[tools] Registered ${getCoreToolCount()} core tools`);
|
|
237
|
+
// Register optional tools (web-llm, site-dependent)
|
|
238
|
+
const optionalCount = registerOptionalTools(toolRegistry);
|
|
239
|
+
if (optionalCount > 0) {
|
|
240
|
+
logger(`[tools] ${WEB_LLM_TOOLS_INFO.disclaimer}`);
|
|
241
|
+
}
|
|
242
|
+
// Load external plugins from MCP_PLUGINS environment variable
|
|
243
|
+
const pluginList = process.env.MCP_PLUGINS;
|
|
244
|
+
if (pluginList) {
|
|
245
|
+
const pluginLoader = new PluginLoader(toolRegistry, logger);
|
|
246
|
+
const { loaded, failed } = await pluginLoader.loadFromList(pluginList);
|
|
247
|
+
if (loaded.length > 0) {
|
|
248
|
+
logger(`[plugins] Successfully loaded: ${loaded.join(', ')}`);
|
|
249
|
+
}
|
|
250
|
+
if (failed.length > 0) {
|
|
251
|
+
logger(`[plugins] Failed to load: ${failed.join(', ')}`);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
// Register all tools with MCP server
|
|
255
|
+
for (const tool of toolRegistry.getAll()) {
|
|
257
256
|
registerTool(tool);
|
|
258
257
|
}
|
|
258
|
+
logger(`[tools] Total registered: ${toolRegistry.size} tools`);
|
|
259
259
|
// Set initialization callback
|
|
260
260
|
server.server.oninitialized = () => {
|
|
261
261
|
initializationComplete = true;
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Registry for managing MCP tools.
|
|
8
|
+
* Allows dynamic registration and querying of tools.
|
|
9
|
+
*/
|
|
10
|
+
export class ToolRegistry {
|
|
11
|
+
tools = new Map();
|
|
12
|
+
categories = new Map();
|
|
13
|
+
/**
|
|
14
|
+
* Register a single tool.
|
|
15
|
+
* @throws Error if a tool with the same name already exists
|
|
16
|
+
*/
|
|
17
|
+
register(tool) {
|
|
18
|
+
if (this.tools.has(tool.name)) {
|
|
19
|
+
throw new Error(`Tool "${tool.name}" is already registered`);
|
|
20
|
+
}
|
|
21
|
+
this.tools.set(tool.name, tool);
|
|
22
|
+
// Track by category
|
|
23
|
+
const category = tool.annotations.category;
|
|
24
|
+
if (!this.categories.has(category)) {
|
|
25
|
+
this.categories.set(category, new Set());
|
|
26
|
+
}
|
|
27
|
+
this.categories.get(category).add(tool.name);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Register multiple tools at once.
|
|
31
|
+
*/
|
|
32
|
+
registerBatch(tools) {
|
|
33
|
+
for (const tool of tools) {
|
|
34
|
+
this.register(tool);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Get all registered tools.
|
|
39
|
+
*/
|
|
40
|
+
getAll() {
|
|
41
|
+
return Array.from(this.tools.values());
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Get tools by category.
|
|
45
|
+
*/
|
|
46
|
+
getByCategory(category) {
|
|
47
|
+
const names = this.categories.get(category);
|
|
48
|
+
if (!names)
|
|
49
|
+
return [];
|
|
50
|
+
return Array.from(names)
|
|
51
|
+
.map((name) => this.tools.get(name))
|
|
52
|
+
.filter(Boolean);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Get a specific tool by name.
|
|
56
|
+
*/
|
|
57
|
+
get(name) {
|
|
58
|
+
return this.tools.get(name);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Check if a tool is registered.
|
|
62
|
+
*/
|
|
63
|
+
has(name) {
|
|
64
|
+
return this.tools.has(name);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Get count of registered tools.
|
|
68
|
+
*/
|
|
69
|
+
get size() {
|
|
70
|
+
return this.tools.size;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Unregister a tool by name.
|
|
74
|
+
* Returns true if the tool was removed, false if it didn't exist.
|
|
75
|
+
*/
|
|
76
|
+
unregister(name) {
|
|
77
|
+
const tool = this.tools.get(name);
|
|
78
|
+
if (!tool)
|
|
79
|
+
return false;
|
|
80
|
+
this.tools.delete(name);
|
|
81
|
+
const category = tool.annotations.category;
|
|
82
|
+
this.categories.get(category)?.delete(name);
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Clear all registered tools.
|
|
87
|
+
*/
|
|
88
|
+
clear() {
|
|
89
|
+
this.tools.clear();
|
|
90
|
+
this.categories.clear();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Plugin loader for dynamically loading plugins.
|
|
95
|
+
*/
|
|
96
|
+
export class PluginLoader {
|
|
97
|
+
plugins = new Map();
|
|
98
|
+
registry;
|
|
99
|
+
log;
|
|
100
|
+
config;
|
|
101
|
+
constructor(registry, log = console.error, config = {}) {
|
|
102
|
+
this.registry = registry;
|
|
103
|
+
this.log = log;
|
|
104
|
+
this.config = config;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Load a plugin from a module path or package name.
|
|
108
|
+
* @param moduleId - Path to module or npm package name
|
|
109
|
+
*/
|
|
110
|
+
async load(moduleId) {
|
|
111
|
+
try {
|
|
112
|
+
this.log(`[plugins] Loading plugin: ${moduleId}`);
|
|
113
|
+
// Dynamic import
|
|
114
|
+
const module = await import(moduleId);
|
|
115
|
+
const plugin = module.default || module.plugin || module;
|
|
116
|
+
if (!plugin.id || !plugin.register) {
|
|
117
|
+
this.log(`[plugins] Invalid plugin (missing id or register): ${moduleId}`);
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
if (this.plugins.has(plugin.id)) {
|
|
121
|
+
this.log(`[plugins] Plugin already loaded: ${plugin.id}`);
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
// Create plugin context
|
|
125
|
+
const ctx = {
|
|
126
|
+
registry: this.registry,
|
|
127
|
+
log: (msg) => this.log(`[${plugin.id}] ${msg}`),
|
|
128
|
+
config: this.config,
|
|
129
|
+
};
|
|
130
|
+
// Register the plugin
|
|
131
|
+
await plugin.register(ctx);
|
|
132
|
+
this.plugins.set(plugin.id, plugin);
|
|
133
|
+
this.log(`[plugins] Loaded: ${plugin.name} v${plugin.version} (${plugin.id})`);
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
catch (error) {
|
|
137
|
+
this.log(`[plugins] Failed to load ${moduleId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Load multiple plugins from environment variable or config.
|
|
143
|
+
* @param pluginIds - Comma-separated list of plugin module IDs
|
|
144
|
+
*/
|
|
145
|
+
async loadFromList(pluginIds) {
|
|
146
|
+
const ids = pluginIds
|
|
147
|
+
.split(',')
|
|
148
|
+
.map((id) => id.trim())
|
|
149
|
+
.filter(Boolean);
|
|
150
|
+
const loaded = [];
|
|
151
|
+
const failed = [];
|
|
152
|
+
for (const id of ids) {
|
|
153
|
+
const success = await this.load(id);
|
|
154
|
+
if (success) {
|
|
155
|
+
loaded.push(id);
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
failed.push(id);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return { loaded, failed };
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Unload a plugin by ID.
|
|
165
|
+
*/
|
|
166
|
+
async unload(pluginId) {
|
|
167
|
+
const plugin = this.plugins.get(pluginId);
|
|
168
|
+
if (!plugin)
|
|
169
|
+
return false;
|
|
170
|
+
try {
|
|
171
|
+
if (plugin.unload) {
|
|
172
|
+
await plugin.unload();
|
|
173
|
+
}
|
|
174
|
+
this.plugins.delete(pluginId);
|
|
175
|
+
this.log(`[plugins] Unloaded: ${pluginId}`);
|
|
176
|
+
return true;
|
|
177
|
+
}
|
|
178
|
+
catch (error) {
|
|
179
|
+
this.log(`[plugins] Failed to unload ${pluginId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Get list of loaded plugins.
|
|
185
|
+
*/
|
|
186
|
+
getLoaded() {
|
|
187
|
+
return Array.from(this.plugins.values());
|
|
188
|
+
}
|
|
189
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
// Input tools
|
|
7
|
+
import { click, hover, fill, drag, fillForm, uploadFile } from './input.js';
|
|
8
|
+
// Navigation tools
|
|
9
|
+
import { pages, navigate, resizePage, handleDialog } from './pages.js';
|
|
10
|
+
// Console tools
|
|
11
|
+
import * as consoleTools from './console.js';
|
|
12
|
+
// Emulation tools
|
|
13
|
+
import * as emulationTools from './emulation.js';
|
|
14
|
+
// Network tools
|
|
15
|
+
import * as networkTools from './network.js';
|
|
16
|
+
// Performance tools
|
|
17
|
+
import * as performanceTools from './performance.js';
|
|
18
|
+
// Screenshot tools
|
|
19
|
+
import * as screenshotTools from './screenshot.js';
|
|
20
|
+
// Script tools
|
|
21
|
+
import * as scriptTools from './script.js';
|
|
22
|
+
// Snapshot tools
|
|
23
|
+
import * as snapshotTools from './snapshot.js';
|
|
24
|
+
/**
|
|
25
|
+
* All core tools as an array.
|
|
26
|
+
*/
|
|
27
|
+
export const coreTools = [
|
|
28
|
+
// Input automation
|
|
29
|
+
click,
|
|
30
|
+
hover,
|
|
31
|
+
fill,
|
|
32
|
+
drag,
|
|
33
|
+
fillForm,
|
|
34
|
+
uploadFile,
|
|
35
|
+
// Navigation
|
|
36
|
+
pages,
|
|
37
|
+
navigate,
|
|
38
|
+
resizePage,
|
|
39
|
+
handleDialog,
|
|
40
|
+
// Console
|
|
41
|
+
...Object.values(consoleTools),
|
|
42
|
+
// Emulation
|
|
43
|
+
...Object.values(emulationTools),
|
|
44
|
+
// Network
|
|
45
|
+
...Object.values(networkTools),
|
|
46
|
+
// Performance
|
|
47
|
+
...Object.values(performanceTools),
|
|
48
|
+
// Screenshot
|
|
49
|
+
...Object.values(screenshotTools),
|
|
50
|
+
// Script
|
|
51
|
+
...Object.values(scriptTools),
|
|
52
|
+
// Snapshot
|
|
53
|
+
...Object.values(snapshotTools),
|
|
54
|
+
];
|
|
55
|
+
/**
|
|
56
|
+
* Register all core tools with a ToolRegistry.
|
|
57
|
+
*/
|
|
58
|
+
export function registerCoreTools(registry) {
|
|
59
|
+
for (const tool of coreTools) {
|
|
60
|
+
// Skip non-tool exports (like constants)
|
|
61
|
+
if (tool && typeof tool === 'object' && 'name' in tool && 'handler' in tool) {
|
|
62
|
+
registry.register(tool);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Get count of core tools.
|
|
68
|
+
*/
|
|
69
|
+
export function getCoreToolCount() {
|
|
70
|
+
return coreTools.filter((tool) => tool && typeof tool === 'object' && 'name' in tool && 'handler' in tool).length;
|
|
71
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
// ChatGPT web tools
|
|
7
|
+
import * as chatgptWebTools from './chatgpt-web.js';
|
|
8
|
+
// Gemini web tools
|
|
9
|
+
import * as geminiWebTools from './gemini-web.js';
|
|
10
|
+
/**
|
|
11
|
+
* All optional (web-llm) tools as an array.
|
|
12
|
+
*/
|
|
13
|
+
export const optionalTools = [
|
|
14
|
+
...Object.values(chatgptWebTools),
|
|
15
|
+
...Object.values(geminiWebTools),
|
|
16
|
+
];
|
|
17
|
+
/**
|
|
18
|
+
* Check if web-llm tools should be loaded.
|
|
19
|
+
* Returns false if MCP_DISABLE_WEB_LLM is set to 'true'.
|
|
20
|
+
*/
|
|
21
|
+
export function shouldLoadWebLlmTools() {
|
|
22
|
+
const disable = process.env.MCP_DISABLE_WEB_LLM;
|
|
23
|
+
return disable !== 'true' && disable !== '1';
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Register optional tools with a ToolRegistry.
|
|
27
|
+
* Respects MCP_DISABLE_WEB_LLM environment variable.
|
|
28
|
+
*/
|
|
29
|
+
export function registerOptionalTools(registry) {
|
|
30
|
+
if (!shouldLoadWebLlmTools()) {
|
|
31
|
+
console.error('[tools] Web-LLM tools disabled via MCP_DISABLE_WEB_LLM');
|
|
32
|
+
return 0;
|
|
33
|
+
}
|
|
34
|
+
let count = 0;
|
|
35
|
+
for (const tool of optionalTools) {
|
|
36
|
+
// Skip non-tool exports (like constants)
|
|
37
|
+
if (tool && typeof tool === 'object' && 'name' in tool && 'handler' in tool) {
|
|
38
|
+
try {
|
|
39
|
+
registry.register(tool);
|
|
40
|
+
count++;
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
// Log but don't fail - optional tools should not block startup
|
|
44
|
+
console.error(`[tools] Failed to register optional tool: ${error instanceof Error ? error.message : String(error)}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (count > 0) {
|
|
49
|
+
console.error(`[tools] Loaded ${count} optional web-llm tools (experimental, may break)`);
|
|
50
|
+
}
|
|
51
|
+
return count;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Get count of optional tools.
|
|
55
|
+
*/
|
|
56
|
+
export function getOptionalToolCount() {
|
|
57
|
+
return optionalTools.filter((tool) => tool && typeof tool === 'object' && 'name' in tool && 'handler' in tool).length;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Metadata about optional tools for documentation.
|
|
61
|
+
*/
|
|
62
|
+
export const WEB_LLM_TOOLS_INFO = {
|
|
63
|
+
disclaimer: 'Web-LLM tools (ask_chatgpt_web, ask_gemini_web) are experimental and best-effort. ' +
|
|
64
|
+
'They depend on specific website UIs and may break when those UIs change. ' +
|
|
65
|
+
'For production use, consider using official APIs instead.',
|
|
66
|
+
disableEnvVar: 'MCP_DISABLE_WEB_LLM',
|
|
67
|
+
tools: ['ask_chatgpt_web', 'ask_gemini_web'],
|
|
68
|
+
};
|
package/package.json
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "chrome-devtools-mcp-for-extension",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.26.1",
|
|
4
4
|
"description": "MCP server for Chrome extension development with Web Store automation. Fork of chrome-devtools-mcp with extension-specific tools.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": "./scripts/cli.mjs",
|
|
7
7
|
"main": "index.js",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": "./index.js",
|
|
10
|
+
"./plugin-api": "./build/src/plugin-api.js"
|
|
11
|
+
},
|
|
8
12
|
"scripts": {
|
|
9
13
|
"build": "tsc && node --experimental-strip-types --no-warnings=ExperimentalWarning scripts/post-build.ts",
|
|
10
14
|
"dev": "MCP_ENV=development node scripts/mcp-wrapper.mjs",
|