feat: browser_mcp — servidor MCP de control de navegador CDP (33 tools + pool de conexiones)
This commit is contained in:
@@ -0,0 +1,145 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/mark3labs/mcp-go/mcp"
|
||||
"github.com/mark3labs/mcp-go/server"
|
||||
|
||||
"fn-registry/functions/browser"
|
||||
)
|
||||
|
||||
// registerCookieTools wires cookie_get (read) + set/delete/clear (MUTA).
|
||||
func registerCookieTools(s *server.MCPServer, d *deps) {
|
||||
s.AddTool(cookieGetTool(), mcp.NewTypedToolHandler(d.handleCookieGet))
|
||||
|
||||
if !d.readOnly {
|
||||
s.AddTool(cookieSetTool(), mcp.NewTypedToolHandler(d.handleCookieSet))
|
||||
s.AddTool(cookieDeleteTool(), mcp.NewTypedToolHandler(d.handleCookieDelete))
|
||||
s.AddTool(cookieClearTool(), mcp.NewTypedToolHandler(d.handleCookieClear))
|
||||
}
|
||||
}
|
||||
|
||||
// ---- cookie_get ----
|
||||
|
||||
type cookieGetArgs struct {
|
||||
Port int `json:"port"`
|
||||
}
|
||||
|
||||
func cookieGetTool() mcp.Tool {
|
||||
return mcp.NewTool("cookie_get",
|
||||
mcp.WithDescription("Return all browser cookies (Network.getAllCookies) as JSON."),
|
||||
mcp.WithNumber("port", mcp.Description("CDP port. Default 9222.")),
|
||||
)
|
||||
}
|
||||
|
||||
func (d *deps) handleCookieGet(_ context.Context, _ mcp.CallToolRequest, a cookieGetArgs) (*mcp.CallToolResult, error) {
|
||||
var cookies []browser.CdpCookie
|
||||
err := d.withConn(portOr(a.Port), func(c *browser.CDPConn) error {
|
||||
var e error
|
||||
cookies, e = browser.CdpGetCookies(c)
|
||||
return e
|
||||
})
|
||||
if err != nil {
|
||||
return mcp.NewToolResultError(err.Error()), nil
|
||||
}
|
||||
b, _ := json.MarshalIndent(cookies, "", " ")
|
||||
return mcp.NewToolResultText(string(b)), nil
|
||||
}
|
||||
|
||||
// ---- cookie_set (MUTA) ----
|
||||
|
||||
type cookieSetArgs struct {
|
||||
Port int `json:"port"`
|
||||
Name string `json:"name"`
|
||||
Value string `json:"value"`
|
||||
Domain string `json:"domain"`
|
||||
Path string `json:"path"`
|
||||
HTTPOnly bool `json:"http_only"`
|
||||
}
|
||||
|
||||
func cookieSetTool() mcp.Tool {
|
||||
return mcp.NewTool("cookie_set",
|
||||
mcp.WithDescription("Set a cookie via Network.setCookie."),
|
||||
mcp.WithNumber("port", mcp.Description("CDP port. Default 9222.")),
|
||||
mcp.WithString("name", mcp.Required(), mcp.Description("Cookie name.")),
|
||||
mcp.WithString("value", mcp.Description("Cookie value.")),
|
||||
mcp.WithString("domain", mcp.Required(), mcp.Description("Cookie domain.")),
|
||||
mcp.WithString("path", mcp.Description("Cookie path. Default /.")),
|
||||
mcp.WithBoolean("http_only", mcp.Description("Mark the cookie HttpOnly.")),
|
||||
)
|
||||
}
|
||||
|
||||
func (d *deps) handleCookieSet(_ context.Context, _ mcp.CallToolRequest, a cookieSetArgs) (*mcp.CallToolResult, error) {
|
||||
if a.Name == "" {
|
||||
return mcp.NewToolResultError("name is required"), nil
|
||||
}
|
||||
if a.Domain == "" {
|
||||
return mcp.NewToolResultError("domain is required"), nil
|
||||
}
|
||||
path := a.Path
|
||||
if path == "" {
|
||||
path = "/"
|
||||
}
|
||||
err := d.withConn(portOr(a.Port), func(c *browser.CDPConn) error {
|
||||
return browser.CdpSetCookie(c, a.Name, a.Value, a.Domain, path, a.HTTPOnly)
|
||||
})
|
||||
if err != nil {
|
||||
return mcp.NewToolResultError(err.Error()), nil
|
||||
}
|
||||
return mcp.NewToolResultText("cookie set: " + a.Name), nil
|
||||
}
|
||||
|
||||
// ---- cookie_delete (MUTA) ----
|
||||
|
||||
type cookieDeleteArgs struct {
|
||||
Port int `json:"port"`
|
||||
Name string `json:"name"`
|
||||
Domain string `json:"domain"`
|
||||
}
|
||||
|
||||
func cookieDeleteTool() mcp.Tool {
|
||||
return mcp.NewTool("cookie_delete",
|
||||
mcp.WithDescription("Delete cookies by name (optionally scoped to a domain) via Network.deleteCookies."),
|
||||
mcp.WithNumber("port", mcp.Description("CDP port. Default 9222.")),
|
||||
mcp.WithString("name", mcp.Required(), mcp.Description("Cookie name to delete.")),
|
||||
mcp.WithString("domain", mcp.Description("Optional domain scope.")),
|
||||
)
|
||||
}
|
||||
|
||||
func (d *deps) handleCookieDelete(_ context.Context, _ mcp.CallToolRequest, a cookieDeleteArgs) (*mcp.CallToolResult, error) {
|
||||
if a.Name == "" {
|
||||
return mcp.NewToolResultError("name is required"), nil
|
||||
}
|
||||
err := d.withConn(portOr(a.Port), func(c *browser.CDPConn) error {
|
||||
return browser.CdpDeleteCookies(c, a.Name, a.Domain)
|
||||
})
|
||||
if err != nil {
|
||||
return mcp.NewToolResultError(err.Error()), nil
|
||||
}
|
||||
return mcp.NewToolResultText("cookie deleted: " + a.Name), nil
|
||||
}
|
||||
|
||||
// ---- cookie_clear (MUTA) ----
|
||||
|
||||
type cookieClearArgs struct {
|
||||
Port int `json:"port"`
|
||||
}
|
||||
|
||||
func cookieClearTool() mcp.Tool {
|
||||
return mcp.NewTool("cookie_clear",
|
||||
mcp.WithDescription("Clear all browser cookies via Network.clearBrowserCookies."),
|
||||
mcp.WithNumber("port", mcp.Description("CDP port. Default 9222.")),
|
||||
)
|
||||
}
|
||||
|
||||
func (d *deps) handleCookieClear(_ context.Context, _ mcp.CallToolRequest, a cookieClearArgs) (*mcp.CallToolResult, error) {
|
||||
err := d.withConn(portOr(a.Port), func(c *browser.CDPConn) error {
|
||||
return browser.CdpClearCookies(c)
|
||||
})
|
||||
if err != nil {
|
||||
return mcp.NewToolResultError(err.Error()), nil
|
||||
}
|
||||
return mcp.NewToolResultText("cookies cleared"), nil
|
||||
}
|
||||
Reference in New Issue
Block a user