news 2026/6/26 2:17:37

实战Demo——Hello Mcp

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
实战Demo——Hello Mcp

文章目录

    • Exercise : Hello MCP
      • 基本信息
      • 学习目标
      • 前置准备
      • 需求规格
      • 步骤指引
      • 期望输出
      • 提示
      • 扩展挑战
      • My Answer

Exercise : Hello MCP

基本信息

项目内容
难度
预估时间1-2 小时
核心技能JSON-RPC 2.0, stdin/stdout 传输, nlohmann/json
产出物一个可运行的最简 MCP 服务器 (约 100 行代码)

学习目标

  • 理解 MCP 协议中最基础的请求-响应循环
  • 掌握 stdin/stdout 行协议
  • 使用 nlohmann/json 解析和构造 JSON 消息
  • 理解 JSON-RPC 的 id 字段和 method 字段

前置准备

阅读以下文档的相关章节:

  • AI与MCP协议入门 – JSON-RPC 2.0规范和 MCP 协议基础
  • C++核心基础 – 熟悉 std::getline 和 std::cout

需求规格

实现一个最简单可能的 MCP 服务器,支持以下功能:

  1. 通过 stdin 读取 JSON-RPC 请求(每行一个请求)
  2. 支持initialize命令:返回服务器能力和版本
  3. 支持ping命令:返回空对象{}
  4. 支持tools/list命令:返回一个硬编码的工具列表(包含一个 “echo” 工具)
  5. 支持tools/call命令:如果调用 “echo”,返回用户传入的文本
  6. 通过 stdout 返回 JSON-RPC 响应(每行一个响应)
  7. 对未知命令返回 Method not found 错误

步骤指引

Step 1: 项目骨架(15分钟)

// hello_mcp.cpp#include<iostream>#include<string>#include"json.hpp"usingjson=nlohmann::json;intmain(){std::string line;while(std::getline(std::cin,line)){// 处理每一行请求if(line.empty())continue;try{autorequest=json::parse(line);autoresponse=handle_request(request);std::cout<<response.dump()<<std::endl;std::cout.flush();// 重要: 立即刷新}catch(constjson::parse_error&e){// 返回 Parse errorjson error_response;error_response["jsonrpc"]="2.0";error_response["id"]=nullptr;error_response["error"]={{"code",-32700},{"message","Parse error"}};std::cout<<error_response.dump()<<std::endl;}}return0;}

Step 2: 实现命令处理函数(20分钟)

