MCP Server
A Dart plugin for implementing Model Context Protocol (MCP) servers. This plugin allows Flutter applications to expose data, functionality, and interaction patterns to Large Language Model (LLM) applications in a standardized way.
Features
- Create MCP servers with standardized protocol support
- Expose data through Resources
- Provide functionality through Tools
- Define interaction patterns through Prompts
- Multiple transport layers:
- Standard I/O for local process communication
- Server-Sent Events (SSE) for HTTP-based communication
- Cross-platform support: Android, iOS, web, Linux, Windows, macOS
Protocol Version
This package implements the Model Context Protocol (MCP) specification version 2024-11-05
.
The protocol version is crucial for ensuring compatibility between MCP clients and servers. Each release of this package may support different protocol versions, so it's important to:
- Check the CHANGELOG.md for protocol version updates
- Ensure client and server protocol versions are compatible
- Stay updated with the latest MCP specification
Version Compatibility
- Supported protocol version: 2024-11-05
- Compatibility: Tested with latest MCP client implementations
For the most up-to-date information on protocol versions and compatibility, refer to the Model Context Protocol specification.
Getting Started
Installation
Add the package to your pubspec.yaml
:
dependencies:
mcp_server: ^0.1.0
Or install via command line:
dart pub add mcp_server
Basic Usage
import 'package:mcp_server/mcp_server.dart';
void main() {
// Create a server
final server = McpServer.createServer(
name: 'Example Server',
version: '1.0.0',
capabilities: ServerCapabilities(
tools: true,
resources: true,
prompts: true,
),
);
// Add a simple calculator tool
server.addTool(
name: 'calculator',
description: 'Perform basic calculations',
inputSchema: {
'type': 'object',
'properties': {
'operation': {
'type': 'string',
'enum': ['add', 'subtract', 'multiply', 'divide'],
},
'a': {'type': 'number'},
'b': {'type': 'number'},
},
'required': ['operation', 'a', 'b'],
},
handler: (arguments) async {
final operation = arguments['operation'] as String;
final a = arguments['a'] as num;
final b = arguments['b'] as num;
double result;
switch (operation) {
case 'add':
result = (a + b).toDouble();
break;
case 'subtract':
result = (a - b).toDouble();
break;
case 'multiply':
result = (a * b).toDouble();
break;
case 'divide':
if (b == 0) {
return CallToolResult(
content: [TextContent(text: 'Division by zero error')],
isError: true,
);
}
result = (a / b).toDouble();
break;
default:
return CallToolResult(
content: [TextContent(text: 'Unknown operation: $operation')],
isError: true,
);
}
return CallToolResult(
content: [TextContent(text: result.toString())],
);
},
);
// Add a resource
server.addResource(
uri: 'time://current',
name: 'Current Time',
description: 'Get the current date and time',
mimeType: 'text/plain',
handler: (uri, params) async {
final now = DateTime.now().toString();
return ReadResourceResult(
contents: [
ResourceContent(
resource: Resource(
uri: uri.toString(),
name: 'Current Time',
mimeType: 'text/plain',
),
),
],
);
},
);
// Add a template prompt
server.addPrompt(
name: 'greeting',
description: 'Generate a customized greeting',
arguments: [
PromptArgument(
name: 'name',
description: 'Name to greet',
required: true,
),
],
handler: (arguments) async {
final name = arguments?['name'] as String? ?? 'User';
return GetPromptResult(
description: 'A friendly greeting',
messages: [
Message(
role: MessageRole.user,
content: TextContent(text: 'Hello, $name!'),
),
],
);
},
);
// Connect to transport
final transport = rMcpServer.createStdioTransport();
await server.connect(transport);
}
Core Concepts
Server
The McpServer
is your core interface to the MCP protocol. It handles connection management, protocol compliance, and message routing:
final server = McpServer.createServer(
name: 'My App',
version: '1.0.0',
capabilities: ServerCapabilities(
tools: true,
resources: true,
prompts: true,
),
);
Resources
Resources are how you expose data to LLMs. They're similar to GET endpoints in a REST API - they provide data but shouldn't perform significant computation or have side effects:
// Static resource
server.addResource(
uri: 'config://app',
name: 'App Configuration',
description: 'Application configuration data',
mimeType: 'text/plain',
handler: (uri, params) async {
return ReadResourceResult(
contents: [
ResourceContent(
resource: Resource(
uri: uri.toString(),
name: 'App Configuration',
mimeType: 'text/plain',
),
),
],
);
},
);
// Dynamic resource with parameters
server.addResourceTemplate(
uriTemplate: 'users://{userId}/profile',
name: 'User Profile',
description: 'Profile data for specific user',
mimeType: 'text/plain',
handler: (uri, params) async {
final userId = params['userId'];
// Fetch user data...
return ReadResourceResult(
contents: [
ResourceContent(
resource: Resource(
uri: uri.toString(),
name: 'User Profile',
mimeType: 'text/plain',
),
),
],
);
},
);
Tools
Tools let LLMs take actions through your server. Unlike resources, tools are expected to perform computation and have side effects:
server.addTool(
name: 'search-web',
description: 'Search the web for information',
inputSchema: {
'type': 'object',
'properties': {
'query': {'type': 'string'},
'maxResults': {'type': 'number'},
},
'required': ['query'],
},
handler: (arguments) async {
final query = arguments['query'] as String;
final maxResults = arguments['maxResults'] as int? ?? 5;
// Perform web search...
return CallToolResult(
content: [TextContent(text: 'Search results here')],
);
},
);
Prompts
Prompts are reusable templates that help LLMs interact with your server effectively:
server.addPrompt(
name: 'analyze-code',
description: 'Analyze code for potential issues',
arguments: [
PromptArgument(
name: 'code',
description: 'Code to analyze',
required: true,
),
PromptArgument(
name: 'language',
description: 'Programming language',
required: false,
),
],
handler: (arguments) async {
final code = arguments?['code'] as String? ?? '';
final language = arguments?['language'] as String? ?? 'unknown';
return GetPromptResult(
description: 'Code analysis request',
messages: [
Message(
role: MessageRole.user,
content: TextContent(text: 'Please analyze this $language code:\n\n$code'),
),
],
);
},
);
Transport Layers
Standard I/O
For command-line tools and direct integrations:
final transport = McpServer.createStdioTransport();
await server.connect(transport);
Server-Sent Events (SSE)
For HTTP-based communication:
final transport = FlutterMcpServer.createSseTransport(
endpoint: '/sse',
messagesEndpoint: '/messages',
);
await server.connect(transport);
MCP Primitives
The MCP protocol defines three core primitives that servers can implement:
Primitive |
Control |
Description |
Example Use |
Prompts |
User-controlled |
Interactive templates invoked by user choice |
Slash commands, menu options |
Resources |
Application-controlled |
Contextual data managed by the client application |
File contents, API responses |
Tools |
Model-controlled |
Functions exposed to the LLM to take actions |
API calls, data updates |
Additional Examples
Check out the example directory for a complete sample application.
Resources
Issues and Feedback
Please file any issues, bugs, or feature requests in our issue tracker.
License
This project is licensed under the MIT License - see the LICENSE file for details.