关于 MCP Server
MCP Server 是供 Flutter 应用开发者构建 MCP 服务的 Dart 插件。它实现多版 MCP 协议及其核心原语,并提供可配置传输、授权、任务处理和会话监控。
主要功能
- 01支持资源、工具、提示词和补全
- 02支持多个 MCP 协议版本
- 03支持 stdio、SSE 和 Streamable HTTP
- 04授权与 Schema 验证
- 05任务与会话管理
- 06健康检查与指标
适用场景
- 01向 LLM 客户端公开 Flutter 应用数据和操作
- 02通过 stdio 或 HTTP 传输提供 MCP 服务
- 03将长时间运行的工具调用作为任务处理
MCP 相关
它实现 MCP 服务,向 MCP 客户端公开资源、工具和提示词,并支持 stdio、SSE 与 Streamable HTTP 传输。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
我们还没有获取到这个服务的安装包或远程地址,请按项目 README 中的说明安装。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
MCP 服务
用于实现 模型上下文协议(MCP) 服务的 Dart 插件。此插件允许 Flutter 应用以标准化方式向大语言模型(LLM)应用公开数据、功能和交互模式。
功能
- 支持所有 MCP 修订版本,从 2024-11-05 到 2026-07-28,以及 2026-07-28 tasks 扩展版——详见下文的 协议版本
- 核心原语——
Resources、Tools、Prompts,以及Completions(2025-06-18 起) - 由服务端发起的请求——
requestClientSampling、requestClientRoots、requestClientElicitation,支持响应路由和超时 - 授权——每个 HTTP 请求都会在分发前进行判定(401 / 403,附带
WWW-Authenticate),支持受保护资源元数据(RFC 9728)、受众和作用域检查 - 结构化工具输出(2025-06-18)——
outputSchema+structuredContent+resource_link内容类型 - 图标 + 采样工具调用(2025-11-25)——
Tool.icons/Resource.icons/Prompt.icons,以及sampling/createMessage中新增的tools/toolChoice字段 - 列表变更通知——符合规范的
notifications/{tools,resources,prompts}/list_changed - 进度 + 取消——出站
notifyProgress;入站notifications/cancelled和notifications/progress监听器 - 会话事件——
onConnect/onDisconnect流、每个会话的协议版本 + 功能 - 缓存提示(2026-07-28)——discover、列表和读取操作中的
ttlMs/cacheScope(cacheTtl、publicLists) - 运行状况 + 指标——
getHealth()、命名计时器、自定义计数器 - 传输方式——stdio、SSE(旧版)、Streamable HTTP(2025-03-26 起的规范方式)
- 平台:支持
dart:io的平台(Android、iOS、Linux、Windows、macOS)
协议版本
实现模型上下文协议的所有修订版本;每个客户端都会使用其连接时指定的版本。
| 版本 | 说明 |
|---|---|
2024-11-05 | 原始版本;HTTP+SSE 传输 |
2025-03-26 | Streamable HTTP、授权、JSON-RPC 批处理 |
2025-06-18 | Elicitation、结构化工具输出、资源链接、MCP-Protocol-Version 标头;移除批处理 |
2025-11-25 | 图标、带工具的采样、URL elicitation、tasks |
2026-07-28 | 无状态:无需握手、server/discover、每个请求的 _meta、subscriptions/listen、多轮请求、缓存提示;tasks 扩展版 |
initialize 会在 McpProtocol.supportedVersions(2025-11-25 及更早版本)中进行协商。2026-07-28 无需握手:在 stdio 上,会根据请求在 _meta 中指定的版本提供服务;通过 Streamable HTTP 时,则在与会话版本相同的端点上提供服务。保留每会话状态的服务会设置 enableStateless: false(TransportConfig.streamableHttp 或 StreamableHttpServerConfig),而 2026-07-28 客户端会回退到 initialize。
从 2.x 迁移:MIGRATION-3.0.md。
任务
工具的 execution.taskSupport(optional、required、forbidden)
决定调用是否作为任务运行。
- 2025-11-25(请求方驱动):声明
ServerCapabilities(tasks: {'list': {}, 'cancel': {}, 'requests': {'tools': {'call': {}}}})。 携带task的调用会收到CreateTaskResult,并在后台运行;随后可调用tasks/get、tasks/result(等待任务结束)、tasks/list和tasks/cancel。服务器也可以请求客户端将sampling/createMessage/elicitation/create作为任务运行 (requestClientTask、clientTaskResult等)。 - 2026-07-28(tasks 扩展,服务器定向):声明
extensions: {tasksExtensionId: {}}。客户端声明了该扩展后,其调用工具时,如果工具允许,则会作为任务运行;随后可调用tasks/get、tasks/update和tasks/cancel。 - 在任务执行过程中,
server.currentTask.requestInput({...})会向客户端请求输入(2025-11-25 使用带标签的请求,扩展中使用inputRequests)。
任务归属于经过身份验证的用户;否则(2025-11-25)归属于创建任务的会话,其他人无法读取、列出或取消这些任务。如果两者都不存在——即未进行身份验证的 2026-07-28 路径——任务仅由其 ID(128 位随机数)保护;如果任务结果敏感,请使用身份验证。限制:McpTaskStore(maxTtl:, defaultTtl:, maxTasksPerOwner:)。
JSON Schema
JsonSchemaValidator(由此软件包导出)会评估 MCP 携带的架构——工具的 inputSchema / outputSchema、elicitation 的 requestedSchema。
- 方言:2020-12(架构未指定
$schema时使用)、2019-09、 draft-07、draft-06、draft-04。若架构指定其他方言,则会以JsonSchemaException拒绝。 - 引用会在架构内部、传入
registry的文档中,以及内置元架构中解析。不会从网络获取内容;无法解析的引用会导致架构被拒绝。 - 评估受到限制(
JsonSchemaLimits:深度、子架构数量、评估次数、时间)。 format默认为注解;设置assertFormat: true后会检查email、uri、date和date-time。- 一致性:官方 JSON-Schema-Test-Suite(涵盖全部五种方言的必需测试,以及上述功能的可选测试)。
开始使用
基本用法
import 'package:mcp_server/mcp_server.dart';
void main() {
// Create a server with simple boolean capabilities
final server = Server(
name: 'Example Server',
version: '1.0.0',
capabilities: ServerCapabilities.simple(
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'],
'description': 'Mathematical operation to perform'
},
'a': {
'type': 'number',
'description': 'First operand'
},
'b': {
'type': 'number',
'description': 'Second operand'
}
},
'required': ['operation', 'a', 'b']
},
handler: (arguments) async {
final operation = arguments['operation'] as String;
final a = (arguments['a'] is int) ? (arguments['a'] as int).toDouble() : arguments['a'] as double;
final b = (arguments['b'] is int) ? (arguments['b'] as int).toDouble() : arguments['b'] as double;
double result;
switch (operation) {
case 'add':
result = a + b;
break;
case 'subtract':
result = a - b;
break;
case 'multiply':
result = a * b;
break;
case 'divide':
if (b == 0) {
return CallToolResult(
content: [TextContent(text: 'Division by zero error')],
isError: true,
);
}
result = a / b;
break;
default:
return CallToolResult(
content: [TextContent(text: 'Unknown operation: $operation')],
isError: true,
);
}
return CallToolResult(content: [TextContent(text: 'Result: $result')]);
},
);
// 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: [
TextResourceContents(
uri: uri,
text: now,
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,
),
PromptArgument(
name: 'formal',
description: 'Whether to use formal greeting style',
required: false,
),
],
handler: (arguments) async {
final name = arguments['name'] as String;
final formal = arguments['formal'] as bool? ?? false;
final String systemPrompt = formal
? 'You are a formal assistant. Address the user with respect and formality.'
: 'You are a friendly assistant. Be warm and casual in your tone.';
// Prompt messages are `user` or `assistant`; instructions go in the
// text (the specification has no system role here).
final messages = [
PromptMessage(
role: Role.user,
content: TextContent(text: '$systemPrompt\n\nPlease greet $name'),
),
];
return GetPromptResult(
description: 'A ${formal ? 'formal' : 'casual'} greeting for $name',
messages: messages,
);
},
);
// Connect to transport - old way (still supported)
final transportResult = McpServer.createStdioTransport();
final transport = transportResult.get();
server.connect(transport);
}
// NEW: Simplified unified API (recommended)
void simplifiedMain() async {
final serverResult = await McpServer.createAndStart(
config: McpServer.simpleConfig(
name: 'Example Server',
version: '1.0.0',
),
transportConfig: TransportConfig.stdio(),
);
await serverResult.fold(
(server) async {
// Add tools, resources, prompts as shown above
// Server is already running
await Future.delayed(const Duration(hours: 24));
},
(error) => print('Server failed: $error'),
);
}
传输配置
MCP Server 现在支持统一的传输配置:
// STDIO Transport
TransportConfig.stdio()
// SSE Transport
TransportConfig.sse(
host: 'localhost',
port: 8080,
endpoint: '/sse',
authToken: 'optional-token',
)
// Streamable HTTP Transport - SSE Streaming Mode (default)
TransportConfig.streamableHttp(
host: 'localhost',
port: 8081,
endpoint: '/mcp',
isJsonResponseEnabled: false, // SSE streaming mode (default)
)
// Streamable HTTP Transport - JSON Response Mode
TransportConfig.streamableHttp(
host: 'localhost',
port: 8081,
endpoint: '/mcp',
isJsonResponseEnabled: true, // JSON response mode
)
核心概念
服务器能力
MCP Server 支持两种配置能力的方式:
简单布尔配置
对于基本用法和测试,请使用 ServerCapabilities.simple():
final server = Server(
name: 'Simple Server',
version: '1.0.0',
capabilities: ServerCapabilities.simple(
tools: true,
toolsListChanged: true,
resources: true,
resourcesSubscribe: true,
resourcesListChanged: true,
prompts: true,
promptsListChanged: true,
logging: true,
completions: true,
),
);
基于对象的配置
架构中的能力对象,以及 tasks 和 extensions:
final server = Server(
name: 'Advanced Server',
version: '1.0.0',
capabilities: ServerCapabilities(
tools: ToolsCapability(listChanged: true),
resources: ResourcesCapability(listChanged: true, subscribe: true),
prompts: PromptsCapability(listChanged: true),
logging: LoggingCapability(),
completions: CompletionsCapability(),
// 2025-11-25 tasks; 2026-07-28 tasks extension
tasks: {'list': {}, 'cancel': {}, 'requests': {'tools': {'call': {}}}},
extensions: {tasksExtensionId: {}},
),
);
采样、根目录和 elicitation 是客户端能力:如果客户端声明了这些能力,服务器便会请求使用它们(通过 requestClientSampling、requestClientRoots、requestClientElicitation,或在 2026-07-28 通过 McpMrtr 输入请求)。
服务器
Server 类是你与 MCP 协议交互的核心接口。它负责连接管理、协议合规性和消息路由:
final server = Server(
name: 'My App',
version: '1.0.0',
capabilities: ServerCapabilities.simple(
tools: true,
resources: true,
prompts: true,
),
);
资源
资源是向大模型公开数据的方式。它们类似于 REST API 中的 GET 端点——提供数据,但不应执行大量计算或产生副作用:
// Static resource
server.addResource(
uri: 'config://app',
name: 'App Configuration',
description: 'Application configuration data',
mimeType: 'text/plain',
handler: (uri, params) async {
final configData = "app_name=MyApp\nversion=1.0.0\ndebug=false";
return ReadResourceResult(
contents: [
TextResourceContents(
uri: uri,
text: configData,
mimeType: 'text/plain',
),
],
);
},
);
// Resource with URI template
server.addResource(
uri: 'file://{path}',
name: 'File Resource',
description: 'Access files on the system',
mimeType: 'application/octet-stream',
uriTemplate: {
'type': 'object',
'properties': {
'path': {
'type': 'string',
'description': 'Path to the file'
}
}
},
handler: (uri, params) async {
// Extract path and read file content
final path = params['path'] ?? uri.substring('file://'.length);
final content = await File(path).readAsString();
return ReadResourceResult(
contents: [
TextResourceContents(
uri: uri,
text: content,
mimeType: 'text/plain',
),
],
);
},
);
工具
工具让大模型能够通过服务器执行操作。与资源不同,工具通常会执行计算并产生副作用:
server.addTool(
name: 'currentDateTime',
description: 'Get the current date and time',
inputSchema: {
'type': 'object',
'properties': {
'format': {
'type': 'string',
'description': 'Output format (full, date, time)',
'default': 'full'
}
},
'required': []
},
handler: (args) async {
final format = args['format'] as String? ?? 'full';
final now = DateTime.now();
String result;
switch (format) {
case 'date':
result = '${now.year}-${now.month.toString().padLeft(2, '0')}-${now.day.toString().padLeft(2, '0')}';
break;
case 'time':
result = '${now.hour.toString().padLeft(2, '0')}:${now.minute.toString().padLeft(2, '0')}:${now.second.toString().padLeft(2, '0')}';
break;
case 'full':
default:
result = now.toIso8601String();
break;
}
return CallToolResult(content: [TextContent(text: result)]);
},
);
提示词
提示词是可复用的模板,可帮助大模型有效地与服务器交互:
server.addPrompt(
name: 'codeReview',
description: 'Generate a code review for a code snippet',
arguments: [
PromptArgument(
name: 'code',
description: 'Code to review',
required: true,
),
PromptArgument(
name: 'language',
description: 'Programming language of the code',
required: true,
),
],
handler: (args) async {
final code = args['code'] as String;
final language = args['language'] as String;
final systemPrompt = '''
You are an expert code reviewer. Review the provided code with these guidelines:
1. Identify potential bugs or issues
2. Suggest optimizations for performance or readability
3. Highlight good practices used in the code
4. Provide constructive feedback for improvements
Be specific in your feedback and provide code examples when suggesting changes.
''';
final messages = [
PromptMessage(
role: Role.user,
content: TextContent(
text: '$systemPrompt\nPlease review this $language code:\n\n```$language\n$code\n```'),
),
];
return GetPromptResult(
description: 'Code review for $language code',
messages: messages,
);
},
);
会话管理
MCP Server 提供了强大的基于流的系统,用于监控客户端会话事件:
// Create a logger
final logger = Logger('mcp_server.sessions');
// Listen for client connections
server.onConnect.listen((session) {
logger.info('Client connected: ${session.id}');
// Initialize session resources
});
// Listen for client disconnections
server.onDisconnect.listen((session) {
logger.info('Client disconnected: ${session.id}');
// Clean up session resources
});
ClientSession 对象包含以下有用信息:
- 会话 ID
- 连接时间戳
- 协议版本
- 客户端能力
- 客户端根目录
会话管理最佳实践
-
始终处理这两种事件:监听连接和断开事件,以维护会话完整性。
-
为流订阅添加错误处理:
server.onConnect.listen( (session) { // Normal event handling }, onError: (error) { logger.severe('Error in connection stream: $error'); }, ); -
不再需要时取消订阅:
final subscription = server.onConnect.listen((session) { /* ... */ }); // Later, when done: subscription.cancel(); -
使用会话事件管理状态:根据会话事件维护应用程序状态。
-
跟踪指标以进行监控:统计会话数、持续时间及其他指标。
传输层
标准 I/O
用于命令行工具和直接集成:
final transportResult = McpServer.createStdioTransport();
final transport = transportResult.get();
server.connect(transport);
服务器发送事件(SSE)
用于基于 HTTP 的通信:
final sseConfig = SseServerConfig(
endpoint: '/sse',
messagesEndpoint: '/messages',
port: 8080,
);
final transportResult = McpServer.createSseTransport(sseConfig);
final transport = transportResult.get();
server.connect(transport);
可流式 HTTP 传输
可流式 HTTP 传输支持两种响应模式:
SSE 流式模式(默认)
用于实时流式传输响应:
final serverResult = await McpServer.createAndStart(
config: McpServer.simpleConfig(
name: 'My Server',
version: '1.0.0',
),
transportConfig: TransportConfig.streamableHttp(
host: 'localhost',
port: 8081,
endpoint: '/mcp',
isJsonResponseEnabled: false, // SSE streaming mode
),
);
JSON 响应模式
用于单个 JSON 响应(更简单,但不支持流式传输):
final serverResult = await McpServer.createAndStart(
config: McpServer.simpleConfig(
name: 'My Server',
version: '1.0.0',
),
transportConfig: TransportConfig.streamableHttp(
host: 'localhost',
port: 8081,
endpoint: '/mcp',
isJsonResponseEnabled: true, // JSON response mode
),
);
重要说明:
- 响应模式在服务启动时固定,无法动态更改
- 无论服务使用哪种模式,客户端都必须在 Accept 标头中同时包含
application/json和text/event-stream - SSE 模式允许流式传输多个响应,而 JSON 模式只返回单个响应
日志记录
该软件包包含全面的日志记录工具,支持自定义级别和格式:
// Create a named logger
final logger = Logger('mcp_server.example');
// Log at different levels
logger.severe('Connection failed: unable to connect to transport');
logger.warning('Resource cache is approaching capacity limit');
logger.info('Server started successfully on port 8080');
logger.fine('Session initialized with protocol version');
// Send structured logs to MCP client
server.sendLog(
McpLogLevel.info,
'Operation registered',
data: {
'operationId': 'op-123',
'sessionId': 'session-456',
'type': 'tool:calculator',
'timestamp': DateTime.now().toIso8601String(),
}
);
MCP 基元
MCP 协议定义了服务可实现的三个核心基元:
| 基元 | 控制方 | 描述 | 示例用途 |
|---|---|---|---|
| 提示词 | 用户控制 | 由用户选择调用的交互式模板 | 斜杠命令、菜单选项 |
| 资源 | 应用程序控制 | 由客户端应用程序管理的上下文数据 | 文件内容、API 响应 |
| 工具 | 模型控制 | 提供给大模型以执行操作的函数 | API 调用、数据更新 |
其他功能
进度与取消
需要进度信息的客户端会发送 progressToken;服务会持续报告进度,
直到调用结束(报告频率受 progressMinInterval 限制):
server.addToolWithProgress(
'longRunningOperation',
'Perform a long-running operation with progress reporting',
{'type': 'object'},
(args, {onProgress}) async {
for (var i = 0; i < 10; i++) {
// The client cancelled: stop (no response is sent for a cancelled call).
if (server.currentRequestCancelled) break;
onProgress?.call(i / 10, 'Step ${i + 1} of 10');
await Future<void>.delayed(const Duration(seconds: 1));
}
return CallToolResult(content: [TextContent(text: 'Done')]);
},
);
资源更新
// To the sessions subscribed to the URI (and, on 2026-07-28, the
// subscriptions/listen streams watching it)
server.notifyResourceUpdated('config://app');
缓存提示(2026-07-28)
server/discover、四种列表方法和 resources/read 支持 ttlMs
(Server(cacheTtl: ...))和 cacheScope(publicLists),因此客户端可以
复用结果。cacheResource / getCachedResource / invalidateCache 是独立的服务端缓存,应用程序可在处理程序中使用。
授权(HTTP)
server.enableAuthentication(
myTokenValidator, // TokenValidator: decides each token, reports its scopes and audience
requiredScopes: (method, params) =>
method == 'tools/call' && params?['name'] == 'delete' ? ['files:write'] : const [],
);
server.configureProtectedResource(
resource: 'https://api.example.com/mcp',
authorizationServers: ['https://auth.example.com'],
scopesSupported: ['files:read', 'files:write'],
);
每个 HTTP 请求都会在分发前接受检查:没有令牌 → 401;令牌无效或面向其他资源 → 401 invalid_token;
缺少作用域 → 403 insufficient_scope;每个响应都包含带有
resource_metadata 的 WWW-Authenticate。处理程序可通过
McpCaller.current 获取调用方信息。捆绑提供的 OAuthTokenValidator(RFC 7662
内省)会拒绝内省结果中未列出任何受众的令牌。
健康监控
final health = server.getHealth();
Logger('mcp_server.health').info('Running: ${health.isRunning}, '
'sessions: ${health.connectedSessions}, uptime: ${health.uptime}, '
'tools: ${health.registeredTools}, resources: ${health.registeredResources}');
server.incrementMetric('api_calls');
server.startTimer('operation_duration');
// ... perform operation
server.stopTimer('operation_duration');
错误处理
工具失败会作为结果返回,而不是协议错误:处理程序抛出异常时,
响应会包含一个 isError 结果;不符合 inputSchema 的参数也会如此
(2025-11-25 及之后版本;此前为 -32602)。未知的工具、提示词或
资源属于协议错误,错误代码由协商后的修订版指定。
处理程序也可以直接返回错误结果:
try {
// Attempt an operation
final result = await performOperation();
return CallToolResult(content: [TextContent(text: result)]);
} catch (e) {
// Return an error result
return CallToolResult(
content: [TextContent(text: 'Operation failed: ${e.toString()}')],
isError: true,
);
}
示例
请查看 示例 目录,了解完整的示例应用程序。
资源
问题与反馈
请在我们的问题跟踪器中提交任何问题、错误或功能请求。
许可证
本项目采用 MIT 许可证授权,详情请参阅 LICENSE 文件。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。