Flutter Analysis Engine (MCP)
The Flutter Analysis Engine (MCP) server provides local-first static analysis for Flutter/Dart projects, using an indexed knowledge base of official repositories without external API calls or LLMs.
Repository Management: Clone and update official Flutter/Dart repositories (
update_repositories), check their status (repository_status), and build/refresh the SQLite index (reindex).Search & Discovery:
Search source code across repos (
search_source).Find widgets by name (
find_widget), explain their declaration and inheritance (explain_widget), and trace hierarchy (trace_widget).Search indexed documentation by kind (
search_docs), locate examples (find_examples), tests (find_tests), best practices (find_best_practice), and determine intended behavior from tests, samples, and migrations (find_intended_behavior).
Project Analysis: Run a comprehensive project review (
review_project) that returns an executive health summary and a session ID for cached follow-up analyses. Then analyze specific aspects: architecture, code quality, state management, complexity, documentation coverage, testing coverage, dependencies, performance, and accessibility. Drill down into findings with mentor-style explanations (explain_finding) and detailed evidence (explore_finding).Diagnostics: Verify the environment with a self-check (
check_environment) for Dart SDK, Node.js, SQLite, and repository readiness.
Provides a local-first static analysis engine for Dart, using the Dart SDK and package:analyzer for full-fidelity AST parsing, along with tools to search Dart SDK source, search official documentation, and analyze Dart project code quality.
Provides a local-first static analysis engine for Flutter projects, including tools for searching Flutter framework source, locating/tracing widgets, reviewing project architecture and code quality, analyzing state management, and finding intended widget behavior using official Flutter/Dart knowledge cloned via git.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Flutter Analysis Engine (MCP)review my Flutter project and summarize the top risks"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Flutter Analysis Engine (MCP)
An MCP server that gives your AI coding agent (Cursor, Claude Code, or any other MCP client) deep, structured knowledge of Flutter/Dart. It does two things: runs 9 static analyzers over your own project (architecture, code quality, performance, accessibility, and more — facts and scored findings, not vibes) and answers "how is X actually meant to be used?" by searching official Flutter/Dart source, tests, samples, and docs cloned locally via git. There's no LLM inside the server and no GitHub API — everything is deterministic analysis grounded in real source.
What it checks — all 9 analyzers
Analyzer | Checks |
Code quality | God-class candidates (multi-signal, not just size), missing |
Architecture | Detected architecture style (clean/feature-first/layered/MVVM/...), layer-violation imports (presentation→data, domain→Flutter), circular import cycles, feature isolation |
State management | Which state approach(es) are in use, heavy |
Complexity | File-size distribution, estimated high-complexity files, deep nesting, high import counts, oversized widget files |
Dependencies | Layer violations, circular import cycles, high-fan-out files, deprecated packages, whether dependency versions are pinned |
Performance | Oversized |
Documentation | Widget/class doc-comment coverage, README/CHANGELOG/ |
Testing | Test-to-lib ratio, widget/golden/integration test presence, features with no tests at all |
Accessibility |
|
Every finding carries a confidence score and a source (dart_analyzer | heuristic | filesystem | pubspec | import_graph) — see Known limitations for what that means in practice.
Related MCP server: Atlas
Install
Quick try (npx, no local checkout)
Cursor — add to mcp.json:
{
"mcpServers": {
"flutter-knowledge": {
"command": "npx",
"args": ["-y", "flutter-knowledge-mcp"]
}
}
}Claude Code:
claude mcp add --scope user flutter-knowledge -- npx -y flutter-knowledge-mcp@latestThis is the fastest way to try it. For real use, read the note below first — it affects where the (multi-GB) Flutter/Dart knowledge base gets stored.
Recommended for real use: a stable config location
By default this server looks for config.json next to its own install location and clones the knowledge-base repos relative to that. Under a bare npx invocation that location isn't guaranteed to persist between runs (npx's cache can be cleared), which means repos you already cloned could vanish. Point it at a stable, user-owned directory instead:
mkdir -p ~/.flutter-knowledge-mcp
cat > ~/.flutter-knowledge-mcp/config.json <<'EOF'
{
"repositoriesRoot": "~/.flutter-knowledge-mcp/repos",
"indexPath": "~/.flutter-knowledge-mcp/data/knowledge.sqlite",
"indexOnUpdate": true
}
EOFThen set FLUTTER_KNOWLEDGE_CONFIG in your MCP client config, e.g. for Cursor:
{
"mcpServers": {
"flutter-knowledge": {
"command": "npx",
"args": ["-y", "flutter-knowledge-mcp"],
"env": {
"FLUTTER_KNOWLEDGE_CONFIG": "/Users/you/.flutter-knowledge-mcp/config.json"
}
}
}
}(~ isn't expanded inside config.json values or MCP client env blocks — use an absolute path.) dartSdkPath is an optional additional key in the same file — see Dart detection below.
From source (contributing, or before this package is published)
git clone https://github.com/Saad0149/Flutter_MCP_Knowledge.git
cd Flutter_MCP_Knowledge
npm install
npm run buildnpm install already ran dart pub get inside parser/ automatically (a postinstall script — see Known limitations) if Dart was found on your machine at that point. If it wasn't (or there was no network at the time), run it manually once Dart/network are available:
cd parser && dart pub get && cd ..Then point your MCP client at the built entry point directly:
{
"mcpServers": {
"flutter-knowledge": {
"command": "node",
"args": ["/ABSOLUTE/PATH/TO/Flutter_MCP_Knowledge/dist/index.js"]
}
}
}Requirements
Node.js 20+
gitonPATH(used only to clone/pull the official Flutter/Dart repos below — no GitHub API)Recommended: Dart SDK 3+ (full-fidelity AST via
parser/; without it, project analysis falls back to heuristics with reduced confidence — see Known limitations)
Knowledge base
On first use, flutter/flutter, flutter/packages, flutter/engine, dart-lang/sdk, dart-lang/site-www, flutter/samples, and flutter/website are shallow-cloned locally and indexed (CHANGELOGs, migration guides, and widget tests included). This is several GB — see the stable-config note above.
Tools
Diagnostics — start here
Tool | What it does |
| One-call self-diagnostic: is Dart found (and how), what's the Node version, did the SQLite native binding load, are the knowledge-base repos ready. Call this any time something "should just work" doesn't. |
Repository management
Tool | What it does |
| Starts background clones/pulls for all official repos; returns immediately with per-repo status |
| Existence, branch, commit, last pull time, path — per repo |
| Builds/refreshes the local SQLite index from cloned repos |
Search & widget knowledge
Tool | What it does |
| Search filenames/contents across cloned official repos |
| Locate a widget by name (index-first, filesystem fallback) |
| Declaration, inheritance, and docs for a widget from the index |
| Inheritance tree and related symbols |
| Search indexed docs, optionally filtered by kind (changelog/migration/guide/cookbook) |
| Examples from official samples and |
| Tests for a symbol, widget tests preferred |
| Ranked migration/cookbook/changelog/guide hits for a topic |
| Joins widget tests + samples + migrations/docs + source for "how is this meant to be used?" |
First-use note: if the knowledge base hasn't been cloned yet, find_intended_behavior (and the other knowledge tools above) auto-trigger a background clone and return { status: "building", suggestedAction } immediately instead of blocking for minutes or silently returning nothing. This is expected the first time you use them — retry shortly, or call repository_status to watch progress. Once the index is partially built, they serve what's available and note which sources are still missing.
Project analysis (session-aware)
Tool | What it does |
| Analyze your project once → executive health summary + |
| One slim, scored view per analyzer, from a |
| Mentor-style explanation for one finding |
| Full evidence for one finding (files, symbols, refactor suggestions) |
Typical flow: review_project({ path }) → grab sessionId → analyze_*({ sessionId }) for the categories you care about → explore_finding({ sessionId, findingCode }) to drill into a specific one. Session reports are cached under data/analysis-sessions/, so steps after the first don't rescan.
Known limitations
Heuristic-fallback mode. Full-fidelity analysis needs the Dart SDK (
dart run package:analyzerunder the hood) and that helper's own resolved dependencies (apostinstallstep handles this automatically when it can — see Analyzer package wasn't resolvable if it couldn't). Without either, symbol extraction falls back to regex-based heuristics with reduced confidence — findings still show aconfidence/sourcefield so you can tell which mode produced them, andreview_projectsurfaces afidelityNoticewhen this is happening. Callcheck_environmentany time to see exactly why (Dart not found vs. found-but-helper-failing, and specifically whether it's an unresolved-dependency issue) and how to fix it.Evidence may contain untrusted content. This server is designed to scan arbitrary third-party Flutter/Dart projects.
evidence/snippetfields in tool responses are raw excerpts from whatever the scanned project (or an indexed repo) actually contains — structurally separate from this server's own narrative fields, but not vetted or sanitized content. See[SECURITY_DECISIONS.md](./SECURITY_DECISIONS.md)(§2) for why this is a deliberate tradeoff, not an oversight.officialReferencematching is coarse. Findings link to official docs/source via keyword search (SQL substring matching against indexed doc chunks and titles), not semantic matching — occasionally a reference will be tangentially related rather than exactly on point. Treat it as supporting evidence, not the primary answer.Local-only knowledge, git-cloned. No GitHub API, no network calls beyond
git clone/git pullagainst the repos listed above. If those repos are unreachable, the affected knowledge tools degrade gracefully (see the auto-bootstrap note above) rather than failing outright.
Architecture
MCP client (Cursor, Claude Code, ...)
└── MCP (stdio) — thin tools/
└── analysis/
├── ast/ AstAdapter (Dart analyzer preferred, heuristic fallback)
├── engines/ the 9 analyzers listed above
├── insight/ explanation + recommendation + health scoring + report builder
├── session/ AnalysisSessionStore + slim summary views
├── metrics/ MetricsEngine
├── rules/ RuleEngine plugin registry
├── project-scanner.ts
└── official-refs.ts
├── repository/ git clone / pull / status
├── indexer/ incremental hashing + path classification
├── parser/ TS heuristics + Dart analyzer client
├── store/ SQLite knowledge store
├── search/ indexed search → filesystem fallback
├── config/ JSON + zod
└── server/ DI (tsyringe) + McpServerDevelopment
npm run test
npm run typecheck
npm run lint
npm run devSee [CONTRIBUTING.md](./CONTRIBUTING.md) for what to include in a bug report or PR.
Error model
Tools return structured JSON failures (never raw exceptions): RepositoryNotFound, RepositoryMissing, GitError, SearchFailed, InvalidArguments, ConfigError, IndexError, AnalyzerUnavailable, ProjectNotFound, NativeBindingError, InternalError.
Logging
Structured JSON on stderr (info / warning / error). stdout is MCP-protocol-only.
Troubleshooting
Run check_environment first — it's a single tool call that reports pass/fail for the two things known to silently degrade this server, plus repo readiness. No need to read logs or guess from an unexplained confidence percentage.
It reports:
Dart: whether it was found, via which method (
config_override/known_location/path_lookup/not_found), and the resolved pathNode: the exact Node version, platform, and arch this server process is running under
SQLite: whether the
better-sqlite3native binding loaded and is responding to a live queryRepositories: how many of the knowledge-base repos are cloned, and which (if any) are missing
Dart not found (analysis running in heuristic mode)
review_project will show astSource: "heuristic" and a prominent fidelityNotice. check_environment will show dart.found: false (or found: true with versionCheckPassed: false, meaning a binary exists at that path but couldn't run — usually a permissions or architecture mismatch).
This server does not rely solely on inherited PATH — it checks, in order: an explicit dartSdkPath in config.json, then common install locations (/usr/local/bin/dart, /opt/homebrew/bin/dart, ~/Documents/flutter/bin/dart, ~/flutter/bin/dart, ~/fvm/versions/*/bin/dart, Windows equivalents), then PATH. If none of those find it:
Confirm Dart actually works in a normal terminal:
dart --version.Find its real path:
which dart(macOS/Linux) orwhere dart(Windows).Set that exact path as
dartSdkPathinconfig.jsonand restart the server — this bypasses PATH entirely, which matters because MCP clients (Cursor, Claude Code, etc.) don't reliably forward a shell-equivalent PATH to spawned servers, and even explicitPATH=entries in a client's env config are often passed through literally (no~or$PATHexpansion), so a config value likePATH=~/flutter/bin:$PATHsilently resolves to nothing useful.
Analyzer package wasn't resolvable (Dart found and working, but heuristic mode anyway)
Distinct from "Dart not found" above: Dart itself is found and runs fine, but the analyzer helper (parser/) fails because its own dependency — the analyzer pub package — was never resolved. check_environment shows this specifically as dart.helperFailureReason: "analyzer_package_unresolved" (as opposed to "other" for a different helper failure), and the dart summary line in check_environment's response spells out the same thing.
Why this happens: parser/ is a small Dart package with its own dependencies, resolved via dart pub get, producing a pubspec.lock and .dart_tool/. This package ships a pre-resolved pubspec.lock and runs dart pub get automatically in a postinstall script right after npm install — but that step only runs if Dart was already found at install time, and only succeeds if there was network access at that moment (the very first resolve needs to fetch analyzer and its dependencies, even with a lockfile pinning exact versions). If either wasn't true — Dart installed after this package, or no network during npm install — the helper's dependencies are simply missing, and every analysis silently falls back to heuristic mode until this is fixed.
Fix — run dart pub get in the installed package's parser/ directory once Dart and network are both available:
# find the install location, e.g. from your MCP client's server command/args,
# or (for a global/local npm install) `npm root -g` / `npm root` + this package's name
cd <path-to-installed-flutter-knowledge-mcp>/parser
dart pub getThen call check_environment again — no reinstall needed. This is a one-time step; once parser/.dart_tool/ exists, it isn't repeated.
SQLite native binding failed
check_environment will show sqlite.ok: false with the underlying error. This almost always means better-sqlite3's native binary doesn't match the Node version/OS/architecture actually running the server (e.g. installed under one Node version, run under another; or copied between machines).
Fix: run npm rebuild better-sqlite3 (or delete node_modules and npm install again) in the server's directory, then restart it.
The server checks for this at startup, before opening the database, and again before touching it — if it fails, the server still starts (so check_environment and every other tool that doesn't need the local index keep working) rather than refusing to start with no explanation. Tools that do need the index (search/find/analyze tools) will fail with this same clear error until it's fixed.
The server crashed / disconnected on startup with no error message at all
This is the more severe version of the same problem: a native module ABI mismatch can, in rare cases, crash the whole Node process before any of the handling above gets a chance to run at all — no structured error, no log line, the MCP client just shows the server as disconnected. If you hit this:
It's still almost certainly the same
better-sqlite3native-binding mismatch described above (this is the one native dependency in this server that can fail this way) — runnpm rebuild better-sqlite3in the server's directory and restart. This fixes the vast majority of cases, including this one.If it keeps happening: check the server's stderr/logs directly (where this server's structured JSON logs go — see Logging) for a
NativeBindingErrorline logged right before the crash; it'll usually still get written even in a hard-crash scenario, since logging happens before the risky database open.As a last resort, delete
node_modulesentirely and runnpm installfresh — this guarantees the native binary was actually built/fetched for the Node version currently running, rather than trusting an existing (possibly stale)node_modules.
Why this can't be fully prevented from JS: normal error handling (try/catch) only works for failures the JS engine gets a chance to observe. A genuine native ABI mismatch can crash at the OS/process level before that happens. This server narrows that risk as much as is realistically possible — it checks that a native binary actually exists for the current platform/architecture before ever attempting to load it, and wraps every load/open attempt it does make in error handling with a clear message — but it can't give an absolute guarantee against every possible native-code failure. What it does guarantee: the common cases (wrong Node version, wrong OS, wrong architecture, missing prebuilt binary) are caught and explained, not silently crashed.
Repositories missing
check_environment lists them by name under repositories.missing. Call update_repositories, poll repository_status until cloneInProgress is false, then reindex.
Security
This server scans arbitrary, potentially-untrusted third-party Flutter/Dart projects by design — see [SECURITY_DECISIONS.md](./SECURITY_DECISIONS.md) for the specific tradeoffs that implies and why they're intentional. To report a vulnerability, see [SECURITY.md](./SECURITY.md) — please don't file it as a public issue.
For non-security bugs, see [CONTRIBUTING.md](./CONTRIBUTING.md).
Roadmap (later)
Monorepo extract (
packages/flutter-analysis-core, CLI, web)Retire heuristic AST fallback when Dart Analyzer coverage is always available
Vector embeddings / semantic search
Optional third-party ecosystems (e.g. FlutterFire)
Available Tools
24 toolsanalyze_accessibilityA
Accessibility view from a review_project session (or path). Returns semantics widget counts, tooltip usage, and missing semantic labels. Prefer sessionId to avoid rescanning.
Inputs: path, limit, sessionId.
analyze_architectureB
Architecture view from a review_project session (or path). Prefer sessionId to avoid rescanning.
Inputs: path, limit, sessionId.
analyze_code_qualityB
Code quality view from a review_project session (or path). Slim findings + score — not a full rescan when sessionId is set.
Inputs: path, limit, sessionId.
analyze_complexityB
Complexity view from a review_project session (or path). Returns file-size distribution, estimated high-complexity files, and slim findings. Prefer sessionId to avoid rescanning.
Inputs: path, limit, sessionId.
analyze_dependenciesA
Dependency health view from a review_project session (or path). Returns layer violations, circular cycles, and slim findings. Use detail=full to include full violation arrays. Prefer sessionId to avoid rescanning.
Inputs: path, limit, detail, sessionId.
analyze_documentationA
Documentation coverage view from a review_project session (or path). Returns widget/class doc ratios, README presence, and findings. Prefer sessionId to avoid rescanning.
Inputs: path, limit, sessionId.
analyze_performanceB
Performance view from a review_project session (or path). Returns build method sizes, setState issues, and animation controller leaks. Prefer sessionId to avoid rescanning.
Inputs: path, limit, sessionId.
analyze_state_managementC
State management view from a review_project session (or path). Prefer sessionId to avoid rescanning.
Inputs: path, limit, sessionId.
analyze_testingA
Testing coverage view from a review_project session (or path). Returns test/lib ratios, test type counts, and untested features. Prefer sessionId to avoid rescanning.
Inputs: path, limit, sessionId.
explain_findingA
Mentor-style explanation for one finding. Prefer sessionId from review_project.
Inputs: findingCode (required), path, findingId, sessionId.
explain_widgetB
Explain a widget from the local index (declaration, inheritance, documentation).
Inputs: name (required), repository.
explore_findingC
Evidence for one finding (files, symbols, refactor). Prefer sessionId from review_project.
Inputs: findingCode (required), path, limit, findingId, +1 more.
find_best_practiceC
Rank website, samples, and docs hits for a best-practice topic.
Inputs: topic (required), limit.
find_examplesC
Find examples related to a topic from samples and example/ directories.
Inputs: topic (required), limit.
find_intended_behaviorC
How is this meant to be used? Joins widget tests, samples, migrations/cookbook/guides, and source.
Inputs: topic (required), limit.
find_testsC
Find tests related to a symbol; widget tests are preferred when available.
Inputs: symbol (required), limit, repository, widgetTestsOnly.
find_widgetB
Locate a Flutter widget by name using the SQLite index when available, else filesystem search.
Inputs: name (required), limit, repository.
reindexC
Build or refresh the local SQLite knowledge index for one or all repositories.
Inputs: force, repository.
repository_statusA
Report existence, branch, commit, last pull time, and path for supported repositories.
Inputs: repository.
review_projectB
Analyze once: executive health summary + sessionId. Pass sessionId to follow-up tools (no rescan). Use detail=full only when you need the entire report.
Inputs: path (required), limit, detail.
search_docsB
Search indexed documentation (guides, cookbook, migrations, CHANGELOGs).
Inputs: query (required), limit, docKind, repository.
search_sourceB
Search filenames and file contents across local official Flutter/Dart repositories (index-aware).
Inputs: query (required), limit, repository.
trace_widgetC
Trace widget/class inheritance and related symbols from the index.
Inputs: symbol (required), depth, repository.
update_repositoriesB
Clone missing official Flutter/Dart repositories, pull latest changes, and optionally reindex.
Inputs: no named parameters.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
TDQS
Scored across 24 tools
Most tools are clearly distinct by purpose: find_* tools target different content types (examples, tests, widgets, best practices, intended behavior) and analyze_* tools target distinct analysis dimensions (architecture, complexity, documentation, testing, dependencies, performance, accessibility). There is some overlap between find_examples and find_best_practice, and between explain_widget and trace_widget, but descriptions help delineate. The find_widget/explain_widget/trace_widget trio has somewhat blurry boundaries.
The naming follows a strong verb_noun snake_case pattern throughout (find_*, analyze_*, explain_*, explore_*, search_*, update_*, reindex, trace_widget, repository_status). This is highly consistent. Minor deviations: review_project and repository_status are noun_verb/noun style rather than verb_noun, and analyze_* uses adjectival suffixes (analyze_code_quality) inconsistently across the set.
24 tools is near the heavy end of the appropriate range for a Flutter analysis engine server, which legitimately spans project review, knowledge indexing, code search, and widget explanations. At 24 it's bordering on 'too many' but the scope is broad enough to justify it. The large number of near-parallel analyze_* tools inflates the count.
The server covers a comprehensive project analysis workflow: review_project initiates, then eight analyze_* dimensions cover architecture, complexity, docs, testing, dependencies, performance, accessibility, and state management, with follow-up exploration via explain_finding and explore_finding. Knowledge management (find/reindex/repository) is covered. Minor gaps include a missing analyze_security dimension and no tool for viewing project configuration.
Maintenance
Related MCP Connectors
Repository knowledge graph MCP server for codebase understanding and debugging.
Lean 4 MCP server: compile, prove theorems, and formalize math with Mathlib.
MCP server for hex.pm and hexdocs.pm: search, inspect, compare, and audit Elixir packages
An MCP server for search and retrieval over a local LanceDB database
Related MCP Servers
- AlicenseCqualityDmaintenanceA distributable Model Context Protocol (MCP) server that exposes Dart SDK commands for AI-powered development. This server bridges the gap between AI coding assistants and Dart/Flutter development workflows by implementing the Model Context Protocol (MCP).1018 npm6MIT
- AlicenseNot gradedqualityCmaintenanceLocal-first MCP server for querying multi-repo engineering documentation artifacts from a SQLite corpus.7 npmAGPL 3.0
- AlicenseNot gradedqualityCmaintenanceLocal-first MCP server that provides project context, verification gates, and structured tools for coding agents to discover knowledge, run diagnostics, and execute allowlisted commands within a repository.41 npmMIT
- AlicenseNot gradedqualityBmaintenanceLocal-first MCP server that scans a repository once and answers architecture questions from an evidence-backed graph, enabling dependency analysis, impact analysis, and codebase exploration without re-reading the source tree.7MIT