fed245a738
Capacidades nuevas y cambios (40 -> 42 tools): - page_perceive ahora se genera de forma NATIVA en Go sobre la conexion CDP viva del pool (cdp_get_ax_outline_go_browser). Elimina el subprocess `fn run cdp_perceive_outline` (Python), el venv y la dependencia del binario `fn` en runtime (se borra resolveRoot/exec.Command). Respeta tab_select. - page_perceive acepta frame_id para percibir DENTRO de un iframe. El campo tab_id queda obsoleto (se ignora; usar tab_select) pero se conserva por compatibilidad. - frame_get_text (nueva, lectura): innerText de un iframe via cdp_get_text_in_frame_go_browser. Activa tambien bajo --read-only. - dom_click_xy (nueva, MUTA): click humanizado por coordenadas absolutas via cdp_click_xy_human_go_browser, con mode human/fast/instant y auto-observe. Fallback para actuar sobre lo que el LLM ve en page_screenshot. - page_screenshot devuelve la imagen como image content (cdp_screenshot_bytes_go_browser + mcp.NewToolResultImage) para que el LLM vea los pixeles; path pasa a ser opcional (si se da, ademas guarda a disco). - Auto-observe de las tools *_ref sube su truncado de 4000 a 8000 chars. - Fix de seguridad documental: todas las descripciones del parametro port que decian "Default 9222" (navegador diario del usuario) corregidas a "Default 9333" (Chrome aislado del MCP). El codigo ya usaba 9333; la doc era falsa y podia inducir al modelo a tocar pestanas de banca/correo. uses_functions del app.md: +cdp_get_ax_outline, +cdp_get_text_in_frame, +cdp_screenshot_bytes; -cdp_perceive_outline_py_pipelines. Verificacion: go build OK, go test OK (4 unit pass, 3 e2e skip gated BMCP_E2E=1), go vet OK, gofmt limpio, sin "Default 9222" en el codigo. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
76 lines
2.5 KiB
Go
76 lines
2.5 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/mark3labs/mcp-go/mcp"
|
|
"github.com/mark3labs/mcp-go/server"
|
|
|
|
"fn-registry/functions/browser"
|
|
)
|
|
|
|
// registerStorageTools wires storage_save (read) + storage_load (MUTA).
|
|
func registerStorageTools(s *server.MCPServer, d *deps) {
|
|
s.AddTool(storageSaveTool(), mcp.NewTypedToolHandler(d.handleStorageSave))
|
|
|
|
if !d.readOnly {
|
|
s.AddTool(storageLoadTool(), mcp.NewTypedToolHandler(d.handleStorageLoad))
|
|
}
|
|
}
|
|
|
|
// ---- storage_save ----
|
|
|
|
type storageSaveArgs struct {
|
|
Port int `json:"port"`
|
|
Path string `json:"path"`
|
|
}
|
|
|
|
func storageSaveTool() mcp.Tool {
|
|
return mcp.NewTool("storage_save",
|
|
mcp.WithDescription("Save the current session storage state (cookies + localStorage) to a JSON file for later reuse."),
|
|
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 JSON file path.")),
|
|
)
|
|
}
|
|
|
|
func (d *deps) handleStorageSave(_ context.Context, _ mcp.CallToolRequest, a storageSaveArgs) (*mcp.CallToolResult, error) {
|
|
if a.Path == "" {
|
|
return mcp.NewToolResultError("path is required"), nil
|
|
}
|
|
err := d.withConn(portOr(a.Port), func(c *browser.CDPConn) error {
|
|
return browser.CdpSaveStorageState(c, a.Path)
|
|
})
|
|
if err != nil {
|
|
return mcp.NewToolResultError(err.Error()), nil
|
|
}
|
|
return mcp.NewToolResultText("storage state saved to " + a.Path), nil
|
|
}
|
|
|
|
// ---- storage_load (MUTA) ----
|
|
|
|
type storageLoadArgs struct {
|
|
Port int `json:"port"`
|
|
Path string `json:"path"`
|
|
}
|
|
|
|
func storageLoadTool() mcp.Tool {
|
|
return mcp.NewTool("storage_load",
|
|
mcp.WithDescription("Load a previously saved session storage state (cookies + localStorage) from a JSON file into the live browser."),
|
|
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("Input JSON file path.")),
|
|
)
|
|
}
|
|
|
|
func (d *deps) handleStorageLoad(_ context.Context, _ mcp.CallToolRequest, a storageLoadArgs) (*mcp.CallToolResult, error) {
|
|
if a.Path == "" {
|
|
return mcp.NewToolResultError("path is required"), nil
|
|
}
|
|
err := d.withConn(portOr(a.Port), func(c *browser.CDPConn) error {
|
|
return browser.CdpLoadStorageState(c, a.Path)
|
|
})
|
|
if err != nil {
|
|
return mcp.NewToolResultError(err.Error()), nil
|
|
}
|
|
return mcp.NewToolResultText("storage state loaded from " + a.Path), nil
|
|
}
|