visa-jobs-mcp

Identifique oportunidades de patrocínio de visto nos EUA no LinkedIn e acesse os contatos certos para acelerar seu alcance.

Documentação

visa-jobs-mcp MIT License Homebrew Tap

visa-jobs-mcp é um servidor MCP que ajuda agentes a encontrar vagas relevantes em buscas recentes do LinkedIn, com filtragem opcional ciente de visto.

Screenshot 2026-02-20 at 10 20 22 am

Foi construído para velocidade e resultados práticos:

  • buscar vagas em uma localização,
  • comparar empregadores com histórico de patrocínio,
  • retornar resultados acionáveis com links e informações de contato,
  • manter os dados do usuário locais.

Primeiros Passos

1. Instalar no macOS (Homebrew)

brew tap neosh11/visa-jobs-mcp
brew install neosh11/visa-jobs-mcp/visa-jobs-mcp

2. Instalar no macOS/Linux (instalador bash)

curl -fsSL https://raw.githubusercontent.com/neosh11/visa-jobs-mcp/main/scripts/install.sh | bash

Fixar uma versão específica:

curl -fsSL https://raw.githubusercontent.com/neosh11/visa-jobs-mcp/main/scripts/install.sh | bash -s -- --version 0.3.1

3. Instalar no Windows (instalador PowerShell)

irm https://raw.githubusercontent.com/neosh11/visa-jobs-mcp/main/scripts/install.ps1 | iex

Fixar uma versão específica:

$env:VISA_JOBS_MCP_VERSION = "0.3.1"
irm https://raw.githubusercontent.com/neosh11/visa-jobs-mcp/main/scripts/install.ps1 | iex

4. Registrar no Codex (macOS/Linux)

codex mcp add visa-jobs-mcp --env VISA_JOB_SITES=linkedin -- visa-jobs-mcp

Registrar no Codex (Windows PowerShell):

codex mcp add visa-jobs-mcp --env VISA_JOB_SITES=linkedin -- "$env:LOCALAPPDATA\\Programs\\visa-jobs-mcp\\bin\\visa-jobs-mcp.exe"

Verificar:

codex mcp list
codex mcp get visa-jobs-mcp

5. Usar no chat

Em uma nova sessão do Codex, pergunte naturalmente:

  • Find IT jobs in Delhi for my skills.
  • Set my visa preference to E3 and find software engineer jobs in New York that sponsor E3.

Compilar a partir do código-fonte (opcional)

go build -o visa-jobs-mcp ./cmd/visa-jobs-mcp
./visa-jobs-mcp --version

Se precisar atualizar data/companies.csv a partir do código-fonte, execute:

./scripts/run_internal_pipeline.sh

Nota: o runtime do MCP é somente Go. Python só é necessário para mantenedores que executam o pipeline interno de dados.

E2E ao vivo no LinkedIn (manual)

Execute uma busca real de ponta a ponta no LinkedIn (não testes simulados):

./scripts/run_live_linkedin_e2e.sh

Substituição opcional de timeout:

VISA_E2E_TEST_TIMEOUT=8m ./scripts/run_live_linkedin_e2e.sh

Parâmetros opcionais de teste ao vivo:

VISA_E2E_VISA_TYPE=E3 \
VISA_E2E_LOCATION="New York, NY" \
VISA_E2E_JOB_TITLE="Software Engineer" \
./scripts/run_live_linkedin_e2e.sh

O Que Ele Suporta

  • Busca somente no LinkedIn.
  • Busca geral de vagas por habilidade/localização sem necessidade de configuração de visto.
  • Correspondência opcional de preferência de visto quando preferred_visa_types está definido.
  • Sessões de busca com paginação e suporte a retomada.
  • Vagas salvas e vagas ignoradas.
  • Extração de contato do empregador quando disponível.
  • Armazenamento local de dados privados.
  • Sem uso de proxy.
  • Sem chamadas de LLM dentro do runtime MCP (o agente lida com o raciocínio).

Ferramentas Principais do MCP

  • start_job_search
  • get_job_search_status
  • get_job_search_results
  • set_user_preferences
  • start_visa_job_search
  • get_visa_job_search_status
  • get_visa_job_search_results
  • save_job_for_later
  • ignore_job
  • list_saved_jobs
  • list_ignored_jobs
  • get_mcp_capabilities

