Skip to main content
Glama
a7512cs

mcp-server-104

by a7512cs

mcp-server-104

MCP-Server für die taiwanesische Jobbörse 104. Ermöglicht Claude (oder jedem MCP-Client), direkt in den aktuellen Stellenangeboten von 104 zu suchen.

Ist dieses Tool das Richtige für dich?

Deine Situation

Bestes Tool

Gelegentlich selbst auf Jobsuche

Direkt die 104-Website nutzen

Einmaligen Scraper für Daten schreiben wollen

Playwright / cycletls-Skript reicht, kein MCP nötig

Claude bei der Analyse/ dem Vergleich/ der Zusammenfassung/ Automatisierung von Stellenangeboten helfen lassen

Dieses MCP

Related MCP server: job-source-mcp

Installation

Wähle eine der folgenden drei Optionen, je nachdem, welchen Client du verwendest:

A: Client mit Schnellbefehl – In einer Zeile erledigt, Konfiguration wird automatisch geschrieben:

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: Client mit manueller Konfiguration – Füge die Konfiguration in die MCP-Konfigurationsdatei des jeweiligen Clients ein:

Claude Desktop / Cursor / Windsurf (JSON):

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

OpenAI Codex CLI (ältere Version) (~/.codex/config.toml):

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

A und B tun dasselbe: Sie teilen dem Client mit, „diesen Server mit npx starten“. Der Kern ist überall npx -y mcp-server-104, der Unterschied liegt nur darin, wie die jeweiligen Clients ihn registrieren.

⚠️ Die ChatGPT-Web-/Desktop-Version kann keine lokalen (stdio) Server wie diesen anbinden – sie unterstützt nur Remote-URL-basierte MCP, und in ihrer Cloud gibt es keinen Computer, auf dem npx ausgeführt werden kann.

C: Entwickler, die Code ändern möchten – Nach dem Klonen dieses Repos:

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

Tägliche Befehle und Teststrategie findest du unten unter „Entwicklung“.

Wie die Daten abgerufen werden

Die Such-API von 104 liegt hinter dem Cloudflare-Bot-Schutz. Mit curl oder Node fetch (selbst mit Referer/User-Agent) wird man blockiert – es kommt eine 403-Antwort oder die Cloudflare-Herausforderungsseite „Just a moment...“.

Der Schlüssel ist nicht der Header, sondern der TLS-Fingerabdruck. Cloudflare prüft den Fingerabdruck des TLS-Handshakes (JA3); der Fingerabdruck normaler Programme sieht nicht wie ein Browser aus und wird direkt blockiert.

Dieses Projekt verwendet cycletls, um den TLS-Fingerabdruck von Chrome zu imitieren, sodass Cloudflare denkt, die Anfrage stamme von einem echten Browser → lässt sie durch. So ist kein Browser erforderlich (eine Größenordnung leichter als Playwright/Selenium, schneller, besser bereitstellbar), und reines HTTP liefert echte JSON-Daten.

cycletls basiert auf einem in Go geschriebenen TLS-Client-Subprozess, der beim Serverstart einmal gestartet und während der gesamten Sitzung gemeinsam genutzt wird.

Was es jetzt gibt

Tool

Status

Beschreibung

search_jobs

✅ Echte Daten

Suche nach Stellenangeboten nach Schlüsselwort + mehreren Filtern, mit Paginierung

get_job_detail

✅ Echte Daten

Ruft die vollständigen Details einer einzelnen Stelle ab: vollständige JD, Gehalt, Standort, Ausbildungs-/Berufserfahrungsanforderungen, Fähigkeiten, Sprachkenntnisse, Zusatzleistungen, Branche

get_company_jobs

✅ Echte Daten

Listet alle offenen Stellen eines Unternehmens auf (paginiert)

Parameter von search_jobs

Parameter

Erforderlich

Beschreibung

keyword

Stellenschlüsselwort, z. B. Rust 工程师

area

Name des Arbeitsbereichs, z. B. 台北市, 新竹 (wird automatisch in den offiziellen 104-Bereichscode aufgelöst). Bei gleichnamigen Bereichen (z. B. „信義区“ gibt es in Taipei und Keelung) wird nicht direkt gesucht, sondern eine ambiguousArea-Kandidatenliste zurückgegeben, damit das Modell mit dir bestätigen kann

salaryMin

Untergrenze des Monatsgehalts (in NT$), z.B. 60000. Stellen mit einem Gehalt deutlich unter diesem Wert werden herausgefiltert; „Verhandelbar“ wird standardmäßig beibehalten

excludeNegotiable

Auf true setzen, um „Verhandelbar“-Stellen auszuschließen. Standard: false

excludeFeatured

Auf true setzen, um bezahlte Anzeigen von 104 auszuschließen (diejenigen mit featured=true). Standard: false

jobCategory

Name der Berufskategorie, z.B. Software-Ingenieur (wird automatisch in den offiziellen 104-Jobkategoriecode aufgelöst)

