mcp-job-intel
Agentic Job Intelligence Pipeline (MCP + LLM)
Eine agentengetriebene Pipeline, die das Model Context Protocol nutzt, um externe Werkzeuge für strukturierten Datenabruf zu orchestrieren, mit einer LLM-Bewertungsebene, die unstrukturierte Stellenbeschreibungen gegen ein Kandidatenprofil rankt. Der Druck auf das Kontextfenster wird durch eine abgestufte Metadaten-zuerst-Abrufstrategie (pipeline.py) bewältigt, und dieselben Werkzeuge werden auch einem echten Tool-Calling-Agenten mit eigener Planungsschleife (agent.py) sowie einer REST + WebSocket-API (api.py) bereitgestellt. Die vollständige Ausarbeitung finden Sie in docs/.
Ausführen
pip install -r requirements.txt
python pipeline.py --benchmark # token comparison, zero API calls
python pipeline.py --dry-run # real MCP subprocess handshake, no LLM
export OPENAI_API_KEY=sk-...
python pipeline.py --top 8 # fixed 3-stage pipeline
python agent.py --dry-run # agent tool discovery, no LLM calls
export OPENAI_API_KEY=sk-...
python agent.py --top 8 # tool-calling agent with a planning loop
python eval.py --prefilter-only # stage-1 recall, deterministic half, no key needed
pytest -q # in-process MCP server, no key needed
uvicorn api:app --reload # REST + WebSocket layer, http://localhost:8000
curl localhost:8000/health
curl -X POST localhost:8000/rank -H 'content-type: application/json' -d '{"use_llm": false}'Gemessenes Ergebnis
Corpus mit 150 Jobs, Shortlist von 8. prefilter() wendet Tag-/Titel-, Senioritäts- (verwirft senior, wenn die Berufsjahre des Kandidaten < 4 sind) und Standort-Gates (bevorzugte Stadt des Kandidaten, alias-normalisiert, oder Remote) an, wodurch die Zahl der Überlebenden von 150 auf 31 sinkt:
Strategie | Prompt tokens | vs. naiv |
A — alle 150 vollständigen Beschreibungen senden | 67,360 | — |
B — Metadaten zuerst, dann 8 abrufen | 13,802 | 4.9× günstiger |
C — Prefilter → Metadaten → 8 abrufen | 6,258 | 10.8× günstiger |
Reproduzierbar mit python pipeline.py --benchmark. Echte Zahlen aus dem heutigen data/jobs.json dieses Repos, keine Platzhalter. Token-Zählungen verwenden den o200k_base-Encoder von tiktoken (den gpt-4o / gpt-4o-mini tatsächlich verwenden) – exakt, nicht geschätzt. Die alte Heuristik Zeichen ÷ 4 hat die Kosten der naiven Strategie bei diesem Corpus um 17.4% überschätzt; das Feld heuristic_vs_real_tokens von benchmark() reproduziert diesen Vergleich.
Architektur
MCP SERVER (stdio subprocess) MCP CLIENT / pipeline.py
--------------------------------- ------------------------------------
tool list_jobs -> metadata <---- Stage 0 prefilter() [0 tokens]
tool get_job_details -> full text Stage 1 shortlist [~5k tokens]
tool get_candidate_profile Stage 2 score [~4k tokens]
tool corpus_stats
resource jobs://schema Meter tracks tokens per stage
prompt rank_jobsDas Argument für den gestuften Abruf
Naiv: Jede vollständige Beschreibung dem Modell geben und es bitten, zu ranken. Drei Probleme.
Kosten — 79k Prompt-Token pro Lauf, und es wächst linear mit dem Corpus.
Obergrenze — ab ein paar hundert Einträgen überschreitet es das Kontextfenster schlichtweg. Nicht langsam, sondern unmöglich.
Qualität — der Long-Context-Recall nimmt in der Mitte eines großen Prompts ab, sodass das Ranking schlechter wird, je mehr Kandidaten Sie hinzufügen.
Gestufter Abruf, günstigster Filter zuerst:
Stufe | Mechanismus | Kosten | Warum hier |
0 | Deterministischer Tag-/Titel-/Standort-Filter in Python | kostenlos | Lassen Sie ein Modell nie lesen, was |
1 | LLM sieht ~55 Token Metadaten pro Job, wählt die Top 8 | ~5k | High-Recall-Sieb. Angewiesen, großzügig einzuschließen, weil Stufe 2 ablehnen kann. |
2 | Vollständige Beschreibungen nur für die 8 Überlebenden | ~4k | Volle Genauigkeit, einmal bezahlt, nur dort, wo es die Antwort ändert. |
Das verallgemeinerbare Prinzip — und das, was man in einem Vorstellungsgespräch laut sagen sollte — ist Kaskade nach Kosten: Ordnen Sie Ihre Filter vom günstigsten zum teuersten, und setzen Sie die Schwelle jeder Stufe auf Recall statt auf Präzision, denn eine spätere Stufe kann zwar noch ablehnen, aber nichts kann wiederherstellen, was eine frühe Stufe verworfen hat.
Agentische Ebene (agent.py)
pipeline.py ist ein festes Skript: Prefilter, dann immer Shortlist, dann immer Score. agent.py reicht dem Modell dieselben MCP-Tools über OpenAI-Funktionsaufrufe und lässt es seinen eigenen Weg planen — ein echter Tool-Calling-Agent, keine fest verdrahtete Sequenz:
Strukturierte Endantwort als Tool-Aufruf. Der Agent antwortet nicht „in JSON und hofft“ — fertig zu sein bedeutet, ein synthetisches Tool
submit_rankingsaufzurufen, dessen Parameterschema istschemas.RankingResult. Ungültige Argumente kommen als Validierungsfehler zurück, den das Modell lesen und korrigieren kann, für eine begrenzte Anzahl von Wiederholungen.Tool-Fehler führen zu Degradierung, nicht zum Absturz. Jede MCP-Tool-Ausnahme wird zu einem normalen Tool-Ergebnis
{"error": ...}, das dem Modell zurückgegeben wird, sodass es um einen fehlerhaften Aufruf herum navigieren kann, statt den gesamten Lauf zum Absturz zu bringen.Ein Modell, das nie konvergiert, gibt trotzdem etwas zurück. Wenn es sein Schritt-/Wiederholungsbudget ohne gültige Ausgabe erschöpft, greift der Agent auf dieselbe deterministische Logik
prefilter → shortlist → scorewiepipeline.pyzurück und meldetfallback_used: true.Transiente API-Fehler erhalten einen eigenen Wiederholungsversuch über
tenacity, getrennt von der obigen Schema-Wiederholungsschleife — eine schlechte Verbindung und eine schlechte Antwort sind verschiedene Fehlermodi.
Den Schritt-für-Schritt-Ablauf finden Sie in docs/CODE_WALKTHROUGH.md.
REST + WebSocket-Ebene (api.py)
Ein FastAPI-Dienst kapselt die MCP-Tools, pipeline.py und agent.py, sodass sie über HTTP erreichbar sind und nicht nur als CLI-Skripte:
Endpunkt | Funktion |
| Liveness-Check |
| Metadatenliste / vollständige Details, dieselbe Invariante ohne Beschreibung wie das MCP-Tool |
| Corpus-Statistiken |
| die Ranking-Pipeline ausführen (Standard: |
| dasselbe wie |
Eine MCP-stdio-Sitzung wird beim Start einmal geöffnet und hinter einer Sperre gemeinsam genutzt (api.MCPSession), anstatt pro Anfrage einen Subprozess zu erzeugen — eine bewusste Vereinfachung gegenüber einem echten Connection-Pool, die im Modul-Docstring von api.py als solche dokumentiert ist und nicht als echtes verteiltes System überverkauft wird. Jede Anfrage erhält eine Korrelations-ID (request_id), die durch Logs und jedes gestreamte Ereignis hindurchläuft, sodass ein Lauf über die asynchronen Hops hinweg verfolgt werden kann.
MCP-Hinweise, die man in- und auswendig kennen sollte
Warum es existiert: N Modelle × M Integrationen wird zu N + M. Ein Protokoll, JSON-RPC 2.0 über stdio oder Streamable HTTP.
Tools vs. Ressourcen vs. Prompts: modellgesteuert / anwendungsgesteuert / benutzergesteuert. Dieses Dreiergespann richtig hinzubekommen, ist ein häufiges Unterscheidungsmerkmal in Vorstellungsgesprächen.
CallToolResult-Form:content(Blöcke),structured_content(typisiert, als{"result": ...}verpackt bei Nicht-Objekt-Rückgaben),is_error. Siehepipeline.call().Tool-Design ist API-Design für einen nicht-menschlichen Aufrufer.
list_jobsundget_job_detailssind getrennt, weil genau diese Trennung den gestuften Abruf ermöglicht. Docstrings sind die Tool-Beschreibung, die das Modell liest — vager Docstring, falsche Tool-Wahl.Batch-Parameter statt skalarer Parameter:
get_job_details(job_ids: list[str])kostet einen Round Trip;get_job_detail(job_id: str)kostet acht.
Bekannte Grenzen
Shortlist-Recall (Behält Stufe 1 die als relevant markierten Jobs, die den Prefilter überleben?) benötigt einen echten
OPENAI_API_KEY, um gemessen zu werden —python eval.py --top 8führt ihn aus; hier aus Kostengründen nicht ausgeführt.Der Corpus ist synthetisch. Echte Stellenausschreibungen sind unordentlicher — HTML, Duplikate, veraltete Einträge.
Kein Caching zwischen Läufen, daher zahlt man bei wiederholten Aufrufen erneut für Stufe 1.
Stufe-1-Recall — gemessen, nicht angenommen
data/relevance_labels.json enthält 20 Job-IDs, die ein Mensch als für den Kandidaten relevant bezeichnen würde, ausgewählt anhand einer dokumentierten, reproduzierbaren Bewertungsrichtlinie (siehe Datei). eval.py prüft zwei Dinge getrennt:
prefilter_recall— Wie viele der 20 als relevant markierten Jobs überleben den deterministischen Prefilter? Kostenlos, kein API-Schlüssel:python eval.py --prefilter-only→ 20/20, Recall 1.0. Die Label-Richtlinie ist eine echte Teilmenge der Prefilter-Gates selbst, daher bestätigt dies, dass der Prefilter die Zielrolle nicht stillschweigend verwirft, anstatt dies anzunehmen.shortlist_recall— Wie viele davon überleben auch die LLM-Shortlist bei demtop, mit dem Sie tatsächlich arbeiten?python eval.py --top 8— benötigtOPENAI_API_KEY, einen echten Modellaufruf, wird daher in diesem Repo nicht ausgeführt; führen Sie es selbst aus, wenn Sie einen Schlüssel haben.
Ihre TODOs
prefilter()— Senioritäts- und Standort-Gates hinzufügen.--benchmarkerneut ausführen und die Zahl notieren.Erledigt: 150 → 31 Überlebende, 10.8× Reduktion gegenüber naiv.approx_tokensdurch echtetiktoken-Zählung ersetzen; festhalten, wie weit die ÷4-Heuristik danebenlag.Erledigt: Die Heuristik überschätzte um 17.4%.Einen markierten Relevanzsatz mit 20 Jobs erstellen und den Stufe-1-Recall messen.Erledigt für die kostenlose Hälfte (prefilter_recall= 1.0); die kostenpflichtige Hälfte (shortlist_recall) ist ineval.py --top 8verdrahtet, führen Sie sie mit Ihrem eigenen Schlüssel aus.Den Server in die MCP-Konfiguration von Claude Desktop einbinden und von Hand aufrufen.Das Konfigurations-Snippet und die Neustartanweisungen finden Sie indocs/OVERVIEW.md— die tatsächliche Registrierung erfolgt in Ihrer eigenen Claude-Desktop-App, was dieses Repo nicht für Sie erledigen kann.
Dokumentation
docs/OVERVIEW.md— was dieses Projekt ist, welches Problem es löst und warum, Architektur, Einbindung von Claude Desktop, lokale Testbarkeit, bekannte Einschränkungen.docs/CODE_WALKTHROUGH.md— jedes Modul, Funktion für Funktion.
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 Connectors
MCP server providing access to the Scorecard API to evaluate and optimize LLM systems.
GetJobzi MCP server for job search, application tracking, and career forecasting.
MCP server for AI job search — find jobs, track applications, get alerts. Claude, ChatGPT, Cursor.
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/jaideepdnaik/mcp-job-intel'
If you have feedback or need assistance with the MCP directory API, please join our Discord server