Add an MCP Server to Your Flutter/Dart Tooling

· 6 min read

âš¡ TL;DR

Integrate a Model Context Protocol (MCP) server into your Flutter/Dart workflow. Step-by-step setup with Claude Code and real-world use cases.

Model Context Protocol (MCP) lets AI tools like Claude Code plug into your local development environment. In this guide, I’ll walk you through adding an MCP server to your Flutter/Dart tooling so Claude Code (or any MCP client) can read your project structure, run tests, and even generate code that matches your team’s patterns.

I’ve been using MCP with Flutter for 3 months now. It’s transformed how I write boilerplate, refactor widgets, and debug platform-specific issues. Here’s how to set it up.

What is MCP?

MCP is an open protocol that standardizes how AI applications connect to data sources and tools. Think of it as a USB-C port for AI: instead of every AI tool building custom integrations, they all plug into MCP servers that expose your data safely.

For Flutter/Dart, an MCP server can:

  • Read your pubspec.yaml to understand dependencies
  • Analyze your lib/ directory structure
  • Run flutter analyze and report issues
  • Generate code that follows your existing patterns
  • Execute dart test and report failures

Prerequisites

  • Flutter SDK installed
  • Claude Code CLI installed (npm install -g @anthropic-ai/claude-code)
  • Basic Dart/Flutter knowledge

Step 1: Create a Dart MCP Server

Create a new Dart package for your MCP server:

Copy
dart create -t package mcp_flutter_server
cd mcp_flutter_server

Add the MCP SDK dependency:

Copy
# pubspec.yaml
dependencies:
  mcp_dart: ^0.3.0
  path: ^1.8.0

Step 2: Implement the MCP Server

Create bin/mcp_server.dart:

Copy
import 'package:mcp_dart/mcp_dart.dart';
import 'dart:io';
import 'dart:convert';
import 'package:path/path.dart' as path;

void main() async {
  final server = McpServer(
    name: 'flutter-mcp-server',
    version: '1.0.0',
  );

  // Tool: List Flutter project structure
  server.addTool(
    name: 'getProjectStructure',
    description: 'Get the structure of a Flutter project',
    inputSchema: ToolInputSchema(
      type: 'object',
      properties: {
        'projectPath': {
          'type': 'string',
          'description': 'Path to the Flutter project',
        },
      },
      required: ['projectPath'],
    ),
    callback: (args, extra) async {
      final projectPath = args['projectPath'] as String;
      final structure = <String, dynamic>{};

      // Read pubspec.yaml
      final pubspecFile = File(path.join(projectPath, 'pubspec.yaml'));
      if (await pubspecFile.exists()) {
        structure['pubspec'] = await pubspecFile.readAsString();
      }

      // List lib directory
      final libDir = Directory(path.join(projectPath, 'lib'));
      if (await libDir.exists()) {
        final files = <String>[];
        await for (final entity in libDir.list(recursive: true)) {
          if (entity is File) {
            files.add(path.relative(entity.path, from: projectPath));
          }
        }
        structure['libFiles'] = files;
      }

      return CallToolResult(
        content: [TextContent(text: jsonEncode(structure))],
      );
    },
  );

  // Tool: Run Flutter analyze
  server.addTool(
    name: 'runFlutterAnalyze',
    description: 'Run flutter analyze on a project',
    inputSchema: ToolInputSchema(
      type: 'object',
      properties: {
        'projectPath': {
          'type': 'string',
          'description': 'Path to the Flutter project',
        },
      },
      required: ['projectPath'],
    ),
    callback: (args, extra) async {
      final projectPath = args['projectPath'] as String;
      final result = await Process.run(
        'flutter',
        ['analyze'],
        workingDirectory: projectPath,
        runInShell: true,
      );

      return CallToolResult(
        content: [
          TextContent(text: 'Exit code: ${result.exitCode}'),
          TextContent(text: result.stdout.toString()),
          if (result.stderr.isNotEmpty) TextContent(text: result.stderr.toString()),
        ],
        isError: result.exitCode != 0,
      );
    },
  );

  // Tool: Run Dart tests
  server.addTool(
    name: 'runDartTest',
    description: 'Run dart test on a specific test file',
    inputSchema: ToolInputSchema(
      type: 'object',
      properties: {
        'projectPath': {'type': 'string'},
        'testFile': {'type': 'string'},
      },
      required: ['projectPath', 'testFile'],
    ),
    callback: (args, extra) async {
      final projectPath = args['projectPath'] as String;
      final testFile = args['testFile'] as String;
      
      final result = await Process.run(
        'dart',
        ['test', testFile],
        workingDirectory: projectPath,
      );

      return CallToolResult(
        content: [
          TextContent(text: result.stdout.toString()),
          if (result.stderr.isNotEmpty) TextContent(text: result.stderr.toString()),
        ],
        isError: result.exitCode != 0,
      );
    },
  );

  // Start the server
  await server.start();
}

