DEV Community

xbill for Google Developer Experts

Posted on • Originally published at Medium on

FireStore MCP Development with Dart and Gemini CLI

Leveraging Gemini CLI and the underlying Gemini LLM to build Model Context Protocol (MCP) AI applications using Flutter/Dart with a local development environment.

Why not just use Python?

Python has traditionally been the main coding language for ML and AI tools. One of the strengths of the MCP protocol is that the actual implementation details are independent of the development language. The reality is that not every project is coded in Python- and MCP allows you to use the latest AI approaches with other coding languages.

Flutter/Dart? For AI? Does that even work?

The goal of this article is to provide a minimal viable basic working MCP stdio server in Dart that can be run locally without any unneeded extra code or extensions.

The key MCP Dart package is here:

mcp_dart | Dart package

What Is Flutter / Dart?

Flutter is Google’s open-source UI toolkit and framework used for building natively compiled, multi-platform applications (mobile, web, desktop, and embedded systems) from a single codebase. Dart is the programming language , also developed by Google, in which Flutter apps are written.

The full details of the language can be found here:

Intro to Dart

Installing Dart

Step by Step instructions vary by platform — a good starting point is here:

Install Flutter manually

For a Debian style Linux Distro these steps are similar to:

sudo apt-get update -y && sudo apt-get upgrade -y
sudo apt-get install -y curl git unzip xz-utils zip libglu1-mesa
Enter fullscreen mode Exit fullscreen mode

The download and extract the latest Flutter Bundle and extract to a common directory like ~/develop :

tar -xf <sdk_zip_path> -C <destination_directory_path>
Enter fullscreen mode Exit fullscreen mode

As of writing the current version is:

tar -xf /mnt/chromeos/MyFiles/Downloads/flutter_linux_3.38.5-stable.tar.xz -C ~/develop/
Enter fullscreen mode Exit fullscreen mode

You can validate the working tools with the — version command:

xbill@penguin:~$ dart --version
Dart SDK version: 3.10.4 (stable) (Tue Dec 9 00:01:55 2025 -0800) on "linux_x64"
xbill@penguin:~$ flutter --version
Flutter 3.38.5 • channel stable • https://github.com/flutter/flutter.git
Framework • revision f6ff1529fd (3 weeks ago) • 2025-12-11 11:50:07 -0500
Engine • hash c108a94d7a8273e112339e6c6833daa06e723a54 (revision 1527ae0ec5) (23 days ago) • 2025-12-11 15:04:31.000Z
Tools • Dart 3.10.4 • DevTools 2.51.1
Enter fullscreen mode Exit fullscreen mode

What is FireStore?

Google FireStore, also known as Cloud FireStore is a part of the Google Firebase application development platform. It is fundamentally a cloud-hosted NoSQL database for storing and syncing data. Firestore can be directly accessed by mobile and web applications through native SDKs.

Firestore | Firebase

Gemini CLI

If not pre-installed you can download the Gemini CLI to interact with the source files and provide real-time assistance:

npm install -g @google/gemini-cli
Enter fullscreen mode Exit fullscreen mode

Testing the Gemini CLI Environment

Once you have all the tools and the correct Node.js version in place- you can test the startup of Gemini CLI. You will need to authenticate with a Key or your Google Account:

gemini
Enter fullscreen mode Exit fullscreen mode

Dart Gemini CLI Extension

To simplify working with Dart/Flutter with Gemini CLI- a Gemini CLI extension is available:

Flutter extension for Gemini CLI

The installation will look similar to this:

xbill@penguin:~/gemini-cli-codeassist/mcp-stdio-flutter$ gemini extensions install https://github.com/gemini-cli-extensions/flutter.git --auto-update
Installing extension "flutter".
**The extension you are about to install may have been created by a third-party developer and sourced from a public repository. Google does not vet, endorse, or guarantee the functionality or security of extensions. Please carefully inspect any extension and its source code before installing to understand the permissions it requires and the actions it may perform.**
This extension will run the following MCP servers:
  * dart (local): dart mcp-server
This extension will append info to your gemini.md context using flutter.md
Do you want to continue? [Y/n]: 
Extension "flutter" installed successfully and enabled.
xbill@penguin:~/gemini-cli-codeassist/mcp-stdio-flutter$
Enter fullscreen mode Exit fullscreen mode

Node Version Management

Gemini CLI needs a consistent, up to date version of Node. The nvm command can be used to get a standard Node environment:

GitHub - nvm-sh/nvm: Node Version Manager - POSIX-compliant bash script to manage multiple active node.js versions

Where do I start?

The strategy for starting MCP development is a incremental step by step approach.

