DocuSky MCP
# DocuSky MCP
<img width="589" height="350" alt="Screenshot 2026-09-12 at 2 17 19 AM" src="https://github.com/user-attachments/assets/8d3dc48e-1d22-46d6-a779-282f38b301d5" />
讓 Claude 直接查詢 **[DocuSky 數位人文學術研究平台](https://docusky.org.tw)** 的資料庫。
打包成 `.mcpb` 之後,使用者**雙擊就能安裝**,不需要碰終端機。裝好就可以用日常語言問問題:
> 「DocuSky 上有哪些公開資料庫?」
>
> 「在 DaoBudMed6D 裡查『針灸』,看它在佛、道、醫三類文獻的分布」
>
> 「把《真誥》那一筆的全文調出來」
---
<img width="88.3" height="78.1" alt="Screenshot 2026-09-12 at 2 17 00 AM" src="https://github.com/user-attachments/assets/9b260acb-3558-4d9d-af55-220f8235c498" />
<img width="98.5" height="59.8" alt="Screenshot 2026-09-12 at 2 56 56 AM" src="https://github.com/user-attachments/assets/f434839e-5c03-4e27-9224-d1c222fb337e" />
<img width="88.7" height="78.7" alt="Screenshot 2026-09-12 at 3 49 26 AM" src="https://github.com/user-attachments/assets/a6fc634f-179e-40cd-866d-de129a7f9ce2" />
<img width="89.2" height="79.2" alt="Screenshot 2026-09-12 at 3 47 28 AM" src="https://github.com/user-attachments/assets/25c55745-0c7d-422d-8f34-ae764c7bcd6a" />
## 給使用者
### 需要準備什麼
- **Claude Desktop**(macOS 或 Windows 桌面應用程式)
- 不需要 DocuSky 帳號,也不需要會寫程式
> 網頁版(claude.ai)和手機 App **不支援**擴充功能,必須用桌面版。
> 沒裝的話可以到 [claude.ai/download](https://claude.ai/download) 下載。
---
### 步驟一:下載
**[⬇️ 點此下載 docusky.mcpb](https://github.com/hcyuser/DocuSky-MCP/releases/latest/download/docusky.mcpb)**
這個連結永遠指向最新版。想看歷史版本或更新說明,到
[Releases 頁面](https://github.com/hcyuser/DocuSky-MCP/releases)。
檔案大約 82 KB,副檔名是 `.mcpb`。瀏覽器可能會提示「不常下載的檔案類型」,選擇保留即可。
---
### 步驟二:安裝
三種方式擇一:
- **雙擊**下載好的 `docusky.mcpb`
- 把檔案**拖進** Claude Desktop 視窗
- Claude Desktop 選單:**設定 → 擴充功能 → 進階設定 → 安裝擴充功能…**
會跳出安裝畫面,上面列出這個擴充功能的名稱、說明,以及它提供的九個工具。確認後點安裝。
**接著會看到兩個欄位:DocuSky 帳號、DocuSky 密碼。**
| 你的情況 | 怎麼填 |
| --- | --- |
| 只想查公開資料庫(大多數人) | **兩個都留空**,直接完成安裝 |
| 想查自己在 DocuSky 建的資料庫 | 填入你的 DocuSky 帳號與密碼 |
帳密之後隨時可以補填或修改,不必重裝。
---
### 步驟三:確認可以用了
到 **設定 → 擴充功能**,應該會看到 **DocuSky** 且開關是開啟狀態。
然後開一個新對話,試著問:
> DocuSky 上有哪些公開資料庫?
第一次使用時,Claude 會詢問你是否允許它使用這個擴充功能的工具,選擇允許即可。
如果它列出了宋會要輯稿、大明一統志、淡新檔案那些資料庫,就代表一切正常。
---
### 實際用起來是什麼樣子
你不需要記任何指令,直接用日常語言描述你想找什麼。
**你問:**
> 在 DaoBudMed6D 裡查「針灸」,看它在佛、道、醫三類文獻的分布
**Claude 會去 DocuSky 查完,然後回給你:**
| 文獻集 | 文件數 |
| --- | --- |
| Medical 醫書 | 14 |
| Buddhist 佛典 | 10 |
| Daoist 道藏 | 8 |
> 共 32 筆。值得注意的是佛道兩家加起來(18)比醫書(14)還多——針灸的討論並不侷限在醫學文本裡。前幾筆命中的是《太上洞淵神咒經》《真誥》《抱朴子》,年代集中在 363–420 年間。
**接著你可以繼續問:**
> 把《真誥》那一筆的全文調出來
它就會把整篇文獻讀出來給你。文章很長的話會分段,你說「繼續」就好。
其他可以這樣問的例子:
> - 宋會要輯稿裡關於「市舶司」的記載有哪些?
> - 淡新檔案有沒有提到樟腦的案件?
> - 幫我比較「疫」和「癘」在道藏裡的分布差異
---
### 日後管理
| 你想做什麼 | 怎麼做 |
| --- | --- |
| 填入或修改 DocuSky 帳密 | 設定 → 擴充功能 → DocuSky → 設定 |
| 暫時停用 | 設定 → 擴充功能 → 把開關關掉 |
| 更新到新版 | 下載新的 `.mcpb` 再安裝一次,會直接覆蓋 |
| 移除 | 設定 → 擴充功能 → 解除安裝 |
---
### 它能做什麼
- **全文檢索** —— 38 個公開資料庫(本草經集注、大明一統志、宋會要輯稿、朝鮮王朝實錄、淡新檔案、馬偕日記……)
- **分布統計** —— 一個詞在不同文獻集、時代、地點的出現分布
- **取全文** —— 單篇文獻完整讀出,長文自動分段
- **標記分析** —— 統計文本裡的人名、地名、時間等標記
- **文字雲** —— 把詞頻畫成 DocuSky 官方 WordCloudLite 的文字雲(同一份數字也能切換成泡泡圖、Top-10 長條圖、表格)
- **地圖** —— 把地點(地名+WGS84 經緯度,可加時間、說明)整理成 DocuSky 官方 DocuGIS2 的匯入 TSV,貼進去就能看時空分布、時間軸、路線、熱區
- **雙維度交叉統計**(實驗性)—— 同時交叉兩個分類維度,DocuSky 伺服器端功能尚未完整,目前測試過的組合都會被拒絕
- **私人資料庫** —— 填入帳密後也能查自己在 DocuSky 建的資料庫
### 內嵌顯示 DocuSky 網頁
在支援 **MCP Apps** 的 Claude 版本裡,查公開資料庫時(全文檢索、分布統計、標記分析)以及畫文字雲時,Claude 的回覆旁邊會直接內嵌顯示 DocuSky 官方網頁本身的畫面,不只是文字結果。畫面上方有一排這個擴充自己加的工具列:
- **上一頁/下一頁/跳頁** —— 直接翻 DocuSky 的檢索結果。**請用這排按鈕翻頁**,不要用 DocuSky 頁面自己那排頁碼:它靠整頁跳轉(`window.location.href`)換頁,而那在對話內嵌的沙箱 iframe 裡會翻出空白頁。
- **全螢幕** —— 把內嵌畫面放大成整頁再看,關掉就回到對話裡。
- **瀏覽器開啟** —— 在真正的瀏覽器打開同一頁,DocuSky 的全部功能(篩選、標記統計、匯出、另開單篇)都在那裡。
查詢類的內嵌只在**公開資料庫**(不需帳密)上生效——私人資料庫的登入狀態是伺服器端的,內嵌畫面沒辦法一起帶過去,所以私人查詢仍然只會拿到文字結果。文字雲不受這個限制:它畫的是已經拿到手的數字,資料從哪個資料庫來都可以。如果你用的 Claude 版本不支援 MCP Apps,這一切照常運作,只是不會出現內嵌畫面。
地圖(`docugis_map`)的內嵌長得不一樣:DocuGIS2 沒有辦法用網址帶資料進去,所以內嵌畫面上半是整理好的 TSV 加一顆「複製 TSV」,下半是 DocuGIS2 本體,**最後一步要你自己貼上**——按複製、在下方地圖左上角的 ⇥ 打開選單、點「1.2 匯入資料 Import Data」、在右邊的框貼上、按[匯入 Import]。貼完之後時間軸、路線、群聚、熱區、匯出都是 DocuGIS2 原生的功能。
少數 client 會用最嚴格的沙箱(沒有 `allow-same-origin`)來跑內嵌畫面,那種環境下 DocuSky 只有第一頁能正常顯示。擴充會自己偵測到並改成提示你按「瀏覽器開啟」,不會給你一排按了只會變空白的翻頁鈕。DocuGIS2 在那種沙箱裡更直接:整頁卡在轉圈載不起來,所以擴充在偵測到時乾脆不嵌它,只給你 TSV 和「瀏覽器開啟 DocuGIS2」。
---
### 檢索語法
平常用日常語言就好,需要精確控制時可以這樣講:
| 寫法 | 意思 |
| --- | --- |
| `針灸` | 全文檢索這個詞 |
| `醫 +方` | 必須同時包含「醫」和「方」 |
| `醫 -註` | 包含「醫」但排除「註」 |
| `.all` | 整個文獻集全部 |
---
### ⚠️ 不要把密碼貼在對話裡
對話內容會被保存。密碼請一律填在**擴充功能的設定欄位**,那是專門為此設計的,會經過安全儲存且不進入對話紀錄。
如果不小心貼了,建議去 DocuSky 改密碼。
---
### 遇到問題
**設定裡找不到「擴充功能」**
確認你用的是桌面版 Claude,不是瀏覽器開的 claude.ai。
**裝好了但 Claude 說查不到 DocuSky**
先重新啟動 Claude Desktop。再到設定 → 擴充功能確認 DocuSky 是開啟狀態。
**擴充功能顯示啟動失敗**
這個擴充功能以 Python 執行,需要系統上有 [uv](https://docs.astral.sh/uv/)。
多數情況下 Claude Desktop 會自行處理,若確實失敗,可在終端機安裝後重啟 Claude:
```bash
curl -LsSf https://astral.sh/uv/install.sh | sh
```
**查不到東西**
古籍常有異體字。試試換字(「醫」vs「毉」)、拆成單字,或換一個資料庫。也可以直接請 Claude 幫你想替代詞。
**查詢很慢**
DocuSky 的全文檢索本來就需要時間,跨大型資料庫時等十幾秒是正常的。
---
## 給開發者:怎麼打包
```bash
npm install -g @anthropic-ai/mcpb
mcpb pack . docusky.mcpb
```
產出約 82 KB。驗證 manifest:
```bash
mcpb validate manifest.json
```
### 自動建置
`.github/workflows/build-mcpb.yml` 會在 **push 到 `main`** 或**手動觸發**時:
1. 驗證 `manifest.json`
2. 打包 `docusky.mcpb`
3. 解開並實際啟動一次,確認九個工具都在(不會連到 DocuSky)
4. 上傳為 workflow artifact
5. 發布 GitHub Release,tag 取自 `manifest.json` 的 `version`
Release 讓沒有 GitHub 帳號的人也能直接下載。版本號沒變而重跑時,會覆蓋既有的附件而不是失敗。
要發新版本就改 `manifest.json` 裡的 `version`,push 之後會自動建立對應的 Release。
### 專案結構
```
manifest.json MCPB manifest(宣告工具、user_config、啟動方式)
server.py 進入點 shim
docusky_mcp/client.py DocuSky Web API client
docusky_mcp/server.py MCP 工具層
docusky_mcp/ui.py MCP Apps:ui:// 檢視器資源與 webUrl 產生邏輯
docusky_mcp/credentials.py 憑證讀取(環境變數優先)
pyproject.toml 相依套件定義
uv.lock 鎖定版本,啟動時用 --frozen 安裝
.mcpbignore 打包時排除的檔案
```
`server.py` 存在的理由:`uv` 型別的 host 會直接執行進入點檔案,而 `docusky_mcp/server.py`
用的是相對匯入,直接跑會 `ImportError`。這個 shim 透過已安裝的套件轉一手。
### 執行環境
`manifest.json` 宣告 `server.type: "uv"`,啟動指令是:
```
uv run --frozen --directory ${__dirname} server.py
```
依 MCPB 規格,`uv` 型別由 host 管理 Python 與相依套件。`manifest_version` 必須是
`0.4` —— `0.3` 的 schema 只接受 `python | node | binary`。
### 憑證
`user_config` 的兩個欄位會被注入成環境變數:
| 欄位 | 環境變數 |
| --- | --- |
| DocuSky 帳號 | `DOCUSKY_USERNAME` |
| DocuSky 密碼(`sensitive: true`) | `DOCUSKY_PASSWORD` |
留空時兩者皆為空字串,`credentials.py` 會判定為未登入並退回公開模式。
其他可用的環境變數:
| 變數 | 預設值 | 用途 |
| --- | --- | --- |
| `DOCUSKY_CREDENTIALS` | `~/.docusky/credentials.json` | 憑證檔位置(給非 Claude Desktop 的 MCP 客戶端用的後備) |
| `DOCUSKY_BASE_URL` | `https://docusky.org.tw/DocuSky/webApi` | API 根路徑 |
| `DOCUSKY_TIMEOUT` | `120` | 單次請求逾時(秒) |
### 提供的工具
| 工具 | 用途 |
| --- | --- |
| `list_databases` | 列出可用資料庫 |
| `list_corpora` | 某資料庫下的文獻集與篇數 |
| `search_documents` | 全文檢索,回傳書目與摘錄 |
| `get_document` | 取單篇全文 |
| `post_classification` | 分布統計 |
| `tag_analysis` | 標記統計 |
| `twodim_analysis` | 雙維度交叉統計(實驗性,見下方說明) |
| `word_cloud` | 把詞頻畫成 DocuSky WordCloudLite 文字雲 |
| `docugis_map` | 把地點整理成 DocuGIS2 地圖的匯入 TSV |
| `check_login` | 檢查登入狀態 |
`search_documents` 刻意不回全文——DocuSky 單篇動輒六千字以上,一次二十筆會塞爆
context。要讀全文請用 `get_document`,帶入該筆的 `n`,並沿用同一組
`db` / `query` / `corpus` / `page_size`。
`twodim_analysis` 包的是 DocuSky 2026-01-28 才加上的
`getQueryTwodimAnalysisJson.php`。實際測試(2026-09-11)發現不管 `dim1`/`dim2`
帶什麼組合(包括直接沿用 `post_classification` 回傳的 facet 代碼,如
`COMP`/`TP1`)都會被回覆 `{"code": 1, "message": "Currently not support ..."}`
拒絕,DocuSky 自己的前端 JS 也還沒接上這個功能的 UI。先留著這個工具,等 DocuSky
補完後不用再改 client 端。
`word_cloud` 不自己統計也不自己查詢,它只負責把**已經有的數字**畫出來:
`tag_analysis` 的標記次數、`post_classification` 的分布(`value` / `docCount`)、
或 Claude 從 `get_document` 全文自行數出來的詞頻,傳成
`{"針灸": 120, "湯液": 48}` 這種 term → 次數的對照表即可。
這個工具包的是 DocuSky 的
[WordCloudLite](https://docusky.org.tw/docusky/docuTools/WordCloudLite/WordCloudLite.html)。
讀過它的原始碼(2026-09-12)後確定,它只吃兩個 URL 參數:`url=<某個.csv>` 和
`data=<詞,值;詞,值;...>`。其餘設定(標題、背景色、隱藏控制列……)只能透過
`postMessage` 傳,而它的 handler 會擋掉所有非 `docusky.org.tw` 的 origin,內嵌用的
沙箱 iframe 過不了這關;`url=` 又需要一個公開可讀的 CSV,stdio MCP server 沒地方放。
所以走 `data=`。實作上有兩個坑,都已實測確認:
- `data=` 傳進去的值在頁面裡**仍然是字串**(它的 parser 只做 `v.split(',')`),
但畫圖那段用的是 `d3.max(data, d => d.value)`,而 d3 v5 對字串是**字典序**比較。
像 100 / 90 / 9 這組,最大值會變成 `"9"`,所有字級跟著爆掉,畫面**全白**。
解法是把每個值補零到同樣位數(`"090" < "100"`),字典序就跟數值序一致,
後面的 `d.value / maxValue` 對補零字串也算得出正確比例。
- DocuSky 的 Apache 對 ~15 KB 的網址回 200、~24 KB 回 414,所以產生的網址會從
最小的詞開始砍,砍到長度安全為止。
另外 WordCloudLite 在詞數多的時候會**刻意隨機取樣**一部分來畫(見它的
`plotWordCloud`),所以想讓每個詞都出現,大約傳 20–40 個詞最穩。
`docugis_map` 同樣不查詢、不做地理編碼:座標要由呼叫端給(使用者提供、
`search_documents` 的 `placeInfo`、地名資料庫,或 Claude 自己確定知道的地點),
不確定的地點就不要編——寧可留空或問使用者。它把 rows 整理成 DocuGIS2 匯入用的
TSV(`id name x y date text` 加上任何額外欄位,`x` 是 WGS84 經度、`y` 是緯度),
回傳 `tsv` 與 `webUrl`。
DocuGIS2 的匯入器比想像中挑(2026-09-12 逐項實測,細節寫在 `docusky_mcp/ui.py`
的註解裡):`date` 欄只要有一格是空的或只寫年份(`1887`),那一列就會被整列丟掉,
但整個 `date` 欄不存在時每一列都進得去。所以 `build_docugis_tsv` 會把純年份補成
`YYYY-01`,而且在只有部分資料有日期時**預設不輸出 `date` 欄**(地圖完整、沒有時間
軸),要時間軸就傳 `include_dates=true`,代價是沒日期的那幾列不會出現。`1887-01`、
`1887/1/1`、`18870101`、`-0200-01-01`(西元前)都吃得下。
DocuGIS2 也是這個專案裡唯一**不能**用網址餵資料的 DocuSky 工具:它 56 支
script 沒有一支讀 `location.search`,也沒有註冊 `message` 監聽器,所以
WordCloudLite 那套 `?data=` 在這裡完全不成立(它認得的 `index.html?f=<id>` 要先把
資料寫進一個共用的公開帳號、資料就此公開,所以刻意不用)。剩下能走的就是它的貼上
框,這也是為什麼地圖的 `ui://` 資源是另一份 HTML(`DOCUGIS_HTML`)。
`search_documents`、`post_classification`、`tag_analysis` 這三個工具,在
`target="OPEN"` 時回傳的 JSON 裡多了一個 `webUrl` 欄位,指向
`docusky.org.tw` 上對應的查詢頁(`webApi/webpage-open-3in1.php`,用
`spType` 切換成一般搜尋 / 分布統計 / 標記分析檢視)。支援 **MCP Apps**
(`docusky_mcp/ui.py`)的 client 會把這個 URL 用一個沒有外部依賴、手刻
postMessage 協定的小型 `ui://` 資源嵌成 iframe 顯示;不支援的 client
就只是多一個可以忽略或當連結用的欄位,行為與加這個功能前完全一樣。`word_cloud`
回傳的 `webUrl` 走的是同一個 `ui://` 資源與同一條 CSP(`frameDomains`
已經涵蓋 `docusky.org.tw`)。
手刻那份 postMessage 有三個地方是照著 ext-apps 的 schema 與實測結果來的
(都寫在 `docusky_mcp/ui.py` 的模組 docstring 裡):
- `ui/initialize` 的 params **三個欄位都是必填**:`appInfo`、`appCapabilities`、
`protocolVersion`。0.3.0 只送了 `appCapabilities`,會驗證 params 的 host
會直接擋掉交握,結果就是什麼都不顯示——0.3.1 修好了這點。
- DocuSky 內建的頁碼是整頁跳轉,在沙箱 iframe 裡會翻成空白,所以翻頁改成由
工具列把 `&page=N` 直接設進 iframe 的 `src`(這條路實測可行)。
- 內嵌畫面預設高度太矮,所以會用 `ui/notifications/size-changed` 要 720px,
並用 `ui/request-display-mode` 提供全螢幕切換。
驗證方式是照 ext-apps 的 `examples/basic-host`(外層 proxy iframe + 內層
sandbox iframe 的雙層架構)架一個假 host,對真正的 docusky.org.tw 跑過
`allow-scripts allow-same-origin allow-forms` 與只有 `allow-scripts` 兩種沙箱。
`target="USER"` 時 `webUrl` 會是 `null`——DocuSky 用伺服器端的 session
cookie 認證私人資料庫,內嵌用的瀏覽器分頁沒有那個 cookie,硬塞連結只會顯示
「未登入」,所以私人查詢乾脆不給這個欄位。
---
## 注意事項
- 本專案使用 DocuSky 的 Web API(`docusky.org.tw/DocuSky/webApi/`)。該 API 沒有公開文件也沒有版本號,DocuSky 改版時可能需要跟著更新。
- 部分端點會在 JSON 前面夾帶 PHP 警告訊息,client 有做容錯。
- 命中數是**文件數**,不是詞頻。
- 少數資料庫的「分類」欄位在 DocuSky 端本身就是亂碼,不要據以推論。
- 部分資料庫仍在建構中,查不到內容是正常的。
- 請遵守 [DocuSky 服務與使用規範](https://hackmd.io/@DocuSky/rJqemuiFQ),並節制查詢頻率。
TDQS
Scored across 10 tools
Tools target distinct actions (search, get, list, analyze, map, login) with clear boundaries. Minor potential confusion between post_classification and twodim_analysis, but descriptions clarify their different purposes (facet breakdown vs. cross-tabulation).
All names follow a consistent verb_noun pattern (e.g., search_documents, get_document, list_databases, post_classification, twodim_analysis). No deviations in casing or style.
10 tools is a well-scoped set for a document search and analysis server, covering search, retrieval, metadata listing, analysis, visualization, mapping, and login without redundancy.
Core lifecycle is covered: list databases/corpora, search, retrieve full text, analyze facets/tags, visualize, map, and check login. Missing direct document export or bulk operations, but agents can work around these gaps.