Step 3: Configure Claude Code to Use Your MCP Server

Create or edit ~/.claude-code/mcp_config.json:

Copy
{
  "mcpServers": {
    "flutter-dart": {
      "command": "dart",
      "args": ["/absolute/path/to/mcp_flutter_server/bin/mcp_server.dart"],
      "description": "Flutter/Dart MCP server for Claude Code"
    }
  }
}

Step 4: Use the MCP Server in Claude Code

Now when you start Claude Code in a Flutter project, it can use your MCP tools:

Copy
cd /path/to/your/flutter/project
claude-code

Inside Claude Code, ask:

Copy
Use the MCP server to analyze my Flutter project structure and tell me:
1. What dependencies I have
2. What files exist in lib/
3. Any analyzer errors

Claude Code will call getProjectStructure and runFlutterAnalyze through your MCP server and report back.


Step 5: Advanced Usage - Auto-Generate Boilerplate

Add a tool to generate BLoC boilerplate:

Copy
server.addTool(
  name: 'generateBloc',
  description: 'Generate BLoC pattern files for a feature',
  inputSchema: ToolInputSchema(
    type: 'object',
    properties: {
      'featureName': {'type': 'string'},
      'projectPath': {'type': 'string'},
    },
    required: ['featureName', 'projectPath'],
  ),
  callback: (args, extra) async {
    final featureName = args['featureName'] as String;
    final projectPath = args['projectPath'] as String;
    final featurePath = path.join(projectPath, 'lib', 'features', featureName);

    // Create directories
    await Directory(path.join(featurePath, 'bloc')).create(recursive: true);
    await Directory(path.join(featurePath, 'ui')).create(recursive: true);

    // Generate BLoC file
    final blocFile = File(path.join(featurePath, 'bloc', '${featureName}_bloc.dart'));
    await blocFile.writeAsString('''
import 'package:flutter_bloc/flutter_bloc.dart';

abstract class ${featureName}Event {}
abstract class ${featureName}State {}

class ${featureName}Bloc extends Bloc<${featureName}Event, ${featureName}State> {
  ${featureName}Bloc() : super(${featureName}Initial()) {
    on<${featureName}Event>((event, emit) {
      // TODO: implement
    });
  }
}
''');

    return CallToolResult(
      content: [TextContent(text: 'Generated BLoC for $featureName')],
    );
  },
);

Real-World Use Cases

1. Onboarding New Team Members

Copy
Ask Claude: "Explain the BLoC pattern used in the auth feature"

The MCP server reads lib/features/auth/bloc/ and Claude explains the existing implementation.

2. Pre-Commit Hook Validation

Copy
Ask Claude: "Run flutter analyze and fix any issues"

MCP runs analysis, Claude suggests fixes, you review before committing.

3. Documentation Generation

Copy
Ask Claude: "Generate API documentation for the UserRepository class"

MCP reads the file, Claude generates markdown docs.


Security Considerations

  1. File System Access: MCP servers can read/write files. Only run servers from trusted sources.
  2. Command Execution: The runFlutterAnalyze tool executes shell commands. Validate inputs to prevent injection.
  3. Authentication: For web-based MCP servers, add authentication headers.

Troubleshooting

MCP Server Not Starting

Check logs:

Copy
dart /path/to/mcp_server.dart 2>&1

Common issues:

  • Dart not in PATH
  • Missing mcp_dart dependency (run dart pub get)
  • Port conflicts (change port in server config)

Claude Code Not Detecting MCP

Verify config:

Copy
cat ~/.claude-code/mcp_config.json

Ensure the command and args match your Dart executable and server path.


Conclusion

Adding an MCP server to your Flutter/Dart tooling bridges AI assistance with your local dev environment. Instead of copying code snippets into chat windows, Claude Code can now understand your project structure, run analysis, and generate code that fits your existing architecture.

The ecosystem is young (MCP was announced in late 2024), but tooling is maturing fast. For Flutter developers, this is a game-changer for productivity.

Scroll down to load comments...
Related Blogs
Add an MCP Server to Your Flutter/Dart Tooling

Add an MCP Server to Your Flutter/Dart Tooling

Integrate a Model Context Protocol (MCP) server into your Flutter/Dart workflow. Step-by-step setup with Claude Code and real-world use cases.

AI TOOLSMCPFLUTTERDARTDEVELOPER TOOLS

October 06, 2026

Flutter On-Device LLM: Run Gemma & Llama Locally (2026)

Flutter On-Device LLM: Run Gemma & Llama Locally (2026)

Run on-device LLMs in Flutter using gemma_flutter and MediaPipe LLM Inference. No API keys, no internet — real-time AI on Android and iOS.

FLUTTERAI MLON DEVICE LLMGEMMALLAMA

September 24, 2026

Claude Code vs Copilot Agent vs Cursor: 3 Months of Real Work

Claude Code vs Copilot Agent vs Cursor: 3 Months of Real Work

