BoilerplateHub

MCP Servers for Flutter

Flutter's API has been stable for years but its widget catalogue has churned, and Dart's move to sound null safety split training data into pre and post eras that do not compile together. An agent needs the Flutter and Dart versions, the state management approach the project actually uses, and whether Material 3 is enabled. Layout errors here are constraint errors rather than style errors, so an agent that does not reason about bounded and unbounded constraints will keep producing overflow warnings it cannot explain.

Wiring MCP into a Flutter project

  • Favour git and GitHub servers here, since most hard Flutter questions are about plugin platform support rather than your own code.
  • Scope the filesystem server to lib/ and test/ so build/ and the ephemeral platform directories stay out of context.
  • Commit .mcp.json at the repo root so every contributor's agent reads the same pubspec and lint configuration.

Servers worth adding

Filesystem MCP server

Scoped read and write access to the project directory.

Reading pubspec.yaml and the analysis options file is how the agent learns the SDK constraint and lint rules it must satisfy.

Git MCP server

History, diffs, and blame.

Diffs show which state management pattern the team has been converging on, which the current file layout alone may not reveal.

GitHub MCP server

Reads issues, releases, and pull requests.

Plugin support for a given platform, especially web and desktop, is usually documented only in the plugin's issue tracker.

Sentry MCP server

Pulls crash reports and stack traces.

Dart exceptions from disposed widgets and async gaps appear on real devices long after the frame that caused them.

Skills, MCP and plugins compared →

Rule these out for Flutter

These are the failures that repeat across sessions, so each one belongs in .mcp.json.

Falling back to setState in a project with real state management

A codebase using Riverpod, Bloc, or Provider will still get StatefulWidget plus setState from an agent, because that is the simplest working answer and the surrounding files may not show the pattern. The result is state that no other widget can observe and that bypasses your testing setup. Add to your rules file: 'This project uses [your solution]. New feature state goes through it. setState is acceptable only for purely local widget concerns such as an animation flag or a text field focus state.'

Emitting removed widgets and pre-null-safety Dart

RaisedButton, FlatButton, OutlineButton, the new keyword, and nullable-by-default parameter handling all still appear in agent output, and none of them compile against a current SDK. The failure is at least loud, but it costs a full round trip every time. State it: 'Flutter 3.x with sound null safety and Material 3. Use ElevatedButton, TextButton, and OutlinedButton. Never emit the new keyword or code that assumes implicit nullability.'

Using BuildContext after an await

Agents write an async handler that awaits a network call and then calls Navigator.of(context) or shows a SnackBar, without checking that the widget is still mounted. If the user navigated away during the await, this throws or targets a disposed element. Add: 'After any await in a widget or State method, check mounted before touching BuildContext. The use_build_context_synchronously lint must stay enabled and its warnings are errors.'

Nesting scrollables without resolving constraints

Agents put a ListView inside a Column, or a Column inside a Column, and hit an unbounded height constraint that renders as a yellow overflow stripe or a hard exception. They then add shrinkWrap: true as a blanket fix, which works visually and destroys scroll performance on long lists. Write: 'Resolve unbounded constraints with Expanded or Flexible, or use CustomScrollView with slivers. shrinkWrap is only for genuinely short, non-scrolling lists and its use needs a comment.'

Leaving controllers and subscriptions undisposed

AnimationController, TextEditingController, ScrollController, and StreamSubscription all get created in initState by agents and then never disposed, which leaks and produces setState-after-dispose errors that surface far from the cause. Add: 'Every controller or subscription created in initState is disposed in dispose. If a widget has initState it must have a matching dispose unless there is nothing to release.'

Omitting const constructors throughout the tree

Agents build widget trees with no const anywhere, so subtrees that never change are rebuilt on every parent rebuild. Nothing breaks, the app just does more work per frame than it needs to, and it compounds in long lists. Write: 'flutter_lints is enabled with prefer_const_constructors and prefer_const_literals_to_create_immutables. Mark every widget const where the analyzer allows it, and run dart analyze before finishing.'

Same framework, other agents