First, the basic development environment is setup with the required system variables, and a working Gemini CLI configuration.

Then, a minimal Hello World Style Dart MCP Server is built with stdio transport. This server is validated with Gemini CLI in the local environment.

The MCP server is backed by a FireStore database that provides basic product inventory.

This setup validates the connection from Gemini CLI to the local process via MCP. The MCP client (Gemini CLI) and the Dart MCP server both run in the same local environment.

Next- the basic MCP server is extended with Gemini CLI to add several new tools in standard Dart code.

Setup the Basic Environment

At this point you should have a working Dart/Flutter environment and a working Gemini CLI installation. The next step is to clone the GitHub samples repository with support scripts:

cd ~
git clone https://github.com/xbill9/gemini-cli-codeassist
Enter fullscreen mode Exit fullscreen mode

Then run init.sh from the cloned directory.

The script will attempt to determine your shell environment and set the correct variables:

cd gemini-cli-codeassist
source init.sh
Enter fullscreen mode Exit fullscreen mode

If your session times out or you need to re-authenticate- you can run the set_env.sh script to reset your environment variables:

cd gemini-cli-codeassist
source set_env.sh
Enter fullscreen mode Exit fullscreen mode

Variables like PROJECT_ID need to be setup for use in the various build scripts- so the set_env script can be used to reset the environment if you time-out.

Hello World with STDIO Transport

One of the key features that the standard MCP libraries provide is abstracting various transport methods.

The high level MCP tool implementation is the same no matter what low level transport channel/method that the MCP Client uses to connect to a MCP Server.

The simplest transport that the SDK supports is the stdio (stdio/stdout) transport — which connects a locally running process. Both the MCP client and MCP Server must be running in the same environment.

The connection over stdio will look similar to this:

final transport = StdioServerTransport();
  await server.connect(transport);
Enter fullscreen mode Exit fullscreen mode

Running the Dart Code

First- switch the directory with the Dart MCP sample code:

cd ~/gemini-cli-codeassist/firestore-stdio-flutter
Enter fullscreen mode Exit fullscreen mode

Current Version of Dart dependencies:

The current version of pubspec.yaml describes the project:

name: firestore_stdio_flutter
description: A Dart-based Model Context Protocol (MCP) server implementation using stdio with Firebase.
version: 1.0.1
repository: https://github.com/xbill9/gemini-cli-codeassist/firebase_stdio_flutter

environment:
  sdk: ^3.10.4

# Add regular dependencies here.
dependencies:
  path: ^1.9.0
  mcp_dart: ^1.2.0
  firedart: ^0.9.8
  dotenv: ^4.2.0

dev_dependencies:
  lints: ^6.0.0
  test: ^1.25.6
Enter fullscreen mode Exit fullscreen mode

Installing and Running the Dart Code

Run the build make target on the local system:

xbill@penguin:~/gemini-cli-codeassist/firestore-stdio-flutter$ make build
dart pub get && dart compile exe bin/firestore_stdio_flutter.dart -o bin/firestore_stdio_flutter
Resolving dependencies... 
Downloading packages... 
  archive 3.6.1 (4.0.7 available)
  googleapis_auth 1.6.0 (2.0.0 available)
  grpc 3.2.4 (5.1.0 available)
  protobuf 3.1.0 (6.0.0 available)
Got dependencies!
4 packages have newer versions incompatible with dependency constraints.
Try `dart pub outdated` for more information.
Generated: /home/xbill/gemini-cli-codeassist/firestore-stdio-flutter/bin/firestore_stdio_flutter
Enter fullscreen mode Exit fullscreen mode

To test the Dart Code:

xbill@penguin:~/gemini-cli-codeassist/firestore-stdio-flutter$ make test
dart test
00:00 +2: All tests passed!     
Enter fullscreen mode Exit fullscreen mode

To lint the Dart Code:

xbill@penguin:~/gemini-cli-codeassist/firestore-stdio-flutter$ make lint
dart analyze
Analyzing firestore-stdio-flutter... 0.2s
No issues found!
Enter fullscreen mode Exit fullscreen mode

Gemini CLI settings.json

The default Gemini CLI settings.json has an entry for the source:

