MCP实战教程:零基础搭建本地工具服务器,5分钟提升开发效率!AI编程必备

实用教程6天前发布 iowen
3 00
MCP实战教程:零基础搭建本地工具服务器,5分钟提升开发效率!AI编程必备MCP实战教程:零基础搭建本地工具服务器,5分钟提升开发效率!AI编程必备

# 从零搭建本地 MCP 工具服务器:一份真正能用的实战教程

AI 编程助手越来越强,但真正把它们接入本地开发环境时,很多人都会卡在一个问题上:模型能调用工具,但工具真的安全吗?

如果你用过 Codex、Cursor 或 Claude 的 MCP 功能,大概会遇到这些场景:模型搜索文件时扫遍了整个硬盘,查询数据库时差点执行了 DELETE,或者工具返回了一大段看不懂的堆栈信息。这些问题不是“注册一个函数”能解决的。

下面这张图展示的是一个自建 MCP 服务器的实际运行效果——两个工具(文件搜索和任务查询)已经注册成功,客户端可以正常调用并返回结果:

MCP 工具服务器运行示例

从这张图可以看到,工具返回的是结构化的文本结果,包含相对路径、行号和内容预览,而不是把整个文件系统暴露出去。这正是 MCP 工具服务器应该有的样子。

本教程会从零开始,用 TypeScript 搭建一个真正能放在本机使用的 MCP 工具服务器。它提供两个工具:search_files(在允许的项目目录中搜索文本)和 query_tasks(从本地 SQLite 数据库读取任务记录)。更重要的是,我们会把路径白名单、参数校验、数量限制、超时、只读、错误返回这些边界逐一补上——这些才是 MCP 工具真正值得花时间的地方。


为什么你需要一个本地 MCP 工具服务器

先说说 MCP 到底是什么。Model Context Protocol(模型上下文协议)是 AI 客户端与本地工具之间的通信标准。简单理解,它让 AI 模型能调用你本地的函数,比如搜索文件、查询数据库、读取日志。

但问题在于:能调用工具,不代表工具就值得调用;能拿到结果,也不代表结果一定安全。

很多入门教程只教你注册一个天气查询的 demo,客户端能返回结果就觉得学会了。但真放进自己的开发环境,问题马上就变了:

  • 能不能只搜索指定项目,而不是把整个硬盘暴露出去?
  • 查询 SQLite 时,怎样保证模型不能执行 DELETE?
  • 文件很多时,怎样限制扫描时间和返回数量?
  • 工具执行失败后,应该返回一大段堆栈,还是返回可判断的错误?
  • 使用 stdio 传输时,为什么随手写一行 console.log 就可能把连接弄断?

这些问题比“注册一个函数”重要得多。所以这篇 MCP 实战教程不做天气接口,也不做只会返回一句 Hello 的演示,而是从零写一个真正能用的工具服务器。


初始化 TypeScript MCP 项目

环境检查

先确认 Node.js 和 npm 版本:

PR0

本文环境示例:v24.15.0 / 11.12.1

SDK v2 拆了包,只写服务端装这些就行:

PR1

> 使用误区提醒:如果看到旧文章仍然从 @modelcontextprotocol/sdk/server/mcp.js 导入,不要把两套示例混在一起。先看项目安装的是 SDK v1 还是 v2,再决定导入路径。

package.json 可以整理为:

PR2

版本号不用抄到最后一位。关键是:SDK v2 使用拆分后的服务端包;项目启用 ESM;Node.js 版本满足当前 SDK 要求;zod 的主版本与 SDK 示例一致。

TypeScript 配置

PR3

我比较建议打开 strictnoUncheckedIndexedAccess。MCP 工具本质上在处理外部参数,类型检查越松,越容易在“理论上有值”的地方得到 undefined。编译器提前指出问题,总比客户端调用后返回内部错误更省时间。


实现安全的文件搜索工具

先定义结果结构

src/file-search.ts

PR4

返回结果只保留:相对路径;行号;截断后的当前行。不返回绝对路径,是为了减少不必要的本机信息暴露;不返回整个文件,是为了控制结果大小。

路径校验不能只用 startsWith

下面这种写法看起来能判断子路径:

PR5

但如果根目录是 D:codeapp,另一个目录是 D:codeapp-backup,字符串同样以 D:codeapp 开头。

更稳妥的判断方式是使用 path.relative

PR6

除此之外,还要注意符号链接。目录表面上在项目中,但符号链接可能指向项目外。真正读取前,应尽量对根目录和目标文件执行 realpath,再做一次范围判断。

> 进阶技巧:这里容易混淆的是“字符串前缀”和“目录边界”。app-backup 的文字前缀包含 app,但它不是 app 的子目录。先解析真实路径,再用 path.relative 判断是否出现 ..,才是在判断文件系统关系。

递归搜索实现

PR7

这里直接跳过符号链接。这不是所有场景的唯一答案,但对本地只读搜索工具来说,它比“跟随链接后再判断”更简单,也更容易解释。

继续完成搜索函数:

PR8

这段代码没有调用 shell,也没有拼接命令。性能肯定比专业搜索工具差,但边界比较清楚,适合作为第一版。项目很大时,可以在服务端内部调用 ripgrep,但必须使用参数数组,不要拼接命令字符串,同时仍然要保留根目录和数量限制。

为什么不能只依赖输入 Schema?

zod 可以保证 limit 是数字,也可以限制它在 1 到 50 之间,但它不能自动判断:当前文件是不是二进制;符号链接是否越界;文件读取是否超时;返回结果是否过大。

