This commit is contained in:
2026-03-31 11:38:32 +08:00
commit 5ca759d280
17 changed files with 2171 additions and 0 deletions

257
docs/development.md Normal file
View File

@@ -0,0 +1,257 @@
# 开发指南
本文档介绍如何开发和扩展 NJUPT MCP Server。
## 架构概述
```
┌─────────────────┐
│ MCP Client │ (Kimi Code CLI, Claude Desktop, etc.)
│ (Kimi, Claude) │
└────────┬────────┘
│ MCP Protocol (stdio / SSE)
┌─────────────────┐
│ njupt-mcp │
│ (FastMCP) │
└────────┬────────┘
┌────┴────┐
▼ ▼
┌───────┐ ┌───────┐
│ Tools │ │Resources│
└───┬───┘ └───┬───┘
│ │
▼ ▼
┌───────┐ ┌───────┐
│ NJUPT │ │ Static│
│ APIs │ │ Data │
└───────┘ └───────┘
```
## 添加新功能
### 1. 添加工具 (Tool)
工具用于执行操作、调用 API。在 `src/njupt_mcp/server.py` 中添加:
```python
@mcp.tool()
async def my_tool(param1: str, param2: int = 10) -> str:
"""工具的描述,会显示给 LLM
详细说明工具的用途、使用场景等。
Args:
param1: 参数1的描述
param2: 参数2的描述默认为 10
Returns:
返回值的描述,通常是 JSON 字符串
Example:
my_tool("test", 20) -> 返回结果
"""
# 实现逻辑
result = {"param1": param1, "param2": param2}
return json.dumps(result, ensure_ascii=False)
```
**最佳实践:**
- 使用 `async def` 定义异步函数
- 提供详细的文档字符串LLM 依赖此信息决定是否调用)
- 使用类型注解
- 返回 JSON 字符串便于 LLM 解析
- 处理异常情况,返回友好的错误信息
### 2. 添加资源 (Resource)
资源用于提供数据、文档等只读内容:
```python
@mcp.resource("njupt://resource-name")
async def get_resource() -> str:
"""资源的描述"""
return "资源内容"
```
资源 URI 格式:`scheme://path`,建议使用 `njupt://` 作为 scheme。
### 3. 添加提示词模板 (Prompt)
提示词模板用于生成特定场景的提示词:
```python
@mcp.prompt()
def my_prompt(context: str, question: str) -> str:
"""提示词模板的描述"""
return f"""基于以下上下文:
{context}
请回答:{question}
"""
```
## 数据获取实现
目前示例代码使用硬编码数据,实际应用中需要对接 NJUPT 的数据源:
### 教务系统
```python
import httpx
async def fetch_course_data(course_code: str) -> dict:
"""从教务系统获取课程数据"""
async with httpx.AsyncClient() as client:
response = await client.get(
"https://jw.njupt.edu.cn/api/course",
params={"code": course_code},
cookies={"session": await get_session()}
)
response.raise_for_status()
return response.json()
```
### 图书馆 OPAC
```python
async def search_library(keyword: str) -> list[dict]:
"""搜索图书馆 OPAC 系统"""
async with httpx.AsyncClient() as client:
response = await client.get(
"http://opac.njupt.edu.cn/opac/search",
params={"q": keyword}
)
# 解析 HTML 或 JSON
return parse_search_results(response.text)
```
## 测试
### 运行测试
```bash
# 运行所有测试
pytest
# 运行特定测试文件
pytest tests/test_helpers.py -v
# 运行并生成覆盖率报告
pytest --cov=njupt_mcp --cov-report=html
```
### 编写测试
```python
# tests/test_new_feature.py
import pytest
from njupt_mcp.server import my_new_tool
@pytest.mark.asyncio
async def test_my_tool():
result = await my_tool("test", 20)
assert "test" in result
assert "20" in result
```
## 调试技巧
### 使用 MCP Inspector
```bash
# 启动服务器
uv run njupt-mcp --transport streamable-http
# 启动 Inspector
npx -y @modelcontextprotocol/inspector
```
访问 http://localhost:5173 进行交互式调试。
### 启用调试日志
```bash
uv run njupt-mcp --debug
```
### 手动测试工具
```python
# test_manual.py
import asyncio
from njupt_mcp.server import search_course
async def main():
result = await search_course("数据结构")
print(result)
if __name__ == "__main__":
asyncio.run(main())
```
## 部署
### 本地部署
使用 `uv` 运行:
```bash
uv run njupt-mcp
```
### Docker 部署
```dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY . .
RUN pip install -e "."
EXPOSE 8000
CMD ["njupt-mcp", "--transport", "sse", "--host", "0.0.0.0"]
```
### 云服务部署
适合使用 SSE 或 streamable-http 模式,部署到:
- [Railway](https://railway.app/)
- [Render](https://render.com/)
- [Fly.io](https://fly.io/)
## 性能优化
### 添加缓存
```python
from functools import lru_cache
import asyncio
from cachetools import TTLCache
# 使用 TTLCache 缓存结果
course_cache = TTLCache(maxsize=100, ttl=3600)
@mcp.tool()
async def search_course(keyword: str) -> str:
if keyword in course_cache:
return course_cache[keyword]
result = await fetch_course_from_api(keyword)
course_cache[keyword] = result
return result
```
### 并发请求
```python
async def fetch_multiple_courses(course_codes: list[str]) -> list[dict]:
async with httpx.AsyncClient() as client:
tasks = [fetch_course(client, code) for code in course_codes]
return await asyncio.gather(*tasks)
```

124
docs/kimi-cli-setup.md Normal file
View File

@@ -0,0 +1,124 @@
# Kimi Code CLI 配置指南
本文档介绍如何在 Kimi Code CLI 中配置和使用 NJUPT MCP Server。
## 配置步骤
### 1. 找到配置文件
Kimi Code CLI 的配置文件通常位于:
- Windows: `%APPDATA%\kimi-cli\config.toml`
- macOS/Linux: `~/.config/kimi-cli/config.toml`
### 2. 添加 MCP 服务器配置
#### stdio 模式(推荐)
```toml
[mcp.servers.njupt-mcp]
type = "stdio"
command = "uv"
args = ["run", "--directory", "E:\\Code\\njupt-mcp", "njupt-mcp"]
```
如果使用 pip 安装:
```toml
[mcp.servers.njupt-mcp]
type = "stdio"
command = "python"
args = ["-m", "njupt_mcp.server"]
```
#### SSE 模式
首先启动服务器:
```bash
cd /path/to/njupt-mcp
uv run njupt-mcp --transport sse --port 8000
```
然后在配置文件中添加:
```toml
[mcp.servers.njupt-mcp]
type = "sse"
url = "http://localhost:8000/sse"
```
### 3. 验证配置
在 Kimi Code CLI 中输入:
```
/mcp
```
你应该能看到 `njupt-mcp` 服务器已列出。
## 使用示例
配置完成后,你可以在 Kimi Code CLI 中这样使用:
```
> 帮我查一下南京邮电大学数据结构的课程信息
```
Kimi Code CLI 会自动调用 `search_course` 工具。
```
> 帮我查一下学号 B21010101 的课表
```
这会调用 `get_course_schedule` 工具。
## 故障排查
### 服务器无法启动
1. 检查 Python 版本:`python --version` 应 >= 3.11
2. 检查依赖是否安装:`uv sync``pip install -e "."`
3. 检查路径是否正确:确保 `--directory` 指向正确位置
### MCP 命令无响应
1. 检查 Kimi Code CLI 版本:`kimi --version`
2. 查看 Kimi Code CLI 日志,通常在 `%APPDATA%\kimi-cli\logs\`
3. 尝试手动运行服务器命令,查看是否有错误输出
### 工具调用失败
1. 确保服务器已正确启动
2. 检查工具参数是否正确
3. 查看服务器日志输出
## 进阶配置
### 环境变量
你可以在配置中设置环境变量:
```toml
[mcp.servers.njupt-mcp]
type = "stdio"
command = "uv"
args = ["run", "--directory", "E:\\Code\\njupt-mcp", "njupt-mcp"]
env = { NJUPP_API_KEY = "your-api-key", DEBUG = "1" }
```
### 多个实例
你可以配置多个服务器实例,分别用于不同环境:
```toml
[mcp.servers.njupt-mcp-dev]
type = "stdio"
command = "uv"
args = ["run", "--directory", "E:\\Code\\njupt-mcp", "njupt-mcp", "--debug"]
[mcp.servers.njupt-mcp-prod]
type = "sse"
url = "https://njupt-mcp.your-domain.com/sse"
```