一个基于 C++17 实现的轻量 MCP Server,支持 Tools、Resources、Prompts、HTTP JSON-RPC、stdio 模式,以及基于 SSE 的实时事件流。
项目里还包含一个 Python 客户端示例 client/ollama_mcp_client.py,可以把本地 Ollama 模型和 MCP Server 串起来,形成一个最小可用的“LLM + 工具调用”智能体闭环。
- 支持 MCP 基础能力:
tools/listtools/callresources/listresources/readprompts/listprompts/get
- 支持三种运行模式:
httpstdioboth
- 支持 SSE 实时事件推送:
/sse/events/sse/tool_calls
- 内置工具:
echocalculateget_timeget_weatherwrite_file
- 内置资源:
system://infoconfig://server
- 内置 Prompt:
code_review
- 提供 Ollama Python 客户端示例,支持:
- 工具发现
- 工具调用
- SSE 工具事件监控
- 自然语言问答
MCP_Server/
├── main.cpp
├── client/
│ └── ollama_mcp_client.py
├── config/
│ └── server.json
├── src/
│ ├── config/
│ ├── json_rpc/
│ ├── logger/
│ └── mcp/
├── tests/
├── conanfile.txt
└── CMakeLists.txt
- C++17
- CMake
- Conan
nlohmann_jsonspdlogcpp-httpliblibcurlgtest- Python
requests - Ollama
这个项目的核心链路可以理解成:
用户
↓
ollama_mcp_client.py
↓
Ollama / 本地 LLM
↓
判断是否调用工具
↓
MCP Server
↓
具体工具执行
↓
工具结果返回
↓
LLM 组织最终回复
其中:
main.cpp负责注册工具、资源、Prompt,并启动 HTTP/stdio 服务src/json_rpc/负责 JSON-RPC 请求分发与序列化src/mcp/负责 MCP 核心类型和工具/资源/Prompt 的注册与调用client/ollama_mcp_client.py是一个带工具调用的简单 Agent Client- SSE 是实时事件流通道,当前主要用于工具调用状态观测,而不是主业务返回通道
输入一个字符串,原样返回。
请求参数:
{
"message": "Hello"
}支持基础四则运算,当前支持:
addsubtractmultiplydivide
请求参数:
{
"operation": "add",
"a": "10",
"b": "20"
}说明:
a和b既支持 JSON number,也支持数字字符串- 除零会返回工具错误
返回当前系统时间。
根据城市名查询天气,使用 Open-Meteo Geocoding API + Forecast API。
当前返回的是封装后的 JSON 文本,而不是上游原始响应。返回字段类似:
{
"city": "Zhanjiang",
"country": "China",
"observation_time": "2026-04-19T15:00",
"temperature_c": 28.7,
"condition": "Overcast",
"humidity_percent": 72,
"wind_speed_kmh": 11.2,
"wind_direction_degrees": 136,
"wind_direction": "SE",
"weather_code": 3,
"source": "Open-Meteo Geocoding API + Forecast API"
}说明:
- 推荐优先使用英文城市名,例如
Zhanjiang - 当前中文城市名不一定能稳定命中地理编码
向指定路径写入内容。
请求参数:
{
"path": "/tmp/demo.txt",
"content": "hello"
}返回系统信息文本。
返回当前服务器配置 JSON。
输入代码和语言,返回一个代码审查 Prompt 消息数组。
POST /jsonrpc
GET /sse/eventsGET /sse/tool_calls
GET /health
GET /
默认配置文件在 config/server.json:
{
"server": {
"port": 8080
},
"logging": {
"log_file_path": "../logs/server.log",
"log_level": "debug",
"log_file_size": 52428800,
"log_file_count": 5,
"log_console_output": true
}
}项目依赖定义在 conanfile.txt。
conan install . --output-folder=build/Debug --build=missing -s build_type=Debugcmake -S . -B cmake-build-debug -DCMAKE_BUILD_TYPE=Debug
cmake --build cmake-build-debug如果你使用的是 CLion,也可以直接用 IDE 打开项目并构建。
可执行文件示例:
/Users/joe/CLionProjects/MCP_Server/cmake-build-debug/MCP_Server --mode http --port 8080/Users/joe/CLionProjects/MCP_Server/cmake-build-debug/MCP_Server --mode stdio/Users/joe/CLionProjects/MCP_Server/cmake-build-debug/MCP_Server --mode both --port 8080/Users/joe/CLionProjects/MCP_Server/cmake-build-debug/MCP_Server --helpcurl -s http://127.0.0.1:8080/jsonrpc \
-H 'Content-Type: application/json' \
-d '{
"jsonrpc":"2.0",
"id":1,
"method":"tools/list",
"params":{}
}' | jqcurl -s http://127.0.0.1:8080/jsonrpc \
-H 'Content-Type: application/json' \
-d '{
"jsonrpc":"2.0",
"id":1,
"method":"tools/call",
"params":{
"name":"get_weather",
"arguments":{"city":"Zhanjiang"}
}
}' | jq只看封装后的天气字段:
curl -s http://127.0.0.1:8080/jsonrpc \
-H 'Content-Type: application/json' \
-d '{
"jsonrpc":"2.0",
"id":1,
"method":"tools/call",
"params":{
"name":"get_weather",
"arguments":{"city":"Zhanjiang"}
}
}' | jq -r '.result.content[0].text | fromjson'curl -s http://127.0.0.1:8080/jsonrpc \
-H 'Content-Type: application/json' \
-d '{
"jsonrpc":"2.0",
"id":1,
"method":"tools/call",
"params":{
"name":"calculate",
"arguments":{
"operation":"add",
"a":"10",
"b":"20"
}
}
}' | jqcurl -s http://127.0.0.1:8080/jsonrpc \
-H 'Content-Type: application/json' \
-d '{
"jsonrpc":"2.0",
"id":1,
"method":"resources/read",
"params":{"url":"config://server"}
}' | jqcurl -s http://127.0.0.1:8080/jsonrpc \
-H 'Content-Type: application/json' \
-d '{
"jsonrpc":"2.0",
"id":1,
"method":"prompts/get",
"params":{
"name":"code_review",
"arguments":{
"language":"cpp",
"code":"int main(){return 0;}"
}
}
}' | jqcurl -N http://127.0.0.1:8080/sse/eventscurl -N http://127.0.0.1:8080/sse/tool_calls/sse/tool_calls 会实时输出类似事件:
{"type":"tool_call_start","tool":"get_weather","arguments":{"city":"Zhanjiang"}}
{"type":"tool_call_end","tool":"get_weather","success":true}示例客户端在 client/ollama_mcp_client.py。
它做的事情包括:
- 从 MCP Server 拉取工具列表
- 转成 Ollama 的 tool calling 格式
- 接收模型返回的
tool_calls - 调用 MCP Server 的
tools/call - 把工具结果再喂回模型
- 通过 SSE 监听工具执行事件
先确保:
- Ollama 已启动
- 本地已经有可用模型
- MCP Server 正在运行
例如:
ollama serve
ollama pull qwen3.5:4bpython3 /Users/joe/CLionProjects/MCP_Server/client/ollama_mcp_client.py默认模型是 qwen3.5:4b。也可以通过环境变量覆盖:
OLLAMA_MODEL='qwen3.5:4b' python3 /Users/joe/CLionProjects/MCP_Server/client/ollama_mcp_client.py帮我查看一下 Zhanjiang 的天气
calculate "add" "10" "20"
tools
当前仓库包含的自动化测试主要覆盖:
- 配置加载
- 日志初始化
运行测试:
ctest --test-dir /Users/joe/CLionProjects/MCP_Server/cmake-build-debug --output-on-failure- 天气查询更适合英文城市名,中文地名匹配仍可能失败
ollama_mcp_client.py目前更偏向单轮工具调用示例,还不是完整的多步 Agent Loop- 天气工具依赖外部 Open-Meteo API,离线环境不可用
write_file目前没有额外的路径安全限制,使用时需要自行注意- 测试覆盖面还不完整,天气工具和 HTTP 链路的自动化测试仍可继续补充
- 多步工具循环
- 工具失败后的自动重试
- 更完整的 Agent 状态管理
- 更好的中文城市名归一化
- 天气工具单元测试和集成测试
- 前端可视化监控面板

