96 lines
3.2 KiB
Go
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
|
|
}
|