Job Ad Intelligence MCP
We need to translate the given text from English to Spanish. The text describes a paid MCP server for analyzing job ads. We must preserve product names, protocol names, URLs, numbers, technical terms. The name "Job Ad Intelligence MCP" is not in the text? Actually it's in the instruction but not in the <text>. The text starts with "A paid MCP server..." So we translate that. Keep "MCP server" as is? "MCP" is a protocol name? Probably keep as MCP. Numbers: $0.002 to $0.05, USDC, Base, x402. Also "API key" is technical. Translate the rest naturally. Translation: "Un servidor MCP de pago que ayuda a los agentes de IA a analizar anuncios de empleo. Cinco herramientas: extraer datos estructurados de cualquier anuncio de empleo (texto o URL), normalizar cadenas salariales a mínimo/máximo/moneda/periodo, detectar el nivel de antig
Documentación
Job Ad Intelligence MCP
Un servicio compatible con MCP de pago que ayuda a los agentes LLM a analizar anuncios de empleo. Expone cinco herramientas para extraer datos estructurados, normalizar salarios, detectar seniority, puntuar la adecuación de candidatos y generar preguntas de solicitud.
Construido con Node.js, TypeScript, el Model Context Protocol SDK y un guardián de pago preparado para x402.
Inicio rápido
# 1. Clone / copy the project
cd job-ad-intelligence-mcp
# 2. Install dependencies
npm install
# 3. Configure environment
cp .env.example .env
# Edit .env as needed (defaults are fine for local development)
# 4. Run in development mode
npm run dev
# 5. Run tests
npm test
# 6. Build for production
npm run build
npm start
Variables de entorno
| Variable | Por defecto | Descripción |
|---|---|---|
PORT | 3000 | Puerto HTTP en el que escuchar |
HOST | 0.0.0.0 | Dirección de enlace |
PAYMENTS_ENABLED | false | Habilitar el bloqueo de pago x402 (true/false) |
FETCH_TIMEOUT_MS | 10000 | Máximo de ms de espera al obtener una URL de anuncio de empleo |
FETCH_MAX_BYTES | 1048576 | Tamaño máximo de respuesta al obtener una URL (bytes) |
NODE_ENV | development | Entorno de Node |
Consulta .env.example para ver un ejemplo completo anotado.
Endpoint MCP
El servidor expone un transporte HTTP Streamable en:
POST http://localhost:3100/mcp ← send MCP messages / initialise session
GET http://localhost:3100/mcp ← SSE stream for server-initiated messages
DELETE http://localhost:3100/mcp ← terminate session
Comprobación de salud (sin autenticación requerida):
GET http://localhost:3100/health
Referencia de herramientas
1. extract_job_ad
Extrae datos estructurados de un anuncio de empleo. Acepta texto sin formato o una URL.
Entrada:
{
"text": "Senior Software Engineer at Acme Corp...",
"url": "https://example.com/jobs/123"
}
Se requiere uno de text o url. Cuando se proporcionan ambos, se prefiere text.
Salida:
{
"title": "Senior Software Engineer",
"company": "Acme Corp",
"location": "London",
"remote_policy": "hybrid",
"employment_type": "full_time",
"salary": {
"raw": "£70,000 - £90,000",
"min": 70000,
"max": 90000,
"currency": "GBP",
"period": "year"
},
"seniority": "senior",
"skills": {
"required": ["typescript", "react", "postgresql"],
"preferred": ["graphql", "redis"]
},
"responsibilities": ["Build and maintain APIs", "..."],
"requirements": ["5+ years experience", "..."],
"benefits": ["25 days holiday", "health insurance"],
"application_instructions": "Apply via our portal...",
"confidence": 0.85
}
2. normalise_salary
Analiza una cadena de salario de formato libre en un objeto estructurado.
Entrada:
{
"salary_text": "£45k to £60k per annum",
"location": "London, UK"
}
Salida:
{
"raw": "£45k to £60k per annum",
"min": 45000,
"max": 60000,
"currency": "GBP",
"period": "year",
"notes": []
}
Maneja: £45k–£60k, up to £70,000, from £500 per day, $120k, €80,000 pa, competitive, DOE.
3. detect_seniority
Clasifica el nivel de seniority a partir de un título de puesto y una descripción opcional.
Entrada:
{
"title": "Senior Software Engineer",
"description": "You'll have 6+ years of experience..."
}
Salida:
{
"seniority": "senior",
"signals": ["Title match: Senior / Sr / experienced keyword detected in title \"Senior Software Engineer\""],
"confidence": 0.8
}
Niveles: entry | junior | mid | senior | lead | head_of | executive | unknown
4. score_candidate_fit
Compara un CV contra un anuncio de empleo. Solo basado en habilidades — sin inferencia de características protegidas.
Entrada:
{
"cv_text": "..full CV text...",
"job_ad_text": "..full job ad text.."
}
Salida:
{
"overall_score": 78,
"summary": "Overall fit is good (78/100)...",
"matched_skills": ["typescript", "react", "docker"],
"missing_skills": ["kubernetes", "terraform"],
"experience_alignment": "strong",
"red_flags": [],
"interview_talking_points": ["Highlight direct experience with: typescript, react..."],
"disclaimer": "This is an automated skills-based comparison and should not be used as the sole basis for hiring or employment decisions."
}
5. generate_application_questions
Genera de 5 a 10 preguntas específicas que un candidato puede hacer antes de postularse o durante la selección, basadas en las señales del anuncio de empleo.
Entrada:
{
"job_ad_text": "..full job ad text.."
}
Salida:
{
"questions": [
{
"question": "Can you share the salary range for this role?",
"why_it_matters": "The advert uses vague compensation language...",
"category": "compensation"
}
]
}
Categorías: role | company | compensation | flexibility | process | expectations
Uso con un cliente MCP
Claude Desktop (claude_desktop_config.json)
{
"mcpServers": {
"job-ad-intelligence": {
"url": "http://localhost:3100/mcp",
"transport": "streamable-http"
}
}
}
Programático (TypeScript con @modelcontextprotocol/sdk)
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
const transport = new StreamableHTTPClientTransport(
new URL('http://localhost:3100/mcp'),
);
const client = new Client({ name: 'my-agent', version: '1.0.0' });
await client.connect(transport);
// List available tools
const tools = await client.listTools();
console.log(tools);
// Call normalise_salary
const result = await client.callTool({
name: 'normalise_salary',
arguments: { salary_text: '£45k - £60k per year' },
});
console.log(result.content[0].text);
await client.close();
Bloqueo de pago (x402)
El servidor utiliza el protocolo x402 oficial a través de @x402/express. Los pagos se recaudan en USDC en Base (o en cualquier red EVM/Solana compatible).
Modo de desarrollo (por defecto)
PAYMENTS_ENABLED=false — todas las solicitudes pasan libremente. No se necesita billetera.
Habilitar pagos (testnet — seguro, sin dinero real)
- Obtén una dirección de billetera (cualquier billetera EVM, por ejemplo MetaMask)
- Obtén USDC de testnet del Coinbase CDP Faucet
- Configura tu
.env:
PAYMENTS_ENABLED=true
X402_PAY_TO_ADDRESS=0xYourWalletAddress
X402_PRICE=$0.001
X402_NETWORK=eip155:84532 # Base Sepolia (testnet)
X402_FACILITATOR_URL=https://x402.org/facilitator
Sin pago, cada solicitud /mcp recibe un 402 Payment Required:
curl -X POST http://localhost:3100/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"initialize","id":1,"params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1"}}}'
# → HTTP 402 { "error": "Payment Required", "accepts": [...] }
Los clientes pagan firmando una transferencia de USDC e incluyendo el encabezado X-PAYMENT — el SDK del cliente x402 (o un agente de IA consciente de x402) maneja esto automáticamente.
Ir a mainnet (pagos reales)
- Regístrate en portal.cdp.coinbase.com y crea claves API
- Actualiza
.env:
X402_NETWORK=eip155:8453
X402_FACILITATOR_URL=https://api.cdp.coinbase.com/platform/v2/x402
CDP_API_KEY_ID=your-key-id
CDP_API_KEY_SECRET=your-key-secret
- En
src/payments/paymentGuard.ts, cambia el cliente facilitador como se muestra en los comentarios (~línea 30)
Toda la lógica de pago está aislada en src/payments/paymentGuard.ts — no es necesario cambiar ningún otro archivo.
Estructura del proyecto
src/
server.ts ← MCP server + Express HTTP transport
types.ts ← All TypeScript types and Zod schemas
payments/
paymentGuard.ts ← x402-ready payment middleware (isolated)
tools/
extractJobAd.ts ← Tool 1
normaliseSalary.ts ← Tool 2
detectSeniority.ts ← Tool 3
scoreCandidateFit.ts ← Tool 4
generateApplicationQuestions.ts ← Tool 5
utils/
fetchUrl.ts ← Secure URL fetcher with SSRF protection
salaryParser.ts ← Deterministic salary parsing
textHelpers.ts ← Shared text utilities
tests/
normaliseSalary.test.ts
detectSeniority.test.ts
scoreCandidateFit.test.ts
paymentGuard.test.ts
generateApplicationQuestions.test.ts
Scripts
npm run dev # Run with tsx (hot-reload friendly)
npm run build # Compile TypeScript to dist/
npm start # Run compiled JS
npm test # Run all tests with Vitest
npm run test:run # Run tests once (no watch)
npm run lint # ESLint
Notas de seguridad
- La obtención de URL rechaza
localhost, rangos de IP privados y protocolos no http/https (protección SSRF) - El tamaño de respuesta está limitado a
FETCH_MAX_BYTES(1 MB por defecto) - El tiempo de espera de obtención se aplica en
FETCH_TIMEOUT_MS(10s por defecto) - Sin secretos codificados — toda la configuración a través de variables de entorno
- La herramienta
score_candidate_fitcompara solo habilidades, experiencia, herramientas y seniority — sin inferencia de características protegidas