How to Build Your First MCP Server

How to Build Your First MCP Server

In this tutorial, we’ll walk through building a simple Model Context Protocol (MCP) server in Dart using the mcp_dart package. We’ll then connect it to an MCP client like Cursor and explore how you can extend it for real-world use cases.

The Basics: What is MCP?

Model Context Protocol (MCP) is an open standard that allows seamless integration between LLM applications and external data sources or tools.

Think of MCP as the USB-C of AI integrations. Instead of building one-off integrations for every assistant, MCP provides a standardized way to connect tools and data.

Why does this matter?

Decoupling: Separates the “AI brain” (LLM) from your business logic.

Security: Provides controlled, local access to data and tools.

Reusability: Build an integration once and use it across multiple teams, clients, or products.

What We’ll Build

In this guide, we’ll create:

 A Dart MCP server that communicates over stdio.

 A sample tool that returns stock information.

 An integration with Cursor, configured through mcp.json.

Prerequisites

Dart SDK installed

Cursor installed

Step 1: Create the Dart Project

Start by creating a new Dart console project and adding the mcp_dart package.

# Create a new console application
dart create -t console mcp_dart_server
cd mcp_dart_server

# Add dependencies
dart pub add mcp_dart

Step 2: Create the MCP Server

Create bin/mcp_server.dart with the following boilerplate code:

import ‘package:mcp_dart/mcp_dart.dart’;

void main() async {
  McpServer server = McpServer(
    Implementation(name: "mcp-dart-server", version: "1.0.0"),
    options: ServerOptions(
      capabilities: ServerCapabilities(
        resources: ServerCapabilitiesResources(),
        tools: ServerCapabilitiesTools(),
      ),
    ),
  );
  server.connect(StdioServerTransport());
}

Run it to confirm everything works:

dart run bin/mcp_server.dart

The server will start and wait for a client connection.

Step 3: Define a Stock Tool

To make this useful, let’s define a tool that provides stock information. For now, we’ll use a hardcoded list.

Project Structure

├── lib
│   ├── models
│   │   ├── models.dart
│   │   └── stock.dart
│   ├── repositories
│   │   └── stock_repository.dart
│   └── mcp_library.dart
└── bin
    └── mcp_server.dart

Create the Model (lib/models/stock.dart)

typedef Ticker = String;
/// A Stock object which contains information of a Stock.
class Stock {
  const Stock({
    required this.ticker,
    required this.name,
    required this.price,
  });
final Ticker ticker;
  final String name;
  final double price;

  Map<String, dynamic> toJson() => {
    'ticker': ticker,
    'name': name,
    'price': price,
  };
}

Create the Repository (lib/repositories/stock_repository.dart

import 'package:mcp_dart_server/models/models.dart';
abstract class StockRepository {
  Future<List<Stock>> getAllStocks();
}
class InMemoryStockRepository implements StockRepository {
  final _stocks = [
    Stock(ticker: 'AAPL', name: 'Apple Inc.', price: 228.86),
    Stock(ticker: 'GOOG', name: 'Alphabet Inc.', price: 202.02),
    Stock(ticker: 'META', name: 'Meta Platforms Inc.', price: 772.12),
  ];

  @override
  Future<List<Stock>> getAllStocks() async => _stocks;
}

Register the Tool in the Server (bin/mcp_server.dart)

import 'dart:convert';
import 'package:mcp_dart/mcp_dart.dart';
import 'package:mcp_dart_server/repositories/stock_repository.dart';

void main() async {
  final server = McpServer(
    Implementation(name: "mcp-dart-server", version: "1.0.0"),
    options: ServerOptions(
      capabilities: ServerCapabilities(
        resources: ServerCapabilitiesResources(),
        tools: ServerCapabilitiesTools(),
      ),
    ),
  );

  // Register stock tool
  server.tool(
    "get_stocks_information",
    description: '''
      MCP tool to get stock price information for Nasdaq tickers
      like AAPL, GOOG, and META (Apple, Google, Meta).
    ''',
    callback: ({args, extra}) async {
      final stockRepository = InMemoryStockRepository();
      final stocks = await stockRepository.getAllStocks();

      return CallToolResult.fromContent(
        content: [
          TextContent(
            text: jsonEncode(stocks.map((s) => s.toJson()).toList()),
          ),
        ],
      );
    },
  );

  server.connect(StdioServerTransport());
}

Step 4: Connect to Cursor

1. Compile the Server

dart compile exe bin/mcp_server.dart -o ./mcp_stocks_server

This generates an executable (mcp_stocks_server) in your project root.

2. Configure Cursor

Create or edit ~/.cursor/mcp.json:

{
  "mcpServers": {
    "stocks": {
      "command": "/absolute/path/to/mcp_stocks_server"
    }
  }
}

Restart Cursor, and your new stocks tool will be available. The AI agent will automatically call it when asked for stock prices.

Next Steps

You now have a working MCP server in Dart that:

Registers tools with descriptive metadata

Exposes structured data

Integrates seamlessly with Cursor

From here, you can:

Replace the in-memory stock list with a real API (e.g., Yahoo Finance, Alpha Vantage).

Add more tools (e.g., “get_stock_history”).

Use MCP as a secure bridge between your AI assistant and internal systems.

Congratulations! You’ve built your first Dart MCP server. This foundation opens up endless possibilities for AI-driven integrations.

Leave a Comment

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *