feat: browser_mcp — servidor MCP de control de navegador CDP (33 tools + pool de conexiones)
This commit is contained in:
+115
@@ -0,0 +1,115 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/mark3labs/mcp-go/mcp"
|
||||
"github.com/mark3labs/mcp-go/server"
|
||||
|
||||
"fn-registry/functions/browser"
|
||||
)
|
||||
|
||||
// registerFrameTools wires frame_list + frame_get_html (read) and frame_eval (MUTA).
|
||||
func registerFrameTools(s *server.MCPServer, d *deps) {
|
||||
s.AddTool(frameListTool(), mcp.NewTypedToolHandler(d.handleFrameList))
|
||||
s.AddTool(frameGetHTMLTool(), mcp.NewTypedToolHandler(d.handleFrameGetHTML))
|
||||
|
||||
if !d.readOnly {
|
||||
s.AddTool(frameEvalTool(), mcp.NewTypedToolHandler(d.handleFrameEval))
|
||||
}
|
||||
}
|
||||
|
||||
// ---- frame_list ----
|
||||
|
||||
type frameListArgs struct {
|
||||
Port int `json:"port"`
|
||||
}
|
||||
|
||||
func frameListTool() mcp.Tool {
|
||||
return mcp.NewTool("frame_list",
|
||||
mcp.WithDescription("List all frames (including iframes) of the current page via Page.getFrameTree. Returns JSON with frame IDs."),
|
||||
mcp.WithNumber("port", mcp.Description("CDP port. Default 9222.")),
|
||||
)
|
||||
}
|
||||
|
||||
func (d *deps) handleFrameList(_ context.Context, _ mcp.CallToolRequest, a frameListArgs) (*mcp.CallToolResult, error) {
|
||||
var frames []browser.CdpFrame
|
||||
err := d.withConn(portOr(a.Port), func(c *browser.CDPConn) error {
|
||||
var e error
|
||||
frames, e = browser.CdpListFrames(c)
|
||||
return e
|
||||
})
|
||||
if err != nil {
|
||||
return mcp.NewToolResultError(err.Error()), nil
|
||||
}
|
||||
b, _ := json.MarshalIndent(frames, "", " ")
|
||||
return mcp.NewToolResultText(string(b)), nil
|
||||
}
|
||||
|
||||
// ---- frame_eval (MUTA) ----
|
||||
|
||||
type frameEvalArgs struct {
|
||||
Port int `json:"port"`
|
||||
FrameID string `json:"frame_id"`
|
||||
Expression string `json:"expression"`
|
||||
}
|
||||
|
||||
func frameEvalTool() mcp.Tool {
|
||||
return mcp.NewTool("frame_eval",
|
||||
mcp.WithDescription("Evaluate a JavaScript expression inside a specific frame's execution context. Returns the stringified result."),
|
||||
mcp.WithNumber("port", mcp.Description("CDP port. Default 9222.")),
|
||||
mcp.WithString("frame_id", mcp.Required(), mcp.Description("Frame ID (from frame_list).")),
|
||||
mcp.WithString("expression", mcp.Required(), mcp.Description("JavaScript expression to evaluate.")),
|
||||
)
|
||||
}
|
||||
|
||||
func (d *deps) handleFrameEval(_ context.Context, _ mcp.CallToolRequest, a frameEvalArgs) (*mcp.CallToolResult, error) {
|
||||
if a.FrameID == "" {
|
||||
return mcp.NewToolResultError("frame_id is required"), nil
|
||||
}
|
||||
if a.Expression == "" {
|
||||
return mcp.NewToolResultError("expression is required"), nil
|
||||
}
|
||||
var res string
|
||||
err := d.withConn(portOr(a.Port), func(c *browser.CDPConn) error {
|
||||
var e error
|
||||
res, e = browser.CdpEvalInFrame(c, a.FrameID, a.Expression)
|
||||
return e
|
||||
})
|
||||
if err != nil {
|
||||
return mcp.NewToolResultError(err.Error()), nil
|
||||
}
|
||||
return mcp.NewToolResultText(truncate(res, htmlMax)), nil
|
||||
}
|
||||
|
||||
// ---- frame_get_html ----
|
||||
|
||||
type frameGetHTMLArgs struct {
|
||||
Port int `json:"port"`
|
||||
FrameID string `json:"frame_id"`
|
||||
}
|
||||
|
||||
func frameGetHTMLTool() mcp.Tool {
|
||||
return mcp.NewTool("frame_get_html",
|
||||
mcp.WithDescription("Return the serialized HTML of a specific frame. Truncated to 200000 chars."),
|
||||
mcp.WithNumber("port", mcp.Description("CDP port. Default 9222.")),
|
||||
mcp.WithString("frame_id", mcp.Required(), mcp.Description("Frame ID (from frame_list).")),
|
||||
)
|
||||
}
|
||||
|
||||
func (d *deps) handleFrameGetHTML(_ context.Context, _ mcp.CallToolRequest, a frameGetHTMLArgs) (*mcp.CallToolResult, error) {
|
||||
if a.FrameID == "" {
|
||||
return mcp.NewToolResultError("frame_id is required"), nil
|
||||
}
|
||||
var html string
|
||||
err := d.withConn(portOr(a.Port), func(c *browser.CDPConn) error {
|
||||
var e error
|
||||
html, e = browser.CdpGetFrameHTML(c, a.FrameID)
|
||||
return e
|
||||
})
|
||||
if err != nil {
|
||||
return mcp.NewToolResultError(err.Error()), nil
|
||||
}
|
||||
return mcp.NewToolResultText(truncate(html, htmlMax)), nil
|
||||
}
|
||||
Reference in New Issue
Block a user