feat: 4 tools nuevas + browser_list enriquecido

Tools nuevas (wrappers finos sobre funciones del registry functions/browser):
- page_collect_console  -> cdp_collect_console (console + exceptions + log, snapshot)
- page_pdf              -> cdp_print_pdf (Page.printToPDF a archivo)
- dom_select_option     -> cdp_select_option (<select> por value/texto + input/change)
- dom_set_files         -> cdp_set_file_input (subir archivos a <input type=file>)

browser_list ahora enriquece cada master con CDP con pages (nº de page targets),
active_title y active_url via GET /json (best-effort: si el puerto no responde
los campos quedan a cero y el listado de procesos no falla).

Total tools: 46 -> 50.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Egutierrez
2026-06-16 20:25:35 +02:00
parent 15949bf4ed
commit 6b7f71c39f
3 changed files with 186 additions and 2 deletions
+65
View File
@@ -27,9 +27,74 @@ func registerDomTools(s *server.MCPServer, d *deps) {
s.AddTool(domTypeRefTool(), mcp.NewTypedToolHandler(d.handleDomTypeRef))
s.AddTool(domHoverRefTool(), mcp.NewTypedToolHandler(d.handleDomHoverRef))
s.AddTool(domClickXYTool(), mcp.NewTypedToolHandler(d.handleDomClickXY))
s.AddTool(domSelectOptionTool(), mcp.NewTypedToolHandler(d.handleDomSelectOption))
s.AddTool(domSetFilesTool(), mcp.NewTypedToolHandler(d.handleDomSetFiles))
}
}
// ---- dom_select_option (MUTA) ----
type domSelectOptionArgs struct {
Port int `json:"port"`
Selector string `json:"selector"`
Value string `json:"value"`
}
func domSelectOptionTool() mcp.Tool {
return mcp.NewTool("dom_select_option",
mcp.WithDescription("Select an <option> in a native <select> element (by CSS selector), matching by option value first, then by visible text, and firing input/change events so React/Vue react. For custom (non-<select>) dropdowns use dom_click_ref on the trigger then on the option instead."),
mcp.WithNumber("port", mcp.Description("CDP port. Default 9333 (Chrome isolated del MCP); usa 9222 explícito solo para adjuntarte al navegador diario.")),
mcp.WithString("selector", mcp.Required(), mcp.Description("CSS selector of the <select> element.")),
mcp.WithString("value", mcp.Required(), mcp.Description("Option value (or visible text if no value matches).")),
)
}
func (d *deps) handleDomSelectOption(_ context.Context, _ mcp.CallToolRequest, a domSelectOptionArgs) (*mcp.CallToolResult, error) {
if a.Selector == "" || a.Value == "" {
return mcp.NewToolResultError("selector and value are required"), nil
}
err := d.withConn(portOr(a.Port), func(c *browser.CDPConn) error {
return browser.CdpSelectOption(c, a.Selector, a.Value)
})
if err != nil {
return mcp.NewToolResultError(err.Error()), nil
}
return mcp.NewToolResultText(fmt.Sprintf("selected %q in %s", a.Value, a.Selector)), nil
}
// ---- dom_set_files (MUTA) ----
type domSetFilesArgs struct {
Port int `json:"port"`
Selector string `json:"selector"`
Paths []string `json:"paths"`
}
func domSetFilesTool() mcp.Tool {
return mcp.NewTool("dom_set_files",
mcp.WithDescription("Upload files to an <input type=\"file\"> (by CSS selector) via DOM.setFileInputFiles, without driving the OS file picker. Paths must be absolute and readable by the Chrome process."),
mcp.WithNumber("port", mcp.Description("CDP port. Default 9333 (Chrome isolated del MCP); usa 9222 explícito solo para adjuntarte al navegador diario.")),
mcp.WithString("selector", mcp.Required(), mcp.Description("CSS selector of the file input element.")),
mcp.WithArray("paths", mcp.Required(), mcp.Description("Absolute file paths to attach."), mcp.Items(map[string]any{"type": "string"})),
)
}
func (d *deps) handleDomSetFiles(_ context.Context, _ mcp.CallToolRequest, a domSetFilesArgs) (*mcp.CallToolResult, error) {
if a.Selector == "" {
return mcp.NewToolResultError("selector is required"), nil
}
if len(a.Paths) == 0 {
return mcp.NewToolResultError("paths is required (at least one file)"), nil
}
err := d.withConn(portOr(a.Port), func(c *browser.CDPConn) error {
return browser.CdpSetFileInput(c, a.Selector, a.Paths)
})
if err != nil {
return mcp.NewToolResultError(err.Error()), nil
}
return mcp.NewToolResultText(fmt.Sprintf("attached %d file(s) to %s", len(a.Paths), a.Selector)), nil
}
// defaultMode es el modo de velocidad cuando ni la llamada ni la sesión fijan uno.
// "auto" = rápido (movimiento de ratón mínimo, escritura en un solo evento, settle
// breve) — el modo por defecto del MCP. "human" (Bézier + esperas aleatorias) se