Install
$ agentstack add mcp-zfinix-mcp-server-dart ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
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_runnerwith extension-based registration - ✨ No
@overriderequired: 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
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
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
dart run build_runner build
This generates my_server.mcp.dart with an extension that provides automatic registration methods.
4. Run Your Server
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:
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/setLevelthreshold - 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:
@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:
@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:
@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:
@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:
@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:
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
@MCPTool('validateEmail')
Future validateEmail(String email) async {
if (!email.contains('@')) {
throw ArgumentError('Invalid email format');
}
// Validation logic
}
Complex Input Schemas
@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:
// 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
- 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 /mcphandles 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-25support - Security: Origin validation and localhost binding for development
Testing with MCP Inspector
# 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
# 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 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
dynamictypes - everything is strongly typed - ⚡ Performance: Uses
Uint8Listinstead ofListfor 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
// 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 metricsGET /status- Detailed server status and capabilitiesPOST/GET /mcp- MCP Streamable HTTP endpointGET /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.
Binary Compilation for Production
Compile your MCP server to a native binary for optimal performance and easy deployment:
# 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:
{
"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:
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.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.