MCP 服务器指南
本指南介绍了如何从你的 Finch 应用程序中暴露一个 Model Context Protocol(MCP) 端点。MCP 是一种基于 JSON-RPC 的协议,旨在让 AI 智能体和语言模型以标准化的方式发现并调用服务器端的能力——工具(tools)、资源(resources)和提示(prompts)。
Finch 的 McpServerController 同时支持两个 MCP 协议版本——2025-11-25 和 2026-07-28——并会针对每个请求自动选择使用哪一个版本进行通信(参见下方的协议版本协商)。你只需通过 McpBuilder 注册一次工具/资源/提示;无论连接的客户端使用哪个版本,控制器都能为其正确地路由请求。
Finch 与 mcp_models 包集成,提供了:
McpServerController—— 一个抽象的 Finch 控制器,自动处理所有 MCP JSON-RPC 路由。McpBuilder—— 一个声明式构建器,用于注册工具、资源、提示以及自定义方法处理程序。mcp_models—— 一个零依赖的 Dart 库,完整覆盖了 MCP2026-07-28版本的模式(schema)。
工作原理
当客户端(AI 智能体、IDE 插件等)发送一个 MCP 请求时,它会通过 HTTP 向你的 Finch 端点发送一个标准的 JSON-RPC 负载。McpServerController 会解码该负载,将其路由到正确的内置处理程序,或路由到你通过 McpBuilder 注册的处理程序,然后以 Server-Sent Events (SSE) 的形式将响应流式返回。
Client ──POST /mcp/books──► McpServerController.index()
│
▼
_dispatch(method, id, payload)
│
┌──────────────┼──────────────────┐
▼ ▼ ▼
tools/call resources/read prompts/get
│ │ │
▼ ▼ ▼
McpBuilder McpBuilder McpBuilder
.toolHandler() .resourceHandler() .promptHandler()
使用 McpBuilder 注册能力
工具
工具(tool) 是一个可供 AI 智能体调用的函数。使用 mcp.tool() 注册一个工具:
mcp.tool(
name: 'add',
description: 'Adds two integers and returns the sum.',
inputSchema: ToolSchema(
type: 'object',
properties: {
'a': Schema(type: 'integer', description: 'First operand', title: 'A'),
'b': Schema(type: 'integer', description: 'Second operand', title: 'B'),
},
required: ['a', 'b'],
),
outputSchema: ToolSchema(
type: 'object',
properties: {
'result': Schema(type: 'integer', description: 'The sum', title: 'Result'),
},
required: ['result'],
),
handler: (CallToolRequest req) async {
final args = req.params.arguments ?? {};
final sum = (args['a'] as int) + (args['b'] as int);
return CallToolResult(
content: [TextContent(text: '$sum', mimeType: 'text/plain')],
structuredContent: {'result': sum},
);
},
);
| 参数 | 类型 | 描述 |
|---|---|---|
name |
String |
唯一的工具标识符 |
description |
String |
展示给 AI 智能体的可读描述 |
inputSchema |
ToolSchema |
描述预期参数的 JSON Schema |
outputSchema |
ToolSchema? |
描述结构化输出的 JSON Schema(可选) |
handler |
Future<CallToolResult> Function(CallToolRequest) |
在 tools/call 时被调用的异步处理程序 |
资源
资源(resource) 暴露一个可通过 URI 寻址的数据源(文件、数据库记录、API 响应等):
mcp.resource(
name: 'config',
uri: 'file:///config.json',
description: 'Application configuration file.',
handler: (ReadResourceRequest req) async {
final content = await File('config.json').readAsString();
return ReadResourceResult(
contents: [
TextResourceContents(
uri: req.params.uri,
text: content,
mimeType: 'application/json',
),
],
);
},
);
| 参数 | 类型 | 描述 |
|---|---|---|
name |
String |
唯一的资源名称 |
uri |
String |
用于标识该资源的 URI |
description |
String? |
可选的描述 |
handler |
Future<ReadResourceResult> Function(ReadResourceRequest) |
在 resources/read 时被调用的处理程序 |
你也可以在
configure()内部使用rq.url('path')动态构建绝对 URI,因为configure是带着实时请求上下文被调用的。
资源模板
对于带参数的 URI(例如 file:///books/{id}),使用 mcp.resourceTemplate():
mcp.resourceTemplate(
name: 'book',
uriTemplate: 'db:///books/{id}',
description: 'Fetches a single book by ID.',
);
提示
提示(prompt) 是一个可供 AI 智能体获取的可复用消息模板:
mcp.prompt(
name: 'greet',
description: 'Returns a greeting message.',
handler: (GetPromptRequest req) async {
final name = req.params.arguments?['name'] ?? 'World';
return GetPromptResult(
messages: [
PromptMessage(
role: Role.assistant,
content: TextContent(text: 'Hello, $name!'),
),
],
);
},
);
| 参数 | 类型 | 描述 |
|---|---|---|
name |
String |
唯一的提示标识符 |
description |
String? |
可选的描述 |
handler |
Future<GetPromptResult> Function(GetPromptRequest) |
在 prompts/get 时被调用的处理程序 |
自定义方法处理程序
使用 mcp.method() 覆盖或扩展任意 JSON-RPC 方法——包括内置方法:
mcp.method(
'notifications/initialized',
(Map<String, Object?> payload) async {
// 客户端初始化通知的自定义逻辑。
return JSONRPCNotification(method: 'notifications/initialized');
},
);
通过 mcp.method() 注册的自定义处理程序,其优先级高于内置的分发器。
注册路由
将 MCP 控制器添加到你的 Finch 路由树中,并使用 Methods.ALL 以同时接受 GET 和 POST 请求:
import 'package:finch/finch_route.dart';
import 'controllers/my_mcp_controller.dart';
List<FinchRoute> getRoutes() {
return [
FinchRoute(
key: 'mcp.my_server',
path: 'mcp/my-server',
methods: Methods.ALL,
index: MyMcpController().index,
),
];
}
使用身份验证
通过提供一个 AuthController 来保护你的 MCP 端点:
import 'controllers/mcp_auth_controller.dart';
FinchRoute(
key: 'mcp.my_server',
path: 'mcp/my-server',
methods: Methods.ALL,
index: MyMcpController().index,
auth: McpAuthController(),
),
一个典型的用于 MCP 的 AuthController 会校验 Bearer API 密钥:
import 'package:finch/finch_route.dart';
class McpAuthController extends AuthController<String> {
final List<String> _allowedKeys = ['your-secret-api-key'];
@override
Future<bool> auth() async => (await checkLogin()).success;
@override
Future<bool> authApi() async {
final auth = rq.authorization;
if (auth.type == AuthType.bearer) {
return _allowedKeys.contains(auth.token);
}
return false;
}
@override
Future<String> loginForm() async => rq.renderJson(
data: {'error': 'Unauthorized'},
status: 401,
);
}
mcp_models 包
mcp_models 为 MCP 2026-07-28 模式(schema)中的每一种类型都提供了纯 Dart 类。它不涉及任何代码生成——每个类都自带:
- 一个用于序列化的
toMap()方法。 - 一个用于反序列化的具名工厂方法
TypeName.toMCP(Map)。
关键类型
| 类别 | 类型 |
|---|---|
| JSON-RPC | JSONRPCRequest, JSONRPCResultResponse, JSONRPCErrorResponse, JSONRPCNotification |
| 生命周期 | InitializeRequest, InitializeResult, InitializeResultResponse |
| 工具 | Tool, ToolSchema, Schema, CallToolRequest, CallToolResult, CallToolResultResponse, ListToolsResult, ListToolsResultResponse |
| 资源 | Resource, ResourceTemplate, ReadResourceRequest, ReadResourceResult, TextResourceContents, BlobResourceContents, ListResourcesResult, ListResourceTemplatesResult |
| 提示 | Prompt, PromptMessage, GetPromptRequest, GetPromptResult, ListPromptsResult |
| 内容 | TextContent, ImageContent, AudioContent, EmbeddedResource |
| 能力 | ServerCapabilities, ClientCapabilities, Implementation |
| 错误 | Error(JSON-RPC 错误对象) |
| 其他 | Result, EmptyResult, Role, LoggingLevel |
序列化示例
import 'package:mcp_models/mcp_models.dart';
// 构建一个 initialize 请求。
final request = InitializeRequest(
id: '1',
params: InitializeRequestParams(
protocolVersion: '2026-07-28',
capabilities: ClientCapabilities({}),
clientInfo: Implementation(name: 'my_client', version: '1.0.0'),
),
);
// 序列化为一个 Map(可直接用于 JSON 编码)。
final json = request.toMap();
// 反序列化回来。
final restored = InitializeRequest.toMCP(json);
ToolSchema 与 Schema
ToolSchema 和 Schema 都用于描述工具输入/输出校验所使用的 JSON Schema 对象:
ToolSchema(
type: 'object',
properties: {
'name': Schema(
type: 'string',
description: 'The name of the item.',
defaultValue: '',
title: 'Name',
),
'count': Schema(
type: 'integer',
description: 'How many items.',
defaultValue: 1,
title: 'Count',
),
},
required: ['name'],
)
MapMC 与 MapModel 基类
对于其序列化形式就是底层 map 本身(而不是一个包装对象)的类型,mcp_models 提供了两个基类:
MapMC<K, V>—— 继承自MCP,直接以其 map 形式进行序列化。MapModel<K, V>—— 一个不继承MCP基类的、纯粹类似 map 的模型。
ServerCapabilities 和 ClientCapabilities 都是基于 MapMC 构建的。
错误处理
在工具处理程序中抛出任意 Exception——McpServerController 会将未处理的异常包装成一个 JSONRPCErrorResponse(错误码为 -32600),并向客户端流式返回一个 400 的 SSE 响应。若需要结构化的错误传递,可以返回一个带有 isError: true 的 CallToolResult:
handler: (req) async {
final id = req.params.arguments?['id'];
if (id == null) {
return CallToolResult(
isError: true,
content: [TextContent(text: 'Missing required argument: id')],
);
}
// ...
},