Skip to main content
Glama
a7512cs

mcp-server-104

by a7512cs

mcp-server-104

Servidor MCP para el portal de empleo 104 de Taiwán. Permite que Claude (o cualquier cliente MCP) busque directamente ofertas de empleo en tiempo real de 104.

¿Es esta herramienta adecuada para ti?

Tu situación

Mejor herramienta

Buscas trabajo ocasionalmente por tu cuenta

Abre directamente el sitio web de 104

Quieres escribir un scraper puntual para obtener datos

Con un script de Playwright / cycletls basta, no necesitas MCP

Quieres que Claude te ayude a analizar/comparar/resumir/automatizar ofertas de empleo

Este MCP

Related MCP server: job-source-mcp

Instalación

Elige una de las siguientes tres opciones, según el cliente que uses:

A: Cliente con comando rápido — se resuelve en una línea, la configuración se escribe automáticamente:

claude mcp add job104 -- npx -y mcp-server-104   # Claude Code
codex mcp add job104 -- npx -y mcp-server-104    # OpenAI Codex CLI(新版才有;舊版走 B 的 TOML)

B: Cliente con configuración manual — pega la configuración en el archivo de configuración MCP de ese cliente:

Claude Desktop / Cursor / Windsurf (JSON):

{
  "mcpServers": {
    "job104": { "command": "npx", "args": ["-y", "mcp-server-104"] }
  }
}

OpenAI Codex CLI versión antigua (~/.codex/config.toml):

[mcp_servers.job104]
command = "npx"
args = ["-y", "mcp-server-104"]

A y B hacen lo mismo: le indican al cliente «inicia este servidor con npx». El núcleo en todos los casos es npx -y mcp-server-104; la diferencia está solo en cómo cada cliente lo registra.

⚠️ La versión web/de escritorio de ChatGPT no puede conectarse a este tipo de servidor local (stdio) — solo admite MCP por URL remota, y en su nube no hay una máquina tuya donde ejecutar npx.

C: Desarrollador, quieres modificar el código — tras clonar este repo:

npm install && npm run build
claude mcp add job104 -- node /你的路徑/104-mcp-server/dist/index.js

Los comandos de uso diario y la estrategia de pruebas están en la sección «Desarrollo» más abajo.

Método de obtención de datos

La API de búsqueda de 104 está detrás de la protección anti-bots de Cloudflare. Con curl o fetch de Node (incluso con Referer / User-Agent) te bloquea — devuelve 403 o la página de desafío "Just a moment..." de Cloudflare.

La clave no son las cabeceras, es la huella TLS. Cloudflare comprueba la huella del handshake TLS (JA3); la huella de los programas normales no parece de navegador y se bloquea directamente.

Este proyecto usa cycletls para hacerse pasar por la huella TLS de Chrome, haciendo que Cloudflare crea que la petición viene de un navegador real → la deja pasar. Así no hace falta abrir un navegador (un orden de magnitud más ligero que Playwright / Selenium, rápido y fácil de desplegar), y se obtiene el JSON real solo con HTTP.

cycletls usa internamente un subproceso de cliente TLS escrito en Go, que se inicia una vez al arrancar el servidor y se comparte durante toda la sesión.

Qué hay ahora

Tool

Estado

Descripción

search_jobs

✅ Datos reales

Busca ofertas por palabra clave + múltiples filtros, con paginación

get_job_detail

✅ Datos reales

Obtiene el detalle completo de una oferta: JD completo, salario, ubicación, requisitos de estudios/experiencia, habilidades, idiomas, beneficios, sector

get_company_jobs

✅ Datos reales

Lista todas las ofertas activas de una empresa (paginado)

Parámetros de search_jobs

Parámetro

Obligatorio

Descripción

keyword

Palabra clave del puesto, por ejemplo Ingeniero Rust

area

Nombre de la zona de trabajo, por ejemplo Taipéi, Hsinchu (se resuelve automáticamente al código de zona oficial de 104). Si hay varias zonas con el mismo nombre (como «Xinyi», que existe en Taipéi y en Keelung), no se busca directamente; se devuelve una lista de candidatos ambiguousArea para que el modelo te confirme

salaryMin

Salario mensual mínimo (Nuevos dólares taiwaneses), por ejemplo 60000. Se filtran las ofertas con salario claramente inferior; las de «salario negociable» se conservan por defecto

excludeNegotiable

Pon true para excluir ofertas de «salario negociable». Por defecto false

excludeFeatured

Pon true para excluir ofertas de anuncio de pago de 104 (las de featured=true). Por defecto false

jobCategory

Nombre de la categoría del puesto, por ejemplo Ingeniero de software (se resuelve automáticamente al código de categoría oficial de 104)

remote

