Install
$ agentstack add mcp-aaronwander-embedmcp ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
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.
[](https://opensource.org/licenses/MIT) [](https://en.wikipedia.org/wiki/C99) [](#platform-support) [](https://modelcontextprotocol.io/)
[English](./README.md) • [简体中文](./README_zh.md)
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
``bash git clone https://github.com/AaronWander/EmbedMCP.git cd EmbedMCP ``
- Copy to your project
``bash 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 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
// 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
)
🎯 Simple Parameters
// Double parameter
MCP_PARAM_DOUBLE_DEF(
"temperature",
"Temperature in Celsius",
1 // required
)
// String parameter
MCP_PARAM_STRING_DEF(
"city",
"City name",
0 // optional
)
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](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: @AaronWander
Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: AaronWander
- Source: AaronWander/EmbedMCP
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.