opencodekit 0.13.2 → 0.14.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/dist/index.js +50 -3
- package/dist/template/.opencode/AGENTS.md +51 -7
- package/dist/template/.opencode/README.md +98 -2
- package/dist/template/.opencode/agent/build.md +44 -1
- package/dist/template/.opencode/agent/explore.md +1 -0
- package/dist/template/.opencode/agent/planner.md +40 -1
- package/dist/template/.opencode/agent/review.md +1 -0
- package/dist/template/.opencode/agent/rush.md +35 -0
- package/dist/template/.opencode/agent/scout.md +1 -0
- package/dist/template/.opencode/command/brainstorm.md +83 -5
- package/dist/template/.opencode/command/finish.md +39 -12
- package/dist/template/.opencode/command/fix.md +24 -15
- package/dist/template/.opencode/command/handoff.md +17 -0
- package/dist/template/.opencode/command/implement.md +81 -18
- package/dist/template/.opencode/command/import-plan.md +30 -8
- package/dist/template/.opencode/command/new-feature.md +37 -4
- package/dist/template/.opencode/command/plan.md +51 -1
- package/dist/template/.opencode/command/pr.md +25 -15
- package/dist/template/.opencode/command/research.md +61 -5
- package/dist/template/.opencode/command/resume.md +31 -0
- package/dist/template/.opencode/command/revert-feature.md +15 -3
- package/dist/template/.opencode/command/skill-optimize.md +71 -7
- package/dist/template/.opencode/command/start.md +81 -5
- package/dist/template/.opencode/command/triage.md +16 -1
- package/dist/template/.opencode/dcp.jsonc +11 -7
- package/dist/template/.opencode/memory/observations/.gitkeep +0 -0
- package/dist/template/.opencode/memory/observations/2026-01-09-pattern-ampcode-mcp-json-includetools-pattern.md +42 -0
- package/dist/template/.opencode/memory/project/conventions.md +31 -0
- package/dist/template/.opencode/memory/project/gotchas.md +52 -5
- package/dist/template/.opencode/memory/vector_db/memories.lance/_transactions/0-0d25ba80-ba3b-4209-9046-b45d6093b4da.txn +0 -0
- package/dist/template/.opencode/memory/vector_db/memories.lance/_versions/1.manifest +0 -0
- package/dist/template/.opencode/memory/vector_db/memories.lance/data/1111100101010101011010004a9ef34df6b29f36a9a53a2892.lance +0 -0
- package/dist/template/.opencode/opencode.json +5 -3
- package/dist/template/.opencode/package.json +3 -1
- package/dist/template/.opencode/plugin/memory.ts +686 -0
- package/dist/template/.opencode/plugin/package.json +1 -1
- package/dist/template/.opencode/plugin/skill-mcp.ts +155 -36
- package/dist/template/.opencode/skill/chrome-devtools/SKILL.md +43 -65
- package/dist/template/.opencode/skill/chrome-devtools/mcp.json +19 -0
- package/dist/template/.opencode/skill/executing-plans/SKILL.md +32 -2
- package/dist/template/.opencode/skill/finishing-a-development-branch/SKILL.md +42 -17
- package/dist/template/.opencode/skill/playwright/SKILL.md +58 -133
- package/dist/template/.opencode/skill/playwright/mcp.json +16 -0
- package/dist/template/.opencode/tool/memory-embed.ts +183 -0
- package/dist/template/.opencode/tool/memory-index.ts +769 -0
- package/dist/template/.opencode/tool/memory-search.ts +358 -66
- package/dist/template/.opencode/tool/observation.ts +301 -12
- package/dist/template/.opencode/tool/repo-map.ts +451 -0
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type ChildProcess, spawn } from "node:child_process";
|
|
2
2
|
import { existsSync, readFileSync } from "node:fs";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
|
-
import { join } from "node:path";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
5
|
import type { Plugin } from "@opencode-ai/plugin";
|
|
6
6
|
import { tool } from "@opencode-ai/plugin/tool";
|
|
7
7
|
|
|
@@ -9,6 +9,7 @@ interface McpServerConfig {
|
|
|
9
9
|
command: string;
|
|
10
10
|
args?: string[];
|
|
11
11
|
env?: Record<string, string>;
|
|
12
|
+
includeTools?: string[]; // Ampcode-style tool filtering with glob patterns
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
interface McpClient {
|
|
@@ -24,6 +25,7 @@ interface McpClient {
|
|
|
24
25
|
resources?: any[];
|
|
25
26
|
prompts?: any[];
|
|
26
27
|
};
|
|
28
|
+
filteredTools?: any[]; // Tools after includeTools filtering
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
interface SkillMcpState {
|
|
@@ -31,6 +33,37 @@ interface SkillMcpState {
|
|
|
31
33
|
loadedSkills: Map<string, Record<string, McpServerConfig>>; // skillName -> mcp configs
|
|
32
34
|
}
|
|
33
35
|
|
|
36
|
+
/**
|
|
37
|
+
* Match a tool name against a glob pattern
|
|
38
|
+
* Supports: exact match, * (any chars), ? (single char)
|
|
39
|
+
*/
|
|
40
|
+
function matchGlobPattern(pattern: string, toolName: string): boolean {
|
|
41
|
+
// Exact match
|
|
42
|
+
if (pattern === toolName) return true;
|
|
43
|
+
|
|
44
|
+
// Convert glob to regex
|
|
45
|
+
const regexPattern = pattern
|
|
46
|
+
.replace(/[.+^${}()|[\]\\]/g, "\\$&") // Escape special regex chars
|
|
47
|
+
.replace(/\*/g, ".*") // * -> .*
|
|
48
|
+
.replace(/\?/g, "."); // ? -> .
|
|
49
|
+
|
|
50
|
+
const regex = new RegExp(`^${regexPattern}$`);
|
|
51
|
+
return regex.test(toolName);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Filter tools based on includeTools patterns
|
|
56
|
+
*/
|
|
57
|
+
function filterTools(allTools: any[], includePatterns?: string[]): any[] {
|
|
58
|
+
if (!includePatterns || includePatterns.length === 0) {
|
|
59
|
+
return allTools; // No filtering, return all
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return allTools.filter((tool) =>
|
|
63
|
+
includePatterns.some((pattern) => matchGlobPattern(pattern, tool.name)),
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
34
67
|
function parseYamlFrontmatter(content: string): {
|
|
35
68
|
frontmatter: any;
|
|
36
69
|
body: string;
|
|
@@ -43,11 +76,10 @@ function parseYamlFrontmatter(content: string): {
|
|
|
43
76
|
|
|
44
77
|
// Simple YAML parser for our use case
|
|
45
78
|
const frontmatter: any = {};
|
|
46
|
-
let currentKey = "";
|
|
47
|
-
let currentIndent = 0;
|
|
48
79
|
let mcpConfig: any = null;
|
|
49
80
|
let serverName = "";
|
|
50
81
|
let serverConfig: any = {};
|
|
82
|
+
let currentArrayKey = "";
|
|
51
83
|
|
|
52
84
|
for (const line of yamlStr.split("\n")) {
|
|
53
85
|
const trimmed = line.trim();
|
|
@@ -67,40 +99,80 @@ function parseYamlFrontmatter(content: string): {
|
|
|
67
99
|
} else {
|
|
68
100
|
frontmatter[key] = value || undefined;
|
|
69
101
|
}
|
|
70
|
-
|
|
71
|
-
currentIndent = indent;
|
|
102
|
+
currentArrayKey = "";
|
|
72
103
|
} else if (mcpConfig !== null && indent === 2) {
|
|
73
104
|
// Server name under mcp
|
|
74
105
|
serverName = key;
|
|
75
106
|
serverConfig = {};
|
|
76
107
|
mcpConfig[serverName] = serverConfig;
|
|
108
|
+
currentArrayKey = "";
|
|
77
109
|
} else if (serverConfig && indent === 4) {
|
|
78
110
|
// Server config property
|
|
79
111
|
if (key === "command") {
|
|
80
112
|
serverConfig.command = value;
|
|
81
|
-
|
|
113
|
+
currentArrayKey = "";
|
|
114
|
+
} else if (key === "args" || key === "includeTools") {
|
|
82
115
|
// Parse inline array or set up for multi-line
|
|
83
116
|
if (value.startsWith("[")) {
|
|
84
117
|
try {
|
|
85
|
-
serverConfig
|
|
118
|
+
serverConfig[key] = JSON.parse(value);
|
|
86
119
|
} catch {
|
|
87
|
-
serverConfig
|
|
120
|
+
serverConfig[key] = [];
|
|
88
121
|
}
|
|
122
|
+
currentArrayKey = "";
|
|
89
123
|
} else {
|
|
90
|
-
serverConfig
|
|
124
|
+
serverConfig[key] = [];
|
|
125
|
+
currentArrayKey = key;
|
|
91
126
|
}
|
|
127
|
+
} else {
|
|
128
|
+
currentArrayKey = "";
|
|
92
129
|
}
|
|
93
130
|
}
|
|
94
|
-
} else if (
|
|
95
|
-
|
|
131
|
+
} else if (
|
|
132
|
+
trimmed.startsWith("- ") &&
|
|
133
|
+
serverConfig &&
|
|
134
|
+
currentArrayKey &&
|
|
135
|
+
serverConfig[currentArrayKey]
|
|
136
|
+
) {
|
|
137
|
+
// Array item for args or includeTools
|
|
96
138
|
const item = trimmed.slice(2).replace(/^["']|["']$/g, "");
|
|
97
|
-
serverConfig.
|
|
139
|
+
serverConfig[currentArrayKey].push(item);
|
|
98
140
|
}
|
|
99
141
|
}
|
|
100
142
|
|
|
101
143
|
return { frontmatter, body };
|
|
102
144
|
}
|
|
103
145
|
|
|
146
|
+
/**
|
|
147
|
+
* Load MCP config from either mcp.json or YAML frontmatter
|
|
148
|
+
* Priority: mcp.json > YAML frontmatter (Ampcode pattern)
|
|
149
|
+
*/
|
|
150
|
+
function loadMcpConfig(
|
|
151
|
+
skillDir: string,
|
|
152
|
+
skillPath: string,
|
|
153
|
+
): Record<string, McpServerConfig> | null {
|
|
154
|
+
// Try mcp.json first (Ampcode pattern)
|
|
155
|
+
const mcpJsonPath = join(skillDir, "mcp.json");
|
|
156
|
+
if (existsSync(mcpJsonPath)) {
|
|
157
|
+
try {
|
|
158
|
+
const mcpJson = JSON.parse(readFileSync(mcpJsonPath, "utf-8"));
|
|
159
|
+
return mcpJson;
|
|
160
|
+
} catch {
|
|
161
|
+
// Fall through to YAML
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Fall back to YAML frontmatter
|
|
166
|
+
const content = readFileSync(skillPath, "utf-8");
|
|
167
|
+
const { frontmatter } = parseYamlFrontmatter(content);
|
|
168
|
+
|
|
169
|
+
if (frontmatter.mcp && Object.keys(frontmatter.mcp).length > 0) {
|
|
170
|
+
return frontmatter.mcp;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
|
|
104
176
|
function findSkillPath(skillName: string, projectDir: string): string | null {
|
|
105
177
|
const locations = [
|
|
106
178
|
join(projectDir, ".opencode", "skill", skillName, "SKILL.md"),
|
|
@@ -216,7 +288,7 @@ export const SkillMcpPlugin: Plugin = async ({ directory }) => {
|
|
|
216
288
|
console.error(`MCP server error [${key}]:`, err.message);
|
|
217
289
|
});
|
|
218
290
|
|
|
219
|
-
proc.on("exit", (
|
|
291
|
+
proc.on("exit", () => {
|
|
220
292
|
state.clients.delete(key);
|
|
221
293
|
});
|
|
222
294
|
|
|
@@ -227,7 +299,7 @@ export const SkillMcpPlugin: Plugin = async ({ directory }) => {
|
|
|
227
299
|
await sendRequest(client, "initialize", {
|
|
228
300
|
protocolVersion: "2024-11-05",
|
|
229
301
|
capabilities: {},
|
|
230
|
-
clientInfo: { name: "opencode-skill-mcp", version: "1.
|
|
302
|
+
clientInfo: { name: "opencode-skill-mcp", version: "1.1.0" },
|
|
231
303
|
});
|
|
232
304
|
|
|
233
305
|
// Send initialized notification
|
|
@@ -241,9 +313,14 @@ export const SkillMcpPlugin: Plugin = async ({ directory }) => {
|
|
|
241
313
|
// Discover capabilities
|
|
242
314
|
try {
|
|
243
315
|
const toolsResult = await sendRequest(client, "tools/list", {});
|
|
244
|
-
|
|
316
|
+
const allTools = toolsResult.tools || [];
|
|
317
|
+
client.capabilities = { tools: allTools };
|
|
318
|
+
|
|
319
|
+
// Apply includeTools filtering (Ampcode pattern)
|
|
320
|
+
client.filteredTools = filterTools(allTools, config.includeTools);
|
|
245
321
|
} catch {
|
|
246
322
|
client.capabilities = { tools: [] };
|
|
323
|
+
client.filteredTools = [];
|
|
247
324
|
}
|
|
248
325
|
} catch (e: any) {
|
|
249
326
|
proc.kill();
|
|
@@ -255,7 +332,7 @@ export const SkillMcpPlugin: Plugin = async ({ directory }) => {
|
|
|
255
332
|
}
|
|
256
333
|
|
|
257
334
|
function disconnectAll() {
|
|
258
|
-
for (const [
|
|
335
|
+
for (const [, client] of state.clients) {
|
|
259
336
|
client.process.kill();
|
|
260
337
|
}
|
|
261
338
|
state.clients.clear();
|
|
@@ -266,10 +343,11 @@ export const SkillMcpPlugin: Plugin = async ({ directory }) => {
|
|
|
266
343
|
skill_mcp: tool({
|
|
267
344
|
description: `Invoke MCP tools from skill-embedded MCP servers.
|
|
268
345
|
|
|
269
|
-
When a skill declares MCP servers
|
|
346
|
+
When a skill declares MCP servers (via mcp.json or YAML frontmatter), use this tool to:
|
|
270
347
|
- List available tools: skill_mcp(skill_name="playwright", list_tools=true)
|
|
271
348
|
- Call a tool: skill_mcp(skill_name="playwright", tool_name="browser_navigate", arguments='{"url": "..."}')
|
|
272
349
|
|
|
350
|
+
Skills can use "includeTools" to filter which MCP tools are exposed (reduces token usage).
|
|
273
351
|
The skill must be loaded first via the skill() tool to register its MCP config.`,
|
|
274
352
|
args: {
|
|
275
353
|
skill_name: tool.schema
|
|
@@ -305,34 +383,34 @@ The skill must be loaded first via the skill() tool to register its MCP config.`
|
|
|
305
383
|
return JSON.stringify({ error: "skill_name required" });
|
|
306
384
|
}
|
|
307
385
|
|
|
308
|
-
// Find skill
|
|
386
|
+
// Find skill path
|
|
309
387
|
const skillPath = findSkillPath(skill_name, directory);
|
|
310
388
|
if (!skillPath) {
|
|
311
389
|
return JSON.stringify({ error: `Skill '${skill_name}' not found` });
|
|
312
390
|
}
|
|
313
391
|
|
|
314
|
-
|
|
315
|
-
const
|
|
392
|
+
// Load MCP config from mcp.json or YAML frontmatter
|
|
393
|
+
const skillDir = dirname(skillPath);
|
|
394
|
+
const mcpConfig = loadMcpConfig(skillDir, skillPath);
|
|
316
395
|
|
|
317
|
-
if (!
|
|
396
|
+
if (!mcpConfig) {
|
|
318
397
|
return JSON.stringify({
|
|
319
|
-
error: `Skill '${skill_name}' has no MCP config`,
|
|
398
|
+
error: `Skill '${skill_name}' has no MCP config (check mcp.json or YAML frontmatter)`,
|
|
320
399
|
});
|
|
321
400
|
}
|
|
322
401
|
|
|
323
402
|
// Determine which MCP server to use
|
|
324
|
-
const
|
|
325
|
-
const serverNames = Object.keys(mcpServers);
|
|
403
|
+
const serverNames = Object.keys(mcpConfig);
|
|
326
404
|
const targetServer = mcp_name || serverNames[0];
|
|
327
405
|
|
|
328
|
-
if (!
|
|
406
|
+
if (!mcpConfig[targetServer]) {
|
|
329
407
|
return JSON.stringify({
|
|
330
408
|
error: `MCP server '${targetServer}' not found in skill`,
|
|
331
409
|
available: serverNames,
|
|
332
410
|
});
|
|
333
411
|
}
|
|
334
412
|
|
|
335
|
-
const serverConfig =
|
|
413
|
+
const serverConfig = mcpConfig[targetServer];
|
|
336
414
|
|
|
337
415
|
// Connect to MCP server
|
|
338
416
|
let client: McpClient;
|
|
@@ -346,17 +424,29 @@ The skill must be loaded first via the skill() tool to register its MCP config.`
|
|
|
346
424
|
return JSON.stringify({ error: `Failed to connect: ${e.message}` });
|
|
347
425
|
}
|
|
348
426
|
|
|
349
|
-
// List tools
|
|
427
|
+
// List tools (filtered by includeTools if configured)
|
|
350
428
|
if (list_tools) {
|
|
429
|
+
const totalTools = client.capabilities?.tools?.length || 0;
|
|
430
|
+
const filteredTools = client.filteredTools || [];
|
|
431
|
+
const isFiltered =
|
|
432
|
+
serverConfig.includeTools && serverConfig.includeTools.length > 0;
|
|
433
|
+
|
|
351
434
|
return JSON.stringify(
|
|
352
435
|
{
|
|
353
436
|
mcp: targetServer,
|
|
354
|
-
tools:
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
437
|
+
tools: filteredTools.map((t: any) => ({
|
|
438
|
+
name: t.name,
|
|
439
|
+
description: t.description,
|
|
440
|
+
schema: t.inputSchema,
|
|
441
|
+
})),
|
|
442
|
+
...(isFiltered && {
|
|
443
|
+
filtering: {
|
|
444
|
+
patterns: serverConfig.includeTools,
|
|
445
|
+
showing: filteredTools.length,
|
|
446
|
+
total: totalTools,
|
|
447
|
+
tokenSavings: `~${Math.round((1 - filteredTools.length / totalTools) * 100)}%`,
|
|
448
|
+
},
|
|
449
|
+
}),
|
|
360
450
|
},
|
|
361
451
|
null,
|
|
362
452
|
2,
|
|
@@ -365,11 +455,28 @@ The skill must be loaded first via the skill() tool to register its MCP config.`
|
|
|
365
455
|
|
|
366
456
|
// Call tool
|
|
367
457
|
if (tool_name) {
|
|
458
|
+
// Validate tool is in filtered list (if filtering is enabled)
|
|
459
|
+
if (
|
|
460
|
+
serverConfig.includeTools &&
|
|
461
|
+
serverConfig.includeTools.length > 0
|
|
462
|
+
) {
|
|
463
|
+
const isAllowed = client.filteredTools?.some(
|
|
464
|
+
(t: any) => t.name === tool_name,
|
|
465
|
+
);
|
|
466
|
+
if (!isAllowed) {
|
|
467
|
+
return JSON.stringify({
|
|
468
|
+
error: `Tool '${tool_name}' is not in includeTools filter`,
|
|
469
|
+
allowed: client.filteredTools?.map((t: any) => t.name) || [],
|
|
470
|
+
hint: "Add this tool to includeTools in mcp.json or YAML frontmatter",
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|
|
368
475
|
let toolArgs = {};
|
|
369
476
|
if (argsJson) {
|
|
370
477
|
try {
|
|
371
478
|
toolArgs = JSON.parse(argsJson);
|
|
372
|
-
} catch
|
|
479
|
+
} catch {
|
|
373
480
|
return JSON.stringify({ error: "Invalid JSON in arguments" });
|
|
374
481
|
}
|
|
375
482
|
}
|
|
@@ -391,7 +498,7 @@ The skill must be loaded first via the skill() tool to register its MCP config.`
|
|
|
391
498
|
error: "Specify either list_tools=true or tool_name to call",
|
|
392
499
|
mcp: targetServer,
|
|
393
500
|
available_tools:
|
|
394
|
-
client.
|
|
501
|
+
client.filteredTools?.map((t: any) => t.name) || [],
|
|
395
502
|
});
|
|
396
503
|
},
|
|
397
504
|
}),
|
|
@@ -403,11 +510,23 @@ The skill must be loaded first via the skill() tool to register its MCP config.`
|
|
|
403
510
|
const servers: any[] = [];
|
|
404
511
|
for (const [key, client] of state.clients) {
|
|
405
512
|
const [skillName, serverName] = key.split(":");
|
|
513
|
+
const totalTools = client.capabilities?.tools?.length || 0;
|
|
514
|
+
const filteredTools = client.filteredTools?.length || 0;
|
|
515
|
+
const isFiltered =
|
|
516
|
+
client.config.includeTools &&
|
|
517
|
+
client.config.includeTools.length > 0;
|
|
518
|
+
|
|
406
519
|
servers.push({
|
|
407
520
|
skill: skillName,
|
|
408
521
|
server: serverName,
|
|
409
522
|
connected: !client.process.killed,
|
|
410
|
-
tools:
|
|
523
|
+
tools: filteredTools,
|
|
524
|
+
...(isFiltered && {
|
|
525
|
+
filtering: {
|
|
526
|
+
total: totalTools,
|
|
527
|
+
filtered: filteredTools,
|
|
528
|
+
},
|
|
529
|
+
}),
|
|
411
530
|
});
|
|
412
531
|
}
|
|
413
532
|
return JSON.stringify({
|
|
@@ -1,88 +1,66 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: chrome-devtools
|
|
3
3
|
description: Chrome DevTools for debugging, performance analysis, and browser automation. Use when debugging web apps, analyzing performance, inspecting network requests, or automating browser interactions.
|
|
4
|
-
mcp:
|
|
5
|
-
chrome-devtools:
|
|
6
|
-
command: npx
|
|
7
|
-
args: ["-y", "chrome-devtools-mcp@latest", "--stdio"]
|
|
8
4
|
---
|
|
9
5
|
|
|
10
6
|
# Chrome DevTools (MCP)
|
|
11
7
|
|
|
12
|
-
Control and inspect a live Chrome browser via Chrome DevTools Protocol.
|
|
8
|
+
Control and inspect a live Chrome browser via Chrome DevTools Protocol.
|
|
13
9
|
|
|
14
|
-
##
|
|
15
|
-
|
|
16
|
-
```
|
|
17
|
-
skill_mcp(skill_name="chrome-devtools", tool_name="take_snapshot")
|
|
18
|
-
skill_mcp(skill_name="chrome-devtools", tool_name="navigate_page", arguments='{"type": "url", "url": "https://example.com"}')
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
## Tools
|
|
22
|
-
|
|
23
|
-
### Input
|
|
10
|
+
## Available Tools
|
|
24
11
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
12
|
+
- `take_snapshot` - Get accessibility tree snapshot with element UIDs
|
|
13
|
+
- `take_screenshot` - Capture screenshot of page or element
|
|
14
|
+
- `navigate_page` - Navigate to URL, back, forward, or reload
|
|
15
|
+
- `new_page` - Open a new browser tab
|
|
16
|
+
- `list_pages` - List all open pages/tabs
|
|
17
|
+
- `click` - Click element by UID
|
|
18
|
+
- `fill` - Type text into element
|
|
19
|
+
- `hover` - Hover over element
|
|
20
|
+
- `press_key` - Press keyboard key (Enter, Tab, etc.)
|
|
21
|
+
- `evaluate_script` - Run JavaScript in page context
|
|
22
|
+
- `wait_for` - Wait for text to appear
|
|
35
23
|
|
|
36
|
-
|
|
24
|
+
## Workflow
|
|
37
25
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
| `list_pages` | List pages | - |
|
|
43
|
-
| `select_page` | Switch page | `pageIdx` |
|
|
44
|
-
| `close_page` | Close page | `pageIdx` |
|
|
45
|
-
| `wait_for` | Wait for text | `text`, `timeout` |
|
|
26
|
+
1. **Snapshot** the page using `take_snapshot` to get element UIDs
|
|
27
|
+
2. **Navigate** to target URL using `navigate_page`
|
|
28
|
+
3. **Interact** using `click`, `fill`, `hover` with UIDs from snapshot
|
|
29
|
+
4. **Screenshot** to capture results using `take_screenshot`
|
|
46
30
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
| Tool | Description | Parameters |
|
|
50
|
-
| ----------------------- | ------------------ | --------------------------- |
|
|
51
|
-
| `take_snapshot` | A11y tree snapshot | `verbose` |
|
|
52
|
-
| `take_screenshot` | Screenshot | `uid`, `fullPage`, `format` |
|
|
53
|
-
| `evaluate_script` | Run JS | `function`, `args` |
|
|
54
|
-
| `list_console_messages` | Console logs | `types` filter |
|
|
55
|
-
| `get_console_message` | Get message | `msgid` |
|
|
56
|
-
|
|
57
|
-
### Network
|
|
31
|
+
## Quick Start
|
|
58
32
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
| `get_network_request` | Request details | `reqid` |
|
|
33
|
+
```
|
|
34
|
+
# Get page structure with element UIDs
|
|
35
|
+
skill_mcp(skill_name="chrome-devtools", tool_name="take_snapshot")
|
|
63
36
|
|
|
64
|
-
|
|
37
|
+
# Navigate to URL
|
|
38
|
+
skill_mcp(skill_name="chrome-devtools", tool_name="navigate_page", arguments='{"type": "url", "url": "https://example.com"}')
|
|
65
39
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
| `performance_start_trace` | Start trace | `reload`, `autoStop` |
|
|
69
|
-
| `performance_stop_trace` | Stop trace | - |
|
|
70
|
-
| `performance_analyze_insight` | Analyze | `insightSetId`, `insightName` |
|
|
40
|
+
# Click element (use UID from snapshot)
|
|
41
|
+
skill_mcp(skill_name="chrome-devtools", tool_name="click", arguments='{"uid": "e123"}')
|
|
71
42
|
|
|
72
|
-
|
|
43
|
+
# Fill input field
|
|
44
|
+
skill_mcp(skill_name="chrome-devtools", tool_name="fill", arguments='{"uid": "e456", "value": "hello"}')
|
|
73
45
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
| `resize_page` | Resize viewport | `width`, `height` |
|
|
46
|
+
# Take screenshot
|
|
47
|
+
skill_mcp(skill_name="chrome-devtools", tool_name="take_screenshot")
|
|
48
|
+
```
|
|
78
49
|
|
|
79
50
|
## Tips
|
|
80
51
|
|
|
81
|
-
- **Always `take_snapshot` first** to get element
|
|
82
|
-
- **Element
|
|
83
|
-
- **
|
|
52
|
+
- **Always `take_snapshot` first** to get element UIDs
|
|
53
|
+
- **Element UIDs change** after navigation - take fresh snapshot
|
|
54
|
+
- **Use `wait_for`** after actions that trigger page changes
|
|
55
|
+
- **Use `evaluate_script`** for custom JS when tools don't cover your need
|
|
84
56
|
|
|
85
57
|
## vs Playwright
|
|
86
58
|
|
|
87
|
-
|
|
88
|
-
|
|
59
|
+
| Feature | chrome-devtools | playwright |
|
|
60
|
+
| ------------------- | -------------------- | ------------------ |
|
|
61
|
+
| Browser support | Chrome only | Chrome, FF, WebKit |
|
|
62
|
+
| Performance tracing | ✅ (full MCP has it) | ❌ |
|
|
63
|
+
| Network inspection | ✅ (full MCP has it) | ❌ |
|
|
64
|
+
| Cross-browser | ❌ | ✅ |
|
|
65
|
+
|
|
66
|
+
> **Note**: This skill loads 11 essential tools. For full 26+ tools (performance, network, console), modify `mcp.json` to remove `includeTools` filter.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"chrome-devtools": {
|
|
3
|
+
"command": "npx",
|
|
4
|
+
"args": ["-y", "chrome-devtools-mcp@latest", "--stdio"],
|
|
5
|
+
"includeTools": [
|
|
6
|
+
"take_snapshot",
|
|
7
|
+
"take_screenshot",
|
|
8
|
+
"navigate_page",
|
|
9
|
+
"new_page",
|
|
10
|
+
"list_pages",
|
|
11
|
+
"click",
|
|
12
|
+
"fill",
|
|
13
|
+
"hover",
|
|
14
|
+
"press_key",
|
|
15
|
+
"evaluate_script",
|
|
16
|
+
"wait_for"
|
|
17
|
+
]
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -19,8 +19,38 @@ Load plan, review critically, execute tasks in batches, report for review betwee
|
|
|
19
19
|
|
|
20
20
|
1. Read plan file
|
|
21
21
|
2. Review critically - identify any questions or concerns about the plan
|
|
22
|
-
3. If concerns:
|
|
23
|
-
|
|
22
|
+
3. If concerns: Use question tool to raise them:
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
question({
|
|
26
|
+
questions: [
|
|
27
|
+
{
|
|
28
|
+
header: "Concerns",
|
|
29
|
+
question: "Plan review complete. Any concerns before proceeding?",
|
|
30
|
+
options: [
|
|
31
|
+
{
|
|
32
|
+
label: "No concerns (Recommended)",
|
|
33
|
+
description: "Plan looks good, execute batches",
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
label: "Has concerns",
|
|
37
|
+
description: "Need clarification before starting",
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
});
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
4. Read plan and identify:
|
|
46
|
+
- What is the goal?
|
|
47
|
+
- What are the deliverables?
|
|
48
|
+
- What are the risks?
|
|
49
|
+
- Does the approach make sense?
|
|
50
|
+
- Are there missing pieces?
|
|
51
|
+
|
|
52
|
+
If no concerns: Create TodoWrite and proceed
|
|
53
|
+
If concerns: Wait for human to decide and resubmit
|
|
24
54
|
|
|
25
55
|
### Step 2: Execute Batch
|
|
26
56
|
|