Remoto: full totalmente remoto / partial parcialmente remoto / any cualquiera

jobType

Tipo de jornada: fulltime jornada completa / parttime media jornada

experience

Años de experiencia requeridos: under-1y / 1-3y / 3-5y / 5-10y / over-10y

page

Número de página (20 resultados por página), por defecto 1. Para ver más, avanza de página

limit

Límite de resultados devueltos en esta página, máximo 20, por defecto 5

Detalles de implementación de los filtros (obtenidos observando las peticiones reales de la interfaz web de 104 + verificados con metadata.total):

  1. salaryMin debe enviarse junto con scmin + sctp=M + scstrict=1; sin scstrict el filtro de salario se ignora por completo.

  2. El valor de salario «negociable» es 0, y 104 lo conserva por defecto (el negociable podría ser muy alto). excludeNegotiable los excluye.

  3. El salario máximo 9,999,999 es el valor centinela de «sin límite superior» de 104; el servidor lo normaliza a «N o más». El prefijo del salario se indica según el tipo original s10 (10=negociable, 30=por hora, 40=por día, 50=por mes, 60=por año) — los de media jornada suelen ser por hora, no lo leas como salario mensual.

  4. remoteWork=1 completo/2 parcial, ro=1 jornada completa/2 media jornada, jobexp=1/3/5/10/99 (rangos de años mutuamente excluyentes).

  5. Zonas/categorías usan tabla de códigos en árbol + poda: si se acierta un nodo padre (como «Condados de Hsinchu»), se usa el código padre, sin expandir a un montón de códigos hijos — expandir demasiado hace que 104 devuelva 400. Las zonas con el mismo nombre en varios lugares (como «Xinyi») no se unen ni se buscan; se devuelve ambiguousArea para que el modelo confirme con el usuario (unir zonas geográficamente inconexas no tiene sentido); en cambio, los múltiples aciertos de categorías sí se unen (buscar categorías relacionadas juntas suele ser lo deseado).

  6. Detección de anuncios: 104 mete anuncios al principio de los resultados (campo original jobType=1), que ignoran la palabra clave (por ejemplo, una búsqueda de enfermeros muestra «COACH ventas de artículos de lujo»). Cada resultado devuelve el flag featured para marcarlos, y excludeFeatured=true los filtra todos de una vez. jobType=2 (posición prioritaria de pago) sigue coincidiendo con la palabra clave y se considera resultado válido, sin marcar. La lista de búsqueda excluye deliberadamente el JD completo (para ser conciso y evitar que el modelo, al organizar la lista, asocie la URL de un resultado con otro); el contenido completo se obtiene con get_job_detail.

Los nombres de campos son coherentes entre las tres herramientas (todos corresponden a la semántica de los campos originales de 104, para evitar que el mismo nombre signifique cosas distintas):

Concepto

search_jobs

get_job_detail

get_company_jobs

Código de oferta (slug, se puede pasar de vuelta a get_job_detail)

jobId

jobId

jobId

URL de la oferta

url

url

url

Zona (nivel de distrito)

area

area

area

Dirección completa (distrito + calle)

location

Años de experiencia requeridos

experience

experience

Herramientas/idiomas dominados (C++, Linux)

skills

skills

Competencias del puesto (nivel de categoría, como «desarrollo de sistemas de software»)

jobSkills

URL de la página de la empresa (para pasar a get_company_jobs)

companyUrl

companyUrl

Si es posición de anuncio (jobType=1)

featured

Fecha de actualización (el «MM/DD actualizado» de la página)

appearDate

appearDate

jobId es siempre un slug (como 7uqyj), no el número interno de 104 — solo el slug se puede pasar de vuelta a get_job_detail. skills es siempre «tecnología concreta». appearDate se unifica como AAAA/MM/DD. Las ofertas de empresa deliberadamente no devuelven fecha: la API de empresa solo tiene el formato original 8/20 sin año, y las ofertas zombi sin actualizar parecen siempre recientes (se ha comprobado que hay ofertas de 2025 mezcladas), lo que engaña silenciosamente entre años — si quieres la fecha de una oferta concreta, pasa su jobId a get_job_detail para obtener la completa.

Parámetros de get_job_detail

Parámetro

Obligatorio

Descripción

jobUrlOrId

URL o código de la oferta, por ejemplo https://www.104.com.tw/job/7uqyj o 7uqyj (usa el url devuelto por search_jobs)

Parámetros de get_company_jobs

Parámetro

Obligatorio

Descripción

companyUrlOrId

URL o código de la empresa, por ejemplo https://www.104.com.tw/company/1a2x6blghh o 1a2x6blghh

page

Número de página (20 resultados por página), por defecto 1

limit

Límite de resultados devueltos en esta página, máximo 20, por defecto 10

