Files
browser_mcp/tools_session.go
T

96 lines
3.2 KiB
Go

package main
import (
"context"
"fmt"
"github.com/mark3labs/mcp-go/mcp"
"github.com/mark3labs/mcp-go/server"
"fn-registry/functions/browser"
)
// registerSessionTools wires browser_launch (MUTA), browser_connect, browser_disconnect.
func registerSessionTools(s *server.MCPServer, d *deps) {
if !d.readOnly {
s.AddTool(launchTool(), mcp.NewTypedToolHandler(d.handleLaunch))
}
s.AddTool(connectTool(), mcp.NewTypedToolHandler(d.handleConnect))
s.AddTool(disconnectTool(), mcp.NewTypedToolHandler(d.handleDisconnect))
}
// ---- browser_launch (MUTA) ----
type launchArgs struct {
Port int `json:"port"`
Headless bool `json:"headless"`
UserDataDir string `json:"user_data_dir"`
URL string `json:"url"`
}
func launchTool() mcp.Tool {
return mcp.NewTool("browser_launch",
mcp.WithDescription("Launch a Chrome/Chromium instance with CDP remote debugging enabled. Returns the launched PID. Waits up to 15s for the CDP port to be ready."),
mcp.WithNumber("port", mcp.Description("CDP remote debugging port. Default 9222.")),
mcp.WithBoolean("headless", mcp.Description("Run headless (--headless=new). Default false.")),
mcp.WithString("user_data_dir", mcp.Description("Chrome profile directory. Empty = /tmp/chrome-cdp-profile.")),
mcp.WithString("url", mcp.Description("Optional initial URL to open on launch.")),
)
}
func (d *deps) handleLaunch(_ context.Context, _ mcp.CallToolRequest, a launchArgs) (*mcp.CallToolResult, error) {
opts := browser.ChromeLaunchOpts{
Port: portOr(a.Port),
Headless: a.Headless,
UserDataDir: a.UserDataDir,
}
if a.URL != "" {
opts.ExtraArgs = append(opts.ExtraArgs, a.URL)
}
pid, err := browser.ChromeLaunch(opts)
if err != nil {
return mcp.NewToolResultError(err.Error()), nil
}
return mcp.NewToolResultText(fmt.Sprintf("launched pid=%d port=%d", pid, opts.Port)), nil
}
// ---- browser_connect ----
type connectArgs struct {
Port int `json:"port"`
}
func connectTool() mcp.Tool {
return mcp.NewTool("browser_connect",
mcp.WithDescription("Open (and pool) a CDP WebSocket connection to a running Chrome's first 'page' tab on the given port. Subsequent tools reuse this live session."),
mcp.WithNumber("port", mcp.Description("CDP port. Default 9222.")),
)
}
func (d *deps) handleConnect(_ context.Context, _ mcp.CallToolRequest, a connectArgs) (*mcp.CallToolResult, error) {
port := portOr(a.Port)
if _, err := d.pool.get(port); err != nil {
return mcp.NewToolResultError(err.Error()), nil
}
return mcp.NewToolResultText(fmt.Sprintf("connected port=%d", port)), nil
}
// ---- browser_disconnect ----
type disconnectArgs struct {
Port int `json:"port"`
}
func disconnectTool() mcp.Tool {
return mcp.NewTool("browser_disconnect",
mcp.WithDescription("Close and drop the pooled CDP connection for the given port (cancels any armed dialog handler). Does NOT kill Chrome."),
mcp.WithNumber("port", mcp.Description("CDP port. Default 9222.")),
)
}
func (d *deps) handleDisconnect(_ context.Context, _ mcp.CallToolRequest, a disconnectArgs) (*mcp.CallToolResult, error) {
port := portOr(a.Port)
d.pool.drop(port)
return mcp.NewToolResultText(fmt.Sprintf("disconnected port=%d", port)), nil
}