Add flow mcp command for Cadence MCP server#2306
Conversation
Dependency ReviewThe following issues were found:
Snapshot WarningsEnsure that dependencies are being submitted on PR branches and consider enabling retry-on-snapshot-warnings. See the documentation for more information and troubleshooting advice. License Issuesgo.mod
OpenSSF Scorecard
Scanned Files
|
|
This pull request introduces dependencies with security vulnerabilities of moderate severity or higher. Vulnerable Dependencies:📦 github.com/buger/jsonparser@1.1.1 What to do next?
Security Engineering contact: #security on slack |
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Pull request overview
This PR introduces a new flow mcp CLI subcommand that runs an MCP (Model Context Protocol) server over stdio, exposing Cadence LSP capabilities plus on-chain query and script execution tools for AI-assisted Cadence development.
Changes:
- Add
flow mcpCobra command that starts an MCP server over stdio. - Implement MCP tool handlers for Cadence LSP actions, contract queries, script execution, and regex-based code review.
- Add tests for LSP wrapper, tool handlers, code review rules, and network-backed integration flows; add
mcp-godependency.
Reviewed changes
Copilot reviewed 10 out of 11 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
cmd/flow/main.go |
Wires the new mcp command into the root CLI. |
internal/mcp/mcp.go |
Implements flow mcp command startup and Flow network gateway resolution. |
internal/mcp/tools.go |
Defines MCP tool schemas and handler implementations (LSP + on-chain + review). |
internal/mcp/lsp.go |
Adds an in-process Cadence language server wrapper and formatting helpers. |
internal/mcp/audit.go |
Adds regex-based Cadence “code review” rule engine + formatting. |
internal/mcp/*_test.go |
Adds unit/integration coverage for the new MCP functionality. |
go.mod / go.sum |
Adds github.com/mark3labs/mcp-go and updates indirect deps. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| func (c *diagConn) captureDiagnostics(diags []protocol.Diagnostic) { | ||
| c.mu.Lock() | ||
| defer c.mu.Unlock() | ||
| c.diagnostics = append(c.diagnostics, diags...) | ||
| } |
There was a problem hiding this comment.
diagConn.captureDiagnostics appends diagnostics, which can duplicate results if the server publishes diagnostics multiple times for the same document update. Consider replacing (not appending) the stored diagnostics per publish event, and (optionally) filtering by scratchURI to avoid capturing diagnostics for unrelated documents.
| // Try to load flow.json for custom network configs | ||
| loader := &afero.Afero{Fs: afero.NewOsFs()} | ||
| state, _ := flowkit.Load(config.DefaultPaths(), loader) | ||
|
|
There was a problem hiding this comment.
flowkit.Load errors are discarded here. If flow.json exists but is invalid/corrupt, MCP will silently fall back to defaults, which is hard to debug. Consider checking the returned error and printing a warning (except for config.ErrDoesNotExist).
| addr := flow.HexToAddress(address) | ||
| account, err := gw.GetAccount(ctx, addr) | ||
| if err != nil { | ||
| return mcplib.NewToolResultError(fmt.Sprintf("failed to get account: %v", err)), nil | ||
| } |
There was a problem hiding this comment.
flow.HexToAddress does not return an error; invalid input can silently become flow.EmptyAddress. To avoid querying the wrong account, validate the parsed address (e.g., check addr == flow.EmptyAddress) and return a tool error for invalid address values.
| addr := flow.HexToAddress(address) | ||
| account, err := gw.GetAccount(ctx, addr) | ||
| if err != nil { | ||
| return mcplib.NewToolResultError(fmt.Sprintf("failed to get account: %v", err)), nil | ||
| } |
There was a problem hiding this comment.
Same address-parsing issue as above: invalid address input can silently map to flow.EmptyAddress. Add validation after flow.HexToAddress and return a clear error if the address is invalid.
| match := rule.pattern.FindStringSubmatch(line) | ||
| if match != nil { | ||
| findings = append(findings, Finding{ | ||
| Rule: rule.id, | ||
| Severity: rule.severity, | ||
| Line: lineNum, | ||
| Message: rule.message(match), | ||
| }) | ||
| } |
There was a problem hiding this comment.
The review rules use FindStringSubmatch, so each rule can only emit at most one finding per line. This can miss multiple occurrences (e.g. multiple force-unwraps on one line). If you want complete findings, iterate matches with FindAllStringSubmatchIndex/FindAllStringSubmatch and emit one finding per match.
| // Check sends code to the LSP and returns any diagnostics. | ||
| func (w *LSPWrapper) Check(code, network string) ([]protocol.Diagnostic, error) { | ||
| w.mu.Lock() | ||
| defer w.mu.Unlock() | ||
|
|
||
| w.conn.reset() |
There was a problem hiding this comment.
The network parameter is accepted by Check/Hover/Definition/Symbols/Completion but never used in this wrapper, so the MCP tool network argument is currently ignored for all LSP-backed tools. Either wire network into the cadence-tools flow integration/address resolution (if supported) or remove the network argument from the LSP wrapper/tool schemas to avoid misleading behavior.
There was a problem hiding this comment.
Removed the network parameter from all LSP wrapper methods and their tool schemas since it wasn't wired to anything. The cadence-tools LSP integration resolves imports based on its own flow.json discovery, not a per-request network param. Adding per-request network switching would require managing multiple LSP server instances (one per network) — worth doing as a follow-up but out of scope for the initial implementation.
| net, err := resolveNetwork(state, network) | ||
| if err != nil { | ||
| return nil, err | ||
| } |
There was a problem hiding this comment.
createGateway always uses gateway.NewGrpcGateway and ignores network.Key. Elsewhere in the CLI, networks with a configured key use gateway.NewSecureGrpcGateway (see internal/command/command.go:createGateway). For consistency and to support custom networks, mirror that logic here (or reuse the existing helper).
| } | |
| } | |
| // Mirror CLI behavior: use a secure gateway when the network has a configured key. | |
| if net.Key != "" { | |
| return gateway.NewSecureGrpcGateway(*net, net.Key) | |
| } |
| network := req.GetString("network", "mainnet") | ||
|
|
||
| gw, err := createGateway(m.state, network) | ||
| if err != nil { | ||
| return mcplib.NewToolResultError(fmt.Sprintf("failed to create gateway: %v", err)), nil | ||
| } |
There was a problem hiding this comment.
Each tool invocation creates a new gRPC gateway (createGateway), which in a long-running MCP server can lead to repeated client/connection setup overhead. Consider caching/reusing gateways per network in mcpContext (and closing them on shutdown if the implementation requires it).
There was a problem hiding this comment.
Valid point for a production service. In the MCP context, tool calls are infrequent (human-driven via AI agent) and connections are short-lived, so the overhead is negligible. Deferring gateway caching to a follow-up if profiling shows it matters.
…DiagnosticSeverity
Per team confirmation that Peter Argue (Flow DX) ported Hao's MCP into the Flow CLI in onflow/flow-cli#2306 (merged 2026-04-03), the canonical Cadence MCP is now `flow mcp` — bundled with every Flow CLI install, zero extra dependencies. flow-ai-tools' install script registers it this way already. The /onflow/cadence-lang.org redesign PR was carrying a parallel `mcp-server/` (Hao's npm @outblock/cadence-mcp source). Two MCPs both registering as 'cadence-mcp' in Claude Code is a footgun. Consolidating to one canonical path. CHANGES: Docs — replace every '@outblock/cadence-mcp' install snippet with 'flow mcp' equivalent across: - content/docs/ai-tools/mcp-server.mdx — full rewrite around Flow CLI - content/docs/ai-tools/integrations/{claude,cursor,antigravity,opencode}.mdx - content/docs/ai-tools/integrations/index.mdx (table + intro) - content/docs/ai-tools/skills.mdx (Next steps; description re-counted) - content/docs/ai-tools/index.mdx - src/routes/index.tsx — homepage hero MCP card - README.md — install commands - AGENTS.md, CLAUDE.md — repo overview Source — remove duplicate implementation: - mcp-server/ (entire dir): 21 files, ~8200 lines deleted - .github/workflows/publish-mcp.yml — npm publish CI no longer needed Skill-count phrasing — replaced hardcoded '11 skills' / '11 Cadence + Flow skills' with 'full Cadence + Flow skill suite' / 'Flow's full skill suite' across all 8 affected files. The skill table in skills.mdx still documents every skill by name with its description — count-free wording. Follow-up issues to file post-merge: - Upstream Hao's 3 unique tools (cadence_security_scan, cadence_validate_args, doc-search trio) into onflow/flow-cli/internal/mcp - Deprecate @outblock/cadence-mcp on npm with redirect notice pointing at 'flow mcp' - Confirm Flow DX team owns flow mcp going forward (Peter Argue) Verified: types:check clean, build clean (96 sitemap URLs), zero '@Outblock' / '@outblock/cadence-mcp' / 'mcp-server/' source references remain in shipped content.
Two related tooling stories were tangled in the original PR — they're now consolidated to the canonical Flow Foundation paths. SKILLS — single Claude Code marketplace ------ Hao's redesign shipped an inline 'skills/cadence/SKILL.md' (single file, 873 lines) plus 'update-ai-files.yml' CI to keep it in sync. Meanwhile, onflow ships an official Claude Code plugin marketplace at [onflow/flow-ai-tools](https://github.com/onflow/flow-ai-tools) — bundles 'flow-dev' plugin with the full Cadence + Flow skill suite (cadence-lang, cadence-tokens, cadence-audit, cadence-scaffold, cadence-testing, flow-react-sdk, flow-project-setup, flow-cli, flow-dev-setup, flow-defi, flow-tokenomics — each with its own reference files). Inline skill is strictly subsumed. - skills/cadence/SKILL.md: DELETED - .github/workflows/update-ai-files.yml: DELETED (auto-sync CI obsolete) - content/docs/ai-tools/skills.mdx: rewritten around '/plugin marketplace add onflow/flow-ai-tools' install path. Skill table phrasing uses 'full Cadence + Flow skill suite' instead of hardcoded count (durable across upstream additions). MCP — single canonical install path (flow mcp) ------ Hao's redesign also shipped 'mcp-server/' as a TypeScript / Bun standalone package published to npm as '@outblock/cadence-mcp'. Meanwhile, Peter Argue (Flow DX) shipped a Go-native Cadence MCP server in [flow-cli #2306](onflow/flow-cli#2306), merged 2026-04-03 (one day after Hao's last npm publish) — inspired by Hao's PR #285 design but implemented from scratch in Go with no extra runtime dependencies. flow-ai-tools' install script ([scripts/install.sh L65–98](https://github.com/onflow/flow-ai-tools/blob/main/scripts/install.sh#L65)) already registers MCP via 'flow mcp', not Hao's npm package — i.e. anyone running the marketplace one-liner is already on the canonical path. Two MCPs both registering as 'cadence-mcp' in Claude Code is a footgun: same tool name, different binaries, surprising about which one served a response. Consolidating to one canonical install path. - mcp-server/: DELETED entirely (~7,000 lines, 21 files, ~330 tests) - .github/workflows/publish-mcp.yml: DELETED (npm publish CI obsolete) - content/docs/ai-tools/mcp-server.mdx: rewritten around 'flow mcp' (Flow CLI ≥ v2.16.0). Tool list updated to the 8 tools 'flow mcp' exposes (LSP-backed: cadence_check, cadence_hover, cadence_definition, cadence_symbols, cadence_completion + on-chain: get_contract_source, get_contract_code, cadence_execute_script). - content/docs/ai-tools/integrations/{antigravity,claude,cursor,opencode}.mdx: install snippets all reference 'claude mcp add --scope user cadence-mcp -- flow mcp' (or editor-equivalent). Cursor deeplink updated. - content/docs/ai-tools/integrations/index.mdx (NEW): per-editor matrix table summarizing project-context source / skills support / MCP support. Fixes broken '../integrations' link from skills.mdx (was 404 because fumadocs needs an index.mdx for directory routes). - content/docs/ai-tools/{,integrations/}meta.json: add '...' rest token so any future pages added to those dirs get auto-included. - content/docs/ai-tools/index.mdx: tweak MCP description to match new tool surface. - src/routes/index.tsx (homepage hero MCP card): replaces 'npx install-mcp @outblock/cadence-mcp --client $CLIENT' with the 'flow mcp' install command. Drops the now-superfluous client + mode selectors. (NOTE: src/routes/index.tsx homepage hero edit goes in the next commit with the rest of the index.tsx changes — bundled with a11y to keep one diff per file.) DOCS / META ------ - CLAUDE.md: removed 'skills/cadence/SKILL.md' line; removed 'mcp-server/' line. The MCP server now lives at onflow/flow-cli/internal/mcp. - README.md: 'AI Integration' section rewritten — Skills via flow-ai-tools marketplace, MCP via 'flow mcp'. Follow-up issues for the 3 unique tools Hao's mcp-server had that 'flow mcp' doesn't yet (cadence_security_scan, cadence_validate_args, doc-search trio): tracked at #307 for upstream contribution to onflow/flow-cli.
Two related tooling stories were tangled in the original PR — they're now consolidated to the canonical Flow Foundation paths. SKILLS — single Claude Code marketplace ------ Hao's redesign shipped an inline 'skills/cadence/SKILL.md' (single file, 873 lines) plus 'update-ai-files.yml' CI to keep it in sync. Meanwhile, onflow ships an official Claude Code plugin marketplace at [onflow/flow-ai-tools](https://github.com/onflow/flow-ai-tools) — bundles 'flow-dev' plugin with the full Cadence + Flow skill suite (cadence-lang, cadence-tokens, cadence-audit, cadence-scaffold, cadence-testing, flow-react-sdk, flow-project-setup, flow-cli, flow-dev-setup, flow-defi, flow-tokenomics — each with its own reference files). Inline skill is strictly subsumed. - skills/cadence/SKILL.md: DELETED - .github/workflows/update-ai-files.yml: DELETED (auto-sync CI obsolete) - content/docs/ai-tools/skills.mdx: rewritten around '/plugin marketplace add onflow/flow-ai-tools' install path. Skill table phrasing uses 'full Cadence + Flow skill suite' instead of hardcoded count (durable across upstream additions). MCP — single canonical install path (flow mcp) ------ Hao's redesign also shipped 'mcp-server/' as a TypeScript / Bun standalone package published to npm as '@outblock/cadence-mcp'. Meanwhile, Peter Argue (Flow DX) shipped a Go-native Cadence MCP server in [flow-cli #2306](onflow/flow-cli#2306), merged 2026-04-03 (one day after Hao's last npm publish) — inspired by Hao's PR #285 design but implemented from scratch in Go with no extra runtime dependencies. flow-ai-tools' install script ([scripts/install.sh L65–98](https://github.com/onflow/flow-ai-tools/blob/main/scripts/install.sh#L65)) already registers MCP via 'flow mcp', not Hao's npm package — i.e. anyone running the marketplace one-liner is already on the canonical path. Two MCPs both registering as 'cadence-mcp' in Claude Code is a footgun: same tool name, different binaries, surprising about which one served a response. Consolidating to one canonical install path. - mcp-server/: DELETED entirely (~7,000 lines, 21 files, ~330 tests) - .github/workflows/publish-mcp.yml: DELETED (npm publish CI obsolete) - content/docs/ai-tools/mcp-server.mdx: rewritten around 'flow mcp' (Flow CLI ≥ v2.16.0). Tool list updated to the 8 tools 'flow mcp' exposes (LSP-backed: cadence_check, cadence_hover, cadence_definition, cadence_symbols, cadence_completion + on-chain: get_contract_source, get_contract_code, cadence_execute_script). - content/docs/ai-tools/integrations/{antigravity,claude,cursor,opencode}.mdx: install snippets all reference 'claude mcp add --scope user cadence-mcp -- flow mcp' (or editor-equivalent). Cursor deeplink updated. - content/docs/ai-tools/integrations/index.mdx (NEW): per-editor matrix table summarizing project-context source / skills support / MCP support. Fixes broken '../integrations' link from skills.mdx (was 404 because fumadocs needs an index.mdx for directory routes). - content/docs/ai-tools/{,integrations/}meta.json: add '...' rest token so any future pages added to those dirs get auto-included. - content/docs/ai-tools/index.mdx: tweak MCP description to match new tool surface. - src/routes/index.tsx (homepage hero MCP card): replaces 'npx install-mcp @outblock/cadence-mcp --client $CLIENT' with the 'flow mcp' install command. Drops the now-superfluous client + mode selectors. (NOTE: src/routes/index.tsx homepage hero edit goes in the next commit with the rest of the index.tsx changes — bundled with a11y to keep one diff per file.) DOCS / META ------ - CLAUDE.md: removed 'skills/cadence/SKILL.md' line; removed 'mcp-server/' line. The MCP server now lives at onflow/flow-cli/internal/mcp. - README.md: 'AI Integration' section rewritten — Skills via flow-ai-tools marketplace, MCP via 'flow mcp'. Follow-up issues for the 3 unique tools Hao's mcp-server had that 'flow mcp' doesn't yet (cadence_security_scan, cadence_validate_args, doc-search trio): tracked at #307 for upstream contribution to onflow/flow-cli.
Two related tooling stories were tangled in the original PR — they're now consolidated to the canonical Flow Foundation paths. SKILLS — single Claude Code marketplace ------ Hao's redesign shipped an inline 'skills/cadence/SKILL.md' (single file, 873 lines) plus 'update-ai-files.yml' CI to keep it in sync. Meanwhile, onflow ships an official Claude Code plugin marketplace at [onflow/flow-ai-tools](https://github.com/onflow/flow-ai-tools) — bundles 'flow-dev' plugin with the full Cadence + Flow skill suite (cadence-lang, cadence-tokens, cadence-audit, cadence-scaffold, cadence-testing, flow-react-sdk, flow-project-setup, flow-cli, flow-dev-setup, flow-defi, flow-tokenomics — each with its own reference files). Inline skill is strictly subsumed. - skills/cadence/SKILL.md: DELETED - .github/workflows/update-ai-files.yml: DELETED (auto-sync CI obsolete) - content/docs/ai-tools/skills.mdx: rewritten around '/plugin marketplace add onflow/flow-ai-tools' install path. Skill table phrasing uses 'full Cadence + Flow skill suite' instead of hardcoded count (durable across upstream additions). MCP — single canonical install path (flow mcp) ------ Hao's redesign also shipped 'mcp-server/' as a TypeScript / Bun standalone package published to npm as '@outblock/cadence-mcp'. Meanwhile, Peter Argue (Flow DX) shipped a Go-native Cadence MCP server in [flow-cli #2306](onflow/flow-cli#2306), merged 2026-04-03 (one day after Hao's last npm publish) — inspired by Hao's PR #285 design but implemented from scratch in Go with no extra runtime dependencies. flow-ai-tools' install script ([scripts/install.sh L65–98](https://github.com/onflow/flow-ai-tools/blob/main/scripts/install.sh#L65)) already registers MCP via 'flow mcp', not Hao's npm package — i.e. anyone running the marketplace one-liner is already on the canonical path. Two MCPs both registering as 'cadence-mcp' in Claude Code is a footgun: same tool name, different binaries, surprising about which one served a response. Consolidating to one canonical install path. - mcp-server/: DELETED entirely (~7,000 lines, 21 files, ~330 tests) - .github/workflows/publish-mcp.yml: DELETED (npm publish CI obsolete) - content/docs/ai-tools/mcp-server.mdx: rewritten around 'flow mcp' (Flow CLI ≥ v2.16.0). Tool list updated to the 8 tools 'flow mcp' exposes (LSP-backed: cadence_check, cadence_hover, cadence_definition, cadence_symbols, cadence_completion + on-chain: get_contract_source, get_contract_code, cadence_execute_script). - content/docs/ai-tools/integrations/{antigravity,claude,cursor,opencode}.mdx: install snippets all reference 'claude mcp add --scope user cadence-mcp -- flow mcp' (or editor-equivalent). Cursor deeplink updated. - content/docs/ai-tools/integrations/index.mdx (NEW): per-editor matrix table summarizing project-context source / skills support / MCP support. Fixes broken '../integrations' link from skills.mdx (was 404 because fumadocs needs an index.mdx for directory routes). - content/docs/ai-tools/{,integrations/}meta.json: add '...' rest token so any future pages added to those dirs get auto-included. - content/docs/ai-tools/index.mdx: tweak MCP description to match new tool surface. - src/routes/index.tsx (homepage hero MCP card): replaces 'npx install-mcp @outblock/cadence-mcp --client $CLIENT' with the 'flow mcp' install command. Drops the now-superfluous client + mode selectors. (NOTE: src/routes/index.tsx homepage hero edit goes in the next commit with the rest of the index.tsx changes — bundled with a11y to keep one diff per file.) DOCS / META ------ - CLAUDE.md: removed 'skills/cadence/SKILL.md' line; removed 'mcp-server/' line. The MCP server now lives at onflow/flow-cli/internal/mcp. - README.md: 'AI Integration' section rewritten — Skills via flow-ai-tools marketplace, MCP via 'flow mcp'. Follow-up issues for the 3 unique tools Hao's mcp-server had that 'flow mcp' doesn't yet (cadence_security_scan, cadence_validate_args, doc-search trio): tracked at #307 for upstream contribution to onflow/flow-cli.
Summary
Adds a
flow mcpcommand that starts an MCP (Model Context Protocol) server over stdio for Cadence smart contract development. This enables AI coding tools like Claude Code, Cursor, and Claude Desktop to interact with the Cadence language server and Flow network directly.Inspired by cadence-lang.org PR #285, but implemented natively in Go with no extra runtime dependencies — if you have
flowinstalled, you have the MCP server.Tools (9 total)
LSP tools (in-process
cadence-tools/languageserver):cadence_check— Check code for syntax/type errorscadence_hover— Get type info at a positioncadence_definition— Find symbol definitionscadence_symbols— List all symbols in codecadence_completion— Get completions at a positionOn-chain query tools:
get_contract_source— Fetch contract manifest from an addressget_contract_code— Fetch contract source codecadence_execute_script— Execute read-only scriptsCode review:
cadence_code_review— Pattern-based review for common issuesUsage
Or in Cursor / Claude Desktop settings:
{ "mcpServers": { "cadence-mcp": { "command": "flow", "args": ["mcp"] } } }Design
server.Serverfromcadence-tools/languageserver, using a single virtual document URI as a scratch bufferflow.jsonif present, otherwise falls back to default mainnet/testnet/emulator endpointsflow.json— useful for ad-hoc queriesTest plan