A minimal, embeddable C++ JSON‑RPC 2.0 server core providing:
- Tool registration and dispatch (
mcp::Tool
/mcp::ToolRegistry
) - Thread‑pool based concurrency
- Structured logging callbacks
- Two transports:
- Stdio (NDJSON line‑delimited)
- HTTP + Server‑Sent Events (SSE):
POST /rpc
returns the JSON‑RPC response synchronously, andGET /events
broadcasts responses, progress, and heartbeats via SSE
Version: 0.1.0 (protocol placeholder 2024‑09‑01)
- JSON‑RPC 2.0:
initialize
,tools/list
,tools/call
(legacy aliaseslistTools
/callTool
supported) - Pluggable tools and execution context (with progress callback)
- Thread pool for concurrent execution
- Optional HTTP + SSE transport (ON by default)
- Periodic SSE heartbeat to keep the stream warm
- CMake ≥ 3.16, C++14 compiler
- Headers:
- nlohmann/json (bundled:
include/nlohmann/json.hpp
) - cpp‑httplib (bundled:
include/httplib.h
; required when HTTP/SSE is enabled)
- nlohmann/json (bundled:
- Linux/macOS supported (examples use csh shell)
mkdir -p build
cd build
cmake .. -DCMAKE_BUILD_TYPE=Release -DMCP_WITH_HTTP=ON -DMCP_BUILD_EXAMPLE=ON
cmake --build . -j4
CMake options:
-DMCP_ENABLE_ASAN=ON
enable AddressSanitizer (debug memory issues)-DMCP_WITH_HTTP=ON|OFF
enable/disable HTTP + SSE transport (default ON)-DMCP_BUILD_EXAMPLE=ON|OFF
build example executables (default ON)
Artifacts:
- Static library:
build/libmcp.a
- Examples:
build/mcp_stdio_server
,build/mcp_sse_server
(when HTTP enabled)
Install (optional):
cmake --install build --prefix /your/prefix
Run the csh scripts to build and start the demos:
chmod +x examples/scripts/run_sse_demo.csh
examples/scripts/run_sse_demo.csh
Stdio demo:
chmod +x examples/scripts/run_stdio_demo.csh
examples/scripts/run_stdio_demo.csh
Environment variables used by demos:
MCP_PORT
(default 8080)MCP_HOST
(default 127.0.0.1)MCP_REPO_ROOT
(optional; helps scripts locate the repo root)
# Build if needed
mkdir -p build
cd build
cmake .. -DMCP_WITH_HTTP=ON -DMCP_BUILD_EXAMPLE=ON
cmake --build . -j4
# Start server
./mcp_sse_server &
set server_pid = $!
# Subscribe to events (you can use another terminal)
curl -N http://127.0.0.1:8080/events &
# Issue a request (sync HTTP response; also broadcast on SSE)
curl -s -X POST -H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":"list1","method":"tools/list"}' \
http://127.0.0.1:8080/rpc
# Stop server
kill $server_pid
# Build and run stdio server (from repo root)
mkdir -p build
cd build
cmake .. -DMCP_BUILD_EXAMPLE=ON
cmake --build . -j4
# Send NDJSON lines
printf '%s\n' \
'{"jsonrpc":"2.0","id":"1","method":"initialize","params":{}}' \
'{"jsonrpc":"2.0","id":"2","method":"tools/list"}' \
'{"jsonrpc":"2.0","id":"3","method":"tools/call","params":{"name":"echo","arguments":{"text":"hi from stdio"}}}' \
| ./mcp_stdio_server
POST /rpc
:- Accepts single request or batch (array), returns synchronous JSON‑RPC response (object or array)
- The same payload is broadcast on SSE with event type
response
GET /events
:- SSE stream emitting:
response
: JSON‑RPC responseprogress
: long‑running tool progress ({id,current,total,message}
)heartbeat
: periodic heartbeat ({ts}
)
- SSE stream emitting:
Requests:
{"jsonrpc":"2.0","id":"1","method":"initialize","params":{}}
{"jsonrpc":"2.0","id":"2","method":"tools/list"}
{"jsonrpc":"2.0","id":"3","method":"tools/call","params":{"name":"echo","arguments":{"text":"hi"}}}
{"jsonrpc":"2.0","id":"4","method":"tools/call","params":{"name":"upper","arguments":{"text":"hello mcp"}}}
{"jsonrpc":"2.0","id":"5","method":"tools/call","params":{"name":"sum","arguments":[1,2,3,4]}}
{"jsonrpc":"2.0","id":"6","method":"tools/call","params":{"name":"time","arguments":{}}}
{"jsonrpc":"2.0","id":"7","method":"tools/call","params":{"name":"env","arguments":{}}}
Example tools/list
response:
{"jsonrpc":"2.0","id":"2","result":{"tools":[{"name":"echo","description":"..."},{"name":"slow","description":"..."},{"name":"getWeather","description":"..."}]}}
Directory: examples/client/
, main script: client_fast.py
(HTTP + SSE adapter).
cd examples/client
python3 -m venv venv
source venv/bin/activate.csh
pip install -r requirements.txt
setenv MCP_HOST 127.0.0.1
setenv MCP_PORT 8080
python client_fast.py --debug --sse-wait 5
#include "mcp/server.hpp"
#include "mcp/tool.hpp"
int main(){
mcp::McpServer srv;
mcp::Tool echo{"echo","Echo text", nlohmann::json::object(),
[](const nlohmann::json& args, mcp::ToolContext&){
nlohmann::json r; if(args.contains("text")) r["text"]=args["text"]; return r; }
};
srv.add_tool(echo);
srv.run();
return 0;
}
include/mcp/*.hpp
core headers (server.hpp
,tool.hpp
,transport_http.hpp
, etc.)src/
implementation (incl. optionaltransport_http.cpp
)examples/stdio_server.cpp
stdio sampleexamples/sse_server.cpp
HTTP + SSE sampleexamples/scripts/
demo scripts (SSE and stdio)examples/client/
Python example client
- Missing
httplib.h
: ensure it’s available underinclude/
or system include path; required when building with-DMCP_WITH_HTTP=ON
- No SSE progress: try the
slow
sample tool - Client timeouts:
/rpc
is synchronous; also ensure SSE connected; run client with--debug --sse-wait 5
- Port in use: change
MCP_PORT
or stop the conflicting process - csh string issues: scripts use
${VAR}
form to avoidBad : modifier
Sample code only; no authn/authz, rate limiting, or sandboxing. Add controls in your integration.
This repository is example‑oriented; honor third‑party licenses (nlohmann/json MIT, cpp‑httplib MIT).
- Cancellation & cooperative stop
- Richer progress / partial results
- JSON Schema validation
- Additional transports (Unix domain sockets, WebSockets)
- Pluggable auth