remote

Remote: full vollständig remote / partial teilweise remote / any egal

jobType

Art der Anstellung: fulltime Vollzeit / parttime Teilzeit

experience

Erforderliche Berufserfahrung: under-1y / 1-3y / 3-5y / 5-10y / over-10y

page

Seitenzahl (20 Einträge pro Seite), Standard: 1. Für mehr nach hinten blättern

limit

Maximale Anzahl der zurückgegebenen Einträge auf dieser Seite, max. 20, Standard: 5

Hinweise zur Implementierung der Filterparameter (alle durch Beobachtung der tatsächlichen Anfragen der 104-Website-UI + metadata.total-Tests ermittelt):

  1. salaryMax muss zusammen mit scmin + sctp=M + scstrict=1 gesendet werden; ohne scstrict wird der Gehaltsfilter vollständig ignoriert.

  2. Der Gehaltswert für „Verhandelbar“ ist 0, und 104 behält diese standardmäßig bei (Verhandelbar kann hoch sein). excludeNegotiable schließt sie aus.

  3. Der Gehaltsobergrenze 9,999,999 ist der Sentinel-Wert für „keine Obergrenze“ von 104; der Server normalisiert ihn zu „N oder mehr“. Das Gehaltspräfix wird gemäß dem ursprünglichen s10-Typ angegeben (10=Verhandelbar, 30=Stundenlohn, 40=Tageslohn, 50=Monatslohn, 60=Jahreslohn) – Teilzeit ist meist Stundenlohn, nicht als Monatslohn lesen.

  4. remoteWork=1 vollständig/2 teilweise, ro=1 Vollzeit/2 Teilzeit, jobexp=1/3/5/10/99 (sich gegenseitig ausschließende Erfahrungsstufen).

  5. Bereich/Jobkategorie verwenden Baumcodetabelle + Pruning: Wenn ein übergeordneter Knoten (z.B. „Neue Landkreise/Städte“) getroffen wird, wird der übergeordnete Code verwendet, nicht in eine Reihe von Untercodes expandiert – zu viele Expansionen führen zu 400 von 104. Bei gleichen Namen an mehreren Orten (z.B. „信義区“) wird weder eine Vereinigung noch eine Suche durchgeführt, sondern ambiguousArea zurückgegeben, damit das Modell den Benutzer bestätigen kann (eine Vereinigung geografisch nicht zusammenhängender Orte ist sinnlos); bei mehreren Treffern in der Jobklasse bleibt die Vereinigung erhalten (zusammenhängende Jobklassen gemeinsam zu suchen ist normalerweise gewünscht).

  6. Anzeigenerkennung: 104 platziert Anzeigen am Anfang der Ergebnisse (ursprüngliches Feld jobType=1), die Schlüsselwörter ignorieren (z.B. erscheint bei der Suche nach „Krankenschwester“ ein „COACH Luxusverkauf“). Jeder Eintrag gibt ein featured-Flag zurück, um dies zu markieren; excludeFeatured=true kann sie in einem Rutsch herausfiltern. jobType=2 (bezahlte Prioritätsposition) entspricht weiterhin dem Schlüsselwort und wird als gültiges Ergebnis nicht markiert. Die Suchliste enthält absichtlich keine vollständige JD (kompakt, um zu vermeiden, dass das Modell beim Erstellen einer Liste die URL eines Eintrags einem anderen zuordnet); den vollständigen Inhalt erhältst du mit get_job_detail.

Feldnamen sind über die drei Tools hinweg konsistent (alle entsprechen der Semantik der ursprünglichen 104-Felder, um Namensgleichheit mit unterschiedlichen Bedeutungen zu vermeiden):

Konzept

search_jobs

get_job_detail

get_company_jobs

Stellen-Code (Slug, kann an get_job_detail zurückgegeben werden)

jobId

jobId

jobId

Stellen-URL

url

url

url

Bereich (Bezirksebene)

area

area

area

Vollständige Adresse (Bezirk+Straße)

location

Erforderliche Berufserfahrung

experience

experience

Bevorzugte Tools/Sprachen (C++, Linux)

skills

skills

Berufliche Fähigkeiten (Jobklassenebene, z.B. „Software-Engineering-Systementwicklung“)

jobSkills

Firmen-URL (für get_company_jobs)

companyUrl

companyUrl

Ist Anzeigenplatz (jobType=1)

featured

Aktualisierungsdatum („MM/DD aktualisiert“ auf der Seite)

appearDate

appearDate

jobId ist immer ein slug (z.B. 7uqyj), nicht die interne Nummer von 104 – nur der slug kann an get_job_detail zurückgegeben werden. skills ist überall „konkrete Technologie“. appearDate ist einheitlich YYYY/MM/DD. Firmenjobs geben bewusst kein Datum zurück: Die Firmen-API hat ursprünglich nur Formate wie 8/20 ohne Jahr, und veraltete Zombie-Stellen sehen immer wie kürzlich aktualisiert aus (in Tests waren 2025er-Stellen darunter gemischt), was über Jahre hinweg stillschweigend irreführend ist – wenn du das Datum eines Eintrags möchtest, gib seine jobId an get_job_detail, um das vollständige Datum zu erhalten.

