实现指南:客户端、服务端与 2025-11-25 规范全覆盖)
V 语言原生 MCPModel Context Protocol实现指南客户端、服务端与 2025-11-25 规范全覆盖【免费下载链接】vSimple, fast, safe, compiled language for developing maintainable software. Compiles itself in 1s with zero library dependencies. Supports automatic C V translation. https://vlang.io项目地址: https://gitcode.com/GitHub_Trending/v/v本篇技术指南以 V 语言标准库vlib/mcp模块为对象讲解如何用 V 语言原生实现 MCPModel Context Protocol的客户端与服务端覆盖 2025-11-25 版本规范的完整能力JSON-RPC 2.0 基座、stdio 与 Streamable HTTP 双传输、Tools/Resources/Prompts 三大能力以及进度上报、协作取消、服务端发起请求等进阶特性。读完本文你将能够直接用import mcp编写可被 Claude Desktop、Cursor 等宿主接入的 MCP 服务器或编写连接远程 MCP 端点的客户端并理解底层传输与合规实现的细节。模块概览原生实现无外部依赖vlib/mcp是 V 语言对 Model Context Protocol 的原生实现同时提供客户端client与服务端server能力完整覆盖2025-11-25版本修订规范。所谓原生意味着整个模块仅依赖 V 标准库自身的net.http、os、time、json2等模块见 vlib/mcp/mcp.v 的 import 段不需要引入任何第三方 C 库或外部服务编译产物是单个零依赖二进制。在深入代码之前先看模块的能力矩阵——这也是 README 声明、且由 vlib/mcp/spec_compliance_test.v 逐一验证的覆盖范围能力状态JSON-RPC 2.0 基础协议✅stdio 传输换行分隔✅Streamable HTTP 传输POST GET、SSE、会话✅Origin头校验DNS 重绑定防护✅MCP-Session-Id与MCP-Protocol-Version头✅Last-Event-ID恢复✅Tools含annotations✅Resources、资源模板、subscribe/updated✅Prompts✅completion/complete✅logging/setLevelnotifications/message✅notifications/progress 协作取消✅*/list_changed通知add_*时自动触发✅服务端发起roots/list、sampling/createMessage、elicitation/create✅Tools/Resources/Prompts 上的Icon、BaseMetadatatitle、Annotations✅Tool.execution.taskSupport广告✅内容助手text、image、audio、嵌入式资源、资源链接✅Tasks 工具tasks/*⏳ 延后实验性OAuth 授权⏳ 延后规范标记为 SHOULD其中延后的两项——Tasks 工具与 OAuth 授权——是 2025-11-25 规范中可选实验性 / SHOULD的部分模块选择暂不实现除这两项外规范要求的能力全部就绪。快速上手客户端在 V 中连接一个 MCP 服务端点只需寥寥几行import mcp fn main() { mut client : mcp.connect(http://localhost:8000/mcp)! init : client.initialize()! println(init.server_info.name) client.close() }这段代码背后发生了什么vlib/mcp/mcp.v 中connect是connect_http的简写它构造了一个HttpTransport并绑定默认的ClientConfiginitialize()则执行规范规定的握手流程客户端发送initialize请求携带protocolVersion、自身capabilities与clientInfo默认名v.mcp、版本dev见 mcp.v 中的default_client_name/default_client_version常量服务端返回它支持的协议版本、能力声明与serverInfo客户端紧接着自动发送notifications/initialized通知见initialize_with_raw实现mcp.v此后才能发起业务请求。自定义客户端配置若需要自定义协议版本、客户端标识或请求头使用connect_http并传入ClientConfigmut client : mcp.connect_http(https://example.com/mcp, mcp.ClientConfig{ protocol_version: 2025-11-25 client_info: mcp.Implementation{ name: my-app version: 1.0.0 title: My App } capabilities: {roots:{listChanged:true}} headers: { Authorization: Bearer token } })!从源码看ClientConfigmcp.v的字段含义如下protocol_version客户端希望协商的协议版本默认为模块当前实现的2025-11-25为空字符串时会被normalize_protocol_version归一为模块默认值。client_infoImplementation结构体name与version必填title、description、website_url、icons是 2025-11-25 新增的可选元数据扩展。capabilities客户端能力声明的原始 JSON 字符串默认{}。headers附加到每个 HTTP 请求上的自定义头例如鉴权令牌。HttpTransport在构造时new_http_transportmcp.v会校验 URL 必须以http://或https://开头否则直接报错。连接本地 stdio 服务进程除了 HTTP客户端还可以通过 stdio 与本地 MCP 服务器进程通信mut client : mcp.connect_stdio(./my-server, [--flag], mcp.ClientConfig{})!connect_stdio内部使用ProcessTransportmcp.v启动子进程、重定向标准输入输出然后按照 MCP 规范的换行分隔帧协议读写。规范要求 stdio 消息以换行符分隔且不得内嵌换行encode_stdio_message会防御性地剔除消息中的 CR/LFmcp.vtry_extract_stdio_message则负责从缓冲区中切出完整帧支持半包缓冲与空行跳过mcp.v。快速上手服务端定义一个 MCP 服务端同样直观。最简形态如下摘自 READMEimport mcp fn main() { mut server : mcp.new_server( name: my-v-mcp-server version: 1.0.0 enable_logging: true ) server.add_tool(mcp.Tool{ name: say_hello description: Greets the caller annotations: mcp.ToolAnnotations{ read_only_hint: true } }, fn (_ mcp.Context, _ string) !mcp.ToolResult { return mcp.tool_text_result(Hello, user!) })! server.serve_stdio()! }new_server接受ServerConfig参数vlib/mcp/server.v逐项说明配置字段说明默认值name/version服务端标识必填会折叠进serverInfo的Implementationv.mcp.server/devtitle/description/website_url/icons2025-11-25 的服务端元数据扩展空protocol_version服务端协商的协议版本2025-11-25capabilities能力声明的原始 JSON 覆盖串为空时由capabilities_json()根据已注册内容自动生成自动instructions通过initialize结果下发给客户端的服务端说明空http_pathHTTP 模式下的端点路径自动补前导//mcpenable_logging声明logging能力并允许客户端调用logging/setLevelfalse关闭allowed_originsStreamable HTTP 下允许的Origin头值列表*表示任意来源不推荐为空时仅接受无 Origin 头或环回地址localhost、127.0.0.1、[::1]、字面量null的请求空环回白名单关于allowed_origins的判定逻辑可参考origin_is_allowed与is_loopback_originserver.v当配置了非空白名单时只有完全匹配项或*才放行白名单为空时走环回地址检查用于防止 DNS 重绑定攻击规范 MUST 要求。add_tool注册工具时会做三重校验validate_tool_nameserver.v名称非空且不超过 128 字符、只能包含字母数字与_/-/.、不得重名。注册成功后服务端自动向所有已初始化会话广播notifications/tools/list_changed通知server.v客户端即可感知工具目录变化。serve_stdio()启动标准输入输出服务循环。从源码看server.v它绕过 libc 的 stdio 缓冲输入端用裸read()读 fd 0StdinReader输出端每写一帧立即flush()StdioWriter从而保证管道对端能即时看到响应。同时服务 HTTP将最后一行换成serve_http即可切换为 Streamable HTTP 传输mut server : mcp.new_server(name: demo, version: 1.0.0) // ...注册 tools / resources / prompts... server.serve_http(127.0.0.1:8080)! // 端点即 http://127.0.0.1:8080/mcpserve_httpserver.v在给定地址上启动内置 HTTP 服务器由HttpHandler分发请求wait_till_running可等待服务器进入运行态。完整演示服务器examples/mcp/server.v仓库提供了覆盖模块全部特性的演示服务器 examples/mcp/server.v它注册了带注解与图标的工具、具体资源、资源模板、提示词、逐参数自动补全并演示了进度通知与协作取消运行方式v run examples/mcp/server.v # stdio 传输默认 v run examples/mcp/server.v -- --http # HTTP 传输127.0.0.1:8080 v run examples/mcp/server.v -- --http 127.0.0.1:9000 # HTTP 传输127.0.0.1:9000该示例中的几个要点值得关注echo工具纯函数、幂等、只读展示了ToolAnnotations的read_only_hint、idempotent_hint、open_world_hint与Icon的用法。count_to工具长时间运行、每步上报进度且可被取消是理解下文取消与进度的最佳范本。delete_record工具destructive_hint: true让宿主可以在调用前向用户告警。review提示词与语言自动补全language参数会从supported_languages常量中按前缀过滤补全候选。示例默认allowed_origins: [*]注释明确提示仅供演示真实部署应收紧白名单。取消与进度Cancellation and progress工具、资源、提示词的处理函数都会收到一个请求级Contextserver.v它携带会话 ID、请求 ID、方法名、传输类型、协商协议版本、客户端信息与能力、以及从请求_meta中提取的progressToken。进度上报当客户端在请求_meta.progressToken中提供 token 时处理函数可调用ctx.notify_progress(progress, total, message)发送notifications/progress。total与message可选传 0 / 空串即省略。协作取消对长时间运行的工作应周期性轮询ctx.is_cancelled()——当客户端发送notifications/cancelled后该标志翻转为true并持续到本次请求结束clear_cancelled在请求处理完的defer中复位server.v。count_to工具把两者结合得很好server.add_tool(mcp.Tool{ name: count_to description: Count up to N with progress notifications. Cooperatively cancellable. input_schema: {type:object,required:[n],properties:{n:{type:integer,minimum:1,maximum:50}}} }, fn (ctx mcp.Context, arguments string) !mcp.ToolResult { args : json.decodeCountArgs or { return mcp.tool_text_result(invalid arguments: ${err.msg()}) } for i in 1 .. args.n 1 { if ctx.is_cancelled() { return mcp.tool_text_result(cancelled at ${i - 1}) } ctx.notify_progress(f64(i), f64(args.n), tick ${i}) time.sleep(50 * time.millisecond) } return mcp.tool_text_result(counted to ${args.n}) })!源码层面有两个值得注意的合规细节均有测试背书进度必须严格单调递增规范要求同一progressToken的progress值严格递增。notify_progress_forserver.v会在发送前与progress_seen记录值比较非递增的通知被静默丢弃避免在线上发出乱序进度。测试test_progress_notifications_must_strictly_increasespec_compliance_test.v验证了这一点。进度通知必须携带正确的 token 字段test_progress_notification_uses_camel_case_progress_token断言通知参数中包含progressToken:abcspec_compliance_test.v。服务端发起的请求Server-initiated requests规范允许服务端向客户端发起三类请求模块将三类请求封装成阻塞式调用README 原文import mcp import time mut server : mcp.new_server(name: demo, version: 0) session_id : session roots : server.list_roots(session_id, 5 * time.second)! sampled : server.sample(session_id, mcp.CreateMessageParams{}, 30 * time.second)! elicited : server.elicit(session_id, mcp.ElicitParams{}, 60 * time.second)!list_roots→roots/list读取客户端声明的根Root边界。sample→sampling/createMessage请求客户端调用 LLM 采样返回CreateMessageResult。CreateMessageParams支持model_preferences成本/速度/智能优先级、max_tokens、temperature、stop_sequences、metadata、tools与tool_choiceauto/required/none、include_context等完整参数server.v。elicit→elicitation/create请求客户端向用户征集信息支持表单模式requested_schema描述字段与 URL 模式mode: urlurlelicitation_id。URL 模式配合notify_elicitation_complete通知完成带外交互闭环。这些调用会阻塞直到客户端返回对应的 JSON-RPC 响应或超时触发错误信息mcp.Server.wait_for_response: timeout waiting for ...。底层实现并不轮询send_server_request为每个在途请求创建一个sync.Semaphorewait_for_response用timed_wait阻塞等待deliver_response在收到客户端应答后post唤醒server.v从而避免忙等浪费 CPU。内容块Content blocks工具、提示词与资源的处理函数返回的是 MCP 内容块数组。模块提供了开箱即用的助手函数server.v可直接返回也可手工拼接import mcp text : mcp.text_content(done) img : mcp.image_content(AAA, image/png) audio : mcp.audio_content(BBB, audio/wav) embedded_text : mcp.embedded_text_resource(res://config, application/json, {}) embedded_blob : mcp.embedded_blob_resource(res://blob, image/png, AAA) resource_link : mcp.resource_link_content(mcp.Resource{ uri: res://docs name: docs })每个助手函数返回符合规范ContentBlock联合类型的 JSON 字符串type: text | image | audio | resource | resource_link具体线格式由测试test_content_helpers_match_spec_shapes精确断言spec_compliance_test.vtext → {type:text,text:hi} image → {type:image,data:AAA,mimeType:image/png} audio → {type:audio,data:BBB,mimeType:audio/wav} embedded → {type:resource,resource:{uri:res://a,mimeType:text/plain,text:hi}} resource_link → {type:resource_link, ...}配套的*_with_annotations变体可为块附加Annotationsaudience受众角色列表、[0.0, 1.0]的priority优先级、ISO 8601 的lastModifiedencode_annotations在所有字段为空时整体省略server.v。工具结果则用tool_text_result包装pub fn tool_text_result(text string) ToolResult { return ToolResult{ content: [${text_content(text)}] } }ToolResult还支持structured_content结构化输出与is_error标志encode_tool_result保证content字段始终存在空结果时输出[]因为 2025-11-25 的CallToolResult.content是必填字段server.v。Streamable HTTP 传输细节服务端在 HTTP 模式下遵循 Streamable HTTP 规范行为细节如下README 原文POST默认返回 JSON仅当客户端发送Accept: text/event-stream时才返回 SSE。GET打开一条 SSE 流推送排队的通知可通过Last-Event-ID断点续传。DELETE终止会话必须携带MCP-Session-Id。403Origin不被允许时返回400MCP-Protocol-Version不被支持时返回406Accept既不含application/json也不含text/event-stream时返回。在源码中这些规则分别对应Accept 协商parse_acceptserver.v解析逗号分隔的 Accept 头*/*与application/*、text/*通配符均视为接受对应类型handle_http_request中use_sse : accept.sse !accept.json决定响应包装方式server.v。会话与协议版本头POST 首响应会携带MCP-Session-Id与协商的MCP-Protocol-Version客户端HttpTransport.send会捕获这两个值并在后续请求中回传mcp.v。GET 与 Last-Event-ID 恢复handle_http_getserver.v要求会话存在且Accept含 SSE若带Last-Event-ID会先把排队通知落盘到事件日志再按id last_event_id重放replay_events_after保证断线期间产生的通知不丢失。事件日志有界event_log_capacity 1024。协议版本校验supports_protocol_versionserver.v实现规范规则——缺失头时默认回退 2025-03-26 兼容模式否则必须与协商版本一致。会话生命周期HTTP 会话 ID 由rand.uuid_v7()生成create_http_sessionDELETE 调用delete_session清理会话并唤醒所有等待中的信号量防止服务端发起的请求悬挂。客户端响应缓冲与通知排空客户端在等待某个请求的响应时如果传输层顺带收到其他消息wait_for_responsemcp.v会按类型分类缓冲无id的消息 → 存入notifications可用take_notifications()排空带id的服务端请求→ 存入server_requests可用take_requests()排空非当前期待的响应 → 存入pending_responses按 id 匹配。mcp_test.v的test_request_buffers_server_messages_after_initialize完整演示了这一行为客户端initialize后发送ping途中收到服务端的roots/list请求与tools/list_changed通知最终take_requests()与take_notifications()分别取回mcp_test.v。测试与规范合规模块测试一条命令即可全部运行v test vlib/mcp测试分三个文件vlib/mcp/mcp_test.v客户端与传输层单元测试——握手流程、stdio 半包/换行处理、SSE 解析、响应缓冲、连接关闭委托。vlib/mcp/server_test.v服务端端到端路由测试——从initialize、notifications/initialized到tools/list、tools/call、resources/read、prompts/get的完整生命周期并断言未初始化前业务请求返回server_not_initialized错误码 -32002。vlib/mcp/spec_compliance_test.v线格式合规测试逐项对照官方 schemaschema/2025-11-25/schema.json校验服务端产出的 JSON 形状——字段命名必须用 camelCase如mimeType、uriTemplate、progressToken、hasMore、completion/complete结果必须包裹在completion对象中、isError与content数组的必填性、错误码与 JSON-RPC 2.0 规范一致-32700/-32600/-32601/-32602/-32603、-32002、-32042等。文件头注释明确约定任何影响线上载荷字段的改动都应在该文件中新增用例。小结vlib/mcp以纯 V 标准库实现了 MCP 2025-11-25 规范的完整客户端与服务端覆盖 stdio 与 Streamable HTTP 两种传输、三大核心能力Tools/Resources/Prompts、进度与取消、服务端发起请求、内容块助手等全部就绪特性并以专门的规范合规测试锁定线上 JSON 形状。对开发者而言这意味着接入 AI 宿主用serve_stdio()将任意 V 程序变成 Claude Desktop / Cursor 可用的 MCP 服务器零外部依赖、单二进制分发消费远程能力用connect()/connect_stdio()编写 MCP 客户端initialize()握手后通过类型化的request[P, R]调用方法、notify[P]发送通知深度集成利用服务端发起请求实现roots/list、LLM 采样sampling/createMessage与用户信息征集elicitation/create等高级交互。下一步建议以 examples/mcp/server.v 为模板跑通端到端演示再结合v test vlib/mcp与 vlib/mcp/spec_compliance_test.v 理解每一处线格式约束即可在自己的项目中放心使用。【免费下载链接】vSimple, fast, safe, compiled language for developing maintainable software. Compiles itself in 1s with zero library dependencies. Supports automatic C V translation. https://vlang.io项目地址: https://gitcode.com/GitHub_Trending/v/v创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考