Dica: peça ao agente para chamar get_mcp_capabilities primeiro para obter um contrato legível por máquina.

Contrato MCP (Gerado)

Expandir Contrato MCP (gerado automaticamente)

Gerado a partir de get_mcp_capabilities() via scripts/generate_contract_docs.py.

Servidor

  • server: visa-jobs-mcp
  • version: 0.3.1
  • capabilities_schema_version: 1.2.0
  • confidence_model_version: v1.1.0-rules-go

Necessário Antes da Busca

  • tool: start_job_search
  • required_fields: user_id

Decisões de Design

  • agent_is_reasoning_layer: True
  • background_search_runs_local_persistence: True
  • data_not_shared_or_sold: True
  • first_class_job_management: True
  • free_forever: True
  • fresh_job_search_per_query: True
  • ignored_companies_local_persistence: True
  • ignored_jobs_local_persistence: True
  • license: MIT
  • llm_api_keys_required_by_mcp: False
  • llm_runtime_inside_mcp: False
  • no_fake_reviews_or_bot_marketing: True
  • proxies_used: False
  • rate_limit_backoff_retries: True
  • saved_jobs_local_persistence: True
  • search_sessions_local_persistence: True
  • strict_user_visa_match: False
  • strictness_modes_supported: ['balanced', 'strict']
  • supported_job_sites: ['linkedin']
  • visa_matching_optional: True

Padrões

  • dataset_stale_after_days: 30
  • job_db_path: data/app/visa_jobs.db
  • max_scan_results: 1200
  • max_search_sessions_per_user: 20
  • rate_limit_initial_backoff_seconds: 2
  • rate_limit_max_backoff_seconds: 30
  • rate_limit_retry_window_seconds: 180
  • scan_multiplier: 8
  • search_run_ttl_seconds: 21600
  • search_session_ttl_seconds: 21600
  • strictness_mode: strict
  • tool_call_soft_timeout_seconds: 48

Ferramentas

FerramentaDescriçãoEntradas ObrigatóriasEntradas Opcionais
get_mcp_capabilitiesRetorna capacidades, ferramentas e contratos do MCP para autodescoberta do agente.--
set_user_preferencesSalva as preferências de visto do usuário para correspondência opcional específica de visto.user_id, preferred_visa_types-
set_user_constraintsSalva restrições de urgência e modo de trabalho usadas para orientação personalizada.user_id-
get_user_preferencesBusca as preferências e restrições salvas do usuário.user_id-
get_user_readinessInforma se o usuário e o conjunto de dados local estão prontos para a busca.user_id-
find_related_titlesRetorna títulos de cargos adjacentes para ampliar buscas de baixo rendimento.job_title-
add_user_memory_lineAdiciona uma linha de memória de perfil (habilidades, objetivos, receios, restrições).user_id, content-
query_user_memory_blobConsulta o bloco de memória local do usuário com filtragem de texto opcional.user_id-
delete_user_memory_lineExclui uma linha de memória por id do bloco local.user_id, line_id-
save_job_for_laterSalva uma vaga na lista local do usuário para acompanhamento.user_idjob_url, result_id, session_id
list_saved_jobsLista vagas salvas em ordem cronológica reversa.user_id-
delete_saved_jobRemove uma vaga salva da lista local.user_id, saved_job_id-
ignore_jobOculta uma vaga dos resultados futuros para este usuário.user_idjob_url, result_id, session_id
list_ignored_jobsLista vagas ignoradas em ordem cronológica reversa.user_id-
unignore_jobReexibe uma vaga anteriormente ignorada por id.user_id, ignored_job_id-
ignore_companyOculta todas as vagas de uma empresa em buscas futuras.user_id-
list_ignored_companiesLista empresas ignoradas em ordem cronológica reversa.user_id-
unignore_companyRemove uma empresa da lista de ignoradas.user_id, ignored_company_id-
mark_job_appliedMarca uma vaga como candidatado e persiste o estado do pipeline.user_id-
update_job_stageAtualiza o estágio do ciclo de vida de uma vaga rastreada (salva/candidatado/entrevista/etc).user_id, stage-
list_jobs_by_stageLista vagas rastreadas filtradas por estágio do ciclo de vida.user_id, stage-
add_job_noteAnexa ou adiciona uma nota ao registro de uma vaga rastreada.user_id, note-
list_recent_job_eventsLista transições de estágio e eventos do ciclo de vida recentes.user_id-
get_job_pipeline_summaryResume as contagens do pipeline rastreado por estágio para um usuário.user_id-
clear_search_sessionExclui uma sessão de busca em cache ou todas as sessões de um usuário.user_id-
export_user_dataExporta todos os registros locais de um usuário em todos os armazenamentos.user_id-
delete_user_dataExclui permanentemente todos os registros locais de um usuário.user_id, confirm-
get_best_contact_strategySugere o melhor canal/contato de abordagem para uma vaga.user_id-
generate_outreach_messageGera um rascunho prático de abordagem adaptado ao usuário e ao cargo.user_id-
start_job_searchInicia uma busca de vagas em segundo plano sem exigir preferências de visto.location, job_title, user_id-
get_job_search_statusConsulta progresso/eventos incrementais de uma execução de busca de vagas em segundo plano.user_id, run_id-
get_job_search_resultsBusca a página de resultados atual de uma execução de busca de vagas em segundo plano.user_id, run_id-
cancel_job_searchSolicita o cancelamento de uma execução de busca de vagas em segundo plano em andamento.user_id, run_id-
start_visa_job_searchInicia uma execução de busca em segundo plano para varreduras longas.location, job_title, user_id-
get_visa_job_search_statusConsulta progresso/eventos incrementais de uma execução de busca em segundo plano.user_id, run_id-
get_visa_job_search_resultsBusca a página de resultados atual de uma execução de busca em segundo plano.user_id, run_id-
cancel_visa_job_searchSolicita o cancelamento de uma execução em segundo plano em andamento.user_id, run_id-
discover_latest_dol_disclosure_urlsDescobre as fontes mais recentes de divulgação DOL LCA/PERM.--
run_internal_dol_pipelineExecuta o pipeline interno para atualizar o conjunto de dados de empresas patrocinadoras.--
refresh_company_dataset_cacheLimpa e recarrega o cache em memória do conjunto de dados de empresas.--

