mcp-server-104
mcp-server-104
台灣 104 人力銀行的 MCP server。讓 Claude(或任何 MCP client)能直接搜尋 104 的即時職缺。
這個工具適合你嗎?
你的情境 | 最佳工具 |
偶爾自己找工作 | 直接開 104 網站 |
想寫個一次性爬蟲抓資料 | Playwright / cycletls 腳本就好,不用 MCP |
想讓 Claude 幫你分析/比對/彙整/自動化職缺 | 這個 MCP |
Related MCP server: job-source-mcp
安裝
以下三種擇一,看你用什麼 client:
A:有快捷指令的 client —— 一行搞定,設定自動寫好:
claude mcp add job104 -- npx -y mcp-server-104 # Claude Codecodex mcp add job104 -- npx -y mcp-server-104 # OpenAI Codex CLI(新版才有;舊版走 B 的 TOML)B:手動貼設定的 client —— 把設定貼進該 client 的 MCP 設定檔:
Claude Desktop / Cursor / Windsurf(JSON):
{
"mcpServers": {
"job104": { "command": "npx", "args": ["-y", "mcp-server-104"] }
}
}OpenAI Codex CLI 舊版(~/.codex/config.toml):
[mcp_servers.job104]
command = "npx"
args = ["-y", "mcp-server-104"]A 和 B 做的是同一件事:告訴 client「用 npx 啟動這個 server」。核心到哪都是
npx -y mcp-server-104,差別只在各家 client 怎麼登記它。⚠️ ChatGPT 網頁/桌面版接不上這種本機型(stdio)server —— 它只支援遠端 URL 型 MCP,它的雲端上沒有你的電腦可以跑
npx。
C:開發者,想改 code —— clone 這個 repo 後:
npm install && npm run build
claude mcp add job104 -- node /你的路徑/104-mcp-server/dist/index.js日常指令與測試策略見下方「開發」。
用什麼方法取得資料
104 的搜尋 API 藏在 Cloudflare bot 防護後面。用 curl 或 Node fetch(即使帶 Referer / User-Agent)都會被擋 —— 回 403 或 Cloudflare 的 "Just a moment..." 挑戰頁。
關鍵不是 header,是 TLS 指紋。 Cloudflare 會檢查 TLS 握手的指紋(JA3);一般程式的指紋一看就不是瀏覽器,直接被攔。
本專案用 cycletls 偽裝成 Chrome 的 TLS 指紋,讓 Cloudflare 以為請求來自真瀏覽器 → 放行。這樣不用開瀏覽器(比 Playwright / Selenium 輕一個量級、快、好部署),純 HTTP 就能拿到真實 JSON。
cycletls 底層是一個 Go 寫的 TLS client 子程序,server 啟動時開一次、全程共用。
現在有什麼
Tool | 狀態 | 說明 |
| ✅ 真實資料 | 依關鍵字 + 多種篩選搜尋職缺,支援分頁 |
| ✅ 真實資料 | 取得單筆職缺完整詳情:完整 JD、薪資、地點、學經歷要求、技能、語言能力、福利、產業別 |
| ✅ 真實資料 | 列出某公司所有在徵職缺(分頁) |
search_jobs 參數
參數 | 必填 | 說明 |
| ✅ | 職務關鍵字,例如 |
| 工作地區名稱,例如 | |
| 月薪下限(新台幣),例如 | |
| 設 | |
| 設 | |
| 職務類別名稱,例如 | |
| 遠端: | |
| 工作性質: | |
| 需求年資: | |
| 第幾頁(每頁 20 筆),預設 1。想看更多就往後翻 | |
| 本頁回傳筆數上限,最多 20,預設 5 |
篩選參數的實作眉角(都是觀察 104 官網 UI 實際請求 +
metadata.total實測得來的):
salaryMin要同時送scmin+sctp=M+scstrict=1,缺了scstrict薪資篩選會被完全忽略。「面議」薪資值是
0,104 預設保留(面議可能開很高)。excludeNegotiable會排除它們。薪資上限
9,999,999是 104「不設上限」哨兵值,server 端已正規化成「N 元以上」。薪資前綴依原始s10類型標示(10=面議、30=時薪、40=日薪、50=月薪、60=年薪)—— 兼職多為時薪,別當月薪讀。
remoteWork=1完全/2部分、ro=1全職/2兼職、jobexp=1/3/5/10/99(互斥年資級距)。地區/職類用樹狀代碼表 + 剪枝:命中父節點(如「新竹縣市」)就用父代碼,不展開成一堆子代碼 —— 展開太多會讓 104 回
400。地區同名多處(如「信義區」)不聯集也不搜尋,回ambiguousArea請模型跟使用者確認(地理上不相干的地方聯集沒意義);職類多重命中則維持聯集(相關職類一起查通常是想要的)。廣告偵測:104 會在結果最前面塞廣告(原始欄位
jobType=1),它會無視關鍵字(例如護理師搜尋跑出「COACH 精品銷售」)。每筆回傳featured旗標標記它,excludeFeatured=true可整批濾掉。jobType=2(付費優先位)仍符合關鍵字,視為有效結果不標記。搜尋列表刻意不含完整 JD(精簡、避免模型整理清單時把某筆網址對錯到別筆),完整內容用get_job_detail。
欄位命名跨三個工具一致(都對照 104 原始欄位語意,避免同名不同物):
概念
search_jobs
get_job_detail
get_company_jobs
職缺代碼(slug,可餵回
get_job_detail)
jobId
jobId
jobId職缺網址
url
url
url地區(區級)
area
area
area完整地址(區+街道)
—
location—
需求年資
—
experience
experience擅長工具/語言(C++、Linux)
skills
skills—
職務技能(職類層級,如「軟體工程系統開發」)
—
jobSkills—
公司頁網址(餵給
get_company_jobs)
companyUrl
companyUrl—
是否為廣告位(
jobType=1)
featured—
—
更新日期(頁面的「MM/DD更新」)
appearDate
appearDate—
jobId一律是 slug(如7uqyj),不是 104 內部數字 —— slug 才能餵回get_job_detail。skills到哪都是「具體技術」。appearDate統一為YYYY/MM/DD。公司職缺刻意不回日期:公司 API 原始只有8/20這種無年份格式,久未更新的殭屍職缺看起來永遠像最近更新(實測有 2025 年的缺混在裡面),跨年靜默誤導 —— 想要某筆的日期,把它的jobId餵給get_job_detail拿完整的。
get_job_detail 參數
參數 | 必填 | 說明 |
| ✅ | 職缺網址或代碼,例如 |
get_company_jobs 參數
參數 | 必填 | 說明 |
| ✅ | 公司網址或代碼,例如 |
| 第幾頁(每頁 20 筆),預設 1 | |
| 本頁回傳筆數上限,最多 20,預設 10 |
三個工具怎麼串:
search_jobs/get_job_detail每筆都回url(職缺)和companyUrl(公司)兩個網址。想看某筆職缺完整內容 → 把它的
url餵給get_job_detail。想看「這家公司還有哪些缺」→ 把
companyUrl餵給get_company_jobs(它是指定公司的職缺列表,不是關鍵字搜尋)。
search_jobs ─ url ──────→ get_job_detail
│ │
└─ companyUrl ───────────┴──→ get_company_jobs104 內部 API 參考
主要 endpoint:
GET https://www.104.com.tw/jobs/search/api/jobs必要 header:Referer: https://www.104.com.tw/jobs/search/、Accept-Language: zh-TW
常用查詢參數(本專案目前只用到部分,其餘供未來擴充):
參數 | 意義 | 範例值 |
| 關鍵字 | 自由文字 |
| 關鍵字運算 |
|
| 排序 |
|
| 分頁 |
|
| 地區碼(逗號分隔) | 查 |
| 職類碼(逗號分隔) | 查 |
| 最低薪資 | 整數 |
| 遠端 |
|
| 全/兼職 |
|
| 年資 |
|
| 學歷 |
|
地區 / 職類代碼表(放 static.104.com.tw,沒有 Cloudflare 擋,一般 fetch 就能拿):
https://static.104.com.tw/category-tool/json/Area.json
https://static.104.com.tw/category-tool/json/JobCat.json其他 endpoint:
職缺詳情:
GET https://www.104.com.tw/job/ajax/content/{slug}(Referer 指向/job/{slug})公司職缺:
GET https://www.104.com.tw/api/companies/{code}/jobs?page=1&pageSize=20(回list.topJobs+list.normalJobs)
檔案結構
src/
index.ts 進入點:建 server、掛 tool、接 stdio、處理關閉
config.ts 所有設定 / 魔術數字(JA3 指紋、endpoint、節流區間…)
types.ts 乾淨型別 + normalizeJob / JobDetail / CompanyJob(防腐層)
query.ts 純函式:組查詢網址、client 端過濾、enum 對照
slug.ts 從 104 網址取出職缺 slug / 公司碼(types/query 共用)
codes.ts 地區/職類「名稱→官方代碼」解析(樹狀比對+剪枝,快取代碼表)
api/
httpClient.ts cycletls 單例(TLS 指紋偽裝)
throttle.ts 禮貌性隨機節流 1.5~3.5s
job104.ts 104 抓取層:組 URL → 打 API → 重試 → 正規化
tools/
searchJobs.ts search_jobs
getJobDetail.ts get_job_detail
getCompanyJobs.ts get_company_jobs
scripts/
smoke-test.mjs 手動發 JSON-RPC 驗證,不用開 Claude 也能測
test/
types.test.mjs normalize 邏輯(薪資格式、面議、哨兵值…)
query.test.mjs 組網址 / slug / 公司碼 / 過濾 / enum 對照
codes.test.mjs 代碼表樹狀比對 + 剪枝開發
npm run build # 編譯 src → dist
npm test # 跑單元測試(先 build 再 node --test,零額外依賴)
node scripts/smoke-test.mjs # 煙霧測試(連真實 104)
npm run inspect # 開 MCP Inspector GUI 除錯改完 code 要 npm run build,然後重啟 Claude Code(或用 /mcp reconnect)才會生效 —— client 只在 session 啟動時抓一次工具清單。
測試策略:純邏輯(normalize、組網址、過濾)都抽到 types.ts / query.ts,用 Node 內建 node --test 測,快又不用連網 —— 改壞馬上知道。碰網路的部分(job104.ts / httpClient.ts)用 smoke-test 對真實 104 驗證。
⚠️ 免責聲明
104 沒有公開官方 API。本專案使用的是網頁前端的非官方內部 endpoint,隨時可能因 104 改版而失效。
自動化存取可能違反 104 的服務條款。本專案僅供個人、低頻、學習用途。
請勿拿去做高頻抓取、大量爬取,或架成公開服務 —— 容易被封鎖,也有法律風險。
本專案已內建禮貌性節流(每次請求間隔隨機 1.5~3.5 秒),請勿移除或調低。
使用本專案造成的任何後果,使用者自負。
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseAqualityCmaintenanceEnables users to search LinkedIn's public job listings with advanced filters like location, salary, and experience level. It allows MCP-compatible clients to retrieve real-time job opportunities without requiring LinkedIn authentication or API keys.12MIT
- AlicenseNot gradedqualityBmaintenanceSearches job listings from Taiwanese job boards (104 and Yourator) and returns normalized results.MIT
- AlicenseAqualityAmaintenanceSearches 104 job listings with natural-language filters and retrieves full postings via MCP tools.322MIT
- FlicenseNot gradedqualityBmaintenanceEnables job search on LinkedIn through MCP tools, including keyword and location search, filtering by remote, easy apply, experience level, job type, and date, and retrieving job details.
Related MCP Connectors
Search live startup jobs from Claude, Cursor, or ChatGPT via MCP. Free, no account needed.
Job search and interview prep MCP. 11 tools, OAuth 2.1, cross-LLM. four-leaf.ai.
Search remote and onsite jobs through the public Corvi Careers MCP server.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/a7512cs/104-mcp-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server