关于 ganjoor-mcp-server
ganjoor-mcp-server 将 Ganjoor 波斯古典诗歌 API 提供给 Agent 和研究者,支持只读浏览与分析。其 44 个工具覆盖诗人、作品、韵律、朗诵、注释及人物关系,无需 API 密钥。
主要功能
- 01浏览诗人与诗歌集
- 02全文及语义诗歌搜索
- 03分析波斯诗歌韵律与押韵
- 04查询朗诵与注释
- 05探索人物关系与家谱图
适用场景
- 01查找特定主题的波斯诗歌
- 02分析诗歌格律和押韵
- 03研究诗人及历史人物关系
- 04检索诗歌朗诵与评论
MCP 相关
这是面向 Ganjoor API 的只读 MCP 服务,提供 44 个工具供 MCP 客户端浏览诗歌数据、分析韵律与押韵,并查询相关资料。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
44收录的工具列表 · 更新于 5 天前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| page | integer | 否 | 页码,从 1 开始。 |
| page_size | integer | 否 | 每页最多返回的项目数(1-100,默认值 20)。 |
| response_format | enum | 否 | 输出格式:'markdown' 表示适合人类阅读的文本(默认值),'json' 表示适合机器读取的结构化数据。markdown | json |
详细介绍
英语 | فارسی
Ganjoor MCP 服务 — 用于 Ganjoor 波斯诗歌 API 的模型上下文协议服务。
它支持 Agent 浏览诗人和诗集、阅读诗歌及其诗句、进行韵律和押韵分析、追踪不同诗人之间的唱和诗、查找吟诵和评注,以及探索相关人物和家谱图。
44 个工具,只读访问。无需 API 密钥。
目录
安装
需要 Node.js 18.17 或更高版本。
npm install ganjoor-mcp-server # for locally installed stdio transport. no need if using VS Code or Claude Desktop / Cursor.
VS Code
无需安装 npm 包——MCP 服务会在进程内运行,并由 VS Code 在需要时启动。
只需点击下方徽章,即可在 VS Code 工作区安装 Ganjoor MCP 服务。它会自动将该服务添加到你的 .vscode/mcp.json 配置中。
或者添加到 .vscode/mcp.json:
{
"servers": {
"io.github.ehsanghaffar/ganjoor-mcp-server": {
"command": "npx",
"args": [
"-y",
"ganjoor-mcp-server"
],
"env": {}
}
}
}
VS Code 命令行:
code --add-mcp '{\"name\":\"io.github.ehsanghaffar/ganjoor-mcp-server\",\"command\":\"npx\",\"args\":[\"-y\",\"ganjoor-mcp-server\"],\"env\":{}}'
Claude Desktop / Cursor
只需点击下方徽章,即可在 Claude Desktop 或 Cursor 应用中安装 Ganjoor MCP 服务。它会自动将该服务添加到你的 MCP 配置中。
或者添加到你的 MCP 配置文件:
{
"mcpServers": {
"io.github.ehsanghaffar/ganjoor-mcp-server": {
"command": "npx",
"args": [
"-y",
"ganjoor-mcp-server"
],
"env": {},
"type": "local",
"tools": [
"*"
]
}
}
}
其他客户端
Claude Code
使用 Claude Code CLI 添加 io.github.ehsanghaffar/ganjoor-mcp-server MCP 服务:
claude mcp add io.github.ehsanghaffar/ganjoor-mcp-server npx -y ganjoor-mcp-server
Claude Desktop
按照 MCP 安装指南,使用上面的标准配置。
Codex
创建或编辑配置文件 ~/.codex/config.toml 并添加:
[mcp_servers.ganjoor-mcp-server]
command = "npx"
args = ["-y", "ganjoor-mcp-server"]
更多信息请参阅 Codex MCP 文档。
Gemini CLI
按照 MCP 安装指南,使用上面的标准配置。
OpenCode
请参阅 MCP 服务文档。例如,在 ~/.config/opencode/opencode.json 中:
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"io.github.ehsanghaffar/ganjoor-mcp-server": {
"type": "local",
"command": [
"npx",
"-y",
"ganjoor-mcp-server"
],
"enabled": true
}
}
}
GitHub Copilot CLI
GitHub Copilot CLI 支持通过交互方式和配置文件添加 MCP 服务。
选项 1:使用 /mcp add 交互式设置
- 以交互模式打开 GitHub Copilot CLI。
- 运行
/mcp add。 - 输入 Server Name:
io.github.ehsanghaffar/ganjoor-mcp-server。 - 选择 Server Type:
STDIO,用于基于命令的服务HTTP,用于远程服务
- 根据上面的标准配置填写命令/URL 设置,并将 Tools 设为
*。 - 按
Ctrl+S保存。
选项 2:编辑 ~/.copilot/mcp-config.json
{
"mcpServers": {
"io.github.ehsanghaffar/ganjoor-mcp-server": {
"command": "npx",
"args": [
"-y",
"ganjoor-mcp-server"
],
"env": {},
"type": "local",
"tools": [
"*"
]
}
}
}
更多信息,请参阅 GitHub Copilot CLI MCP 文档。
GitHub Copilot Coding Agent
GitHub Copilot Coding Agent 可以使用 MCP 服务扩展其功能。请使用专为 Coding Agent 格式化的以下配置:
{
"mcpServers": {
"ganjoor-mcp-server": {
"command": "npx",
"args": [
"-y",
"ganjoor-mcp-server"
],
"env": {},
"type": "local",
"tools": [
"*"
]
}
}
}
将此配置添加到仓库设置中的 Copilot > Coding agent 下。"tools": ["*"] 设置会启用 MCP 服务提供的所有可用工具。
更多信息,请参阅 GitHub Copilot Coding Agent MCP 文档。
从此源安装
npm install
npm run build
npm start # stdio transport (default)
VS Code
添加到 .vscode/mcp.json:
{
"servers": {
"ganjoor": {
"type": "stdio",
"command": "node",
"args": ["${workspaceFolder}/dist/index.js"]
}
}
}
Claude Desktop / Cursor
添加到 MCP 配置文件:
{
"mcpServers": {
"ganjoor": {
"command": "node",
"args": ["/absolute/path/to/ganjoor-mcp/dist/index.js"]
}
}
}
Streamable HTTP(远程/共享部署)
HTTP=true PORT=3000 npm start
MCP 端点为 POST /mcp,GET /health 会报告服务和上游状态。HTTP 传输以无状态方式运行(每个请求都会创建一个新的服务实例),因此可以水平扩展。默认绑定到 127.0.0.1,并会验证 Origin 标头以阻止 DNS 重绑定攻击;如果需要非环回源,请设置 ALLOWED_ORIGINS(以逗号分隔)。
MCP Inspector
npm run inspector
Docker
项目包含多阶段 Dockerfile 和 docker-compose.yml。镜像基于 node:22-alpine 构建,仅包含编译后的输出和生产依赖项。
docker compose up --build
compose 文件会以 streamable HTTP 模式在 http://localhost:3000/mcp 上启动服务,GET /health 会报告服务和上游状态。HOST 设为 0.0.0.0,以便从主机访问发布的端口;下表中的所有配置变量都可作为普通环境变量使用。若要在不使用 compose 的情况下运行单个容器:
docker build -t ganjoor-mcp .
docker run --rm -p 3000:3000 -e HTTP=true -e HOST=0.0.0.0 ganjoor-mcp
通过 Docker 使用 stdio 传输
自行启动服务(而非通过 HTTP 连接)的客户端可以使用 stdio 配置文件,该模式会打开 stdin 作为协议流,且不会启动 HTTP 监听器:
docker compose --profile stdio run --rm ganjoor-mcp-stdio
配合 Claude Desktop 使用
若要通过 Docker 运行服务,而不是使用本地 Node 安装:
{
"mcpServers": {
"ganjoor": {
"command": "docker",
"args": ["run", "--rm", "-i", "ganjoor-mcp"]
}
}
}
配置
所有设置均为环境变量;没有必填项。
| 变量 | 默认值 | 用途 |
|---|---|---|
HTTP | (未设置) | 设为 true 可使用 streamable HTTP,而不是 stdio。 |
PORT | 3000 | HTTP 端口。 |
HOST | 127.0.0.1 | HTTP 绑定地址。 |
ALLOWED_ORIGINS | (空) | 额外允许的 Origin 值,以逗号分隔。 |
GANJOOR_API_BASE_URL | https://api.ganjoor.net | 上游 API 基础 URL——开发时可指向本地 RMuseum 实例。 |
GANJOOR_SITE_BASE_URL | https://ganjoor.net | 用于生成可点击链接的前端基础 URL。 |
概念
Ganjoor 的数据模型分为三个嵌套层级。理清这些层级,是高效完成 Agent 会话与徒劳无功的区别。
graph TD
P["Poet — e.g. Hafez, id 2, slug /hafez"] --> C1["Category — e.g. Ghazals, id 24"]
P --> C2["Category — e.g. Qeta, id 25"]
C1 --> M1["Poem — e.g. Ghazal 494, id 2623, /hafez/ghazal/sh494"]
C2 --> M2["Poem"]
M1 --> V["Verses (hemistichs, paired into couplets)"]
M1 --> S["Sections (nested stanzas with metre + rhyme)"]
M1 --> R["Recitations (audio)"]
M1 --> CM["Comments (reader commentary)"]
M1 --> Q["Quoted / related poems"]
- 诗人 — 作者。Hafez 的诗人 id 为
2,Saadi 为7,Rumi 为5,Khayyam 为3,Ferdowsi 为4。ganjoor_list_poets可将姓名解析为 id。 - 类别 — 诗人作品中的书籍或章节(CatType
0表示通用类别,1表示诗歌,2表示书籍)。Hafez 的根类别是9;他的 ghazal 类别是24。 - 诗作 — 一篇文本,通过数字 id 和 URL slug 标识,例如
hafez/ghazal/sh494。 - 诗句 — 半行诗。连续两句构成一个
couplet(versePosition为0和1)。
URL slug 前面需要加斜杠。 上游 API 对
?url=hafez/ghazal/sh494返回 404,但可以解析?url=/hafez/ghazal/sh494。此服务会为你进行规范化,因此两种形式均可使用。
波斯语文本会原样返回。 文本采用从右向左的书写方向,并使用阿拉伯文字的变音符号来标注韵律。除非用户明确要求,否则不要转写或翻译。
工具参考
诗人与诗集
| 工具 | 描述 |
|---|---|
ganjoor_list_poets | 所有已发布诗人的信息,包括传记、年代和地点。支持分页。 |
ganjoor_get_poet | 根据 id 或 slug 获取一位诗人的信息,包括传记和顶层书籍/章节。 |
ganjoor_get_poets_by_century | 按历史半世纪分组的所有诗人。 |
ganjoor_list_books | 命名诗集,可按诗人或名称子字符串筛选。 |
类别
| 工具 | 描述 |
|---|---|
ganjoor_get_category | 获取类别及其面包屑导航、子章节和所含诗作。 |
ganjoor_list_category_poems | 获取类别中的诗作,支持分页和可选标题筛选。 |
ganjoor_get_category_geotags | 获取类别子树下标记的地理/历史地点。 |
ganjoor_get_category_people_graph | 获取类别“人物”标签页背后的人物网络。 |
诗作
| 工具 | 描述 |
|---|---|
ganjoor_search_poems | 在诗作中进行全文搜索,可限定诗人或类别。 |
ganjoor_semantic_search_poems | 按含义搜索诗作(“查找一首关于……的诗”)。 |
ganjoor_get_poem | 根据 URL 获取完整诗作,并按联句分组诗句。 |
ganjoor_get_poem_by_id | 根据数字 id 获取同一内容。 |
ganjoor_get_poem_verses | 仅获取诗句,比获取整首诗更轻量。 |
ganjoor_get_random_poem | 获取一首随机诗作,可选限定诗人。 |
ganjoor_get_hafez_faal | 获取一首随机的 Hafez ghazal,用于波斯占卜。 |
ganjoor_get_page_url | 将任意页面 id(诗作、类别、诗人)解析为网页 URL。 |
ganjoor_get_redirect_url | 将旧版 Ganjoor URL 解析为当前地址。 |
韵律、押韵与结构
| 工具 | 描述 |
|---|---|
ganjoor_list_rhythms | 所有波斯诗律及其使用次数。 |
ganjoor_analyze_poem_rhythm | 检测诗作的韵律格律。 |
ganjoor_analyze_poem_rhyme | 检测诗作的押韵字母和押韵模式。 |
ganjoor_find_similar_poems | 查找共享韵律格律和押韵的诗作——应答诗图谱。 |
ganjoor_get_poem_sections | 获取诗作的结构段落(联结、masnavi 段、三行诗节)。 |
ganjoor_get_section | 获取一个段落及其中的诗句和相关段落。 |
ganjoor_get_related_sections | 获取其他诗作中与此段落韵律格律和押韵相符的段落。 |
ganjoor_get_couplet_sections | 获取指定联句所属的段落。 |
ganjoor_get_language_tagged_sections | 获取标记了非波斯语语言代码的诗节。 |
音频朗诵
| 工具 | 描述 |
|---|---|
ganjoor_search_recitations | 按朗诵者、诗人或类别搜索朗诵。 |
ganjoor_get_recitation | 获取一条朗诵及其音频 URL。 |
ganjoor_get_recitation_sync_info | 获取逐句时间信息,以便跟随音频收听。 |
ganjoor_get_poem_recitations | 获取为一首诗作发布的所有朗诵。 |
ganjoor_get_category_top_recitations | 获取类别中获赞最多的朗诵。 |
人物
| 工具 | 描述 |
|---|---|
ganjoor_list_people | Ganjoor 知识图谱中的历史人物和文学人物。 |
ganjoor_get_person | 一个人物的传记、日期和地点。 |
ganjoor_get_person_poems | 标记了某个人物的诗歌。 |
ganjoor_get_person_relations | 一个人物的亲属关系和隶属关系边。 |
ganjoor_get_person_family_tree | 从某个人物出发,获取完整的关联亲属关系网络。 |
评论、常见问题和补充材料
| 工具 | 描述 |
|---|---|
ganjoor_get_recent_comments | 最近发布的读者评论。 |
ganjoor_list_faq_categories | Ganjoor 的编辑部常见问题类别。 |
ganjoor_get_faq_items | 某个常见问题类别中的所有问答条目。 |
ganjoor_get_faq_item | 按 ID 获取单个常见问题条目。 |
ganjoor_get_poem_images | 手稿和影印图像。 |
ganjoor_get_poem_quoted_poems | 此诗引用的诗歌,以及引用此诗的诗歌。 |
ganjoor_get_poem_effective_corrections | 文本修订的编辑前后记录。 |
ganjoor_get_poem_geotags | 标记到某首诗的地点和纪念日期。 |
每个工具都带有 readOnlyHint、idempotentHint 和 openWorldHint 注解,并且它们都不会
修改 Ganjoor 上的状态。
响应格式
每个工具都接受一个 response_format 参数:
markdown(默认)——包含标题、列表和可点击链接的易读输出。json——相同数据,以结构化对象形式返回;也会作为 MCPstructuredContent返回,因此 支持此格式的客户端无需解析文本即可直接读取字段。
列表工具使用统一的分页封装:
{
"total": 842,
"count": 20,
"page": 1,
"page_size": 20,
"has_more": true,
"next_page": 2,
"poems": [{ "id": 2623, "title": "غزل شمارهٔ ۴۹۴", "full_url": "/hafez/ghazal/sh494" }]
}
page 和 page_size 均从 1 开始;page_size 上限为 100。超过 25,000 个字符的响应会被截断,并明确设置
truncated 标志,而非静默截断。
两个上游端点(/api/ganjoor/poets 和 /api/ganjoor/rhythms)会忽略分页参数,始终返回整个集合。
服务会检测这种情况,并在本地切分出请求的范围,从而确保每个列表工具的 page 和 has_more 都准确且一致。
错误会作为工具结果返回(而非协议错误),并附带指出端点且建议后续操作的消息——例如,404 会引导你使用
ganjoor_list_poets 查找有效 ID。
用法
“Hafez 是谁?”
ganjoor_get_poet { "url": "hafez" }
“给我看看 Hafez 的第 494 首 ghazal”
ganjoor_get_poem { "url": "hafez/ghazal/sh494", "include_recitations": true }
“Hafez 的哪些诗包含 صبر 这个词?”
ganjoor_search_poems { "term": "صبر", "poet_id": 2, "page_size": 10 }
“这首诗采用什么格律?还有谁写过这种格律的诗?”
ganjoor_analyze_poem_rhythm { "poem_id": 2623 }
ganjoor_list_rhythms { "page_size": 100 }
ganjoor_find_similar_poems { "metre": "<rhythm from the previous step>", "page_size": 10 }
“这个人物的祖先有哪些人?”
ganjoor_get_person { "person_id": 22 }
ganjoor_get_person_family_tree { "person_id": 22 }
“Hafez 对我的问题有什么说法?”
ganjoor_get_hafez_faal { }
架构
src/
├── index.ts # Process entry: stdio or streamable HTTP transport
├── server.ts # createServer() — registers every tool
├── client.ts # fetch wrapper, error mapping, pagination helpers
├── types.ts # TypeScript interfaces for Ganjoor's payloads
├── constants.ts # Base URLs, limits, server identity
├── schemas.ts # Shared Zod schemas (pagination, URL slugs, ids)
├── format.ts # Markdown rendering and formatting helpers
└── tools/
├── registry.ts # defineTool() wrapper: consistent errors + both formats
├── poets.ts # Poet discovery
├── categories.ts # Category browsing
├── poems.ts # Poem retrieval, search, URL resolution
├── analysis.ts # Prosody, rhyme, sections
├── audio.ts # Recitations
├── content.ts # Images, quotations, corrections, geo tags
└── people.ts # People graph, comments, FAQ
代码库中贯穿着两项约定:
- **
defineTool()封装每项注册。**它确保每个工具都以带有可操作消息的isError结果报告失败, 以一致的方式呈现 markdown 或 JSON,并在文本之外返回structuredContent。 - **
md()用于构建文档。**它保留显式空行,确保 markdown 标题和列表正确分隔,同时移除null/false,使条件片段能够干净地消失。
上游接口的特殊情况会在 client.ts 和工具模块中规范化,而不会暴露给调用方——
例如类别端点的 { poet, cat } 封装、诗歌负载中嵌套的 category.cat,以及 URL 参数必须带前导斜杠的要求。
开发
npm run build # compile to dist/
npm run typecheck # type-check without emitting
npm test # live smoke test against api.ganjoor.net
npm run inspect # print real tool output for review
npm run clean
npm test 会通过内存传输启动服务,断言每个工具都有详尽的描述,并针对在线 API 调用全部 44 个工具;任何错误响应都会导致测试失败。
已知限制
- 可能禁用语义搜索。 Ganjoor 的嵌入后端是可选的;如果部署时将其关闭,
ganjoor_semantic_search_poems会返回 503。该工具会显示清晰的提示,并建议改用波斯语关键词调用ganjoor_search_poems。 - 重定向解析较少。 Ganjoor 只会为实际更改过名称的路径保存重定向,因此大多数有效 URL 返回的都是
has_redirect: false,而不是目标地址。 - 某些工具始终需要身份验证。 需要 Ganjoor 账户的端点(书签、发布评论、上传更正)按设计不在支持范围内——此服务为只读且匿名。
- 书目经过筛选。
ganjoor_list_books涵盖约 168 个有名称的诗集,但未收录一些重要诗人——其中没有哈菲兹的条目。请改用ganjoor_get_poet并设置include_cats: true,该工具会直接从每位诗人的根类别读取其分区。 - 分页端点不提供总数。 上游 API 仅提供分页结果,不报告总数,因此总数未知时会省略
total;has_more则通过多获取一条记录来推断。 - 诗歌文本的标注覆盖经过筛选。 人物标签、地理标签和语言标签本身并不完整——结果为空通常表示覆盖不足,并不能证明相关内容不存在。
- 日期字段有时是近似值。 Ganjoor 会标记不确定的日期(
validBirthDate/validDeathDate);工具会公开这些标记,供调用方筛选。
评估
evaluation/evaluation.xml 包含 10 个带有已验证答案的只读问题。回答每个问题都需要调用多个工具,并且在记录答案前已对照实时 API 进行核验:
npx tsx tests/verify-evaluation.ts # replays every question through the MCP tools
这些问题刻意避开只需单次查询即可回答的冷知识。它们会交叉比对诗人与世纪、沿亲属关系图谱追溯、将一首诗的格律与全语料的韵律列表进行比较,并通过引用记录解析唱和诗链。
贡献
请参阅 CONTRIBUTING.md。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。