EmbedMCP
Provides easy-to-use kits that allow you to quickly create MCP servers Any embedded devices
Ask AI about EmbedMCP
Powered by Claude ยท Grounded in docs
I know everything about EmbedMCP. Ask me about installation, configuration, usage, or troubleshooting.
0/500
Reviews
Documentation
EmbedMCP - Embedded MCP Server Library
A lightweight C library for creating MCP (Model Context Protocol) servers that transforms your existing C functions into AI-accessible tools with minimal code changes.
English โข ็ฎไฝไธญๆ
Why EmbedMCP?
EmbedMCP bridges the gap between your existing C codebase and modern AI systems. Instead of rewriting your battle-tested C functions, EmbedMCP lets you expose them to AI models through the standardized Model Context Protocol (MCP) with minimal code changes.
Key Features
- ๐ Simple Integration: Copy one folder, include one header file
- โก High Performance: Direct C function calls with minimal overhead
- ๐ง Cross-Platform: Runs on 15+ platforms via Universal HAL
- ๐ฆ Zero Dependencies: Self-contained library with no external requirements
- ๐ฏ Two Registration Methods: Magic macros for simple functions, full control for complex ones
- ๐ Multiple Transports: Streamable HTTP and STDIO support for different use cases
- ๐ง Smart Memory Management: Automatic cleanup with clear ownership rules
- ๐ Array Support: Handle both simple parameters and complex data structures
Quick Start
Installation
-
Download EmbedMCP
git clone https://github.com/AaronWander/EmbedMCP.git cd EmbedMCP -
Copy to your project
cp -r embed_mcp/ your_project/
Basic Usage
#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 and Run
# Build
make
# Run Streamable HTTP server
./bin/mcp_server --transport http --port 8080
# Or run STDIO server
./bin/mcp_server --transport stdio
Function Registration
EmbedMCP supports two registration approaches:
Strict Parameter Access (Recommended for robust validation)
In addition to get_* helpers, you can use strict try_get_* accessors to distinguish between missing/invalid input and real zero/empty values.
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)
}
Simple Functions (Recommended)
// 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);
Array Functions (Advanced)
// Business function
double sum_numbers(double* numbers, size_t count) {
double sum = 0.0;
for (size_t i = 0; i < count; i++) {
sum += numbers[i];
}
return sum;
}
// Manual wrapper (handles memory management)
void* sum_wrapper(mcp_param_accessor_t* params, void* user_data) {
size_t count;
double* numbers = params->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);
Complex Nested Input (Schema-Based)
Use embed_mcp_add_tool_with_schema when your tool needs nested objects, arrays of objects, or strict schema constraints.
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);
Memory Management
EmbedMCP handles most memory management automatically:
- Parameters: All input parameters are automatically freed after your function returns
- JSON processing: Request/response parsing and cleanup is handled internally
- Arrays: Dynamic arrays are automatically allocated and freed
- Error handling: Memory is properly cleaned up even when errors occur
Your responsibility: String return values must use malloc():
char* get_weather(const char* city) {
char* result = malloc(200); // โ
EmbedMCP will call free()
sprintf(result, "Weather for %s: Sunny", city);
return result;
}
Server Modes
Streamable HTTP Transport (Example)
./my_server --transport http --port 8080
- Multiple concurrent clients
- Session management with
MCP-Session-Idheaders - Protocol version negotiation via
MCP-Protocol-Versionheaders - Web application backends
- Development and testing
STDIO Transport
For MCP clients like Claude Desktop:
./my_server --transport stdio --quiet
- Claude Desktop integration
- AI assistant tools
- Command-line workflows
- Single client communication
--quietsuppresses business debug logs to keep stdio output cleaner for protocol tooling
๐ง Parameter Definition Macros
Powerful macros for complex parameter definitions
๐ Array Parameters
|
๐ฏ Simple Parameters
|
Example Server
Validation errors now include clearer field-level details (for example: missing required field, unexpected field, or invalid nested field type).
Smoke regression is available via:
make test-smoke
The included example demonstrates all EmbedMCP features:
# Build and run example
make && ./bin/mcp_server --transport stdio
Available Demo Tools
| Tool | Parameters | Description | Example |
|---|---|---|---|
add | a: number, b: number | Add two numbers | add(10, 20) โ 30 |
sum_numbers | numbers: number[] | Sum array of numbers | sum_numbers([1,2,3]) โ 6 |
join_strings | strings: string[], separator: string | Join string array | join_strings(["a","b"], ",") โ "a,b" |
weather | city: string | Get weather info | weather("ๆตๅ") โ Weather report |
calculate_score | base_points: int, grade: string, multiplier: number | Calculate score with bonus | calculate_score(80, "A", 1.2) โ 120 |
submit_order | customer: object, items: object[], priority?: int | Schema-based nested payload example | submit_order({...}) โ accepted result |
Testing with MCP Inspector
- Start the server:
./bin/mcp_server --transport http --port 8080 - Open MCP Inspector
- Connect to:
http://localhost:8080/mcp - Test the available tools
Platform Support
EmbedMCP is designed for maximum portability across embedded systems:
Embedded Systems
- RTOS: FreeRTOS, Zephyr, ThreadX, embOS
- MCUs: STM32, ESP32, Nordic nRF series
- SBCs: Raspberry Pi, BeagleBone, Orange Pi
Requirements
- Minimum: C99 compiler, 64KB RAM, 100KB flash
- Recommended: 512KB RAM for complex applications
- Dependencies: None (self-contained)
Use Cases
Industrial IoT
- Sensor data processing: Expose C sensor drivers to AI models
- Equipment monitoring: Real-time analysis of machine data
- Predictive maintenance: AI-driven failure prediction
Embedded AI
- Edge computing: Run AI inference on embedded devices
- Smart devices: Voice assistants, smart cameras, IoT hubs
- Robotics: AI-controlled robotic systems
Troubleshooting
Common Issues
Build errors:
# Missing dependencies
make deps
# Clean build
make clean && make
Runtime errors:
# Enable debug logging
./bin/mcp_server --transport stdio --debug
# Check memory usage
valgrind ./bin/mcp_server --transport stdio
Connection issues:
- Ensure correct transport mode (Streamable HTTP vs STDIO)
- Check firewall settings for Streamable HTTP mode
- Verify MCP client configuration and protocol version headers
Contributing
At this time, weโre not accepting external code contributions (PRs).
Issues are welcome for bug reports and feature requests.
Development Setup
# Clone repository
git clone https://github.com/AaronWander/EmbedMCP.git
cd EmbedMCP
# Build debug version
make debug
# Run tests
make test
License
This project is licensed under the MIT License - see the LICENSE file for details.
๐ฅ Community & Support
Community Resources
-
Contributing: At this time, weโre not accepting external code contributions (PRs).
-
Issues are welcome for bug reports and feature requests.
-
๐ Report bugs via GitHub Issues
-
๐ก Suggest features in Discussions
-
๐ฌ Join our Discord for real-time community support
Stay Connected
- ๐ฆ Twitter: @Aaron_Wander
