从零搭建拾光课程表 MCP 服务器:一次 AI 工具化的实践
2026-06-14 | 拾光课程表 MCP开发日志
前言
最近在为拾光课程表构建智能问答服务时,我接触到了 MCP(Model Context Protocol) —— 一个让 AI 大模型能够调用外部工具的开放协议。经过几天的摸索,我成功搭建了一个拾光课程表专属的 MCP 知识库服务器,并部署到了云服务器上。
这篇文章记录了整个过程:从了解 MCP 是什么,到动手写代码、踩坑、部署、调试的完整经历。
一、什么是 MCP?
MCP(Model Context Protocol) 是由 Anthropic 提出的一个开放标准协议,用于在 AI 大模型与外部工具 / 数据源之间建立标准化的连接。
简单来说:
传统方式:AI 只能基于训练数据回答问题
MCP 方式:AI 可以调用外部工具(搜索、查询数据库、读文件等)
MCP 定义了三种核心能力:
- Tools(工具):AI 可以调用的函数,比如搜索知识库、获取数据
- Resources(资源):AI 可以读取的数据源,比如文件、API 返回
- Prompts(提示模板):预定义的提示词模板
MCP 的传输方式
MCP 支持两种传输模式:(Rinty 已经部署好 MCP 服务,您可直接使用 详见 五、部署与验证)
| 模式 | 适用场景 | 说明 |
|---|---|---|
| stdio | 本地客户端 | 客户端直接启动服务器进程,通过标准输入输出通信 |
| Streamable HTTP | 远程/Web 客户端 | 通过 HTTP 协议通信,支持远程部署 |
二、为什么要做拾光课程表的 MCP 服务器?
拾光课程表作为一个课程表应用,用户经常会问:
- "怎么导入课表?"
- "课程提醒不响怎么办?"
- "怎么分享课表给同学?"
- "支持哪些学校的教务系统?"
这些问题的答案都在我们的文档里,但分散在不同的页面和 FAQ 中。如果有一个 AI 助手能够直接从知识库中检索答案,用户体验会好很多。
MCP 正好提供了这个桥梁:让 AI 大模型能够主动查询我们的知识库,而不是凭 "记忆" 回答。
三、技术实现
项目结构
shiguang-server/
├── src/
│ └── index.ts
├── knowledge/ # 知识库(Markdown 文件)
│ ├── index.md
│ ├── faq/ # 常见问题
│ └── guide/ # 使用指南
├── Dockerfile
├── docker-compose.yml
├── package.json
└── tsconfig.json
使用技术
- Runtime: Node.js
- Language: TypeScript (ESM)
- SDK:
@modelcontextprotocol/sdk^1.27.1 - Web 框架: Express(用于 HTTP 模式)
- 部署: Docker + Docker Compose
核心设计
1. 知识库加载
知识库使用 Markdown 文件 + YAML frontmatter 组织:
---
title: 课表导入
tags:
- 导入
- 教务系统
---
# 课表导入
拾光课程表支持多种方式导入课表...
服务器启动时递归扫描 knowledge/ 目录,解析所有 .md 文件,构建内存知识库:
function loadKnowledgeBase(): KnowledgeItem[] {
const items: KnowledgeItem[] = [];
const mdFiles = getAllMdFiles(KNOWLEDGE_DIR);
for (const filePath of mdFiles) {
const rawContent = fs.readFileSync(filePath, "utf-8");
const { metadata, body } = parseFrontmatter(rawContent);
// ... 提取标题、标签、内容摘要
items.push({ title, filename, tags, content, summary });
}
return items;
}
2. 实现的 6 个 MCP 工具
| 工具 | 功能 | 使用场景 |
|---|---|---|
search_knowledge | 按关键词搜索知识库 | 用户提问时首选 |
list_knowledge | 列出所有文档 | AI 了解知识库范围 |
get_knowledge | 获取文档完整内容 | 搜索后深入阅读 |
fetch_url | 抓取网页内容 | 获取 GitHub 等在线资源 |
fetch_school_list | 获取已适配学校列表 | 动态数据,不缓存 |
edit_knowledge | 编辑知识库文档 | 管理员维护内容 |
3. 双模式传输
同一个服务器支持两种启动方式:
# stdio 模式 —— 本地客户端(VS Code、Cursor)
node build/index.js
# HTTP 模式 —— 远程客户端(Cherry Studio、picoclaw)
node build/index.js --http 3030
通过命令行参数切换,核心代码共用同一套工具处理逻辑。
四、踩坑记录
坑 1:Accept 头不完整(在使用picoclaw时遇到的问题)
问题:部分 MCP 客户端发送请求时,Accept 头只包含 application/json,但 StreamableHTTPServerTransport 要求同时接受 application/json 和 text/event-stream。
表现:服务器返回 400 错误,客户端无法连接。
解决:在 Express 中间件中自动补全 Accept 头:
app.all("/mcp", async (req, res) => {
const accept = req.headers["accept"] || "";
if (!accept.includes("text/event-stream") || !accept.includes("application/json")) {
req.headers["accept"] = "application/json, text/event-stream";
}
});
坑 2:Docker 镜像过大
问题:初始镜像包含完整的 node_modules 和开发依赖,镜像体积超过 800MB。
解决:使用多阶段构建(multi-stage build):
# 阶段一:编译
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npx tsc -p tsconfig.json
# 阶段二:运行
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY --from=builder /app/build ./build
COPY knowledge ./knowledge
CMD ["node", "build/index.js", "--http", "3030"]
坑 3:跨服务器部署
问题:如果将项目完整搬移到服务器,那势必要重新部署环境,因此需要本地构建的 Docker 镜像需要部署到远程云服务器。
解决:使用 docker save / docker load 方式:
# 本地导出
docker save shiguang-mcp -o shiguang-mcp-server.tar
# 传输到服务器
scp shiguang-mcp-server.tar user@server:/opt/
# 服务器导入
五、部署与验证
Docker Compose 一键部署
services:
shiguang-mcp:
image: shiguang-mcp:latest
container_name: shiguang-mcp
restart: unless-stopped
ports:
- "3030:3030"
volumes:
- /path/to/school_index.pb:/data/school_index.pb:ro
environment:
- SCHOOL_INDEX_PB=/data/school_index.pb
验证 MCP 协议
# 健康检查
curl https://mcp.rinty.xyz/shiguang/health
# → {"status":"ok","service":"shiguang-mcp-server","version":"1.0.0"}
# MCP 握手
curl -X POST https://mcp.rinty.xyz/shiguang/ \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{
"jsonrpc": "2.0",
"method": "initialize",
"params": {
"protocolVersion": "2025-11-25",
"capabilities": {},
"clientInfo": {"name": "test", "version": "1.0.0"}
},
"id": 1
}'
# → 200 OK + session-id
接入 picoclaw
在 picoclaw 配置中添加 MCP 服务器:
!!!注意!!!
https://monitor.rinty.xyz/
MCP 服务监测上线,已停止使用 IP 端口使用 MCP 的功能,转由https://mcp.rinty.xyz/shiguang/ 提供 MCP 服务使用https://mcp.rinty.xyz/shiguang/health 作为健康监测网址
目前 MCP 处于开发中,后续可能会开发 MCP Hub 作为 MCP 共享平台。因此本 MCP 链接不保证长期有效,若无法使用请访问监测平台获取最新 mcp 服务链接,感谢您的支持!
mcp:
servers:
- name: shiguang
type: http
url: "https://mcp.rinty.xyz/shiguang/"
如果您使用 WebUI 版的 picoclaw 的话,可在
配置 ==> MCP ==>MCP 服务
添加好您的 MCP 服务,然后就可以使用询问,例如:
| 回复案例一 | 回复案例二 |
|---|---|
![]() | ![]() |
重启后日志显示连接成功:
INF mcp > Connected to MCP server protocol=2025-11-25 server=shiguang serverName=shiguang-server
INF mcp > Listed tools from MCP server server=shiguang toolCount=6
INF mcp > MCP tools registered successfully total_registrations=6 unique_tools=6
六、思考与展望
MCP 的价值
MCP 让 AI 从 "背答案" 变成了 "查资料"。对于拾光课程表这样的应用,这意味着:
- 知识库可以实时更新 —— 添加新文档后,AI 立即可用,无需重新训练
- 答案更准确 —— AI 基于官方文档回答,而不是靠猜测
- 可扩展 —— 未来可以添加更多工具,比如直接查询用户的课表
MCP 的发现机制
目前 MCP 还处于早期阶段,没有统一的服务发现和注册机制。每个客户端都需要手动配置 MCP 服务器地址。我在考虑构建一个 MCP 社区 / 平台:
- MCP Gateway(网关):统一入口,客户端只需连一个地址
- MCP Hub(注册中心):开发者注册服务器,用户搜索/浏览/一键接入
- 工具市场:类似 Skill 商店,降低使用门槛
下一步计划
- 优化知识库内容,覆盖更多 FAQ
- 探索 picoclaw 的工具调用机制,让 LLM 能正确使用 MCP 工具
- 研究 MCP Gateway 的可行性
- 考虑支持 MCP Resources 和 Prompts
七、相关资源
本文由拾光课程表开发者撰写,记录了从零搭建 MCP 服务器的完整过程。如果你也在考虑为自己的项目接入 AI 能力,MCP 是一个值得尝试的方向。


评论交流
欢迎留下你的想法