Campos de Resposta da Busca

  • run
  • status
  • stats
  • guidance
  • dataset_freshness
  • pagination
  • recovery_suggestions
  • jobs[].result_id
  • jobs[].job_url
  • jobs[].title
  • jobs[].company
  • jobs[].location
  • jobs[].site
  • jobs[].date_posted
  • jobs[].description_fetched
  • jobs[].description
  • jobs[].description_excerpt
  • jobs[].salary_text
  • jobs[].salary_currency
  • jobs[].salary_interval
  • jobs[].salary_min_amount
  • jobs[].salary_max_amount
  • jobs[].salary_source
  • jobs[].job_type
  • jobs[].job_level
  • jobs[].company_industry
  • jobs[].job_function
  • jobs[].job_url_direct
  • jobs[].is_remote
  • jobs[].employer_contacts
  • jobs[].visa_counts
  • jobs[].visas_sponsored
  • jobs[].visa_match_strength
  • jobs[].eligibility_reasons
  • jobs[].confidence_score
  • jobs[].confidence_model_version
  • jobs[].agent_guidance

Caminhos

  • dataset_default: data/companies.csv
  • ignored_companies_default: data/config/ignored_companies.json
  • ignored_jobs_default: data/config/ignored_jobs.json
  • job_management_db_default: data/app/visa_jobs.db
  • pipeline_manifest_default: data/pipeline/last_run.json
  • saved_jobs_default: data/config/saved_jobs.json
  • search_runs_store_default: data/config/search_runs.json
  • search_session_store_default: data/config/search_sessions.json
  • user_memory_blob_default: data/config/user_memory_blob.json
  • user_preferences_default: data/config/user_preferences.json

Deprecações

  • build_company_dataset_from_dol_disclosures -> run_internal_dol_pipeline (soft_deprecated)
