# Mcp Server Dart

> A developer-friendly MCP (Model Context Protocol) framework for Dart with annotations and code generation. Build MCP servers as easily as annotating methods with @MCPTool, @MCPResource, or @MCPPrompt - similar to how json_serializable or freezed works.

- **Type:** MCP server
- **Install:** `agentstack add mcp-zfinix-mcp-server-dart`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [Zfinix](https://agentstack.voostack.com/s/zfinix)
- **Installs:** 0
- **Category:** [Integrations](https://agentstack.voostack.com/c/integrations)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [Zfinix](https://github.com/Zfinix)
- **Source:** https://github.com/Zfinix/mcp_server_dart
- **Website:** https://pub.dev/packages/mcp_server_dart

## Install

```sh
agentstack add mcp-zfinix-mcp-server-dart
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

[](https://dart.dev)
[](https://modelcontextprotocol.io/)
[](https://opensource.org/licenses/MIT)

A **developer-friendly MCP (Model Context Protocol) framework for Dart** with **annotations** and **code generation**. Build MCP servers as easily as annotating methods with `@MCPTool`, `@MCPResource`, or `@MCPPrompt` - similar to how `json_serializable` or `freezed` works.

## ✨ Features

- **🏷️ Annotation-based**: Declare MCP tools, resources, and prompts with simple annotations
- **🔧 Code generation**: Automatic boilerplate generation using `build_runner` with extension-based registration
- **✨ No `@override` required**: Clean method declarations without inheritance boilerplate
- **📡 Multiple transports**: Support for stdio, HTTP, and Streamable HTTP with Server-Sent Events (SSE)
- **🔍 Type-safe**: Full Dart type safety with automatic parameter extraction
- **📚 JSON Schema**: Automatic input schema generation from method signatures
- **🧪 Fully tested**: Comprehensive test suite with JSON-RPC command validation
- **⚡ Production ready**: Current MCP 2025-11-25-aligned protocol implementation with Relic HTTP server
- **🧠 Modern capabilities**: Built-in support for MCP logging, completions, task-augmented tool calls, and richer initialize metadata
- **🌐 Modern HTTP**: Built on Relic framework with middleware support, CORS, logging, and health checks
- **🔧 Monitoring**: Built-in health check endpoints and connection monitoring
- **📊 SSE Support**: Server-Sent Events for real-time streaming on the modern MCP streamable HTTP transport

## 🚀 Quick Start

### 1. Add Dependencies

```yaml
dependencies:
  mcp_server_dart: ^1.1.2
  relic: ^0.5.0  # Modern HTTP framework
  logging: ^1.3.0  # For server logging

dev_dependencies:
  build_runner: ^2.4.13
```

### 2. Create Your MCP Server

```dart
import 'package:mcp_server_dart/mcp_server_dart.dart';

part 'my_server.mcp.dart'; // Generated file

class MyMCPServer extends MCPServer {
  MyMCPServer() : super(name: 'my-server', version: '1.0.0') {
    // Register all generated handlers using the extension
    registerGeneratedHandlers();
  }

  @MCPTool('greet', description: 'Greet someone by name')
  Future greet(String name) async {
    return 'Hello, $name! 👋';
  }

  @MCPTool('calculate', description: 'Perform basic arithmetic')
  Future calculate(double a, double b, String operation) async {
    switch (operation) {
      case 'add': return a + b;
      case 'subtract': return a - b;
      case 'multiply': return a * b;
      case 'divide': return b != 0 ? a / b : throw ArgumentError('Division by zero');
      default: throw ArgumentError('Unknown operation: $operation');
    }
  }

  @MCPResource('status', description: 'Server status information')
  Future> getStatus() async {
    return {
      'server': name,
      'version': version,
      'uptime': DateTime.now().toIso8601String(),
      'status': 'healthy',
    };
  }

  @MCPPrompt('codeReview', description: 'Generate code review prompts')
  String codeReviewPrompt(String code, String language) {
    return '''Please review this $language code for:
- Best practices and conventions
- Potential bugs or issues
- Performance improvements
- Security considerations

Code:
```$language
$code
```''';
  }
}
```

### 3. Generate Code

```bash
dart run build_runner build
```

This generates `my_server.mcp.dart` with an extension that provides automatic registration methods.

### 4. Run Your Server

```dart
import 'dart:io';
import 'package:logging/logging.dart';

void main() async {
  Logger.root.level = Level.INFO;

  final server = MyMCPServer(); // Handlers auto-registered in constructor
  server.attachLogger(Logger.root); // Forward Dart LogRecord events to MCP logging

  // Optional: also mirror logs locally for humans
  Logger.root.onRecord.listen((record) {
    stderr.writeln('${record.level.name}: ${record.time}: ${record.message}');
  });

  // Choose your transport:
  await server.start();        // For CLI integration (stdio)
  // OR
  await server.serve(port: 8080);   // For HTTP server with health checks
}
```

**Server Features:**
- 🌐 **HTTP Server**: Runs on specified port with Relic framework
- 🔍 **Health Check**: Available at `http://localhost:8080/health`
- 📊 **Status Endpoint**: Server metrics at `http://localhost:8080/status`
- 📡 **MCP Endpoint**: Streamable HTTP at `http://localhost:8080/mcp`
- 📝 **Request Logging**: All HTTP requests logged with timing
- 🛡️ **CORS Support**: Cross-origin requests enabled by default
- ⚡ **Graceful Shutdown**: Handles SIGINT/SIGTERM signals properly
- 🔄 **SSE Streaming**: Server-Sent Events for real-time communication

### MCP logging bridge

If your server already uses `package:logging`, you can forward Dart `LogRecord`
events directly to MCP `notifications/message`:

```dart
final server = MyMCPServer();
server.attachLogger(Logger.root);
```

Attaching a logger automatically enables MCP logging capability advertisement.
You can still set `enableLogging: true` explicitly, but it is no longer required
for the common attached-logger case.

The bridge:
- respects the client's `logging/setLevel` threshold
- maps Dart logging levels to MCP logging levels
- includes message, time, sequence number, and optional error/stack trace

### Auto-advertised capabilities

Some modern MCP capabilities can now be advertised automatically:
- **Logging**: enabled automatically when a logger is attached with `server.attachLogger(...)`
- **Completions**: enabled automatically when an `@MCPCompletion(...)` handler is registered
- **Tasks**: enabled automatically when any tool uses `annotations: {'taskSupport': ...}`

You can still opt in explicitly with `enableLogging: true`, `enableCompletions: true`, or `enableTasks: true`, but they're no longer required for these common cases.

## 📖 Annotations Reference

### `@MCPTool`

Marks a method as an MCP tool that LLMs can call:

```dart
@MCPTool('toolName', description: 'What this tool does')
Future myTool(ParameterType param) async {
  // Implementation
}
```

**Features:**
- Automatic parameter extraction and type checking
- JSON Schema generation from method signature
- Support for optional parameters with defaults
- Async and sync method support

### `@MCPResource`

Marks a method as an MCP resource that provides data:

```dart
@MCPResource('resourceName', 
  description: 'What this resource contains',
  mimeType: 'application/json'  // Optional
)
Future> getResource() async {
  // Return resource data
}
```

### `@MCPPrompt`

Marks a method as an MCP prompt template:

```dart
@MCPPrompt('promptName', description: 'What this prompt does')
String generatePrompt(String context, String task) {
  return 'Generated prompt based on $context and $task';
}
```

### `@MCPCompletion`

Marks a method as a completion provider for a prompt or resource:

```dart
@MCPCompletion('classify')
Future completeClassify(
  MCPCompletionRequest request,
) async {
  final value = request.argument.value.toLowerCase();
  return MCPCompletionResult(
    completion: MCPCompletionData(
      values: ['bug', 'feature'].where((v) => v.startsWith(value)).toList(),
      hasMore: false,
    ),
  );
}
```

Use a plain name like `classify` for prompt completions. Use a full
`mcp://...` URI to attach a completion provider to a resource. Completion
capability advertisement is automatic when one or more completion providers
are registered, though you can still set `enableCompletions: true` explicitly
if you prefer.

### `@MCPParam`

Provides additional metadata for parameters:

```dart
@MCPTool('example')
Future example(
  @MCPParam(description: 'The user name', example: 'John Doe') 
  String name,
  
  @MCPParam(required: false, description: 'Age in years')
  int age = 25,
) async {
  return 'Hello $name, age $age';
}
```

## 🌟 Complete Example

See the [Google Maps MCP example](example/lib/advanced/google_maps.dart) for a comprehensive demonstration:

```dart
class GoogleMapsMCP extends MCPServer {
  GoogleMapsMCP() : super(name: 'google-maps-mcp', version: '1.0.0') {
    registerGeneratedHandlers();
  }

  @MCPTool('searchPlace', description: 'Find places by name or address')
  Future> searchPlace(String query, int limit = 5) async {
    // Implementation with mock Google Maps API calls
  }

  @MCPTool('getDirections', description: 'Get directions between two points')
  Future> getDirections(
    String origin, 
    String destination, 
    String mode = 'driving'
  ) async {
    // Implementation
  }

  @MCPResource('currentLocation', description: 'Current user location')
  Future> getCurrentLocation() async {
    // Implementation
  }

  @MCPPrompt('locationSummary', description: 'Generate location summaries')
  String locationSummaryPrompt(String location, String summaryType = 'general') {
    // Generate contextual prompts
  }
}
```

## 🔧 Advanced Usage

### Custom Parameter Validation

```dart
@MCPTool('validateEmail')
Future validateEmail(String email) async {
  if (!email.contains('@')) {
    throw ArgumentError('Invalid email format');
  }
  // Validation logic
}
```

### Complex Input Schemas

```dart
@MCPTool('complexTool', inputSchema: {
  'type': 'object',
  'properties': {
    'config': {
      'type': 'object',
      'properties': {
        'timeout': {'type': 'integer', 'minimum': 1},
        'retries': {'type': 'integer', 'maximum': 10}
      }
    }
  }
})
Future complexTool(Map config) async {
  // Handle complex nested parameters
}
```

### Multiple Transport Support

The server supports both stdio and HTTP transports. You can extend the basic example above to handle command-line arguments:

```dart
// Add argument handling to your main() function:
if (args.contains('--stdio')) {
  print('🔌 Starting MCP server on stdio...');
  await server.start();
} else {
  final port = args.contains('--port') 
      ? int.parse(args[args.indexOf('--port') + 1])
      : 8080;
  
  print('🌐 Starting HTTP server on port $port...');
  print('🔍 Health check: http://localhost:$port/health');
  print('📊 Status: http://localhost:$port/status');
  print('📡 MCP endpoint: http://localhost:$port/mcp');
  
  await server.serve(port: port);
}
```

**Transport Options:**
- **Stdio**: Perfect for Claude Desktop integration and CLI tools
- **HTTP**: Ideal for web applications, testing, and debugging with [Relic framework](https://pub.dev/packages/relic)
- **Streamable HTTP**: Latest MCP 2025-11-25 transport expectations with Server-Sent Events support
- **Health Monitoring**: Built-in endpoints for production monitoring

## 🌐 Streamable HTTP Transport (MCP 2025-11-25 aligned)

The MCP Dart framework now supports the latest **Streamable HTTP** transport specification:

### Key Features
- **Single MCP Endpoint**: `POST/GET /mcp` handles all MCP communication
- **Server-Sent Events**: Real-time streaming for server-initiated messages
- **Session Management**: Automatic session ID generation and validation
- **Protocol Headers**: `MCP-Protocol-Version: 2025-11-25` support
- **Security**: Origin validation and localhost binding for development

### Testing with MCP Inspector

```bash
# Start your server
dart run main.dart --example calculator --http --port 8080

# Test with Inspector CLI
npx @modelcontextprotocol/inspector --cli http://localhost:8080/mcp --transport streamable-http --method tools/list

# Test with Inspector UI
npx @modelcontextprotocol/inspector
# Then connect to: http://localhost:8080/mcp with "Streamable HTTP" transport
```

### cURL Testing

```bash
# Initialize connection
curl -X POST http://localhost:8080/mcp \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -H 'MCP-Protocol-Version: 2025-11-25' \
  --data '{"jsonrpc":"2.0","id":"1","method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{}}}'

# List tools
curl -X POST http://localhost:8080/mcp \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -H 'MCP-Protocol-Version: 2025-11-25' \
  --data '{"jsonrpc":"2.0","id":"2","method":"tools/list"}'

# Open SSE stream
curl -H 'Accept: text/event-stream' http://localhost:8080/mcp
```

## 🌐 Relic Framework Integration

The MCP Dart framework uses [**Relic**](https://pub.dev/packages/relic) as its HTTP server foundation. Relic is a modern, type-safe web server framework inspired by Shelf but with significant improvements:

### Why Relic?
- **🔒 Type Safety**: No more `dynamic` types - everything is strongly typed
- **⚡ Performance**: Uses `Uint8List` instead of `List` for better performance
- **🛣️ Advanced Routing**: Efficient trie-based routing with parameter extraction
- **🔧 Modern Headers**: Typed header parsing with validation
- **🧪 Well Tested**: Extended test coverage and production-ready

### Server Features Powered by Relic

```dart
// Your MCP server automatically gets these features:
await server.serve(
  port: 8080,
  address: InternetAddress.anyIPv4,
  enableCors: true,  // CORS middleware
  keepAliveTimeout: Duration(seconds: 30),
);
```

**Built-in Endpoints:**
- `GET /health` - Health check with server metrics
- `GET /status` - Detailed server status and capabilities  
- `POST/GET /mcp` - MCP Streamable HTTP endpoint
- `GET /ws` - WebSocket upgrade endpoint (coming soon)

**Middleware Stack:**
- 🌐 **CORS Middleware**: Cross-origin request support
- 📝 **Logging Middleware**: Request/response logging with timing
- 🛡️ **Error Handling**: Graceful error handling and responses
- 🛣️ **Routing**: Automatic route registration and parameter extraction

For more details about Relic's capabilities, see the [official Relic documentation](https://pub.dev/packages/relic).

### Binary Compilation for Production

Compile your MCP server to a native binary for optimal performance and easy deployment:

```bash
# Compile to standalone binary
dart compile exe my_server.dart -o mcp-server

# Cross-platform compilation
dart compile exe my_server.dart -o mcp-server-linux --target-os=linux
dart compile exe my_server.dart -o mcp-server-macos --target-os=macos
dart compile exe my_server.dart -o mcp-server.exe --target-os=windows
```

**Benefits of binary deployment:**
- ✅ **No Dart runtime required** - Standalone executable
- ✅ **Faster startup** - No VM overhead
- ✅ **Easy distribution** - Single file deployment
- ✅ **Production ready** - Optimized performance

**Claude Desktop configuration with binary:**
```json
{
  "mcpServers": {
    "my-server": {
      "command": "/path/to/mcp-server"
    }
  }
}
```

## 🧪 Testing

The framework includes comprehensive testing capabilities with both unit and integration testing. Here are several approaches:

### Testing the HTTP Server

With Relic integration, you can easily test your MCP server's HTTP endpoints:

```dart
import 'dart:convert';
import 'dart:io';
import 'package:test/test.dart';

void main() {
  group('MCP Server HTTP Tests', () {
    late MyMCPServer server;
    late HttpClient client;
    
    setUpAll(() async {
      server = MyMCPServer(); // Handlers auto-registered
      await server.serve(port: 8081); // Use different port for testing
      
      client = HttpClient();
    });
    
    tearDownAll(() async {
      await server.shutdown();
      client.close();
    });

    test('health check endpoint works', () async {
      final request = await client.get('localhost', 8081, '/health');
      final response = await request.close();
      
      expect(response.statusCode, equals(200));
      
      final body = await response.transform(utf8.decoder).join();
      final data = jsonDecode(body);
      expect(data['status'], equals('healthy'));
      expect(data['server'], equals('my-server'));
    });

    test('MCP endpoint works with Streamable HTTP', () async {
      final request = await client.post('localhost', 8081, '/mcp');
      request.headers.set('content-type', 'application/json');
      request.headers.set('mcp-protocol-version', '2025-11-25');
      request.write(jsonEncode({
        'jso

…

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [Zfinix](https://github.com/Zfinix)
- **Source:** [Zfinix/mcp_server_dart](https://github.com/Zfinix/mcp_server_dart)
- **License:** MIT
- **Homepage:** https://pub.dev/packages/mcp_server_dart

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** yes
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-zfinix-mcp-server-dart
- Seller: https://agentstack.voostack.com/s/zfinix
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
