这是一个使用V8隔离环境中的代码执行来为AI代理提供高效访问SignalK海洋数据的模型上下文协议(MCP)服务器。与传统的MCP工具相比,这种方法可以减少高达**90-96%**的令牌使用量。
🚀 版本 1.0.6:现在使用代码执行引擎实现大量令牌节省!详情请参阅CHANGELOG.md。
传统的MCP工具会将所有数据返回给AI,消耗大量的令牌。而这个服务器使用了V8隔离环境(类似于Cloudflare Workers),让AI代理在返回数据之前运行JavaScript代码进行过滤。
令牌节省:
# 通过npx安装(推荐)
npx signalk-mcp-server
# 或者全局安装
npm install -g signalk-mcp-server
添加到你的Claude Desktop配置文件中(macOS路径:~/Library/Application Support/Claude/claude_desktop_config.json):
{
"mcpServers": {
"signalk": {
"command": "npx",
"args": ["signalk-mcp-server"],
"env": {
"SIGNALK_HOST": "localhost",
"SIGNALK_PORT": "3000",
"SIGNALK_TLS": "false"
}
}
}
}
AI代理查询:"我的船舶位置和最近的3个AIS目标是什么?"
代码执行(自动):
(async () => {
// 获取船舶位置
const vessel = await getVesselState();
const position = vessel.data["navigation.position"]?.value;
// 获取AIS目标并在隔离环境中过滤
const ais = await getAisTargets({ pageSize: 50 });
const closest = ais.targets.slice(0, 3);
return JSON.stringify({ position, closest });
})()
// 返回:约300个令牌(比传统工具节省97%!)
使用execute_code时,这些函数可用。重要提示:所有函数都是异步的,必须等待:
// 船舶数据
const vessel = await getVesselState();
// AIS目标(带分页和可选距离过滤)
const ais = await getAisTargets({ page: 1, pageSize: 50, maxDistance: 5000 });
// 系统报警
const alarms = await getActiveAlarms();
// 发现可用的数据路径
const paths = await listAvailablePaths();
// 获取特定路径值(字符串和对象语法都适用)
const speed = await getPathValue("navigation.speedOverGround");
const heading = await getPathValue({ path: "navigation.headingTrue" });
// 连接状态 - 也需要等待!
const status = await getConnectionStatus();
# SignalK连接(必需)
SIGNALK_HOST=localhost # SignalK服务器主机名/IP
SIGNALK_PORT=3000 # SignalK服务器端口
SIGNALK_TLS=false # 使用WSS/HTTPS(true/false)
# 执行模式(可选)
EXECUTION_MODE=code # code(默认)| tools(旧版)| hybrid
# 可选设置
SERVER_NAME=signalk-mcp-server
SERVER_VERSION=1.0.6
| 模式 | 描述 | 使用场景 |
|---|---|---|
| code(默认) | 仅V8隔离执行 | 生产使用,最大效率 |
| tools | 旧版MCP工具 | 向后兼容 |
| hybrid | 两种方法均可 | 迁移期 |
查询:"获取我的船舶名称和位置"
代码:
(async () => {
const vessel = await getVesselState();
return JSON.stringify({
name: vessel.data.name?.value,
position: vessel.data["navigation.position"]?.value
});
})()
结果:约200个令牌(比旧版工具节省2,000个令牌)
查询:"显示1海里内的船舶"
代码:
(async () => {
const ais = await getAisTargets({ pageSize: 50 });
// 在隔离环境中过滤 - 大幅节省!
const nearby = ais.targets.filter(t =>
t.distanceMeters && t.distanceMeters < 1852
);
return JSON.stringify({
total: ais.count,
nearby: nearby.length,
vessels: nearby.slice(0, 5)
});
})()
结果:约300个令牌(比旧版工具节省10,000个令牌)
查询:"有关键报警吗?"
代码:
(async () => {
const alarms = await getActiveAlarms();
const critical = alarms.alarms.filter(a =>
a.state === "alarm" || a.state === "emergency"
);
return JSON.stringify({
hasCritical: critical.length > 0,
count: critical.length,
details: critical
});
})()
结果:约100个令牌(比旧版工具节省1,000个令牌)
查询:"给我一个情况报告"
代码:
(async () => {
// 所有调用在一个执行中!
const vessel = await getVesselState();
const ais = await getAisTargets({ pageSize: 50 });
const alarms = await getActiveAlarms();
// 在隔离环境中处理一切
const closeVessels = ais.targets.filter(t =>
t.distanceMeters && t.distanceMeters < 1852
).length;
const criticalAlarms = alarms.alarms.filter(a =>
a.state === "alarm" || a.state === "emergency"
).length;
return JSON.stringify({
position: vessel.data["navigation.position"]?.value,
speed: vessel.data["navigation.speedOverGround"]?.value,
vesselsNearby: closeVessels,
criticalAlarms: criticalAlarms
});
})()
结果:约300个令牌(比3次单独工具调用节省13,000个令牌!)
# 克隆仓库
git clone <repository-url>
cd signalk-mcp-server
# 安装依赖
npm install
# 构建
npm run build
# 运行单元测试
npm run test:unit
# 开发模式运行
npm run dev
# 单元测试(快速)
npm run test:unit
# 集成测试(需要实时SignalK服务器)
npm run test:e2e
# 完整CI流水线
npm run ci
AI代理
↓
execute_code工具
↓
V8隔离沙箱(isolated-vm)
↓
SignalK SDK函数(全部异步,必须等待)
↓
SignalK绑定层(RPC风格)
↓
SignalK客户端(HTTP REST API)
↓
SignalK服务器
注意:HTTP-only模式确保每次请求都有新鲜数据。WebSocket代码保留以支持未来的流媒体功能。
src/execution-engine/isolate-sandbox.ts):安全的V8隔离执行src/bindings/signalk-binding.ts):RPC风格的方法调用src/sdk/generator.ts):从工具定义自动生成SDKsrc/signalk-client.ts):SignalK的HTTP/WebSocket客户端版本1.0.6将默认模式从hybrid更改为code。默认情况下不再提供旧版工具。
要使用旧版工具,请设置执行模式:
{
"mcpServers": {
"signalk": {
"env": {
"EXECUTION_MODE": "tools"
}
}
}
}
请参阅TOOL-MIGRATION-GUIDE.md获取完整的迁移示例。
之前(旧版):
工具:get_vessel_state
返回:所有船舶数据(约2000个令牌)
之后(代码):
(async () => {
const vessel = await getVesselState();
return JSON.stringify({
name: vessel.data.name?.value,
position: vessel.data["navigation.position"]?.value
});
})()
// 返回:约200个令牌
检查连接状态(注意:需要等待):
(async () => {
const status = await getConnectionStatus(); // 需要等待!
return JSON.stringify(status);
})()
如果暂时需要旧版工具:
EXECUTION_MODE=tools npx signalk-mcp-server
启用详细日志记录:
DEBUG=true
LOG_LEVEL=debug
欢迎贡献!请参阅CONTRIBUTING.md获取指南。
MIT许可证 - 详情请参阅LICENSE。
构建于:
🚢 享受AI驱动的海洋数据带来的航行吧!