JSON Bruto de Capacidades
{
  "capabilities_schema_version": "1.2.0",
  "confidence_model_version": "v1.1.0-rules-go",
  "defaults": {
    "dataset_stale_after_days": 30,
    "job_db_path": "data/app/visa_jobs.db",
    "max_scan_results": 1200,
    "max_search_sessions_per_user": 20,
    "rate_limit_initial_backoff_seconds": 2,
    "rate_limit_max_backoff_seconds": 30,
    "rate_limit_retry_window_seconds": 180,
    "scan_multiplier": 8,
    "search_run_ttl_seconds": 21600,
    "search_session_ttl_seconds": 21600,
    "strictness_mode": "strict",
    "tool_call_soft_timeout_seconds": 48
  },
  "deprecations": [
    {
      "name": "build_company_dataset_from_dol_disclosures",
      "replacement": "run_internal_dol_pipeline",
      "status": "soft_deprecated"
    }
  ],
  "design_decisions": {
    "agent_is_reasoning_layer": true,
    "background_search_runs_local_persistence": true,
    "data_not_shared_or_sold": true,
    "first_class_job_management": true,
    "free_forever": true,
    "fresh_job_search_per_query": true,
    "ignored_companies_local_persistence": true,
    "ignored_jobs_local_persistence": true,
    "license": "MIT",
    "llm_api_keys_required_by_mcp": false,
    "llm_runtime_inside_mcp": false,
    "no_fake_reviews_or_bot_marketing": true,
    "proxies_used": false,
    "rate_limit_backoff_retries": true,
    "saved_jobs_local_persistence": true,
    "search_sessions_local_persistence": true,
    "strict_user_visa_match": false,
    "strictness_modes_supported": [
      "balanced",
      "strict"
    ],
    "supported_job_sites": [
      "linkedin"
    ],
    "visa_matching_optional": true
  },
  "pagination_contract": {
    "next_step": "use pagination.next_offset to request the next page",
    "offset_model": "offset is applied to accepted jobs, not raw scraped jobs",
    "result_id_aliases": "use jobs[].result_id in save_job_for_later/ignore_job to avoid URL copy friction",
    "scan_behavior": "server can increase raw scan depth when auto_expand_scan=true",
    "session_behavior": "pass search_session.session_id for stable paging without redundant rescans"
  },
  "paths": {
    "dataset_default": "data/companies.csv",
    "ignored_companies_default": "data/config/ignored_companies.json",
    "ignored_jobs_default": "data/config/ignored_jobs.json",
    "job_management_db_default": "data/app/visa_jobs.db",
    "pipeline_manifest_default": "data/pipeline/last_run.json",
    "saved_jobs_default": "data/config/saved_jobs.json",
    "search_runs_store_default": "data/config/search_runs.json",
    "search_session_store_default": "data/config/search_sessions.json",
    "user_memory_blob_default": "data/config/user_memory_blob.json",
    "user_preferences_default": "data/config/user_preferences.json"
  },
  "rate_limit_contract": {
    "failure_message": "asks agent to retry shortly when the retry window is exhausted",
    "max_retry_window_seconds": 180,
    "retry_behavior": "automatic exponential backoff on rate-limit errors (429/Too Many Requests)"
  },
  "required_before_search": {
    "required_fields": [
      "user_id"
    ],
    "tool": "start_job_search"
  },
  "search_response_fields_for_agents": [
    "run",
    "status",
    "stats",
    "guidance",
    "dataset_freshness",
    "pagination",
    "recovery_suggestions",
    "jobs[].result_id",
    "jobs[].job_url",
    "jobs[].title",
    "jobs[].company",
    "jobs[].location",
    "jobs[].site",
    "jobs[].date_posted",
    "jobs[].description_fetched",
    "jobs[].description",
    "jobs[].description_excerpt",
    "jobs[].salary_text",
    "jobs[].salary_currency",
    "jobs[].salary_interval",
    "jobs[].salary_min_amount",
    "jobs[].salary_max_amount",
    "jobs[].salary_source",
    "jobs[].job_type",
    "jobs[].job_level",
    "jobs[].company_industry",
    "jobs[].job_function",
    "jobs[].job_url_direct",
    "jobs[].is_remote",
    "jobs[].employer_contacts",
    "jobs[].visa_counts",
    "jobs[].visas_sponsored",
    "jobs[].visa_match_strength",
    "jobs[].eligibility_reasons",
    "jobs[].confidence_score",
    "jobs[].confidence_model_version",
    "jobs[].agent_guidance"
  ],
  "server": "visa-jobs-mcp",
  "tools": [
    {
      "description": "Return MCP capabilities, tools, and contracts for agent self-discovery.",
      "name": "get_mcp_capabilities",
      "required_inputs": []
    },
    {
      "description": "Save the user's visa preferences for optional visa-specific matching.",
      "name": "set_user_preferences",
      "required_inputs": [
        "user_id",
        "preferred_visa_types"
      ]
    },
    {
      "description": "Save urgency and work-mode constraints used for personalized guidance.",
      "name": "set_user_constraints",
      "required_inputs": [
        "user_id"
      ]
    },
    {
      "description": "Fetch the saved user preferences and constraints.",
      "name": "get_user_preferences",
      "required_inputs": [
        "user_id"
      ]
    },
    {
      "description": "Report whether the user and local dataset are ready for search.",
      "name": "get_user_readiness",
      "required_inputs": [
        "user_id"
      ]
    },
    {
      "description": "Return adjacent role titles to widen low-yield searches.",
      "name": "find_related_titles",
      "required_inputs": [
        "job_title"
      ]
    },
    {
      "description": "Append a profile memory line (skills, goals, fears, constraints).",
      "name": "add_user_memory_line",
      "required_inputs": [
        "user_id",
        "content"
      ]
    },
    {
      "description": "Query the user's local memory blob with optional text filtering.",
      "name": "query_user_memory_blob",
      "required_inputs": [
        "user_id"
      ]
    },
    {
      "description": "Delete one memory line by id from the local blob.",
      "name": "delete_user_memory_line",
      "required_inputs": [
        "user_id",
        "line_id"
      ]
    },
    {
      "description": "Save a job to the user's local shortlist for follow-up.",
      "name": "save_job_for_later",
      "optional_inputs": [
        "job_url",
        "result_id",
        "session_id"
      ],
      "required_inputs": [
        "user_id"
      ]
    },
    {
      "description": "List saved jobs in reverse-chronological order.",
      "name": "list_saved_jobs",
      "required_inputs": [
        "user_id"
      ]
    },
    {
      "description": "Remove one saved job from the local shortlist.",
      "name": "delete_saved_job",
      "required_inputs": [
        "user_id",
        "saved_job_id"
      ]
    },
    {
      "description": "Hide one job from future results for this user.",
      "name": "ignore_job",
      "optional_inputs": [
        "job_url",
        "result_id",
        "session_id"
      ],
      "required_inputs": [
        "user_id"
      ]
    },
    {
      "description": "List ignored jobs in reverse-chronological order.",
      "name": "list_ignored_jobs",
      "required_inputs": [
        "user_id"
      ]
    },
    {
      "description": "Unhide a previously ignored job by id.",
      "name": "unignore_job",
      "required_inputs": [
        "user_id",
        "ignored_job_id"
      ]
    },
    {
      "description": "Hide all jobs from a company in future searches.",
      "name": "ignore_company",
      "required_inputs": [
        "user_id"
      ]
    },
    {
      "description": "List ignored companies in reverse-chronological order.",
      "name": "list_ignored_companies",
      "required_inputs": [
        "user_id"
      ]
    },
    {
      "description": "Remove one company from the ignored list.",
      "name": "unignore_company",
      "required_inputs": [
        "user_id",
        "ignored_company_id"
      ]
    },
    {
      "description": "Mark a job as applied and persist pipeline state.",
      "name": "mark_job_applied",
      "required_inputs": [
        "user_id"
      ]
    },
    {
      "description": "Update lifecycle stage for a tracked job (saved/applied/interview/etc).",
      "name": "update_job_stage",
      "required_inputs": [
        "user_id",
        "stage"
      ]
    },
    {
      "description": "List tracked jobs filtered by lifecycle stage.",
      "name": "list_jobs_by_stage",
      "required_inputs": [
        "user_id",
        "stage"
      ]
    },
    {
      "description": "Attach or append a note to a tracked job record.",
      "name": "add_job_note",
      "required_inputs": [
        "user_id",
        "note"
      ]
    },
    {
      "description": "List recent stage transitions and lifecycle events.",
      "name": "list_recent_job_events",
      "required_inputs": [
        "user_id"
      ]
    },
    {
      "description": "Summarize tracked pipeline counts by stage for one user.",
      "name": "get_job_pipeline_summary",
      "required_inputs": [
        "user_id"
      ]
    },
    {
      "description": "Delete one cached search session or all sessions for a user.",
      "name": "clear_search_session",
      "required_inputs": [
        "user_id"
      ]
    },
    {
      "description": "Export all local records for a user across stores.",
      "name": "export_user_data",
      "required_inputs": [
        "user_id"
      ]
    },
    {
      "description": "Permanently delete all local records for a user.",
      "name": "delete_user_data",
      "required_inputs": [
        "user_id",
        "confirm"
      ]
    },
    {
      "description": "Suggest best outreach channel/contact for a job.",
      "name": "get_best_contact_strategy",
      "required_inputs": [
        "user_id"
      ]
    },
    {
      "description": "Generate a practical outreach draft tailored to user and role.",
      "name": "generate_outreach_message",
      "required_inputs": [
        "user_id"
      ]
    },
    {
      "description": "Start a background job search without requiring visa preferences.",
      "name": "start_job_search",
      "required_inputs": [
        "location",
        "job_title",
        "user_id"
      ]
    },
    {
      "description": "Poll incremental progress/events for a background job search run.",
      "name": "get_job_search_status",
      "required_inputs": [
        "user_id",
        "run_id"
      ]
    },
    {
      "description": "Fetch current result page from a background job search run.",
      "name": "get_job_search_results",
      "required_inputs": [
        "user_id",
        "run_id"
      ]
    },
    {
      "description": "Request cancellation of an in-progress background job search run.",
      "name": "cancel_job_search",
      "required_inputs": [
        "user_id",
        "run_id"
      ]
    },
    {
      "description": "Start a background search run for long scans.",
      "name": "start_visa_job_search",
      "required_inputs": [
        "location",
        "job_title",
        "user_id"
      ]
    },
    {
      "description": "Poll incremental progress/events for a background search run.",
      "name": "get_visa_job_search_status",
      "required_inputs": [
        "user_id",
        "run_id"
      ]
    },
    {
      "description": "Fetch current result page from a background search run.",
      "name": "get_visa_job_search_results",
      "required_inputs": [
        "user_id",
        "run_id"
      ]
    },
    {
      "description": "Request cancellation of an in-progress background run.",
      "name": "cancel_visa_job_search",
      "required_inputs": [
        "user_id",
        "run_id"
      ]
    },
    {
      "description": "Discover latest DOL LCA/PERM disclosure sources.",
      "name": "discover_latest_dol_disclosure_urls",
      "required_inputs": []
    },
    {
      "description": "Run internal pipeline to refresh sponsor-company dataset.",
      "name": "run_internal_dol_pipeline",
      "required_inputs": []
    },
    {
      "description": "Clear and reload in-memory company dataset cache.",
      "name": "refresh_company_dataset_cache",
      "required_inputs": []
    }
  ],
  "version": "0.3.1"
}