Cómo se encadenan las tres herramientas:

  • search_jobs / get_job_detail devuelven en cada resultado dos URLs: url (oferta) y companyUrl (empresa).

  • Si quieres el contenido completo de una oferta → pasa su url a get_job_detail.

  • Si quieres ver «qué otras ofertas tiene esta empresa» → pasa companyUrl a get_company_jobs (es la lista de ofertas de una empresa concreta, no una búsqueda por palabra clave).

search_jobs ─ url ──────→ get_job_detail
      │                        │
      └─ companyUrl ───────────┴──→ get_company_jobs

Referencia de la API interna de 104

Endpoint principal:

GET https://www.104.com.tw/jobs/search/api/jobs

Cabeceras necesarias: Referer: https://www.104.com.tw/jobs/search/, Accept-Language: zh-TW

Parámetros de consulta habituales (este proyecto solo usa una parte; el resto queda para ampliaciones futuras):

Parámetro

Significado

Valor de ejemplo

keyword

Palabra clave

Texto libre

kwop

Operación de palabra clave

7 (coincidencia total)

order

Ordenación

15 relevancia (por defecto) · 16 más reciente · 13 salario

page / pagesize

Paginación

pagesize recomendado 20

area

Código de zona (separado por comas)

Consultar Area.json (ver abajo)

jobcat

Código de categoría (separado por comas)

Consultar JobCat.json

scmin + scstrict=1

Salario mínimo

Entero

remoteWork

Remoto

1 totalmente remoto · 2 parcial · 1,2 ambos (verificado)

ro

Jornada completa/media jornada

1 jornada completa · 2 media jornada (verificado; algunos valores de wt devuelven 400, no usar)

jobexp

Años de experiencia

1/3/5/10/99 = menos de 1 año/1-3/3-5/5-10/más de 10 años (rangos mutuamente excluyentes, verificado)

edu

Nivel de estudios

4,5,6 universidad o superior, etc.

Tablas de códigos de zona / categoría (en static.104.com.tw, sin bloqueo de Cloudflare, se pueden obtener con un fetch normal):

https://static.104.com.tw/category-tool/json/Area.json
https://static.104.com.tw/category-tool/json/JobCat.json

Otros endpoints:

  • Detalle de oferta: GET https://www.104.com.tw/job/ajax/content/{slug} (Referer apuntando a /job/{slug})

  • Ofertas de empresa: GET https://www.104.com.tw/api/companies/{code}/jobs?page=1&pageSize=20 (devuelve list.topJobs + list.normalJobs)

Estructura de archivos

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      代碼表樹狀比對 + 剪枝

Desarrollo

npm run build                 # 編譯 src → dist
npm test                      # 跑單元測試(先 build 再 node --test,零額外依賴)
node scripts/smoke-test.mjs   # 煙霧測試(連真實 104)
npm run inspect               # 開 MCP Inspector GUI 除錯

Después de modificar el código hay que ejecutar npm run build y reiniciar Claude Code (o reconectar con /mcp) para que surta efecto — el cliente solo obtiene la lista de herramientas una vez al iniciar la sesión.

Estrategia de pruebas: toda la lógica pura (normalización, construcción de URLs, filtrado) está extraída a types.ts / query.ts, y se prueba con el node --test integrado de Node: rápido y sin necesidad de conexión — si algo se rompe, lo sabes al momento. La parte que toca la red (job104.ts / httpClient.ts) se verifica con smoke-tests contra el 104 real.

  • 104 no tiene API oficial pública. Este proyecto usa endpoints internos no oficiales del frontend web, que pueden dejar de funcionar en cualquier momento si 104 cambia su sitio.

  • El acceso automatizado puede violar los términos de servicio de 104. Este proyecto es solo para uso personal, de baja frecuencia y con fines educativos.

  • No lo uses para scraping de alta frecuencia, rastreo masivo, ni lo montes como servicio público — es fácil que te bloqueen y hay riesgo legal.

  • Este proyecto ya incluye limitación de velocidad cortés (intervalo aleatorio de 1,5~3,5 segundos entre peticiones); no lo elimines ni lo reduzcas.

  • El usuario asume toda responsabilidad por las consecuencias del uso de este proyecto.

A
license - permissive license
Not graded
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

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

  • A
    license
    A
    quality
    C
    maintenance
    Enables 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.
    1
    2
    MIT
  • A
    license
    A
    quality
    A
    maintenance
    Searches 104 job listings with natural-language filters and retrieves full postings via MCP tools.
    3
    22
    MIT
  • F
    license
    Not graded
    quality
    B
    maintenance
    Enables 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.

View all related MCP servers

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.

View all MCP Connectors

Latest Blog Posts

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