嵌入式MCP-嵌入式MCP服务器库
一个轻量级的C库,用于创建MCP(模型上下文协议)服务器,将现有的C函数转换为AI可访问的工具,只需最小的代码更改。
   
为什么要嵌入MCP?
EmbeddedMCP弥合了现有C代码库和现代AI系统之间的差距。EmbedMCP允许您通过标准化的模型上下文协议(MCP)将它们暴露给AI模型,而不是重写经过战斗测试的C函数,只需进行最小的代码更改。
主要特点
- 🚀 简单集成:复制一个文件夹,包括一个头文件
- ⚡ 高性能:直接调用C函数,开销最小
- 🔧 交叉平台的:通过通用HAL在15个以上的平台上运行
- 📦 零依赖:无外部要求的独立库
- 🎯 两种注册方式:简单功能的魔术宏,复杂功能的完全控制
- 🌐 多个传输:针对不同用例的流式HTTP和STDIO支持
- 🧠 智能内存管理:具有明确所有权规则的自动清理
- 📊 阵列支持:处理简单参数和复杂数据结构
快速开始
安装
- 下载嵌入式MCP
git clone https://github.com/AaronWander/EmbedMCP.git
cd EmbedMCP- 复制到您的项目
cp -r embed_mcp/ your_project/基本用法
#include "embed_mcp/embed_mcp.h"
// Your business function
double add_numbers(double a, double b) {
return a + b;
}
// Generate wrapper with macro
EMBED_MCP_WRAPPER(add_wrapper, add_numbers, DOUBLE, DOUBLE, a, DOUBLE, b)
int main() {
embed_mcp_config_t config = {
.name = "MathServer",
.version = "1.0.0",
.instructions = "Simple math operations server",
.port = 8080
};
embed_mcp_server_t *server = embed_mcp_create(&config);
// Register function
const char* names[] = {"a", "b"};
const char* descs[] = {"First number", "Second number"};
mcp_param_type_t types[] = {MCP_PARAM_DOUBLE, MCP_PARAM_DOUBLE};
embed_mcp_add_tool(server, "add", "Add two numbers",
names, descs, types, 2, MCP_RETURN_DOUBLE, add_wrapper, NULL);
embed_mcp_run(server, EMBED_MCP_TRANSPORT_HTTP);
embed_mcp_destroy(server);
return 0;
}构建并运行
# Build
make
# Run Streamable HTTP server
./bin/mcp_server --transport http --port 8080
# Or run STDIO server
./bin/mcp_server --transport stdio功能注册
EmbeddedMCP支持两种注册方法:
严格参数访问(建议用于稳健验证)
此外 get_* 助手,你可以使用严格 try_get_* 用于区分缺失/无效输入和实际零/空值的访问器。
int64_t user_id;
if (!params->try_get_int(params, "user_id", &user_id)) {
// handle missing or invalid type
}
double* values = NULL;
size_t count = 0;
if (params->try_get_double_array(params, "values", &values, &count)) {
// use values, then free(values)
}简单功能(推荐)
// Business function
double add_numbers(double a, double b) {
return a + b;
}
// One-line wrapper generation
EMBED_MCP_WRAPPER(add_wrapper, add_numbers, DOUBLE, DOUBLE, a, DOUBLE, b)
// Register
const char* names[] = {"a", "b"};
const char* descs[] = {"First number", "Second number"};
mcp_param_type_t types[] = {MCP_PARAM_DOUBLE, MCP_PARAM_DOUBLE};
embed_mcp_add_tool(server, "add", "Add two numbers",
names, descs, types, 2, MCP_RETURN_DOUBLE, add_wrapper, NULL);数组函数(高级)
// Business function
double sum_numbers(double* numbers, size_t count) {
double sum = 0.0;
for (size_t i = 0; i get_double_array(params, "numbers", &count);
double result_val = sum_numbers(numbers, count);
free(numbers); // Clean up
double* result = malloc(sizeof(double));
*result = result_val;
return result;
}
// Register with array parameter
mcp_param_desc_t params[] = {
MCP_PARAM_ARRAY_DOUBLE_DEF("numbers", "Array of numbers", "A number", 1)
};
embed_mcp_add_tool(server, "sum", "Sum numbers", params, NULL, NULL, 1,
MCP_RETURN_DOUBLE, sum_wrapper, NULL);复杂嵌套输入(基于模式)
使用 embed_mcp_add_tool_with_schema 当您的工具需要嵌套对象、对象数组或严格的模式约束时。
cJSON* submit_order_with_schema(const cJSON *args) {
const cJSON *customer = cJSON_GetObjectItem(args, "customer");
const cJSON *name = customer ? cJSON_GetObjectItem(customer, "name") : NULL;
const cJSON *items = cJSON_GetObjectItem(args, "items");
cJSON *result = cJSON_CreateObject();
cJSON_AddStringToObject(result, "status", "accepted");
cJSON_AddStringToObject(result, "customer",
(name && cJSON_IsString(name)) ? cJSON_GetStringValue(name) : "unknown");
cJSON_AddNumberToObject(result, "itemCount", cJSON_IsArray(items) ? cJSON_GetArraySize(items) : 0);
return result;
}
const char *schema_json =
"{\"type\":\"object\",\"properties\":{"
"\"customer\":{\"type\":\"object\",\"properties\":{\"name\":{\"type\":\"string\"}},\"required\":[\"name\"],\"additionalProperties\":false},"
"\"items\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"properties\":{\"sku\":{\"type\":\"string\"},\"qty\":{\"type\":\"integer\"}},\"required\":[\"sku\",\"qty\"],\"additionalProperties\":false}}"
"},\"required\":[\"customer\",\"items\"],\"additionalProperties\":false}";
cJSON *schema = cJSON_Parse(schema_json);
embed_mcp_add_tool_with_schema(server, "submit_order", "Submit nested order payload", schema, submit_order_with_schema);
cJSON_Delete(schema);内存管理
EmbeddedMCP自动处理大部分内存管理:
- 参数:函数返回后,所有输入参数都会自动释放
- JSON处理:请求/响应解析和清理在内部处理
- 数组:动态数组会自动分配和释放
- 错误处理:即使发生错误,内存也会被正确清理
你的责任:字符串返回值必须使用 malloc():
char* get_weather(const char* city) {
char* result = malloc(200); // ✅ EmbedMCP will call free()
sprintf(result, "Weather for %s: Sunny", city);
return result;
}服务器模式
流式HTTP传输(示例)
./my_server --transport http --port 8080- 多个并发客户端
- 会话管理
MCP-Session-Id标头 - 协议版本协商
MCP-Protocol-Version标头 - Web应用程序后端
- 开发和测试
STDIO传输
对于像Claude Desktop这样的MCP客户端:
./my_server --transport stdio --quiet- Claude桌面集成
- AI辅助工具
- 命令行工作流
- 单客户端通信
--quiet抑制业务调试日志,以保持协议工具的stdio输出更清晰
🔧 参数定义宏
用于复杂参数定义的强大宏
📊 数组参数
// Double array
MCP_PARAM_ARRAY_DOUBLE_DEF(
"numbers",
"Array of numbers",
"A numeric value",
1 // required
)
// String array
MCP_PARAM_ARRAY_STRING_DEF(
"items",
"List of items",
"An item name",
1 // required
)
// Bool array
MCP_PARAM_ARRAY_BOOL_DEF(
"flags",
"List of boolean flags",
"A boolean value",
0 // optional
)🎯 简单参数
// Double parameter
MCP_PARAM_DOUBLE_DEF(
"temperature",
"Temperature in Celsius",
1 // required
)
// String parameter
MCP_PARAM_STRING_DEF(
"city",
"City name",
0 // optional
)示例服务器
验证错误现在包括更清晰的字段级详细信息(例如:缺少必填字段、意外字段或无效的嵌套字段类型)。
烟雾回归可通过以下方式获得:
make test-smoke包含的示例演示了所有EmbeddedMCP功能:
# Build and run example
make && ./bin/mcp_server --transport stdio可用演示工具
| 工具 | 参数 | 说明 | 示例 |
|---|---|---|---|
add | a: number, b: number | 加两个数字 | add(10, 20) → 30 |
sum_numbers | numbers: number[] | 数字求和数组 | sum_numbers([1,2,3]) → 6 |
join_strings | strings: string[], separator: string | 连接字符串数组 | join_strings(["a","b"], ",") → "a,b" |
weather | city: string | 获取天气信息 | weather("济南") → 天气预报 |
calculate_score | base_points: int, grade: string, multiplier: number | 用奖金计算分数 | calculate_score(80, "A", 1.2) → 120 |
submit_order | customer: object, items: object[], priority?: int | 基于模式的嵌套有效载荷示例 | submit_order({...}) → 公认结果 |
MCP检验员测试
- 启动服务器:
./bin/mcp_server --transport http --port 8080 - 打开 MCP检查员
- 连接到:
http://localhost:8080/mcp - 测试可用工具
平台支持
EmbeddedMCP旨在实现嵌入式系统之间的最大可移植性:
嵌入式系统
- 实时操作系统:FreeRTOS、Zephyr、ThreadX、embOS
- 微控制器:STM32、ESP32、北欧nRF系列
- 嵌段共聚物:树莓派、BeagleBone、橙派
需求
- 最小:C99编译器,64KB RAM,100KB闪存
- 推荐:512KB RAM,适用于复杂应用程序
- 依赖项:无(独立)
用例
工业物联网
- 传感器数据处理:将C传感器驱动程序暴露于AI模型
- 设备监测:机器数据的实时分析
- 预测性维护:人工智能驱动的故障预测
嵌入式人工智能
- 边缘计算:在嵌入式设备上运行AI推理
- 智能设备:语音助手、智能摄像头、物联网中心
- 机器人学:人工智能控制的机器人系统
故障排除
常见问题
构建错误:
# Missing dependencies
make deps
# Clean build
make clean && make运行时错误:
# Enable debug logging
./bin/mcp_server --transport stdio --debug
# Check memory usage
valgrind ./bin/mcp_server --transport stdio连接问题:
- 确保正确的传输模式(流式HTTP与STDIO)
- 检查Streamable HTTP模式的防火墙设置
- 验证MCP客户端配置和协议版本标头
贡献
目前,我们不接受外部代码贡献(PR)。
欢迎提交bug报告和功能请求。
开发设置
# Clone repository
git clone https://github.com/AaronWander/EmbedMCP.git
cd EmbedMCP
# Build debug version
make debug
# Run tests
make test许可证
此项目根据MIT许可证获得许可-请参阅 许可证 文件以获取详细信息。
👥 社区与支持
社区资源
- 贡献:目前,我们不接受外部代码贡献(PR)。
- 欢迎提交bug报告和功能请求。
- 🐛 通过以下方式报告错误
- 💡 建议中的功能 讨论
- 💬 加入我们 Discord 的中文翻译是“不和谐”或“纷争”。 实时社区支持
保持联系
- 🐦 推特: @Aaron_Warder