Regenere esta seção e o bloco de contrato do site com:

python3 scripts/generate_contract_docs.py

Valide se os blocos gerados estão atualizados:

python3 scripts/generate_contract_docs.py --check

CLI Manual (opcional)

Verifique a versão do binário:

visa-jobs-mcp --version

Execute o servidor MCP diretamente (para depuração):

visa-jobs-mcp

Execute o pipeline interno DOL (fluxo de mantenedor, a partir do checkout do código-fonte):

./scripts/run_internal_pipeline.sh

Solução de Problemas

  • Se a busca não retornar vagas, continue consultando get_visa_job_search_status e chame get_visa_job_search_results novamente para o mesmo run_id.
  • Se ocorrerem limites de taxa upstream, aguarde alguns minutos e tente novamente.
  • Se a instalação via Homebrew falhar devido a artefatos de release ausentes, tente novamente após a conclusão dos fluxos de release.

Dados e Privacidade

  • Os dados são armazenados localmente por padrão.
  • Sem telemetria ou venda de dados externos.
  • A correspondência de patrocínio usa data/companies.csv e saídas do pipeline baseado em DOL.

Para Mantenedores

  • Repositório tap do Homebrew: https://github.com/neosh11/homebrew-visa-jobs-mcp
  • Guia do colaborador: AGENTS.md
  • Fluxo de release: .github/workflows/build-release-binaries.yml
  • Build local de artefato de release: ./scripts/build_release_binaries.sh (binário Go nativo + data/companies.csv incluído)

Licença

MIT. Consulte LICENSE.