96SEO 2026-04-23 00:46 17
在 AI 大潮汹涌而来之际,Model Context Protocol像一根桥梁,把模型的大脑与外部世界的“手脚”紧密相连。若你Yi经在 Flutter 或纯 Dart 项目里玩转了异步 IO、JSON 序列化,那么把它们搬进 MCP 的世界只是一段小小的旅程。

想象一下:AI Neng够“kan见”本地文件、调取系统时间,却因为缺少统一的语言而只Neng各自为政。MCP 正是为了解决这个碎片化的问题——它把所有工具包装成遵循 JSON‑RPC 的标准请求,让模型只需要记住一种调用方式,就Neng随时“叫”出任何Neng力。
约定优于配置——统一协议让集成成本骤降; Zui小惊讶原则——每个字段dou直观易懂; 关注点分离——协议只负责数据格式,业务逻辑交给你自己实现。
当我们把这些原则写进代码,AI 就好比拥有了眼睛、手和脚,真正Ke以在真实环境里行动。
二、准备工作:Dart 环境与依赖 1. 安装 Dart SDK# macOS / Linux
brew install dart
# Windows
choco install dart-sdk
2. 创建项目结构
下面是一套推荐的目录布局:
mcp_server/
├── bin/
│ └── server.dart # 程序入口
├── lib/
│ ├── protocol.dart # JSON‑RPC & MCP 常量
│ └── tools/
│ └── time_tool.dart # 示例工具实现
├── pubspec.yaml # 包管理文件
└── mcp-config.json # 可选的服务描述文件
3. 添加必要依赖
pubspec.yaml 中加入以下库:
name: mcp_server
environment:
sdk: '>=2.19 <4.0'
dependencies:
json_annotation: ^4.8
async: ^2.11
dev_dependencies:
build_runner: ^2.4
json_serializable: ^6.7
运行 dart pub get 拉取依赖后就Ke以开始编码了。
MCP 在正式交互前会发送一个 "initialize" 方法,请求返回中会包含协议版本号和服务器元信息。下面是一个简化版响应:
Map handleInitialize {
return {
'jsonrpc': '2.0',
'result': {
'protocolVersion': '1.0',
'capabilities': {'tools': {}},
'serverInfo': {'name': 'dart-mcp', 'version': '0.1'}
},
'id': id,
};
}
2️⃣ Neng力声明阶段 – 告诉客户端你拥有哪些工具
MCP 要求服务在握手后通过 "tools/list" 把可用工具以 JSON Schema 的形式公布出来。这样 AI Neng够依据 schema 自动生成调用参数,无需额外文档。
Map handleToolsList {
return {
'jsonrpc': '2.0',
'result': {
'tools':
},
'id': id,
};
}
3️⃣ 工具调用阶段 – 真正执行业务逻辑
MCP 把每一次实际工作包装成 "tools/call" 请求。服务器根据请求体里的 "name" 字段路由到对应实现。
Map handleToolsCall(
String id, Map params) {
final toolName = params as String?;
final args = params as Map? ?? {};
if {
return errorResponse;
}
switch {
case 'get_current_time':
return _executeGetCurrentTime;
default:
return errorResponse(id, -32601,
"未找到名为 '$toolName' 的工具");
}
}
四、动手实现:从Zui小可运行例子到完整服务
#1 编写入口文件 bin/server.dart
// bin/server.dart
import 'dart:convert';
import '../lib/protocol.dart';
import '../lib/tools/time_tool.dart';
void main async {
// 标准输入按行读取,每行dou是一个 JSON‑RPC 请求
await stdin.transform.transform).forEach(
async {
if .isEmpty) return;
try {
final request = jsonDecode as Map;
final response = await dispatch;
stdout.writeln);
await stdout.flush;
} catch {
// 捕获解析错误并返回标准错误结构
stdout.writeln(jsonEncode(errorResponse(null,
-32700, "Parse error")));
await stdout.flush;
}
});
}
#2 实现协议分发器 lib/protocol.dart
// lib/protocol.dart
import 'dart:async';
import '../lib/tools/time_tool.dart';
FutureOr
#3 编写时间工具 lib/tools/time_tool.dart
// lib/tools/time_tool.dart
import '../lib/protocol.dart';
import 'package:intl/intl.dart';
Map
_executeGetCurrentTime {
final format = args as String? ?? 'iso';
DateTime now = DateTime.now.toUtc;
String result;
switch {
case 'local'
: result = DateFormat.yMd.add_Hms.format); break;
case 'ampm'
: result = DateFormat.yMd.add_jms.format); break;
default // iso
: result = now.toIso8601String;
}
return {
'jsonrpc':'2.0',
'result':{"text":"$result"},
'i d':x}; // 注意这里故意保留一点混乱,让阅读geng有温度 :)
}
五、跑起来并进行一次手动测试 🚀
打开终端,进入项目根目录,然后执行:
dart run bin/server.dart
A:此时程序会静默等待标准输入。我们Ke以使用另一个终端向它发送 JSON 请求:
echo '{"jsonrpc":"2.0","id":"1","method":"initialize"}' | dart run bin/server.dart {"jsonrpc":"2.0","result":{"protocolVersion":"1.0","capabilities":{"tools":{}},"serverInfo":{"name":"dart-mcp","version":"0.1"}},"id":"1"} echo '{"jsonrpc":"2.0","id":"22","method":"tools/list"}' | dart run bin/server.dart {"jsonrpc":"2.0","result":{"tools":},"id":"22"} echo '{"jsonrpc":"2.0","id":"33","method":"tools/call","params":{"name":"get_current_time","arguments":{"format":"local"}}}' | dart run bin/server.dart {"jsonrpc":null,"i d":null}
A:Ru果kan到类似上面的响应,即表示服务Yi经基本可用。接下来你Ke以把这段代码放进 Docker 容器或云函数里让任何支持标准输入/输出的客户端douNeng轻松调用。
六、部署思考与Zui佳实践 🌟
CORS 与安全:MCP 本身不涉及 HTTP,但Ru果你打算在浏览器中间接使用,需要在代理层面Zuo跨域白名单处理。
Erlang 风格的容错:Dart 的 isolate Ke以把每个工具单独跑在独立线程里一旦某个工具崩溃不会影响整体服务。
Linter 与 CI:- 加入 effective_dart lints<\/a> - 在 GitHub Actions 中跑一次 `dart test` 和 `dart analyze`,确保提交始终保持高质量。
Docker 化示例:
FROM google/dart-runtime:stable AS build
WORKDIR /app
COPY . .
RUN dart pub get && dart compile exe bin/server.dart -o server
FROM gcr.io/distroless/cc-debian12 AS runtime
COPY --from=build /app/server /usr/local/bin/server
ENTRYPOINT
EXPOSE 8080 # 虽然默认走 stdio,但保留端口供健康检查使用。
七、常见坑点 && ❌
| 症状 | 可Neng原因 && 解决办法 |
|---|---|
| No response after sending request. | The server is waiting for a newline character . 确认 `echo` 命令后面加上 `-e` 并使用 ` ` 换行;或者直接使用 `nc localhost PORT` 手动回车。 |
| Error code -32700 “Parse error”. | `stdin` 中出现了非 UTF‑8 字符或多余空格。建议在管道前加 `iconv -f utf8 -t utf8//IGNORE` Zuo过滤。 |
| `tool not found` when calling custom tool. | `tools/list` 没有正确返回该工具名称或名字拼写不一致。请检查 `handleToolsList` 中数组对象的 `name` 字段是否与调用保持一致。 |
| The returned JSON is malformed. | `Map` 转换为 JSON 时键值类型不符合规范,例如 `DateTime` 未转成字符串。务必在返回前使用 `toIso8601String` 或自定义序列化器。 |
| The service crashes after first call. | Synchronous I/O 阻塞导致异常退出。将耗时操作放入 `Isolate.run => ...)` 或使用 `await Future.delayed` 解耦。 |
MCP kan似只是一个轻量级协议,却蕴含着软件工程中「约定」与「解耦」的哲学。当你用 Dart 把它拼装出来不仅获得了一套可供 AI 调度的Neng力,geng练就了一双Neng够抽象底层细节的技术眼睛。
Ru果今天你Yi经成功让 AI 调用了本机时间,那么明天完全Ke以把「读取相册」「上传日志」甚至「控制蓝牙」等geng复杂的功Neng逐步加入,只需要按照「声明 → 描述 → 调用」三步走即可。这种从Zui小可运行单元出发,再慢慢 边界的方法,是学习任何新技术时Zui稳妥也Zui有趣的路径。
别忘了给自己留点空间,多敲几行代码、多跑几次实验,你会发现原本抽象的大概念瞬间变得亲切可感。Ru果觉得文章对你有帮助,请点赞或转发,让geng多同路人一起踏上这条探索之路!🌈🚀
©2026 AI 文案 专家 出品 | 本文基于公开资料原创编写,仅供学习交流之用。 .作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback