news 2026/9/12 7:27:30

如何用 V 语言 mcp 模块编写 MCP Server 并接入 AI 客户端

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
如何用 V 语言 mcp 模块编写 MCP Server 并接入 AI 客户端

如何用 V 语言 mcp 模块编写 MCP Server 并接入 AI 客户端

【免费下载链接】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

vlib/mcp是 V 语言对 Model Context Protocol(MCP)的原生实现,同时提供客户端和服务端,覆盖2025-11-25版规范。如果你的目标是写一个能被 Claude Desktop、Cursor 等 AI 客户端调用的 MCP Server,本文给出完整路径:用mcp模块创建 Server、注册 tools/resources/prompts、选择 stdio 或 Streamable HTTP 传输启动,最后用 V 自带客户端和模块测试套件验证接入是否成功。

模块能力与适用边界

编写前先确认你的功能在模块支持范围内。vlib/mcp/README.md 给出的能力清单包括:

  • JSON-RPC 2.0 基础协议
  • stdio 传输(换行分隔)
  • Streamable HTTP 传输(POST + GET,SSE,会话管理)
  • Origin头校验(DNS rebinding 防护)
  • Tools(含annotations)、Resources、资源模板、Prompts、completion/complete
  • logging/setLevel+notifications/messagenotifications/progress与合作式取消
  • 服务端主动发起的roots/listsampling/createMessageelicitation/create