Schema 是第一层,业务校验是第二层,操作系统权限是第三层。 安全不是某一个 z.object() 能解决的。


SQLite 查询:不要把“任意 SQL”包装成工具

先建立一个最小任务表

Node.js 24 可以使用 node:sqlite。初始化脚本 scripts/init-db.mjs

PR9

注意最后使用的是 console.error。对 stdio MCP Server 来说,标准输出承载协议消息。调试信息写到 stdout,可能和 JSON-RPC 数据混在一起,客户端最后只会告诉你“连接断开”或“解析失败”。

> 常见错误:本地 stdio 服务端的普通日志写 stderr,不要把 console.log 当成无害操作。

一个看似灵活、实际很危险的工具

不要设计成这样:

PR10

然后在代码里判断:

PR11

这种校验挡不住复杂注释、多个语句、不同大小写和数据库特性。即使能挡住写操作,模型也可能一次读取整个数据库。

更合理的接口是让工具表达业务意图:按状态、优先级和数量查询任务。 模型不需要知道表结构,更不需要自己拼 SQL。

任务仓库实现

src/task-repository.ts

PR12

这里用了三层限制:数据库以只读模式打开;SQL 模板由服务端固定;条件值使用参数绑定。就算模型传入 open' OR 1=1 --,zod 枚举也不会接受;即使绕过了上层,参数绑定也不会把它当作 SQL 结构执行。


注册两个 MCP 工具

创建服务器

src/index.ts

PR13

> 进阶技巧:工具名称应该稳定、清晰。像 do_itrunexecute 这种名字几乎不能帮助模型选择。描述中也不要写空话,要说明输入、结果和限制。

注册文件搜索工具

PR14

这里故意没有把完整堆栈返回给客户端。堆栈可以写进本地日志,但工具结果只需要告诉模型:什么操作失败了;用户可以检查什么;是否可以重试。把本机绝对路径、依赖位置和内部堆栈全部返回,不但噪声大,还可能泄露不必要的信息。

注册任务查询工具

PR15

连接 stdio

PR16

至此,两个工具已经注册完成。

最后再提醒一个很隐蔽的坑:使用 stdio 时,标准输出本身就是协议通道。普通日志混进 stdout,客户端读到的就不再是完整协议消息。调试日志写到 stderr,协议消息留在 stdout。这个习惯看起来不起眼,实际能省掉不少“工具明明注册了,客户端却突然断开”的排查时间。


行业趋势:为什么 MCP 工具服务器越来越重要

AI 编程工具正在经历从“代码补全”到“自主执行”的转变。2024 年以来,Cursor、Claude Code、Codex 等工具纷纷支持 MCP 协议,让模型不仅能写代码,还能直接操作本地环境。

但这也带来了新的问题:工具越多,安全边界越重要。 一个能搜索文件、查询数据库、读取日志的 AI 助手,如果边界没设好,可能比没有助手更危险。

用户需求也在变化。早期开发者只关心“模型能不能生成代码”,现在更关心“模型能不能安全地操作我的项目”。MCP 工具服务器正是解决这个问题的标准方案——它把能力拆成一个个边界明确的工具,每个工具都清楚自己能读什么、能改什么、失败后会留下什么。

如果你正在筛选类似工具,可以参考「

」进行系统对比。


使用建议:这个工具服务器适合谁?

推荐使用

  • AI 编程重度用户:每天使用 Cursor、Claude Code 或 Codex 进行开发,需要模型能搜索项目文件、查询本地数据
  • 团队效率负责人:希望为团队搭建标准化的 AI 工具接口,统一安全策略
  • MCP 协议学习者:想深入理解 MCP 的安全边界设计,而不是只跑通 demo

不推荐使用

  • 只需要简单代码补全:如果只是用 GitHub Copilot 写代码,不需要本地工具调用
  • 对安全要求极低:如果只是个人玩具项目,不需要这么严格的边界控制
  • 不想维护 Node.js 环境:这个方案依赖 Node.js 24+,如果环境不满足,可能需要考虑其他方案

免费版够用吗?

这个工具服务器完全开源,使用 Node.js 原生模块和 MCP SDK,没有任何付费限制。免费版完全够用,唯一需要的是 Node.js 运行环境和基本的 TypeScript 知识。


总结

写完了。两个工具——文件搜索和任务查询——代码本身不复杂,真正花时间的是边界。

  • 根目录由服务端配置,不由模型决定
  • 文件搜索限制扩展名、大小和返回数量
  • 数据库只读打开,不接收任意 SQL
  • 所有参数经过 Schema 和业务逻辑双重校验
  • stdio 日志写入 stderr
  • 错误结果能判断,但不暴露内部细节

MCP 最有价值的地方不是让 AI “什么都能调”,是能让我们把能力拆成一个个边界明确的工具。 工具多了反而更要写清楚:允许范围、校验证据、失败方式。

后面如果继续扩展,可以增加:项目构建结果读取;Git diff 摘要;测试报告查询;只读日志分析;先生成补丁、确认后再写入的配置修改。

但不管加什么工具,先想清楚三件事:

  • 它能读什么?
  • 它能改什么?
  • 它失败后会留下什么?

这篇 MCP 实战教程从零搭建了一个本地工具服务器,涵盖了文件搜索和 SQLite 查询两个典型场景。如果你正在学习 MCP 工具怎么用,或者想为自己的开发环境搭建安全可控的 AI 工具接口,这份代码可以作为起点。记住:能调用工具,不代表工具就值得调用;能拿到结果,也不代表结果一定安全。

© 版权声明

相关文章

暂无评论

none
暂无评论...