chore: sync from fn-registry agent
This commit is contained in:
+79
@@ -0,0 +1,79 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"github.com/mark3labs/mcp-go/mcp"
|
||||
)
|
||||
|
||||
type runArgs struct {
|
||||
ID string `json:"id"`
|
||||
Args []string `json:"args,omitempty"`
|
||||
}
|
||||
|
||||
func runTool() mcp.Tool {
|
||||
return mcp.NewTool("fn_run",
|
||||
mcp.WithDescription("Execute a registry function/pipeline via `fn run <id> [args...]`. Dispatches by language: Go (go run/test), Python (.venv), Bash, TypeScript (tsx). Mutating side-effects possible. Off by default — server must be launched with --enable-run."),
|
||||
mcp.WithString("id",
|
||||
mcp.Required(),
|
||||
mcp.Description("Registry ID or function name."),
|
||||
),
|
||||
mcp.WithArray("args",
|
||||
mcp.Description("Positional args appended to fn run."),
|
||||
mcp.Items(map[string]any{"type": "string"}),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
func (d *deps) handleRun(ctx context.Context, _ mcp.CallToolRequest, args runArgs) (*mcp.CallToolResult, error) {
|
||||
if args.ID == "" {
|
||||
return mcp.NewToolResultError("id is required"), nil
|
||||
}
|
||||
bin := d.fnBin()
|
||||
cmdArgs := append([]string{"run", args.ID}, args.Args...)
|
||||
cmd := exec.CommandContext(ctx, bin, cmdArgs...)
|
||||
cmd.Dir = d.root
|
||||
cmd.Env = os.Environ()
|
||||
|
||||
var stdout, stderr bytes.Buffer
|
||||
cmd.Stdout = &stdout
|
||||
cmd.Stderr = &stderr
|
||||
runErr := cmd.Run()
|
||||
|
||||
exit := 0
|
||||
if cmd.ProcessState != nil {
|
||||
exit = cmd.ProcessState.ExitCode()
|
||||
}
|
||||
|
||||
out := map[string]any{
|
||||
"id": args.ID,
|
||||
"args": args.Args,
|
||||
"exit_code": exit,
|
||||
"stdout": truncate(stdout.String(), 100_000),
|
||||
"stderr": truncate(stderr.String(), 100_000),
|
||||
}
|
||||
if runErr != nil && exit == 0 {
|
||||
out["error"] = runErr.Error()
|
||||
}
|
||||
|
||||
b, _ := json.MarshalIndent(out, "", " ")
|
||||
return mcp.NewToolResultText(string(b)), nil
|
||||
}
|
||||
|
||||
func (d *deps) fnBin() string {
|
||||
if v := os.Getenv("FN_BIN"); v != "" {
|
||||
return v
|
||||
}
|
||||
candidate := d.root + "/fn"
|
||||
if _, err := os.Stat(candidate); err == nil {
|
||||
return candidate
|
||||
}
|
||||
if path, err := exec.LookPath("fn"); err == nil {
|
||||
return path
|
||||
}
|
||||
return "fn"
|
||||
}
|
||||
Reference in New Issue
Block a user