Parameter von get_job_detail

Parameter

Erforderlich

Beschreibung

jobUrlOrId

✅ Ja

Stellen-URL oder Code, z.B. https://www.104.com.tw/job/7uqyj oder 7uqyj (verwende die von search_jobs zurückgegebene url)

Parameter von get_company_jobs

Parameter

Erforderlich

Beschreibung

companyUrlOrId

✅ Ja

Firmen-URL oder Code, z.B. https://www.104.com.tw/company/1a2x6blghh oder 1a2x6blghh

page

Seitenzahl (Standard: 1)

limit

Maximale Anzahl der zurückgegebenen Einträge auf dieser Seite, max. 20, Standard: 10

Wie die drei Tools zusammenarbeiten:

  • search_jobs / get_job_detail geben jeweils url (Stelle) und companyUrl (Firma) zurück.

  • Wenn du den vollständigen Inhalt einer Stelle sehen möchtest → gib ihre url an get_job_detail.

  • Wenn du sehen möchtest, „welche anderen Stellen diese Firma hat“ → gib companyUrl an get_company_jobs (es ist eine Liste von Stellen für bestimmte Firma, keine Schlüsselwortsuche).

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

Referenz der internen API von 104

Haupt-Endpoint:

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

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

Häufig verwendete Abfrageparameter (dieses Projekt verwendet derzeit nur einen Teil; der Rest ist für zukünftige Erweiterungen):

Parameter

Bedeutung

Beispielwert

keyword

Schlüsselwort

Freitext

kwop

Schlüsselwortoperation

7 (alle erfüllen)

order

Sortierung

15 Relevanz (Standard) · 16 Neueste · 13 Gehalt

page / pagesize

Paginierung

pagesize empfohlen 20

area

Bereichscode (durch Komma getrennt)

Siehe Area.json (unten)

jobcat

Jobklassencode (durch Komma getrennt)

Siehe JobCat.json

scmin + scstrict=1

Mindestgehalt

Ganzzahl

remoteWork

Remote

1 vollständig remote · 2 teilweise · 1,2 egal (getestet)

ro

Vollzeit/Teilzeit

1 Vollzeit · 2 Teilzeit (getestet; wt-Teilwerte ergeben 400, nicht verwenden)

jobexp

Berufserfahrung

1/3/5/10/99 = unter 1 Jahr/1-3/3-5/5-10/über 10 Jahre (sich gegenseitig ausschließende Stufen, getestet)

edu

Ausbildung

4,5,6 Bachelor oder höher usw.

Bereichs-/Jobklass-Codetabellen (auf static.104.com.tw, nicht durch Cloudflare blockiert, normaler Fetch reicht):

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

Andere Endpoints:

  • Stellendetails: GET https://www.104.com.tw/job/ajax/content/{slug} (Referer zeigt auf /job/{slug})

  • Firmenjobs: GET https://www.104.com.tw/api/companies/{code}/jobs?page=1&pageSize=20 (gibt list.topJobs + list.normalJobs zurück)

Dateistruktur

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

Entwicklung

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

Nach Codeänderungen muss npm run build ausgeführt und dann Claude Code neu gestartet werden (oder /mcp reconnect verwenden), damit die Änderungen wirksam werden – der Client ruft die Tool-Liste nur einmal beim Start der Sitzung ab.

Teststrategie: Reine Logik (Normalisierung, URL-Aufbau, Filterung) ist in types.ts / query.ts ausgelagert und wird mit dem integrierten node --test von Node getestet – schnell und ohne Netzwerkverbindung – sofortige Fehlererkennung. Netzwerkbezogene Teile (job104.ts / httpClient.ts) werden mit einem Smoke-Test gegen die echte 104-Website verifiziert.

⚠️ Haftungsausschluss

  • 104 hat keine offizielle öffentliche API. Dieses Projekt verwendet nicht offizielle interne Endpoints des Web-Frontends, die jederzeit durch Änderungen von 104 ungültig werden können.

  • Automatisierter Zugriff kann gegen die Nutzungsbedingungen von 104 verstoßen. Dieses Projekt ist nur für persönliche, niederfrequente, Lernzwecke gedacht.

  • Nicht für Hochfrequenz-Abrufe, Massen-Scraping oder als öffentlicher Dienst verwenden – das kann zur Sperrung führen und birgt rechtliche Risiken.

  • Dieses Projekt enthält bereits eine höfliche Drosselung (zufällige Verzögerung von 1,5 bis 3,5 Sekunden zwischen Anfragen). Bitte nicht entfernen oder reduzieren.

  • Jegliche Konsequenzen aus der Nutzung dieses Projekts trägt der Benutzer selbst.

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