diff --git a/internal/mcp/tools.go b/internal/mcp/tools.go index faa2d2e..df748f8 100644 --- a/internal/mcp/tools.go +++ b/internal/mcp/tools.go @@ -71,7 +71,7 @@ func RegisterAll(s *Server) { USE THIS: - For LOCAL FILES: bin="cat" / "tail" / "head" / "zcat" with the file path in args. - For provider CLIs that don't have a named codag.tail_* tool (railway, - fly, heroku, render, journalctl, stern, wrangler, gcloud, netlify). + fly, heroku, render, journalctl, stern, wrangler, gcloud, netlify, pm2). Examples (file reads — preferred when the user points at a path): bin="cat", args=["test4.log"] @@ -89,9 +89,10 @@ Examples (provider CLIs): bin="wrangler", args=["tail", "my-worker", "--format=pretty"] bin="journalctl", args=["-u", "myapp.service", "--since=10m"] bin="stern", args=["my-app", "-n", "prod", "--since", "10m"] + bin="pm2", args=["logs", "my-app", "--lines", "200", "--nostream", "--raw"] Allowlisted read-only log shapes: cat/tail/head/zcat for files, aws logs tail, -gcloud logging read, kubectl logs, vercel/railway/flyctl/heroku/render/netlify logs, +gcloud logging read, kubectl logs, vercel/railway/flyctl/heroku/render/netlify/pm2 logs, docker logs or docker compose logs, wrangler tail, gh run view, journalctl, stern, and logcli query.`, InputSchema: schemaWithArgs(map[string]string{ @@ -236,7 +237,7 @@ var allowlistedBins = []string{ "cat", "tail", "head", "zcat", "aws", "gcloud", "kubectl", "vercel", "railway", "flyctl", "heroku", "render", "netlify", "wrangler", "docker", "journalctl", "stern", "gh", - "logcli", + "logcli", "pm2", } func validateLogCommand(bin string, args []string) error { @@ -253,7 +254,7 @@ func validateLogCommand(bin string, args []string) error { return requirePrefix(bin, args, "logs", "tail") case "gcloud": return requirePrefix(bin, args, "logging", "read") - case "kubectl", "vercel", "railway", "flyctl", "heroku", "render", "netlify": + case "kubectl", "vercel", "railway", "flyctl", "heroku", "render", "netlify", "pm2": return requirePrefix(bin, args, "logs") case "wrangler": return requirePrefix(bin, args, "tail") diff --git a/internal/mcp/tools_test.go b/internal/mcp/tools_test.go index 389dddc..1e4ed10 100644 --- a/internal/mcp/tools_test.go +++ b/internal/mcp/tools_test.go @@ -27,6 +27,8 @@ func TestValidateLogCommand_AllowsKnownLogShapes(t *testing.T) { {"docker", []string{"logs", "api"}}, {"docker", []string{"compose", "logs", "api"}}, {"gh", []string{"run", "view", "123", "--log-failed"}}, + {"pm2", []string{"logs"}}, + {"pm2", []string{"logs", "my-app", "--lines", "200", "--nostream", "--raw"}}, } for _, c := range cases { if err := validateLogCommand(c.bin, c.args); err != nil { @@ -46,6 +48,8 @@ func TestValidateLogCommand_RejectsMutatingShapes(t *testing.T) { {"kubectl", []string{"delete", "pod/api"}}, {"gh", []string{"repo", "delete", "owner/repo"}}, {"journalctl", []string{"--vacuum-time=1s"}}, + {"pm2", []string{"flush"}}, + {"pm2", []string{"delete", "my-app"}}, } for _, c := range cases { if err := validateLogCommand(c.bin, c.args); err == nil {