MCP项目笔记二(server/main)
本文旨在梳理 main.cpp 在 MCP Server 中承担的核心职责,明确服务启动阶段的关键执行路径,包括 程序初始化、插件加载、MCP 方法注册 以及 传输层启动 四个部分。
从工程实现角度看,main.cpp 本身并不负责具体工具逻辑,而是作为整个服务的装配入口,完成以下目标:
- 初始化服务器运行环境,包括服务名称、插件目录、日志目录与运行模式;
- 加载外部插件并建立插件与服务端之间的通知通道;
- 将 MCP 标准方法注册为可执行回调,实现协议层到插件层的映射;
- 选择并启动传输层,使服务器进入正式对外服务状态。
程序模块
围绕 main.cpp 的实现逻辑,可以将整个 MCP Server 的启动主线归纳为以下四个模块。
1. 程序启动流程

功能定位:完成服务运行前的基础环境准备,包括核心对象创建、参数解析、信号处理与日志初始化。
- 基础对象初始化:程序进入
main后,首先初始化服务器名称、插件目录、日志目录、输出级别等运行变量,并创建PluginsLoader与Server两个核心对象。其中PluginsLoader负责后续插件扫描与加载,Server负责承载 MCP 回调注册与请求处理。 - 信号处理机制:通过注册
SIGINT对应的stop_handler,当用户触发Ctrl+C时,程序会调用server->Stop()执行优雅退出,而不是直接终止进程。 - 命令行参数解析:使用
popl解析运行参数,支持服务器名称、插件目录、日志目录、详细输出模式以及 SSE 传输模式等配置项。 - 日志系统初始化:程序根据当前 UTC 时间生成日志文件名,并使用
AixLog初始化日志输出系统,记录启动版本、Transport 信息及运行状态。
2. 加载插件
功能定位:通过插件加载器扫描插件目录,动态注入工具、Prompt 与资源能力,并为插件建立服务端通知通道。
- 扫描与加载:
main.cpp调用loader->LoadPlugins(plugins_directory)扫描插件目录并加载插件。插件加载成功后,Server 才具备实际的工具执行能力。 - 插件能力来源:后续
tools/list、tools/call、prompts/list、prompts/get、resources/list、resources/read六类 MCP 方法的实际能力,都来源于这些被加载的插件,而不是主程序自身。 - 通知系统绑定:插件加载完成后,程序遍历所有插件实例,为每个插件分配
NotificationSystem,并将SendToClient绑定到统一的ClientNotificationCallbackImpl,使插件具备主动向客户端发送通知的能力。 - 并发安全控制:通知回调内部通过互斥锁保护共享访问,确保多个插件同时向客户端发送消息时不会发生竞态。
3. 注册 callback
功能定位:将 MCP 协议方法与插件能力建立映射关系,完成从 JSON-RPC 请求到插件执行逻辑的分发。
-
服务基础属性设置:在注册回调前,程序首先调用
server->Name(name)和server->VerboseLevel(verbose ? 1 : 0)配置服务名称和输出等级。 -
工具类方法注册:
tools/list:遍历工具类插件,返回所有工具的名称、描述与inputSchema。tools/call:根据请求中的工具名称查找目标插件,调用HandleRequest()执行业务逻辑,并将结果解析为 JSON 返回。
-
Prompt 类方法注册:
prompts/list:枚举 Prompt 类型插件,返回 Prompt 名称、描述与参数定义。prompts/get:根据名称定位 Prompt,并执行插件逻辑生成具体内容。
-
资源类方法注册:
resources/list:返回所有资源插件暴露的资源列表,包括名称、描述、URI 与 MIME 类型。resources/read:根据请求中的 URI 定位目标资源,并调用插件读取内容。
从结构上看,这一层实现的是标准的协议分发机制:客户端发送的是 MCP 方法名,服务器内部执行的是插件实例的 HandleRequest()。因此,main.cpp 的 callback 注册本质上是在完成 MCP 协议接口 -> 插件执行入口 的映射。
4. 启动 transport
功能定位:根据运行参数选择具体传输模式,并将 Server 与 Transport 绑定,使服务开始接收并处理请求。
-
传输层抽象:程序以
std::shared_ptr<vx::ITransport>统一持有传输层实例,体现出对具体通信方式的抽象封装。 -
模式选择逻辑:
- 启用
--sse时,创建vx::transport::SSE; - 默认情况下,使用
vx::transport::Stdio。
- 启用
-
运行信息输出:日志中会记录 Transport 名称、版本与端口信息,用于确认当前服务运行模式。
-
正式启动服务:最后通过
server->Connect(transport)将服务器与选定的传输层绑定,进入服务状态。此前完成的 callback 注册与插件加载,也在这一时刻开始真正对外生效。
调用链
从 main.cpp 的实现逻辑来看,服务端调用链可以概括为:启动服务 -> 加载插件 -> 注册方法 -> 通过 Transport 接收请求 -> 定位插件并执行 -> 返回响应。
更具体地说,整个运行路径如下:
程序启动后,首先初始化 Server、PluginsLoader、日志系统和运行参数;然后根据配置选择 Stdio 或 SSE 作为传输层;接着从插件目录中加载所有插件,并为插件建立通知通道;完成这些准备后,main.cpp 通过 OverrideCallback 注册 tools/list、tools/call、prompts/list、prompts/get、resources/list、resources/read 六个标准 MCP 方法;最后调用 server->Connect(transport),使服务开始监听来自客户端的 JSON-RPC 请求。
调用链逻辑
本文件体现出的核心调用链可以概括为 “初始化 -> 注入能力 -> 注册协议 -> 接收请求 -> 插件执行 -> 返回结果”:
-
初始化阶段
程序启动,创建Server与PluginsLoader,完成参数解析、信号注册和日志初始化。 -
能力注入阶段
通过LoadPlugins()扫描插件目录,动态注入 tools、prompts 和 resources 三类能力,并为插件建立通知系统。 -
协议绑定阶段
使用server->OverrideCallback(...)注册六个标准 MCP 方法,使外部协议请求可以映射到内部插件逻辑。 -
请求执行阶段
服务器通过选定的 Transport 接收 JSON-RPC 请求,根据 method 名称进入对应 callback,再由 callback 根据工具名、Prompt 名或 URI 定位具体插件,调用HandleRequest()执行逻辑。 -
结果返回阶段
插件返回执行结果后,主程序负责将其解析并封装为标准 JSON 响应,通过当前 Transport 原路返回给客户端。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)