Skip to content

Commit 46946da

Browse files
authored
feat: Overhaul MCP server for 2025-11-25 spec and add llms.txt doc (#386)
Refactors the MCP server to conform to current MCP spec best practices and adds an llmstxt.org-style docs index so AI clients can pull documentation on demand rather than having it pre-baked into tool responses. MCP server - Upgrade mcp-go v0.43.2 -> v0.47.1 - Declare listChanged on tool/resource capabilities and subscribe on resources - Add WithOutputSchema on every tool using new Go output structs - Cursor-based pagination (opaque base64 offsets) on list_workspaces, list_executables, get_execution_logs - Structured error responses with machine-readable codes (INVALID_INPUT, NOT_FOUND, EXECUTION_FAILED, CANCELLED, VALIDATION_FAILED, etc.) - Progress notifications and context cancellation for execute/sync_executables - New MCP resources: flow://workspace/{name}, flow://executable/{ws}/{ns}/{name}, flow://flowfile/{path}, flow://logs/{run-id} - Emit resources/list_changed after switch_workspace, sync_executables, and write_flowfile - New tools: write_flowfile (YAML-validated flowfile authoring) and get_workspace_config - Split tools.go into tools_workspace.go / tools_executable.go / tools_system.go - Extend CommandExecutor with ExecuteContext for cancellation support get_info slimdown - Dropped embedded concepts/file-types markdown and JSON schemas (~20KB) - Returns compact summary, docsUrl, llmsTxtUrl, schemaUrls, guideUrls instead - Removed the now-unused MCP resource copies and the docsgen path that produced them Docs - Add docs/public/llms.txt following the llmstxt.org format - Add docs/public/robots.txt pointing at the sitemap - Enable VitePress built-in sitemap generation - Update server-instructions.md to describe the new get_info shape and point agents at llmsTxtUrl / schemaUrls / guideUrls Tests - New pagination unit tests (empty, first/middle/last page, invalid cursor, cursor past end, round-trip) - New Ginkgo specs: resource template registration, output schema presence, structured error responses, write_flowfile (valid/invalid extension/invalid YAML/exists/overwrite), list_executables pagination
1 parent 53b5f6e commit 46946da

26 files changed

Lines changed: 1796 additions & 1796 deletions

docs/.vitepress/config.mts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ export default defineConfig({
88
base: '/',
99
outDir: './dist',
1010

11+
sitemap: {
12+
hostname: 'https://flowexec.io'
13+
},
14+
1115
head: [
1216
['link', { rel: 'icon', href: '/favicon.ico' }]
1317
],

docs/public/llms.txt

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
# Flow
2+
3+
> Flow is a local-first automation platform that helps you organize and execute any kind of workflow through declarative YAML. It provides a CLI, an interactive TUI, secret management via vaults, templating for code generation, and an MCP server for AI-agent integration.
4+
5+
Flow organizes automation into **workspaces** (projects/domains), each rooted at a `flow.yaml` config file. Inside a workspace, **executables** are declared in `*.flow` (or `*.flow.yaml`) files and run by invoking a **verb** (e.g. `run`, `build`, `test`, `deploy`) optionally combined with a `workspace/namespace:name` reference. Executables can be simple commands, HTTP requests, or orchestrated serial/parallel pipelines. **Templates** (`*.flow.tmpl`) generate new workflows interactively.
6+
7+
## Getting Started
8+
9+
- [Home](https://flowexec.io/): Landing page with feature overview
10+
- [Installation](https://flowexec.io/installation): Install flow on macOS, Linux, or Windows
11+
- [Quick Start](https://flowexec.io/quickstart): Five-minute walkthrough from install to first executable
12+
13+
## Core Guides
14+
15+
- [Guides Overview](https://flowexec.io/guides/): Index of all user guides
16+
- [Concepts](https://flowexec.io/guides/concepts): Executables, verbs, workspaces, namespaces, templates, vaults, execution model
17+
- [Your First Workflow](https://flowexec.io/guides/first-workflow): End-to-end tutorial for building a workflow
18+
- [Executables](https://flowexec.io/guides/executables): Full reference for executable types (exec, serial, parallel, request, launch, render)
19+
- [Workspaces](https://flowexec.io/guides/workspaces): How workspaces organize projects and domains
20+
- [Secrets](https://flowexec.io/guides/secrets): Vault-backed secret storage and injection into executions
21+
- [Execution History & Logs](https://flowexec.io/guides/execution-history): Viewing, attaching to, and inspecting past runs
22+
23+
## Advanced
24+
25+
- [Imported Executables](https://flowexec.io/guides/generated-config): Auto-import from Makefile, package.json, docker-compose, shell scripts
26+
- [Templates & Workflow Generation](https://flowexec.io/guides/templating): Generate executables from templates with interactive forms
27+
- [Advanced Workflows](https://flowexec.io/guides/advanced): Serial/parallel pipelines, retries, conditional execution, arguments/params
28+
- [Interactive UI](https://flowexec.io/guides/interactive): TUI customization and keybindings
29+
- [Integrations](https://flowexec.io/guides/integrations): MCP server, GitHub Actions, Docker, CI pipelines
30+
31+
## Configuration Reference
32+
33+
- [Config Reference Overview](https://flowexec.io/types/): Index with direct JSON schema links
34+
- [FlowFile Schema](https://flowexec.io/types/flowfile): Structure of `*.flow` / `*.flow.yaml` files
35+
- [Workspace Schema](https://flowexec.io/types/workspace): Structure of `flow.yaml` workspace config
36+
- [Template Schema](https://flowexec.io/types/template): Structure of `*.flow.tmpl` template files
37+
- [Config Schema](https://flowexec.io/types/config): Structure of the user-level flow config
38+
39+
## JSON Schemas
40+
41+
- [flowfile_schema.json](https://flowexec.io/schemas/flowfile_schema.json): Use this to validate or generate `*.flow` files
42+
- [workspace_schema.json](https://flowexec.io/schemas/workspace_schema.json): Use this to validate or generate `flow.yaml` files
43+
- [template_schema.json](https://flowexec.io/schemas/template_schema.json): Use this to validate or generate `*.flow.tmpl` files
44+
- [config_schema.json](https://flowexec.io/schemas/config_schema.json): Use this to validate or generate the user-level config
45+
46+
## CLI Reference
47+
48+
- [CLI Overview](https://flowexec.io/cli/flow): Top-level `flow` command and global flags
49+
- [flow browse](https://flowexec.io/cli/flow_browse): Interactive TUI for discovering and running executables
50+
- [flow exec](https://flowexec.io/cli/flow_exec): Run an executable directly
51+
- [flow sync](https://flowexec.io/cli/flow_sync): Refresh cached executable and workspace state
52+
- [flow mcp](https://flowexec.io/cli/flow_mcp): Start the MCP server over stdio for AI-agent integration
53+
54+
### Logs
55+
56+
- [flow logs](https://flowexec.io/cli/flow_logs): View execution history
57+
- [flow logs attach](https://flowexec.io/cli/flow_logs_attach): Attach to a running background execution
58+
- [flow logs clear](https://flowexec.io/cli/flow_logs_clear): Clear log history
59+
- [flow logs kill](https://flowexec.io/cli/flow_logs_kill): Terminate a background execution
60+
61+
### Cache
62+
63+
- [flow cache](https://flowexec.io/cli/flow_cache): Manage cached executable metadata
64+
- [flow cache clear](https://flowexec.io/cli/flow_cache_clear): Clear all cache entries
65+
- [flow cache get](https://flowexec.io/cli/flow_cache_get): Read a specific cache entry
66+
- [flow cache list](https://flowexec.io/cli/flow_cache_list): List cache entries
67+
- [flow cache remove](https://flowexec.io/cli/flow_cache_remove): Remove a specific entry
68+
- [flow cache set](https://flowexec.io/cli/flow_cache_set): Write a cache entry
69+
70+
### Config
71+
72+
- [flow config](https://flowexec.io/cli/flow_config): User-level configuration commands
73+
- [flow config get](https://flowexec.io/cli/flow_config_get): Read current config
74+
- [flow config reset](https://flowexec.io/cli/flow_config_reset): Reset to defaults
75+
- [flow config set](https://flowexec.io/cli/flow_config_set): Update a config value
76+
- [flow config set namespace](https://flowexec.io/cli/flow_config_set_namespace): Set current namespace
77+
- [flow config set workspace](https://flowexec.io/cli/flow_config_set_workspace): Set current workspace
78+
- [flow config set workspace-mode](https://flowexec.io/cli/flow_config_set_workspace-mode): Set fixed vs dynamic workspace mode
79+
- [flow config set log-mode](https://flowexec.io/cli/flow_config_set_log-mode): Set default log output format
80+
- [flow config set timeout](https://flowexec.io/cli/flow_config_set_timeout): Set default execution timeout
81+
- [flow config set theme](https://flowexec.io/cli/flow_config_set_theme): Customize TUI theme
82+
- [flow config set tui](https://flowexec.io/cli/flow_config_set_tui): Toggle interactive mode defaults
83+
- [flow config set notifications](https://flowexec.io/cli/flow_config_set_notifications): Configure notification behavior
84+
85+
### Secrets & Vaults
86+
87+
- [flow secret](https://flowexec.io/cli/flow_secret): Manage secrets in the active vault
88+
- [flow secret get](https://flowexec.io/cli/flow_secret_get): Read a secret value
89+
- [flow secret list](https://flowexec.io/cli/flow_secret_list): List secrets
90+
- [flow secret remove](https://flowexec.io/cli/flow_secret_remove): Delete a secret
91+
- [flow secret set](https://flowexec.io/cli/flow_secret_set): Store a secret
92+
- [flow vault](https://flowexec.io/cli/flow_vault): Manage vaults
93+
- [flow vault create](https://flowexec.io/cli/flow_vault_create): Create a new vault (AES256, Age, Keyring, or unencrypted)
94+
- [flow vault edit](https://flowexec.io/cli/flow_vault_edit): Edit vault metadata
95+
- [flow vault get](https://flowexec.io/cli/flow_vault_get): Show vault details
96+
- [flow vault list](https://flowexec.io/cli/flow_vault_list): List registered vaults
97+
- [flow vault remove](https://flowexec.io/cli/flow_vault_remove): Remove a vault
98+
- [flow vault switch](https://flowexec.io/cli/flow_vault_switch): Switch active vault
99+
100+
### Templates
101+
102+
- [flow template](https://flowexec.io/cli/flow_template): Manage workflow templates
103+
- [flow template add](https://flowexec.io/cli/flow_template_add): Register a template
104+
- [flow template generate](https://flowexec.io/cli/flow_template_generate): Generate a workflow from a template
105+
- [flow template get](https://flowexec.io/cli/flow_template_get): Show template metadata
106+
- [flow template list](https://flowexec.io/cli/flow_template_list): List registered templates
107+
108+
### Workspaces
109+
110+
- [flow workspace](https://flowexec.io/cli/flow_workspace): Workspace management commands
111+
- [flow workspace add](https://flowexec.io/cli/flow_workspace_add): Register a workspace
112+
- [flow workspace get](https://flowexec.io/cli/flow_workspace_get): Show workspace details
113+
- [flow workspace list](https://flowexec.io/cli/flow_workspace_list): List registered workspaces
114+
- [flow workspace remove](https://flowexec.io/cli/flow_workspace_remove): Unregister a workspace
115+
- [flow workspace switch](https://flowexec.io/cli/flow_workspace_switch): Change active workspace
116+
- [flow workspace view](https://flowexec.io/cli/flow_workspace_view): Open workspace in TUI
117+
118+
## Optional
119+
120+
- [Contributing](https://flowexec.io/development): Development setup and contribution guide
121+
- [TUI Kit](https://flowexec.io/tuikit): Companion Bubble Tea-based TUI framework
122+
- [GitHub Repository](https://github.com/flowexec/flow): Source code, issues, releases
123+
- [Examples Repository](https://github.com/flowexec/examples): Real-world workflow examples
124+
- [Discord Community](https://discord.gg/CtByNKNMxM): Community chat

docs/public/robots.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
User-agent: *
2+
Allow: /
3+
4+
Sitemap: https://flowexec.io/sitemap.xml

go.mod

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ require (
1313
github.com/gen2brain/beeep v0.11.2
1414
github.com/google/uuid v1.6.0
1515
github.com/jahvon/expression v0.1.4
16-
github.com/mark3labs/mcp-go v0.43.2
16+
github.com/mark3labs/mcp-go v0.47.1
1717
github.com/onsi/ginkgo/v2 v2.28.1
1818
github.com/onsi/gomega v1.39.0
1919
github.com/otiai10/copy v1.14.1
@@ -40,8 +40,6 @@ require (
4040
github.com/alecthomas/chroma/v2 v2.20.0 // indirect
4141
github.com/aymanbagabas/go-udiff v0.4.1 // indirect
4242
github.com/aymerick/douceur v0.2.0 // indirect
43-
github.com/bahlo/generic-list-go v0.2.0 // indirect
44-
github.com/buger/jsonparser v1.1.2 // indirect
4543
github.com/catppuccin/go v0.3.0 // indirect
4644
github.com/charmbracelet/ultraviolet v0.0.0-20260205113103-524a6607adb8 // indirect
4745
github.com/charmbracelet/x/ansi v0.11.6 // indirect
@@ -66,13 +64,12 @@ require (
6664
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
6765
github.com/godbus/dbus/v5 v5.1.0 // indirect
6866
github.com/google/go-cmp v0.7.0 // indirect
67+
github.com/google/jsonschema-go v0.4.2 // indirect
6968
github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83 // indirect
7069
github.com/gorilla/css v1.0.1 // indirect
7170
github.com/inconshreveable/mousetrap v1.1.0 // indirect
72-
github.com/invopop/jsonschema v0.13.0 // indirect
7371
github.com/jackmordaunt/icns/v3 v3.0.1 // indirect
7472
github.com/lucasb-eyer/go-colorful v1.3.0 // indirect
75-
github.com/mailru/easyjson v0.9.0 // indirect
7673
github.com/mattn/go-runewidth v0.0.23 // indirect
7774
github.com/microcosm-cc/bluemonday v1.0.27 // indirect
7875
github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect
@@ -87,7 +84,6 @@ require (
8784
github.com/sergeymakinen/go-ico v1.0.0-beta.0 // indirect
8885
github.com/spf13/cast v1.9.2 // indirect
8986
github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af // indirect
90-
github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
9187
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
9288
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
9389
github.com/yuin/goldmark v1.7.13 // indirect

go.sum

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,6 @@ github.com/aymanbagabas/go-udiff v0.4.1 h1:OEIrQ8maEeDBXQDoGCbbTTXYJMYRCRO1fnodZ
3434
github.com/aymanbagabas/go-udiff v0.4.1/go.mod h1:0L9PGwj20lrtmEMeyw4WKJ/TMyDtvAoK9bf2u/mNo3w=
3535
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
3636
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
37-
github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
38-
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
39-
github.com/buger/jsonparser v1.1.2 h1:frqHqw7otoVbk5M8LlE/L7HTnIq2v9RX6EJ48i9AxJk=
40-
github.com/buger/jsonparser v1.1.2/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
4137
github.com/catppuccin/go v0.3.0 h1:d+0/YicIq+hSTo5oPuRi5kOpqkVA5tAsU6dNhvRu+aY=
4238
github.com/catppuccin/go v0.3.0/go.mod h1:8IHJuMGaUUjQM82qBrGNBv7LFq6JI3NnQCF6MOlZjpc=
4339
github.com/charmbracelet/colorprofile v0.4.3 h1:QPa1IWkYI+AOB+fE+mg/5/4HRMZcaXex9t5KX76i20Q=
@@ -120,6 +116,8 @@ github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
120116
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
121117
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
122118
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
119+
github.com/google/jsonschema-go v0.4.2 h1:tmrUohrwoLZZS/P3x7ex0WAVknEkBZM46iALbcqoRA8=
120+
github.com/google/jsonschema-go v0.4.2/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE=
123121
github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83 h1:z2ogiKUYzX5Is6zr/vP9vJGqPwcdqsWjOt+V8J7+bTc=
124122
github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI=
125123
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
@@ -132,8 +130,6 @@ github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUq
132130
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
133131
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
134132
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
135-
github.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcIi21E=
136-
github.com/invopop/jsonschema v0.13.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0=
137133
github.com/jackmordaunt/icns/v3 v3.0.1 h1:xxot6aNuGrU+lNgxz5I5H0qSeCjNKp8uTXB1j8D4S3o=
138134
github.com/jackmordaunt/icns/v3 v3.0.1/go.mod h1:5sHL59nqTd2ynTnowxB/MDQFhKNqkK8X687uKNygaSQ=
139135
github.com/jahvon/expression v0.1.4 h1:4q/jvM5G2mBJDqXtTUDThtJ4Sfajx+vIhUf4r6EAy6A=
@@ -148,10 +144,8 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0
148144
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
149145
github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag=
150146
github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
151-
github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
152-
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
153-
github.com/mark3labs/mcp-go v0.43.2 h1:21PUSlWWiSbUPQwXIJ5WKlETixpFpq+WBpbMGDSVy/I=
154-
github.com/mark3labs/mcp-go v0.43.2/go.mod h1:YnJfOL382MIWDx1kMY+2zsRHU/q78dBg9aFb8W6Thdw=
147+
github.com/mark3labs/mcp-go v0.47.1 h1:A9sJJ20mscl/ssLYHjodfaoBmq6uuhMG7pAPNYaQymQ=
148+
github.com/mark3labs/mcp-go v0.47.1/go.mod h1:JKTC7R2LLVagkEWK7Kwu7DbmA6iIvnNAod6yrHiQMag=
155149
github.com/maruel/natural v1.1.1 h1:Hja7XhhmvEFhcByqDoHz9QZbkWey+COd9xWfCfn1ioo=
156150
github.com/maruel/natural v1.1.1/go.mod h1:v+Rfd79xlw1AgVBjbO0BEQmptqb5HvL/k9GRHB7ZKEg=
157151
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
@@ -222,8 +216,6 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
222216
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
223217
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
224218
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
225-
github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc=
226-
github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
227219
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
228220
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
229221
github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4=

internal/mcp/command_executor.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package mcp
22

33
import (
4+
"context"
45
"os"
56
"os/exec"
67

@@ -12,6 +13,7 @@ const cliBinaryEnvKey = "FLOW_CLI_BINARY"
1213
//go:generate mockgen -destination=mocks/command_executor.go -package=mocks . CommandExecutor
1314
type CommandExecutor interface {
1415
Execute(args ...string) (string, error)
16+
ExecuteContext(ctx context.Context, args ...string) (string, error)
1517
}
1618

1719
// FlowCLIExecutor runs the flow CLI with provided arguments. The CLI is being executed instead of importing the
@@ -23,11 +25,15 @@ type CommandExecutor interface {
2325
type FlowCLIExecutor struct{}
2426

2527
func (c *FlowCLIExecutor) Execute(args ...string) (string, error) {
28+
return c.ExecuteContext(context.Background(), args...)
29+
}
30+
31+
func (c *FlowCLIExecutor) ExecuteContext(ctx context.Context, args ...string) (string, error) {
2632
name := "flow"
2733
if envName := os.Getenv(cliBinaryEnvKey); envName != "" {
2834
name = envName
2935
}
30-
cmd := exec.Command(name, args...) // #nosec G204,G702
36+
cmd := exec.CommandContext(ctx, name, args...) // #nosec G204,G702
3137
output, err := cmd.CombinedOutput()
3238
if err != nil {
3339
// Only return an error if it's not an exit error.

internal/mcp/errors.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package mcp
2+
3+
import (
4+
"encoding/json"
5+
6+
"github.com/mark3labs/mcp-go/mcp"
7+
)
8+
9+
// Machine-readable error codes for structured error responses.
10+
const (
11+
ErrCodeInvalidInput = "INVALID_INPUT"
12+
ErrCodeNotFound = "NOT_FOUND"
13+
ErrCodeExecutionFailed = "EXECUTION_FAILED"
14+
ErrCodeTimeout = "TIMEOUT"
15+
ErrCodeCancelled = "CANCELLED"
16+
ErrCodeValidationFailed = "VALIDATION_FAILED"
17+
ErrCodeInternal = "INTERNAL_ERROR"
18+
ErrCodePermissionDenied = "PERMISSION_DENIED"
19+
)
20+
21+
type errorPayload struct {
22+
Error errorDetail `json:"error"`
23+
}
24+
25+
type errorDetail struct {
26+
Code string `json:"code"`
27+
Message string `json:"message"`
28+
Details map[string]any `json:"details,omitempty"`
29+
}
30+
31+
// toolError returns a CallToolResult with IsError set and a structured JSON error payload.
32+
func toolError(code, message string) *mcp.CallToolResult {
33+
return toolErrorWithDetails(code, message, nil)
34+
}
35+
36+
// toolErrorWithDetails is like toolError but includes a details object in the error payload.
37+
func toolErrorWithDetails(code, message string, details map[string]any) *mcp.CallToolResult {
38+
payload := errorPayload{Error: errorDetail{
39+
Code: code,
40+
Message: message,
41+
Details: details,
42+
}}
43+
data, err := json.Marshal(payload)
44+
if err != nil {
45+
return mcp.NewToolResultError(message)
46+
}
47+
return mcp.NewToolResultError(string(data))
48+
}

internal/mcp/mocks/command_executor.go

Lines changed: 21 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)