jsonhandle_request(constjson&request){std::string method=request.value("method","");if(method=="initialize"){returnhandle_initialize(request);}elseif(method=="ping"){returnhandle_ping(request);}elseif(method=="tools/list"){returnhandle_tools_list(request);}elseif(method=="tools/call"){returnhandle_tools_call(request);}else{// Method not foundjson error;error["jsonrpc"]="2.0";error["id"]=request.value("id",nullptr);error["error"]={{"code",-32601},{"message","Method not found: "+method}};returnerror;}}

Step 3: 实现各个命令(20分钟)

jsonhandle_initialize(constjson&request){json response;response["jsonrpc"]="2.0";response["id"]=request["id"];response["result"]={{"protocolVersion","2024-11-05"},{"serverInfo",{{"name","hello-mcp"},{"version","1.0.0"}}},{"capabilities",{{"tools",{{"listChanged",false}}}}}};returnresponse;}jsonhandle_ping(constjson&request){json response;response["jsonrpc"]="2.0";response["id"]=request["id"];response["result"]=json::object();returnresponse;}jsonhandle_tools_list(constjson&request){json response;response["jsonrpc"]="2.0";response["id"]=request["id"];json echo_tool;echo_tool["name"]="echo";echo_tool["description"]="Echoes back the input text";echo_tool["inputSchema"]={{"type","object"},{"properties",{{"text",{{"type","string"},{"description","Text to echo"}}}}},{"required",json::array({"text"})}};response["result"]["tools"]=json::array({echo_tool});returnresponse;}jsonhandle_tools_call(constjson&request){std::string tool_name=request["params"]["name"];if(tool_name=="echo"){std::string text=request["params"]["arguments"]["text"];json response;response["jsonrpc"]="2.0";response["id"]=request["id"];response["result"]={{"content",json::array({{{"type","text"},{"text","Echo: "+text}}})},{"isError",false}};returnresponse;}// Tool not foundjson error;error["jsonrpc"]="2.0";error["id"]=request["id"];error["error"]={{"code",-32602},{"message","Unknown tool: "+tool_name}};returnerror;}

Step 4: 编译和测试(15分钟)

# 编译g++-std=c++17 hello_mcp.cpp -I../libs_tier_01/json/include-ohello_mcp# 测试 initializeecho'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}'|./hello_mcp# 测试 tools/listecho'{"jsonrpc":"2.0","id":2,"method":"tools/list"}'|./hello_mcp# 测试 tools/callecho'{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"echo","arguments":{"text":"Hello MCP!"}}}'|./hello_mcp# 测试未知命令echo'{"jsonrpc":"2.0","id":4,"method":"unknown"}'|./hello_mcp

期望输出

initialize 请求的输出应类似:

{"id":1,"jsonrpc":"2.0","result":{"capabilities":{"tools":{"listChanged":false}},"protocolVersion":"2024-11-05","serverInfo":{"name":"hello-mcp","version":"1.0.0"}}}

提示

  1. std::cout.flush()很关键 – stdin/stdout 是行缓冲的,不 flush 客户端收不到响应
  2. request.value("id", nullptr)安全地获取 id 字段(JSON-RPC 通知没有 id)
  3. 空行要跳过,否则json::parse("")会抛异常

扩展挑战

  • 添加prompts/list命令,返回一个硬编码的提示词
  • 添加请求日志(输出到 stderr,避免干扰 stdout 协议)
  • 支持多个工具(添加 “time” 工具返回当前时间)
  • 让你的 Hello MCP 能被 Claude Desktop 直接加载使用

My Answer

#include<iostream>#include<nlohmann/json.hpp>#include<unordered_map>usingjson=nlohmann::json;/// @brief 构造一个空的响应消息/// @param request :请求消息/// @return 空的响应消息jsonResponse(constjson&request){json response;response["jsonrpc"]="2.0";response["id"]=request["id"];response["result"]=json::object();returnresponse;}enumclassErrorCode{// JSON解析失败ParseError=-32700,// 请求对象无效InvalidRequest=-32600,// 请求的方法不存在MethodNotFound=-32601,// 方法参数无效InvalidParams=-32602,// 服务器内部错误InternalError=-32603};classServer{public:Server(){FunctionMap={{"initialize",[this](constjson&request){returnthis->InitializeImpl(request);}},{"ping",[this](constjson&request){returnthis->PingImpl(request);}},{"tools/list",[this](constjson&request){returnthis->ToolsListImpl(request);}},{"tools/call",[this](constjson&request){returnthis->ToolsCallImpl(request);}}};}voidstart(){json response,request;std::string message;while(true){if(!std::getline(std::cin,message)||message.empty()){break;// EOF or empty line, exit gracefully}try{request=json::parse(message);}catch(constjson::parse_error&e){response=Error(ErrorCode::ParseError,"null",e.what());std::cout<<response.dump()<<std::endl;continue;}std::string method;if(request.contains("method")){method=request["method"].get<std::string>();autoit=FunctionMap.find(method);if(it!=FunctionMap.end()){response=FunctionMap[method](request);std::cout<<response.dump()<<std::endl;}else{response=Error(ErrorCode::MethodNotFound,method,"Method not Found");std::cout<<response.dump()<<std::endl;}}else{response=Error(ErrorCode::InvalidRequest,request["id"].dump(),"Missing method");std::cout<<response.dump()<<std::endl;}}}private:jsonError(ErrorCode code,conststd::string&id,conststd::string&message){return{{"jsonrpc","2.0"},{"error",{{"code",static_cast<int>(code)},{"message",message}}},{"id",id}};}jsonInitializeImpl(constjson&request){json response=Response(request);if(!request.contains("params")){returnError(ErrorCode::InvalidParams,request["id"].dump(),"Missing Params");}if(request["params"].empty()){response["result"]["protocolVersion"]=json::object();}else{response["result"]["protocolVersion"]=request["params"]["protocolVersion"];}response["result"]["capabilities"]["tools"]=json::object({{"listChanged",true}});response["result"]["capabilities"]["prompts"]=json::object({{"listChanged",true}});response["result"]["capabilities"]["resources"]["subscribe"]=true;response["result"]["capabilities"]["resources"]["listChanged"]=true;response["result"]["capabilities"]["logging"]=json::object();returnresponse;}jsonPingImpl(constjson&request){returnResponse(request);}jsonToolsListImpl(constjson&request){json response=Response(request);json tool;tool["name"]="echo";tool["description"]="server echo message from user";tool["inputSchema"]=json::object();response["result"]["tools"]=json::array();response["result"]["tools"].push_back(tool);returnresponse;}jsonToolsCallImpl(constjson&request){json response=Response(request);if(!request.contains("params")){returnError(ErrorCode::InvalidParams,request["id"].dump(),"Missing Params");}if(request["params"]["name"]=="echo"){json context;context["type"]="text";context["text"]=request["params"]["arguments"];response["result"]["content"]=json::array();response["result"]["content"].push_back(context);}else{response["result"]["content"]=json::object();}returnresponse;}private:std::unordered_map<std::string,std::function<json(constjson&)>>FunctionMap;};intmain(){Server server;server.start();return0;}

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/26 2:15:23

深圳设备机箱机柜生产厂家:支持非标定制加工

在深圳&#xff0c;众多行业对设备机箱机柜的需求日益增长&#xff0c;而且越来越多的企业需要非标定制加工服务。在这样的市场背景下&#xff0c;选择一家合适的生产厂家至关重要。深圳钣金加工厂家找机汇五金&#xff0c;它就是一家在机箱机柜定制等领域表现出色的企业。行业…

作者头像 李华
网站建设 2026/6/26 2:10:43

ROS C++回调机制与Spinning原理深度解析

1. 项目概述&#xff1a;为什么Callbacks和Spinning是ROS C开发的“呼吸节奏” 刚接触ROS C编程的人&#xff0c;十有八九会在 ros::spin() 这行代码前卡住两小时——程序跑起来没反应&#xff0c;话题不回调&#xff0c;日志不打印&#xff0c; rqt_graph 里节点连着线却…

作者头像 李华
网站建设 2026/6/26 2:10:14

照片总修不出“通透感“?这款AI修图神器,一键让废片变大片!

拍完照片总觉得差点意思——光线平淡像蒙了层灰&#xff0c;肤色暗沉没有气色&#xff0c;风景照色彩寡淡毫无层次&#xff1f;手动调参数吧&#xff0c;PS里曲线、色阶、HSL一层层调&#xff0c;折腾半小时效果还不一定满意&#xff1b;套滤镜吧&#xff0c;千篇一律的预设让每…

作者头像 李华
网站建设 2026/6/26 2:09:38

AI 算法评测体系:如何量化评估大模型的算法能力?

AI 算法评测体系&#xff1a;如何量化评估大模型的算法能力&#xff1f; 一、大模型算法能力的评估困境&#xff1a;准确率不够用 当前评估 LLM 算法能力的常见做法是&#xff1a;跑 HumanEval / MBPP&#xff0c;报告 pass1。但这个数字掩盖了太多信息&#xff1a;一道题第一次…

作者头像 李华
网站建设 2026/6/26 2:09:14

AI 智能查询优化:从语义理解到执行计划自动改写

AI 智能查询优化&#xff1a;从语义理解到执行计划自动改写 一、一条慢查询的 N 种写法&#xff0c;优化器只理解语法不理解意图 同一条业务查询&#xff0c;三种 SQL 写法&#xff0c;执行时间分别为 45 秒、3 秒、0.2 秒&#xff1a; -- 写法1: 子查询嵌套, 优化器无法下推条…

作者头像 李华
网站建设 2026/6/26 2:09:09

AI 前端工具链整合:从设计稿到可交付代码的自动化工作流搭建

AI 前端工具链整合&#xff1a;从设计稿到可交付代码的自动化工作流搭建 一、前端工具链的碎片化困境——当 5 个工具拼不出 1 条流水线 一个典型的前端开发工作流涉及至少 5 个独立工具&#xff1a;Figma&#xff08;设计稿&#xff09;、Storybook&#xff08;组件文档&#…

作者头像 李华