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:
@@ -3,6 +3,8 @@ package main
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/mark3labs/mcp-go/mcp"
|
||||
@@ -20,12 +22,91 @@ func registerReadTools(s *server.MCPServer, d *deps) {
|
||||
s.AddTool(pageGetTextTool(), mcp.NewTypedToolHandler(d.handlePageGetText))
|
||||
s.AddTool(pagePerceiveTool(), mcp.NewTypedToolHandler(d.handlePagePerceive))
|
||||
s.AddTool(pageScreenshotTool(), mcp.NewTypedToolHandler(d.handlePageScreenshot))
|
||||
s.AddTool(pageCollectConsoleTool(), mcp.NewTypedToolHandler(d.handlePageCollectConsole))
|
||||
s.AddTool(pagePDFTool(), mcp.NewTypedToolHandler(d.handlePagePDF))
|
||||
|
||||
if !d.readOnly {
|
||||
s.AddTool(pageEvalJSTool(), mcp.NewTypedToolHandler(d.handlePageEvalJS))
|
||||
}
|
||||
}
|
||||
|
||||
// ---- page_collect_console ----
|
||||
|
||||
type pageCollectConsoleArgs struct {
|
||||
Port int `json:"port"`
|
||||
DurationMs int `json:"duration_ms"`
|
||||
}
|
||||
|
||||
func pageCollectConsoleTool() mcp.Tool {
|
||||
return mcp.NewTool("page_collect_console",
|
||||
mcp.WithDescription("Capture the page's console output (console.log/info/warn/error), uncaught JS exceptions and browser log entries during a time window, and return them as JSON. It is a SNAPSHOT: it records what happens during duration_ms AFTER the call starts, not past history — so trigger the action you want to observe (reload, click) right before or during the window. Use this to debug why a page misbehaves without flying blind."),
|
||||
mcp.WithNumber("port", mcp.Description("CDP port. Default 9333 (Chrome isolated del MCP); usa 9222 explícito solo para adjuntarte al navegador diario.")),
|
||||
mcp.WithNumber("duration_ms", mcp.Description("Capture window in milliseconds. Default 1500.")),
|
||||
)
|
||||
}
|
||||
|
||||
func (d *deps) handlePageCollectConsole(_ context.Context, _ mcp.CallToolRequest, a pageCollectConsoleArgs) (*mcp.CallToolResult, error) {
|
||||
var entries []browser.ConsoleEntry
|
||||
err := d.withConn(portOr(a.Port), func(c *browser.CDPConn) error {
|
||||
var e error
|
||||
entries, e = browser.CdpCollectConsole(c, a.DurationMs)
|
||||
return e
|
||||
})
|
||||
if err != nil {
|
||||
return mcp.NewToolResultError(err.Error()), nil
|
||||
}
|
||||
if entries == nil {
|
||||
entries = []browser.ConsoleEntry{}
|
||||
}
|
||||
b, _ := json.MarshalIndent(entries, "", " ")
|
||||
return mcp.NewToolResultText(truncate(string(b), htmlMax)), nil
|
||||
}
|
||||
|
||||
// ---- page_pdf ----
|
||||
|
||||
type pagePDFArgs struct {
|
||||
Port int `json:"port"`
|
||||
Path string `json:"path"`
|
||||
Landscape bool `json:"landscape"`
|
||||
PrintBackground bool `json:"print_background"`
|
||||
Scale float64 `json:"scale"`
|
||||
}
|
||||
|
||||
func pagePDFTool() mcp.Tool {
|
||||
return mcp.NewTool("page_pdf",
|
||||
mcp.WithDescription("Render the current page to a PDF (Page.printToPDF) and write it to a local file path. Use for archiving an article/invoice/report exactly as laid out, when a screenshot is not enough (multi-page, selectable text)."),
|
||||
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("path", mcp.Required(), mcp.Description("Output .pdf file path.")),
|
||||
mcp.WithBoolean("landscape", mcp.Description("Landscape orientation. Default false (portrait).")),
|
||||
mcp.WithBoolean("print_background", mcp.Description("Include background graphics/colors. Default false.")),
|
||||
mcp.WithNumber("scale", mcp.Description("Render scale. Default 1.0.")),
|
||||
)
|
||||
}
|
||||
|
||||
func (d *deps) handlePagePDF(_ context.Context, _ mcp.CallToolRequest, a pagePDFArgs) (*mcp.CallToolResult, error) {
|
||||
if a.Path == "" {
|
||||
return mcp.NewToolResultError("path is required"), nil
|
||||
}
|
||||
opts := browser.CdpPrintPDFOpts{
|
||||
Landscape: a.Landscape,
|
||||
PrintBackground: a.PrintBackground,
|
||||
Scale: a.Scale,
|
||||
}
|
||||
var data []byte
|
||||
err := d.withConn(portOr(a.Port), func(c *browser.CDPConn) error {
|
||||
var e error
|
||||
data, e = browser.CdpPrintPDF(c, opts)
|
||||
return e
|
||||
})
|
||||
if err != nil {
|
||||
return mcp.NewToolResultError(err.Error()), nil
|
||||
}
|
||||
if e := os.WriteFile(a.Path, data, 0o644); e != nil {
|
||||
return mcp.NewToolResultError("saving pdf to " + a.Path + ": " + e.Error()), nil
|
||||
}
|
||||
return mcp.NewToolResultText(fmt.Sprintf("pdf saved to %s (%d bytes)", a.Path, len(data))), nil
|
||||
}
|
||||
|
||||
// ---- page_get_text ----
|
||||
|
||||
type pageGetTextArgs struct {
|
||||
|
||||
Reference in New Issue
Block a user