I used Claude Code, GitHub Copilot Agent, and Cursor daily for 3 months on production projects. An honest comparison with costs and workflows.

AI TOOLSDEVELOPER TOOLSCOMPARISONPRODUCTIVITYCLAUDE CODE

August 19, 2026

Antigravity vs Claude Code vs Codex: Honest 2026 Test

Antigravity vs Claude Code vs Codex: Honest 2026 Test

I tested Antigravity vs Claude Code vs Codex on the same REST API task. Claude won on code quality. Codex grew 8x in 5 months. Here's my honest verdict.

AI TOOLSDEVELOPER TOOLSCOMPARISONPRODUCTIVITY

July 04, 2026

Related Tutorials
A Comprehensive Guide to Flutter Buttons: Choosing the Right One for Your App

A Comprehensive Guide to Flutter Buttons: Choosing the Right One for Your App

Complete guide to Flutter Button widgets. Learn how to use ElevatedButton, TextButton, OutlinedButton, IconButton, CupertinoButton, and FAB with examples.

CUPERTINO BUTTONELEVATED BUTTONFLOATING ACTION BUTTONFLUTTERFLUTTER BUTTON

April 17, 2024

Show an Offline Message for No Internet in Flutter

Show an Offline Message for No Internet in Flutter

You have to use the 'Connectivity Flutter Package' to achieve this feature on your App. This package helps to know whether your device is online or offline.

CONNECTIVITY PLUSDEPENDENCIESFLUTTERFLUTTER DEVELOPMENTFLUTTER PACKAGES

April 09, 2024

Mastering TabBar & TabBarView in Flutter: A Complete Guide

Mastering TabBar & TabBarView in Flutter: A Complete Guide

Implement TabBar and TabBarView in Flutter step by step — customize tab indicators, enable scrollable tabs, and change tabs programmatically.

CODINGDEFAULT TAB CONTROLLERFLUTTERLEARN TO CODETAB CONTROLLER

July 26, 2023

File Manipulation in Flutter: Best Practices & Examples

File Manipulation in Flutter: Best Practices & Examples

Master Flutter file manipulation — permission management, directory handling, and practical read-write scenarios to elevate your app's file handling.

CODINGFLUTTERFLUTTER DEVELOPMENTFLUTTER FILE OPERATIONFLUTTER PATH PROVIDER

June 30, 2023

Related Recommended Services
Visual Studio Code for the Web

Visual Studio Code for the Web

Build with Visual Studio Code, anywhere, anytime, in your browser.

IDEVISUAL STUDIOVISUAL STUDIO CODEWEB
Renovate | Automated Dependency Updates

Renovate | Automated Dependency Updates

Renovate Bot keeps source code dependencies up-to-date using automated Pull Requests.

AUTOMATED DEPENDENCY UPDATESBUNDLERCOMPOSERGITHUBGO MODULES
Best XML Formatter and XML Beautifier

Best XML Formatter and XML Beautifier

Online XML Formatter will format xml data, helps to validate, and works as XML Converter. Save and Share XML.

XMLXML BEAUTIFIERXML CONVERTERXML FORMATXML FORMATTER
Kubecost | Kubernetes cost monitoring and management

Kubecost | Kubernetes cost monitoring and management

Kubecost started in early 2019 as an open-source tool to give developers visibility into Kubernetes spend. We maintain a deep commitment to building and supporting dedicated solutions for the open source community.

CLOUDKUBECOSTKUBERNETESOPEN SOURCESELF HOSTED
Related Recommended Stories
How GitHub reduced testing time for iOS apps with new runner features

How GitHub reduced testing time for iOS apps with new runner features

Learn how GitHub used macOS and Apple Silicon runners for GitHub Actions to build, test, and deploy our iOS app faster.

IOSGITHUBTESTINGRUNNER
5 ways to transform your workflow using GitHub Copilot and MCP

5 ways to transform your workflow using GitHub Copilot and MCP

Learn how to streamline your development workflow with five different MCP use cases.

AGENT MODECODING AGENTCOPILOTFIGMAGITHUB
One weird trick for powerful Git aliases

One weird trick for powerful Git aliases

Advanced Git Aliases

ALIASALIAS TEMPLATEATLASSIANBITBUCKETGIT
Awesome Python

Awesome Python

An opinionated list of awesome Python frameworks, libraries, software and resources

AWESOMEAWESOME PYTHONCOLLECTIONSGITHUBPYTHON
Related Recommended Tools
Find out what websites are built with - Wappalyzer

Find out what websites are built with - Wappalyzer

Find out the technology stack of any website. Create lists of websites and contacts by the technologies they use.

ADD ONSANALYTICSAPP STOREAPPLEBOOKING
Sourcetree | Free Git GUI for Mac and Windows

Sourcetree | Free Git GUI for Mac and Windows

A Git GUI that offers a visual representation of your repositories. Sourcetree is a free Git client for Windows and Mac.

GITGITHUBGITLABATLASSIANBITBUCKET
Related Recommended Videos