两项能力目前是 deferred 状态,规划内不包含:Tasks 工具(tasks/*,实验性)和 OAuth 授权。如果你的接入方案依赖这两项,当前版本无法满足。

准备条件

需要一个可用的 V 编译器(仓库自带Makefile等构建入口可自行构建v)。本文所有命令均假定vPATH中,且你在 V 仓库根目录下执行——示例代码路径(如examples/mcp/server.v)都是相对仓库根目录的。

写一个最小可运行的 MCP Server

模块 README 给出的 server quick start 是最短主路径:mcp.new_server创建服务、add_tool注册一个工具、serve_stdio()以 stdio 传输启动。

import 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()! }

几个关键字段的用途(定义见 vlib/mcp/server.v 中的ServerConfig):

  • name/version:服务端标识,客户端initialize握手后通过server_info拿到的就是它;
  • enable_logging:声明logging能力,允许客户端调用logging/setLevel。默认关闭,只有当 Server 会发出notifications/message时才打开;
  • allowed_origins:Streamable HTTP 下接受的Origin头白名单。留空时只接受没有Origin头或来自回环地址(http://localhost[:port]http://127.0.0.1[:port]http://[::1][:port]、字面量null)的请求;
  • http_path:HTTP 模式下服务挂载的路径,默认/mcp

add_tool的 handler 签名是fn (ctx mcp.Context, arguments string) !ToolResult:第二个参数是调用方传入的 JSON 字符串,需要自己解码。input_schema字段则是原样的 JSON Schema 字符串,AI 客户端靠它决定怎么传参。返回结果用mcp.tool_text_result(...)这类内容助手生成,它们返回符合规范ContentBlock联合(type: "text" | "image" | "audio" | "resource" | "resource_link")的 JSON 字符串。

参考完整示例:tools、resources、prompts 与 completions

仓库内的 examples/mcp/server.v 是覆盖vlib/mcp全部能力的参考 Server,可直接作为你的项目骨架。它的main里先注册四类能力,再按命令行参数选择传输:

register_tools(mut server)! register_resources(mut server)! register_prompts(mut server)! register_completions(mut server)! // Strip a leading `--` so the same binary works whether launched as // `./v run server.v -- --http :8080` (V's run forwards `--`) or as the // pre-compiled binary `./server --http :8080`. args := os.args[1..].filter(it != '--') if args.len > 0 && args[0] == '--http' { addr := if args.len > 1 { args[1] } else { '127.0.0.1:8080' } eprintln('mcp showcase listening on http://${addr}/mcp') server.serve_http(addr)! } else { server.serve_stdio()! }

注册 tools 时,示例展示了三类典型的ToolAnnotations写法:echo标注read_only_hint: trueidempotent_hint: true(纯只读、可重复调用);delete_record标注destructive_hint: true,提示宿主在调用前提醒用户。参数解码用的是json2

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()}') } // ... return mcp.tool_text_result('counted to ${args.n}') })!

resources、prompts 和 completions 的注册方式与 tools 同构,分别在register_resourcesregister_promptsregister_completions函数中:静态资源demo://welcome.txt、URI 模板demo://greet/{language}、带两个必填参数的reviewprompt,以及针对language参数的补全(对照supported_languages列表做前缀过滤)。

启动 Server 并选择传输

参考示例文件头注释给出了两种启动方式:

# stdio 传输(默认) v run examples/mcp/server.v # Streamable HTTP 传输,监听 127.0.0.1:8080 v run examples/mcp/server.v -- --http # 指定其他地址 v run examples/mcp/server.v -- --http 127.0.0.1:9000

注意--http前的--v run会把--之后的参数转发给程序,示例代码里的filter(it != '--')同时兼容v run和已编译二进制两种启动方式。HTTP 模式启动后会在 stderr 打印mcp showcase listening on http://127.0.0.1:8080/mcp,这是服务已就绪的信号。

HTTP 模式下客户端与http://127.0.0.1:8080/mcp的交互行为由 README 明确约定:

  • POST:默认返回 JSON;仅当客户端发送Accept: text/event-stream时返回 SSE;
  • GET:打开一个 SSE 流读取排队的通知,可用Last-Event-ID断点续读;
  • DELETE:终止会话(必须携带MCP-Session-Id);
  • 状态码语义:Origin不被允许返回 403,MCP-Protocol-Version不支持返回 400,Accept中既无application/json也无text/event-stream返回 406。

可选分支(生产环境注意):示例为了演示把allowed_origins设为['*'],源码注释明确写了 "*only for the demo; tighten this for real deployments"。真实部署应改成具体的 Origin 值;改成回环场景时也可以直接留空,利用默认的回环白名单。

接入 AI 客户端

examples/mcp/server.v 的头部注释直接说明了接入方式:

Connect a client (e.g. Claude Desktop / Cursor / a custom MCP client) to the command above for stdio, or POST tohttp://127.0.0.1:8080/mcpfor HTTP.

对应两条接入路径:

  1. stdio:在 AI 客户端的 MCP Server 配置中,把启动命令指向上面的v run examples/mcp/server.v(或你替换后的自己的 Server 文件),客户端通过子进程的 stdin/stdout 与 Server 交换换行分隔的 JSON-RPC 消息。具体的客户端配置文件格式取决于各客户端自身文档,V 仓库没有提供。
  2. HTTP:客户端直接连接http://127.0.0.1:8080/mcp(或你--http指定的地址),按 Streamable HTTP 协议交互。

如果你不用现成的 AI 客户端,而是自己写一个 V 的 MCP 客户端,mcp.v 提供了三种连接入口:connect(url)/connect_http(url, config)连接 Streamable HTTP 端点,connect_stdio(command, args, config)启动本地 stdio Server 进程作为传输层。

验证接入结果

验证分两层。

第一层:用 V 客户端完成握手。README 的 client quick start:

import mcp fn main() { mut client := mcp.connect('http://localhost:8000/mcp')! init := client.initialize()! println(init.server_info.name) client.close() }

运行前把connect的 URL 换成你自己 HTTP 端点的实际地址(参考示例的默认值是http://127.0.0.1:8080/mcp)。initialize()返回的server_info.name应该等于你new_server时传入的name——两边一致说明握手和序列化都正确。client.close()释放底层传输。

第二层:跑模块自身的测试套件。README 给出的命令:

v test vlib/mcp

其中 spec_compliance_test.v 会把线上报文形状与官方 schema 逐项交叉比对。README 同时提醒:任何时候改动了 payload 字段,都要在这里补一个用例。

长耗时工具:进度与取消

如果注册的工具要跑较长时间(如示例的count_to),handler 收到的Context提供两个协作机制(README "Cancellation and progress" 一节):

  • 客户端请求里带_meta.progressToken时,handler 调用ctx.notify_progress(progress, total, message)上报进度;
  • 长循环中定期轮询ctx.is_cancelled()——客户端发送notifications/cancelled后该标记翻转为true,直到请求结束。示例的count_to就是在循环里检查它并提前返回'cancelled at ${i - 1}'

这两个机制是可选项:纯短耗时工具(如echo)不需要处理ctx

已知限制

  • Tasks 工具(tasks/*)与 OAuth 授权在能力表中均为 deferred,不可用;
  • mcp.connect/mcp.connect_http只面向 Streamable HTTP 端点;stdio 场景要用mcp.connect_stdio启动子进程;
  • HTTP 模式的Origin校验默认只放行回环来源,跨机器接入时务必显式配置allowed_origins,避免所有请求被 403 拒绝。

完成v test vlib/mcp与客户端握手验证后,这个 V 编写的 MCP Server 就可以作为常驻服务挂给 AI 客户端使用了。

【免费下载链接】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),仅供参考

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

ADHD成人实用操作系统:从神经特性到日常适配

1. 这不是标签&#xff0c;是真实存在的神经多样性特征“i-have-adhd”最近在社交平台高频出现&#xff0c;但它绝不是一句轻飘飘的网络自嘲或流量梗。我接触过上百位主动提及ADHD的成年人——程序员、设计师、自由撰稿人、教师、创业者&#xff0c;甚至有两位三甲医院的主治医…

作者头像 李华
网站建设 2026/9/12 7:22:06

Simulink微电网仿真:可再生能源并网与能源管理策略

1. 项目背景与核心价值这个微电网仿真项目本质上是在解决可再生能源并网中的关键痛点——如何协调多种异质能源的出力特性。光伏发电的间歇性、燃料电池的慢动态响应、电池的充放电效率限制&#xff0c;这些因素在直流微电网中会产生复杂的交互影响。通过Simulink搭建的ACDC微电…

作者头像 李华
网站建设 2026/9/12 7:16:42

视频学习为何总忘?4款AI工具将视频转为可检索知识库

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/12 7:13:42

gpt-image-2实战指南:从awesome资源清单到API调用与避坑技巧

先别急着去翻各种社交平台上刷屏的AI神图&#xff0c;作为一个天天和各种生成模型打交道的人&#xff0c;我最近在GitHub上蹲到了一个非常有意思的资源合集——awesome-gpt-image-2。它并不是某个炫酷的工具本身&#xff0c;而是一个把gpt-image-2相关资料、案例、API封装、提示…

作者头像 李华
网站建设 2026/9/12 7:12:02

C语言安全编程:snprintf函数详解与应用实践

1. 为什么需要snprintf&#xff1f;在C语言中处理字符串格式化输出时&#xff0c;我们最熟悉的可能是printf函数。但当你需要将格式化结果存储到缓冲区而非直接输出时&#xff0c;snprintf就成为了更安全的选择。我在处理一个嵌入式项目时&#xff0c;曾因为使用sprintf导致缓冲…

作者头像 李华