mcp-job-intel
Pipeline de inteligencia laboral agéntico (MCP + LLM)
Un pipeline impulsado por agentes que utiliza el Model Context Protocol para orquestar herramientas externas de recuperación estructurada de datos, con una capa de puntuación LLM que clasifica descripciones de empleo no estructuradas frente a un perfil de candidato. La presión de la ventana de contexto se gestiona con una estrategia de recuperación escalonada que prioriza los metadatos (pipeline.py), y las mismas herramientas se exponen también a un agente real de llamada a herramientas con su propio bucle de planificación (agent.py) y a una API REST + WebSocket (api.py). Consulta docs/ para el documento completo.
Ejecútalo
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}'Resultado medido
Corpus de 150 empleos, lista corta de 8. prefilter() aplica filtros de etiqueta/título, seniority (descarta senior cuando los años del candidato < 4) y ubicación (ciudad preferida del candidato, normalizada por alias, o remoto), que reducen el número de supervivientes de 150 a 31:
Estrategia | Tokens de prompt | vs. ingenua |
A — enviar las 150 descripciones completas | 67,360 | — |
B — primero metadatos, luego recuperar 8 | 13,802 | 4.9× más barato |
C — prefilter → metadatos → recuperar 8 | 6,258 | 10.8× más barato |
Reprodúcelo con python pipeline.py --benchmark. Son números reales del data/jobs.json de este repositorio, no marcadores de posición. Los recuentos de tokens usan el codificador o200k_base de tiktoken (el que usan gpt-4o / gpt-4o-mini) — exactos, no estimados. La antigua heurística de caracteres ÷ 4 sobreestimó el coste de la estrategia ingenua en un 17.4% en este corpus; el campo heuristic_vs_real_tokens de benchmark() reproduce esa comparación.
Arquitectura
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_jobsEl argumento de la recuperación escalonada
Ingenua: entregar al modelo cada descripción completa y pedirle que las clasifique. Tres problemas.
Coste — 79k tokens de prompt por ejecución, y crece linealmente con el corpus.
Límite — a partir de unos cientos de ofertas supera la ventana de contexto por completo. No lento: imposible.
Calidad — la recuperación en contexto largo se degrada en medio de un prompt grande, así que la clasificación empeora a medida que añades más candidatos.
Recuperación escalonada, primero el filtro más barato:
Etapa | Mecanismo | Coste | Por qué aquí |
0 | Filtro determinista de etiqueta/título/ubicación en Python | gratis | Nunca dejes que un modelo lea lo que un |
1 | El LLM ve ~55 tokens de metadatos por empleo, elige los 8 mejores | ~5k | Pantalla de alta recuperación (recall). Se le indica que sobre-incluya, porque la etapa 2 puede rechazar. |
2 | Descripciones completas solo para los 8 supervivientes | ~4k | Fidelidad total, pagada una vez, solo donde cambia la respuesta. |
El principio generalizable — y lo que hay que decir en voz alta en una entrevista — es cascada por coste: ordena los filtros de más barato a más caro, y ajusta el umbral de cada etapa para la recuperación (recall) en lugar de la precisión, porque una etapa posterior aún puede rechazar, pero nada puede recuperar lo que una etapa temprana descartó.
Capa de agente (agent.py)
pipeline.py es un script fijo: prefiltrar, luego siempre seleccionar la lista corta, luego siempre puntuar. agent.py entrega al modelo las mismas herramientas MCP a través de la llamada a funciones de OpenAI y le permite planificar su propio camino — un agente real de llamada a herramientas, no una secuencia fija:
Respuesta final estructurada como llamada a herramienta. El agente no "responde en JSON y espera" — terminar significa llamar a una herramienta sintética
submit_rankingscuyo esquema de parámetros esschemas.RankingResult. Los argumentos no válidos vuelven como un error de validación que el modelo puede leer y corregir, con un número limitado de reintentos.Los fallos de herramientas se degradan, no rompen. Cualquier excepción de herramienta MCP se convierte en un resultado de herramienta normal
{"error": ...}que se devuelve al modelo, para que pueda sortear una llamada incorrecta en lugar de tumbar toda la ejecución.Un modelo que nunca converge sigue devolviendo algo. Si agota su presupuesto de pasos/reintentos sin una salida válida, el agente recurre a la misma lógica determinista
prefilter → shortlist → scorequepipeline.py, e informafallback_used: true.Los errores transitorios de API tienen su propio reintento, mediante
tenacity, separado del bucle de reintentos de esquema anterior — una mala conexión y una mala respuesta son modos de fallo distintos.
Consulta docs/CODE_WALKTHROUGH.md para el bucle paso a paso.
Capa REST + WebSocket (api.py)
Un servicio FastAPI envuelve las herramientas MCP, pipeline.py y agent.py para que sean accesibles por HTTP en lugar de solo como scripts CLI:
Endpoint | Qué hace |
| comprobación de actividad |
| lista de metadatos / detalle completo, misma invariante sin descripción que la herramienta MCP |
| estadísticas del corpus |
| ejecuta el pipeline de clasificación (bucle de planificación |
| igual que |
Una única sesión MCP stdio se abre al inicio y se comparte detrás de un bloqueo (api.MCPSession) en lugar de lanzar un subproceso por petición — una simplificación deliberada frente a un pool de conexiones real, documentada como tal en el docstring del módulo api.py, no vendida como un sistema distribuido real. Cada petición recibe un id de correlación (request_id), que se propaga por los registros y por cada evento transmitido, de modo que una ejecución puede rastrearse a través de los saltos asíncronos.
Notas sobre MCP que conviene saber de memoria
Por qué existe: N modelos × M integraciones se convierte en N + M. Un protocolo, JSON-RPC 2.0 sobre stdio o Streamable HTTP.
Herramientas vs recursos vs prompts: controlado por el modelo / controlado por la aplicación / controlado por el usuario. Acertar con este trío es un diferenciador habitual en entrevistas.
Forma de
CallToolResult:content(bloques),structured_content(tipado, envuelto como{"result": ...}para devoluciones que no son objetos),is_error. Verpipeline.call().El diseño de herramientas es diseño de API para un llamador no humano.
list_jobsyget_job_detailsestán separadas porque esa separación es lo que permite la recuperación escalonada. Los docstrings son la descripción de la herramienta que lee el modelo — docstring vago, elección de herramienta equivocada.Mejor parámetros por lotes que escalares:
get_job_details(job_ids: list[str])cuesta un viaje de ida y vuelta;get_job_detail(job_id: str)cuesta ocho.
Limitaciones conocidas
La recuperación de la lista corta (¿mantiene la etapa 1 los empleos etiquetados como relevantes que sobreviven al prefilter?) necesita una
OPENAI_API_KEYreal para medirse —python eval.py --top 8la ejecuta; no se ha ejecutado aquí por razones de coste.El corpus es sintético. Las ofertas reales son más desordenadas — HTML, duplicados, anuncios obsoletos.
No hay caché entre ejecuciones, así que las invocaciones repetidas vuelven a pagar la etapa 1.
Recuperación de la etapa 1 — medida, no supuesta
data/relevance_labels.json contiene 20 identificadores de empleo que un humano consideraría relevantes para el candidato, elegidos con una rúbrica documentada y reproducible (consulta el archivo). eval.py comprueba dos cosas por separado:
prefilter_recall— de los 20 empleos etiquetados como relevantes, ¿cuántos sobreviven al prefilter determinista? Gratis, sin clave API:python eval.py --prefilter-only→ 20/20, recall 1.0. La rúbrica de etiquetas es un subconjunto estricto de los propios filtros de prefilter, por lo que esto confirma que prefilter no está descartando silenciosamente el rol objetivo, en lugar de asumirlo.shortlist_recall— de esos, ¿cuántos sobreviven también a la lista corta del LLM con eltopque realmente usas?python eval.py --top 8— necesitaOPENAI_API_KEY, una llamada real al modelo, por lo que no se ejecuta en este repositorio; ejecútalo tú mismo cuando tengas una clave.
Tus tareas pendientes
prefilter()— añadir filtros de seniority y ubicación. Volver a ejecutar--benchmark, registrar el número.Hecho: 150 → 31 supervivientes, reducción de 10.8× frente al enfoque ingenuo.Sustituirapprox_tokenspor el recuento real contiktoken; anota cuánto se desviaba la heurística ÷4.Hecho: la heurística sobreestimaba en un 17.4%.Crear un conjunto etiquetado de relevancia de 20 empleos y medir la recuperación de la etapa 1.Hecho para la mitad gratuita (prefilter_recall= 1.0); la mitad de pago (shortlist_recall) está conectada eneval.py --top 8, ejecútala con tu propia clave.Conectar el servidor a la configuración MCP de Claude Desktop y llamarlo manualmente.El fragmento de configuración y las instrucciones de reinicio están endocs/OVERVIEW.md— el registro real se hace en tu propia aplicación de Claude Desktop, no es algo que este repositorio pueda hacer por ti.
Documentación
docs/OVERVIEW.md— qué es este proyecto, qué problema resuelve y por qué, arquitectura, conexión con Claude Desktop, prueba local, limitaciones conocidas.docs/CODE_WALKTHROUGH.md— cada módulo, función por función.
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