Job Ad Intelligence MCP

Um servidor MCP pago que ajuda agentes de IA a analisar anúncios de emprego. Cinco ferramentas: extrair dados estruturados de qualquer anúncio de emprego (texto ou URL), normalizar strings salariais em mínimo/máximo/moeda/período, detectar nível de senioridade a partir de títulos de cargos, pontuar um currículo contra um anúncio de emprego e gerar perguntas direcionadas para candidatura. Preço de $0,002 a $0,05 por chamada, pago em USDC na Base via x402. Nenhuma chave de API necessária.

Documentação

Job Ad Intelligence MCP

Um serviço pago compatível com MCP que ajuda agentes de LLM a analisar anúncios de emprego. Expõe cinco ferramentas para extrair dados estruturados, normalizar salários, detectar senioridade, avaliar a adequação de candidatos e gerar perguntas de candidatura.

Construído com Node.js, TypeScript, o Model Context Protocol SDK e um guarda de pagamento pronto para x402.


Início 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

Variáveis de ambiente

VariávelPadrãoDescrição
PORT3000Porta HTTP para escutar
HOST0.0.0.0Endereço de bind
PAYMENTS_ENABLEDfalseAtivar gate de pagamento x402 (true/false)
FETCH_TIMEOUT_MS10000Máx. ms para aguardar ao buscar uma URL de anúncio de emprego
FETCH_MAX_BYTES1048576Tamanho máximo de resposta ao buscar uma URL (bytes)
NODE_ENVdevelopmentAmbiente do Node

Consulte .env.example para um exemplo completo anotado.


Endpoint MCP

O servidor expõe um transporte HTTP Streamable em:

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

Verificação de saúde (sem autenticação necessária):

GET http://localhost:3100/health

Referência de ferramentas

1. extract_job_ad

Extrai dados estruturados de um anúncio de emprego. Aceita texto bruto ou uma URL.

Entrada:

{
  "text": "Senior Software Engineer at Acme Corp...",
  "url": "https://example.com/jobs/123"
}

Um de text ou url é obrigatório. Quando ambos são fornecidos, text é preferido.

Saída:

{
  "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

Analisa uma string de salário de formato livre em um objeto estruturado.

Entrada:

{
  "salary_text": "£45k to £60k per annum",
  "location": "London, UK"
}

Saída:

{
  "raw": "£45k to £60k per annum",
  "min": 45000,
  "max": 60000,
  "currency": "GBP",
  "period": "year",
  "notes": []
}

Lida com: £45k–£60k, up to £70,000, from £500 per day, $120k, €80,000 pa, competitive, DOE.


3. detect_seniority

Classifica o nível de senioridade a partir de um título de cargo e descrição opcional.

Entrada:

{
  "title": "Senior Software Engineer",
  "description": "You'll have 6+ years of experience..."
}

Saída:

{
  "seniority": "senior",
  "signals": ["Title match: Senior / Sr / experienced keyword detected in title \"Senior Software Engineer\""],
  "confidence": 0.8
}

Níveis: entry | junior | mid | senior | lead | head_of | executive | unknown


4. score_candidate_fit

Compara um currículo contra um anúncio de emprego. Baseado apenas em habilidades — sem inferência de características protegidas.

Entrada:

{
  "cv_text": "..full CV text...",
  "job_ad_text": "..full job ad text.."
}

Saída:

{
  "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

Gera de 5 a 10 perguntas direcionadas que um candidato pode fazer antes de se candidatar ou durante a triagem, com base em sinais no anúncio de emprego.

Entrada:

{
  "job_ad_text": "..full job ad text.."
}

Saída:

{
  "questions": [
    {
      "question": "Can you share the salary range for this role?",
      "why_it_matters": "The advert uses vague compensation language...",
      "category": "compensation"
    }
  ]
}

Categorias: role | company | compensation | flexibility | process | expectations


Uso com um cliente MCP

Claude Desktop (claude_desktop_config.json)

{
  "mcpServers": {
    "job-ad-intelligence": {
      "url": "http://localhost:3100/mcp",
      "transport": "streamable-http"
    }
  }
}

Programático (TypeScript com @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();

Gate de pagamento (x402)

O servidor usa o protocolo x402 oficial via @x402/express. Os pagamentos são coletados em USDC na Base (ou em qualquer rede EVM/Solana suportada).

Modo de desenvolvimento (padrão)

PAYMENTS_ENABLED=false — todas as solicitações passam livremente. Nenhuma carteira necessária.

Ativando pagamentos (testnet — seguro, sem dinheiro real)

  1. Obtenha um endereço de carteira (qualquer carteira EVM, ex.: MetaMask)
  2. Obtenha USDC de testnet do Coinbase CDP Faucet
  3. Defina seu .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

Sem pagamento, cada solicitação /mcp recebe um 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": [...] }

Os clientes pagam assinando uma transferência de USDC e incluindo o cabeçalho X-PAYMENT — o SDK do cliente x402 (ou um agente de IA ciente de x402) lida com isso automaticamente.

Indo para mainnet (pagamentos reais)

  1. Cadastre-se em portal.cdp.coinbase.com e crie chaves de API
  2. Atualize .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
  1. Em src/payments/paymentGuard.ts, troque o cliente facilitador conforme mostrado nos comentários (~linha 30)

Toda a lógica de pagamento está isolada em src/payments/paymentGuard.ts — nenhum outro arquivo precisa ser alterado.


Estrutura do projeto

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 segurança

  • A busca de URL rejeita localhost, faixas de IP privadas e protocolos não-http/https (proteção SSRF)
  • O tamanho da resposta é limitado a FETCH_MAX_BYTES (padrão 1 MB)
  • O timeout de busca é aplicado em FETCH_TIMEOUT_MS (padrão 10s)
  • Sem segredos codificados — toda configuração via variáveis de ambiente
  • A ferramenta score_candidate_fit compara apenas habilidades, experiência, ferramentas e senioridade — sem inferência de características protegidas