job104-mcp
This server provides MCP tools to search and retrieve job listings from Taiwan's 104 Job Bank (104.com.tw), with automatic resolution of Chinese area and job category names to internal codes. It also bypasses Cloudflare bot protection via TLS fingerprint impersonation.
Search jobs (
search_jobs): Filter listings by keyword, area (e.g.,["台北市大安區"]), job category (e.g.,["軟體工程師"]), minimum salary, remote work, recency, experience, education, job type, sort order, and pagination. Each result includes adetail_idfor fetching full details.Get job detail (
get_job_detail): Retrieve the complete job posting — description, requirements, salary, and location — using adetail_idfrom search results. Often reveals salary info not shown in search listings.Look up codes (
lookup_code): Resolve Chinese job category or area names into their 104 internal codes, returning matching{name, code}pairs for disambiguation.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@job104-mcpfind software engineer jobs in Taipei"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
job104-mcp
An MCP server for searching 104 人力銀行 job listings with natural-language filters. Works with any MCP client — Claude, Cursor, Windsurf, Cline, Zed, VS Code, and others.
Disclaimer: This is an unofficial, educational/personal-use tool. It is not affiliated with, endorsed by, or sponsored by 104 Corporation. It calls 104's public web endpoints; please respect 104's Terms of Service and use it at a reasonable, low frequency. No scraped job data is distributed with this project.
How it works
104 sits behind Cloudflare bot protection — a plain HTTP request to its JSON API
returns 403. This server uses curl_cffi
with impersonate="chrome" to match a real browser's TLS fingerprint, so the same
public endpoints return their normal JSON. The AI sees clean structured results; the
104 category/area codes are resolved from Chinese names automatically.
Related MCP server: JobSpy MCP Server
Prerequisite: install uv
Every install path runs the server through uv, so it must
be installed first (uvx ships with uv):
# macOS / Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
# Windows (PowerShell)
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"Install in any MCP client (Cursor, Windsurf, Cline, Zed, VS Code, …)
MCP is an open protocol, so any MCP-capable client works — not just Claude. Add this to
the client's MCP config (e.g. Cursor's ~/.cursor/mcp.json); the command/args form is
what most clients accept:
{
"mcpServers": {
"job104": { "command": "uvx", "args": ["job104-mcp@latest"] }
}
}Install in Claude Code (User scope)
claude mcp add job104 -s user -- uvx job104-mcp@latestOr from a local clone (no PyPI required):
claude mcp add job104 -- uv run --project /absolute/path/to/job104-mcp -m job104_mcpInstall in Claude Desktop (.mcpb bundle)
The .mcpb bundle is a Claude-Desktop-only convenience (other clients use the JSON config
above). Download job104-mcp-vX.Y.Z.mcpb from the
Releases page and double-click it (or drag
it into Claude Desktop → Settings → Extensions).
To build the bundle yourself:
npx @anthropic-ai/mcpb pack . # produces job104-mcp.mcpbRun manually (stdio)
uv run job104-mcp
# or
uv run python -m job104_mcpTools
search_jobs— search with keyword, area, job category, salary floor, remote, recency, experience, education, sort, paging. Use Chinese names forarea/jobcat(e.g.["台北市大安區"],["軟體工程師"]); they resolve to 104 codes automatically. Each result carries adetail_id.get_job_detail— full posting for adetail_idfromsearch_jobs.lookup_code— resolve a job-category or area name to its 104 code.
Refresh code tables
The bundled jobcat.json / area.json come from 104's public category tool. Regenerate:
uv run python scripts/fetch_codes.pyTests
uv run pytest # fast unit tests
uv run pytest -m live # hits the real 104 siteReleasing (maintainer)
Releases are automated by .github/workflows/release.yml, triggered when the
version in pyproject.toml changes on main. It publishes to PyPI, builds the
.mcpb bundle, and attaches it to a GitHub Release.
One-time PyPI setup (uses Trusted Publishing,
no API token stored): on https://pypi.org/manage/account/publishing/ add a pending
publisher with project job104-mcp, owner mozzan, repo job104-mcp, workflow
release.yml.
To cut a release: bump version in pyproject.toml, commit to main.
License
MIT — see LICENSE. Provided as-is, without warranty.
Available Tools
3 toolsget_job_detailA
取得單一職缺的完整內容(職務說明、條件、薪資、地點)。 detail_id 來自 search_jobs 結果的 detail_id 欄位。
| Name | Required | Description | Default |
|---|---|---|---|
| detail_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It discloses the content returned (職務說明、條件、薪資、地點) but does not mention any behavioral traits like read-only nature, authentication requirements, rate limits, or potential errors. This is adequate for a read operation but could be more transparent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences: one clearly stating the tool's function and the second explaining the parameter source. Every word earns its place, with no redundancy or unnecessary detail, making it highly efficient and front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's simplicity (1 parameter, no output schema) and sibling tools, the description is fairly complete. It explains what the tool does and where the input comes from. It could be more explicit about the return format, but listing the content areas (job description, conditions, etc.) provides sufficient context.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The parameter 'detail_id' has 0% schema coverage, meaning the schema provides no description. The tool's description compensates by explaining that the ID comes from 'search_jobs' results, adding crucial semantic context beyond the raw schema. It does not specify format or constraints, but the origin is valuable.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it retrieves full content of a single job listing, specifying details like job description, conditions, salary, and location. It also distinguishes itself from the sibling tool 'search_jobs', which lists jobs, making the purpose unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly states that the 'detail_id' comes from 'search_jobs' results, providing clear context for when to use this tool (after a search). However, it does not explicitly mention when not to use it or suggest alternatives beyond the implied dependency.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
lookup_codeB
查 104 職類/地區代碼。kind: 'jobcat' 或 'area'。回傳 [{name, code}]。
| Name | Required | Description | Default |
|---|---|---|---|
| kind | Yes | ||
| query | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description must carry full behavioral disclosure. It adds the allowed values for kind and the return format, but does not mention side effects, authorization, rate limits, or error scenarios. The behavior is partially disclosed but incomplete.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is very concise at two sentences. It front-loads the core purpose and provides necessary details without waste. However, it could be slightly more structured (e.g., separate lines for each parameter).
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The complexity is low, but with 0% schema coverage, the description should fully cover parameter behavior. It handles kind but not query. The output schema exists but the description already mentions the return format. Overall, it is adequate but not complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must compensate. It adds meaning for the 'kind' parameter (possible values) but does not explain the 'query' parameter at all. This is incomplete for a tool with two required parameters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: to look up 104 job category/area codes. It specifies the kind parameter values ('jobcat' or 'area') and the return format. This distinguishes it from sibling tools like get_job_detail and search_jobs.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies the tool is for code lookup when you need job category or area codes, but it does not explicitly state when to use it over siblings or provide exclusion criteria. The guidance is minimal but sufficient for a simple lookup.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_jobsA
搜尋 104 職缺。area/jobcat 用中文名稱(如 ["台北市大安區"]、["軟體工程師"]), 內部自動轉成 104 代碼;若名稱不明確會回傳建議選項。每筆結果的 detail_id 可傳給 get_job_detail 取得完整內容。
sort: relevance|date|salary(不填時:有給 salary_min 就自動用 salary 排序, 否則 relevance)。
薪資門檻提醒:104 沒有可靠的伺服器端薪資篩選,所以給 salary_min 時是「用薪資 排序把高薪職缺排到前面」,不是硬篩。薪資會標月薪/年薪(年薪職缺數字較大)。標 「待遇面議」的職缺薪資未公開——若職稱/公司看起來可能達標,呼叫 get_job_detail 通常能拿到真實薪資(detail 常有列表沒有的數字)。
| Name | Required | Description | Default |
|---|---|---|---|
| edu | No | ||
| area | No | ||
| page | No | ||
| sort | No | ||
| is_new | No | ||
| jobcat | No | ||
| remote | No | ||
| keyword | No | ||
| job_type | No | ||
| exp_years | No | ||
| page_size | No | ||
| salary_min | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries full burden. It explains that area/jobcat are converted from Chinese names, ambiguous inputs return suggestions, salary_min sorts rather than filters, and '待遇面議' jobs may have actual salary in detail. However, it does not cover behavior for other parameters like 'remote', 'is_new', etc., leaving gaps.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with clear sections: purpose, area/jobcat handling, sort behavior, and salary notes. It front-loads the main purpose. While not extremely concise, every sentence adds value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given 12 parameters, no output schema, and no annotations, the description is incomplete. It does not explain the output format (only mentions detail_id) and omits many parameters. The salary note, though helpful, does not fully compensate for missing behavioral details.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. It adds meaning for area, jobcat, sort, and salary_min (explaining conversion, suggestions, and sorting behavior). However, 8 of 12 parameters (e.g., keyword, job_type, exp_years) are not described, so the compensation is partial.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states '搜尋 104 職缺' (search 104 job openings), specifying the verb and resource. It differentiates from sibling tools by noting that the 'detail_id' from results can be used with 'get_job_detail', and 'lookup_code' is a separate tool for code lookup.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides context on when to use this tool (searching jobs) and references 'get_job_detail' for detailed info. It explains sorting behavior and salary filter limitations. However, it does not explicitly mention when not to use this tool or alternatives for other parameters.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
1 tool update
v0.1.7- Changed
search_jobs3 fields changed- added
Input schema / properties / sort / anyOfAdded value: +[ + { + "type": "string" + }, + { + "type": "null" + } +] - changed
Input schema / properties / sort / defaultPrevious value: -"relevance"New value: +null - removed
Input schema / properties / sort / typeRemoved value: -"string"
3 tool updates
v0.1.1- First observed
get_job_detail - First observed
lookup_code - First observed
search_jobs
TDQS
Each tool has a distinct purpose: search_jobs for querying listings, get_job_detail for retrieving full details of a specific job, and lookup_code for resolving category and area codes. There is no functional overlap, and the descriptions clearly differentiate them.
All tools follow a consistent verb_noun snake_case pattern: search_jobs, get_job_detail, lookup_code. While 'lookup' is a compound verb, the naming is predictable and clear, aiding agent comprehension.
With only 3 tools, the server is minimal yet sufficient for its purpose of job searching. It covers the essential operations (search, detail retrieval, code lookup) without excess. While a few additional tools (e.g., listing filters) could be added, the current count is reasonable.
The tool surface offers a complete workflow for job discovery: lookup codes to build search parameters, search for jobs, and retrieve full details. The search tool handles ambiguous inputs by providing suggestions, and the detail tool can uncover hidden salary data. No obvious gaps exist for the stated purpose.
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 Connectors
Semantic search over 3.5M+ live US job postings pulled straight from company ATSes. Read-only.
Search live startup jobs from Claude, Cursor, or ChatGPT via MCP. Free, no account needed.
Google Jobs listings with direct apply links via the Apify Google Jobs Scraper, hosted MCP.
Search job postings, companies, and technology stacks across 10M+ companies.
Related MCP Servers
- AlicenseNot gradedqualityAmaintenanceMCP server that exposes job search data from multiple boards, enabling clients to query and manage job listings via natural language.7MIT
- AlicenseNot gradedqualityAmaintenanceEnables job search and scraping across multiple job boards (LinkedIn, Indeed, Glassdoor, etc.) with advanced filtering, directly from Claude Desktop or other MCP clients.5MIT
- 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.-
- FlicenseNot gradedqualityBmaintenanceEnables searching real job listings from multiple job boards (Indeed, LinkedIn, Glassdoor, Google Jobs, etc.) through a single MCP tool, designed for use as a custom connector in Claude Cowork.-
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/mozzan/job104-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server