{
  "mcpServers": {
    "firestore-stdio-flutter": {
      "command": "/home/xbill/gemini-cli-codeassist/firestore-stdio-flutter/bin/firestore_stdio_flutter",
      "args": []
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Validation with Gemini CLI

Finally- Gemini CLI is restarted and the MCP connection over stdio to the Dart Code is validated, The full Gemini CLI Session will start:

gemini

> /mcp list

Configured MCP servers:

🟢 firestore-stdio-flutter - Ready (6 tools)
  Tools:
  - check_db
  - get_product_by_id
  - get_products
  - get_root
  - reset
  - seed

> check_db

✦ I will check if the inventory database is running.
╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ check_db (firestore-stdio-flutter MCP Server) {} │
│ │
│ Database running: true │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ The database is running. What would you like to do next?

> reset

✦ I will clear all products from the inventory database.
╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ reset (firestore-stdio-flutter MCP Server) {} │
│ │
│ Database reset successfully. │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ The database has been reset successfully.

> seed

✦ I will seed the inventory database with products.
╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ seed (firestore-stdio-flutter MCP Server) {} │
│ │
│ Database seeded successfully. │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ The database has been seeded successfully.

> get_products

✦ I will retrieve the list of all products from the inventory database.
✦ I have retrieved the list of products. There are several items available, including Sunflower Seeds, Wasabi Party Mix, and
  White Chocolate Caramel Corn. Would you like to see more details on any specific product?

                                                                   │
> Coffee

✦ I will retrieve the details for the Coffee Beans product.
╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ get_product_by_id (firestore-stdio-flutter MCP Server) {"id":"tJ7Br576FxaCoB6Iye55"} │
│ │
│ {"id":"tJ7Br576FxaCoB6Iye55","name":"Coffee │
│ Beans","price":6.0,"quantity":73,"imgfile":"product-images/coffeebeans.png","timestamp":"2025-02-05T07:43:28.742323","actuald │
│ ateadded":"2026-01-06T12:43:45.268326"} │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ The Coffee Beans are priced at $6.00, and there are 73 units currently in stock. Would you like to know anything else about
  this product?

Enter fullscreen mode Exit fullscreen mode

Using the Dart Gemini CLI Extension

The Gemini CLI Extension provides tools for working with Dart Code:

> run_tests

✦ I will run the project's tests to ensure everything is functioning correctly.
╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ? run_tests (dart MCP Server) {"roots":[{"root":"file:///home/xbill/gemini-cli-codeassist/firestore-stdio-flutter"}]} ← │
│ │
│ MCP Server: dart │
│ Tool: run_tests │
│ │
│ Allow execution of MCP tool "run_tests" from server "dart"? │
│ │
│ 1. Allow once │
│ 2. Allow tool for this session │
│ ● 3. Allow all server tools for this session │
│ 4. No, suggest changes (esc) │
│ │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ run_tests (dart MCP Server) {"roots":[{"root":"file:///home/xbill/gemini-cli-codeassist/firestore-stdio-flutter"}]} │
│ │
│ dart|flutter test in /home/xbill/gemini-cli-codeassist/firestore-stdio-flutter: │
│ \u001b[32m+2\u001b[0m: All tests passed!\u001b[0m │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ Tests passed successfully. I'm ready for your next instruction.

> dart_fix

✦ I will run dart fix --apply to automatically address common issues and keep the codebase clean.
╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ dart_fix (dart MCP Server) {"roots":[{"root":"file:///home/xbill/gemini-cli-codeassist/firestore-stdio-flutter"}]} │
│ │
│ dart fix in /home/xbill/gemini-cli-codeassist/firestore-stdio-flutter: │
│ Computing fixes in firestore-stdio-flutter... │
│ Nothing to fix! │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ dart fix found nothing to change. How can I help you next?

> dart_foramt

✦ I will run dart format . to ensure the code follows standard Dart formatting conventions.
╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ dart_format (dart MCP Server) {"roots":[{"paths":["."],"root":"file:///home/xbill/gemini-cli-codeassist/firestore-stdio-f… │
│ │
│ dart format in /home/xbill/gemini-cli-codeassist/firestore-stdio-flutter: │
│ Formatted 4 files (0 changed) in 0.01 seconds. │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ dart format completed, and no files needed changes. What's next?

Enter fullscreen mode Exit fullscreen mode

Publishing Dart Packages with Gemini CLI

Gemini CLI offers support and automation for publishing your Dart code. Start the processs from within Gemini CLI:

✦ The package is ready for publishing with 0 warnings. I will now run dart pub publish. Please note that this command may require
  you to authenticate via a web browser or provide input in the terminal (press ctrl + f to focus the shell if needed).
╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ Shell dart pub publish [current working directory /home/xbill/gemini-cli-codeassist/firestore-stdio-flutter] (Publishing … │
│ │
│ Resolving dependencies... │
│ Downloading packages... │
│ archive 3.6.1 (4.0.7 available) │
│ googleapis_auth 1.6.0 (2.0.0 available) │
│ grpc 3.2.4 (5.1.0 available) │
│ protobuf 3.1.0 (6.0.0 available) │
│ Got dependencies! │
│ 4 packages have newer versions incompatible with dependency constraints. │
│ Try `dart pub outdated` for more information. │
│ Publishing firestore_stdio_flutter 1.0.1 to https://pub.dev: │
│ ├── CHANGELOG.md (<1 KB) │
│ ├── GEMINI.md (1 KB) │
│ ├── LICENSE (1 KB) │
│ ├── Makefile (<1 KB) │
│ ├── README.md (1 KB) │
│ ├── analysis_options.yaml (1 KB) │
│ ├── bin │
│ │ └── firestore_stdio_flutter.dart (2 KB) │
│ ├── lib │
│ │ ├── product.dart (1 KB) │
│ │ └── tools.dart (7 KB) │
│ ├── pubspec.yaml (<1 KB) │
│ └── test │
│ └── greet_test.dart (<1 KB) │
│ │
│ Total compressed archive size: 6 KB. │
│ Validating package... │
│ │
│ Publishing is forever; packages cannot be unpublished. │
│ Policy details are available at https://pub.dev/policy │
│ │
│ Do you want to publish firestore_stdio_flutter 1.0.1 to https://pub.dev (y/N)? y │
│ Uploading... (1.6s) │
│ Message from server: Successfully uploaded https://pub.dev/packages/firestore_stdio_flutter version 1.0.1, it may take up-to │
│ 10 minutes before the new version is available. │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ The package firestore_stdio_flutter 1.0.1 has been successfully published to pub.dev. It may take up to 10 minutes for the new
  version to appear on the site.

Enter fullscreen mode Exit fullscreen mode

Extending the Dart MCP Server with Gemini CLI

Now that the basic MCP functionality has been tested and verified with Gemini CLI- the Dart code can be extended with new MCP tools:

> extend @bin/firebase_stdio_flutter.dart with new MCP tools - 
  one that builds a detailled inventory report and 
  one that gets dart and flutter runtime information
Enter fullscreen mode Exit fullscreen mode

Gemini CLI will get right to work:

 281 + │
│ 282 + Future<CallToolResult> getInventoryReportHandler( │
│ 283 + Map<String, dynamic> args, │
│ 284 + dynamic extra, │
│ 285 + ) async { │
│ 286 + if (!dbRunning) { │
│ 287 + return CallToolResult( │
│ 288 + isError: true, │
│ 289 + content: [TextContent(text: "Inventory database is not running.")], │
│ 290 + ); │
│ 291 + } │
│ 292 + try { │
│ 293 + final productsSnapshot = │
│ 294 + await Firestore.instance.collection("inventory").get(); │
│ 295 + final products = │
│ 296 + productsSnapshot.map((doc) => Product.fromFirestore(doc)).toList(); │
Enter fullscreen mode Exit fullscreen mode

Once the tools are generated you will get a confirmation:

✦ I have successfully extended the firestore-stdio-flutter application with the requested MCP tools.

  Here's a summary of the changes:
   1. Modified `lib/tools.dart`: Added two new handler functions:
       * getInventoryReportHandler: Fetches all products, calculates total quantity, total value, identifies the most expensive
         item, and lists items with low stock (quantity < 10). It returns a formatted text report.
       * getRuntimeInfoHandler: Retrieves the current Dart version using Platform.version and attempts to get the Flutter version
         by running flutter --version.
   2. Modified `bin/firestore_stdio_flutter.dart`: Registered the new tools (get_inventory_report and get_runtime_info) with the
      MCP server so they can be called by clients.
   3. Created `test/inventory_tools_test.dart`: Added a test file to verify the get_runtime_info tool and the error handling of
      get_inventory_report (when the database is not running).

  Verified the changes by running the tests and dart analyze.

  User, please restart the server to use the new tools.
Enter fullscreen mode Exit fullscreen mode

Restart Gemini CLI and check for the new MCP tools:

xbill@penguin:~/gemini-cli-codeassist/firestore-stdio-flutter$ make build
dart pub get && dart compile exe bin/firestore_stdio_flutter.dart -o bin/firestore_stdio_flutter
Resolving dependencies... 
Downloading packages... 
Generated: /home/xbill/gemini-cli-codeassist/firestore-stdio-flutter/bin/firestore_stdio_flutter

gemini
> /mcp list

Configured MCP servers:

🟢 firestore-stdio-flutter - Ready (8 tools)
  Tools:
  - check_db
  - get_inventory_report
  - get_product_by_id
  - get_products
  - get_root
  - get_runtime_info
  - reset
  - seed
Enter fullscreen mode Exit fullscreen mode

The new MCP tools can be used in the current context:

> get_runtime_info

✦ I will retrieve the Dart and Flutter runtime information for you.

╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ get_runtime_info (firestore-stdio-flutter MCP Server) {} │
│ │
│ === Runtime Information === │
│ Dart Version: 3.10.4 (stable) (Tue Dec 9 00:01:55 2025 -0800) on "linux_x64" │
│ OS: linux Linux 6.6.99-09000-gd3ae1caecf39 #1 SMP PREEMPT_DYNAMIC Thu, 27 Nov 2025 21:00:42 -0800 │
│ Flutter Version: Flutter 3.38.5 • channel stable • https://github.com/flutter/flutter.git │
│ Framework • revision f6ff1529fd (4 weeks ago) • 2025-12-11 11:50:07 -0500 │
│ Engine • hash c108a94d7a8273e112339e6c6833daa06e723a54 (revision 1527ae0ec5) (26 days ago) • 2025-12-11 15:04:31.000Z │
│ Tools • Dart 3.10.4 • DevTools 2.51.1 │
│ =========================== │
│ │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ The runtime information has been retrieved:

   * Dart Version: 3.10.4 (stable)
   * Flutter Version: 3.38.5 (stable)
   * OS: Linux 6.6.99

  I am ready for your next command.

Enter fullscreen mode Exit fullscreen mode

and inventory information:

> get_inventory_report

✦ I will now generate a detailed inventory report for you, including total value and low stock items.

╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ get_inventory_report (firestore-stdio-flutter MCP Server) {} │
│ │
│ === Inventory Report === │
│ Total Products: 34 │
│ Total Quantity: 6699 │
│ Total Value: $41331.00 │
│ Most Expensive Item: Sunflower Seeds ($10.00) │
│ Low Stock Items (< 10): │
│ - Wasabi Party Mix (Qty: 0) │
│ - Jalapeno Seasoning (Qty: 0) │
│ ======================== │
│ │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ The inventory report has been generated:

   * Total Products: 34
   * Total Quantity: 6,699
   * Total Value: $41,331.00
   * Most Expensive Item: Sunflower Seeds ($10.00)
   * Low Stock Items:
       * Wasabi Party Mix (Qty: 0)
       * Jalapeno Seasoning (Qty: 0)
Enter fullscreen mode Exit fullscreen mode

Use The New MCP Tools in the Current Context

Once the generated code has been exposed as MCP tools - the current context in Gemini CLI has full access to the information:

> with get_inventory_report and current products recommend 
a menu that optimizes profit

✦ Based on the inventory report and current product list, here is a recommended menu designed to optimize profit.

  Strategy: This menu prioritizes High-Value Items ($8 - $10) that are currently in stock. By featuring premium-priced goods, we
  aim to maximize revenue per transaction. Items with 0 quantity (Wasabi Party Mix, Jalapeno Seasoning) have been excluded.

  💰 High-Yield Menu Recommendations

  Starters & Snacks
  Focusing on high-ticket pantry items.
   * Sunflower Seeds - $10.00 (High Stock: 361)
   * Parmesan Crisps - $9.00
   * Walnuts - $8.00

  Mains
  Premium protein and staples.
   * Shrimp Feast - $10.00
   * Whole Chicken - $6.00 (Volume driver: 250 in stock)
   * Side of Black Beans - $8.00

  Beverages
  Top-tier drink selection.
   * Premium Green Tea - $10.00 (High Stock: 424)
   * Classic Cola - $9.00
   * Apple Juice - $8.00

  Sweets & Spreads
  High-margin dessert add-ons.
   * Mint Chocolate Cookies - $10.00
   * Maple Almond Butter - $10.00
   * Fresh Bananas - $9.00

  ---
  💡 Inventory Note: You currently have 0 stock of Wasabi Party Mix and Jalapeno Seasoning. Ensure these are removed from any
  active physical menus to avoid customer dissatisfaction.

Enter fullscreen mode Exit fullscreen mode

The information from the MCP tool execution comes back into the current Gemini CLI context. You can use the information returned from the tools along with the underlying Gemini Models.

Summary

The strategy for using Dart/Flutter for MCP development with Gemini CLI was validated with a incremental step by step approach.

A minimal stdio transport MCP Server was started from source code and validated with Gemini CLI running as a MCP client in the same local environment.

FireStore was used as a backing database to provide basic inventory support.

Gemini CLI was then used to extend the sample source code with several new MCP tools and use these tools inside the context for the underlying LLM.

This approach can be extended to more complex deployments using other MCP transports and Cloud based options.

Top comments (0)