linkedin-pilot
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@linkedin-pilot apply to the first Easy Apply job in my saved searches"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
linkedin-pilot
Servidor MCP (y CLI) que controla LinkedIn con tu sesión real, en un navegador persistente. Cubre las tres cosas de punta a punta:
Actualizar tu perfil completo: titular, acerca de, experiencia, educación, aptitudes, certificaciones, proyectos, idiomas, foto, portada, información de contacto, URL personalizada y "Abierto a trabajar".
Interactuar con otros perfiles: buscar personas, invitar a conectar con nota, enviar mensajes, seguir, validar aptitudes, gestionar invitaciones, reaccionar y comentar publicaciones, publicar en el feed.
Postular a ofertas de empleo: buscar con todos los filtros de LinkedIn, leer el detalle y completar la Solicitud sencilla (Easy Apply) paso a paso.
Por qué está hecho así
La API oficial no sirve para esto. Desde 2015 LinkedIn exige entrar al Partner Program para cualquier acceso real, y ni siquiera los partners tienen escritura sobre el perfil: la API pública devuelve nombre, titular y correo, y poco más. SNAP dejó de aceptar solicitudes nuevas. No hay ruta oficial para "actualiza mi experiencia" ni para "postula a esta oferta".
Entonces la vía es la interfaz real, conducida por Playwright con tu propia sesión.
Leer y escribir van por caminos distintos
LinkedIn migró el perfil, la oferta de empleo y los resultados de búsqueda a
renderizado SDUI: ya no hay <h1>, desaparecieron las anclas de sección
(#experience, #about), las clases CSS son hashes que cambian solos y el
contenido se carga de forma diferida. Raspar ese HTML para leer es frágil y
lento.
Por eso el proyecto usa dos vías:
Para leer: la API interna (Voyager), que devuelve el perfil completo y el detalle de una oferta en una sola llamada, estructurados. Se aprovecha la sesión del propio navegador, así que las peticiones salen con las mismas cookies, el mismo user-agent y la misma IP que la navegación real.
Para escribir: la interfaz, porque no hay otra: no existe endpoint para guardar tu experiencia ni para postular.
Cuando una vía falla se cae a la otra, y ambas quedan reportadas.
Tres decisiones sostienen lo demás
Sesión persistente, login manual. El navegador guarda su perfil en disco, así que inicias sesión una sola vez (con verificación en dos pasos y captcha incluidos) y las cookies sobreviven entre ejecuciones. No se automatiza el login a propósito: automatizarlo es justo lo que dispara los bloqueos, y además obligaría a guardar tu contraseña en algún lado.
Los campos se identifican por su etiqueta visible, no por clases CSS. LinkedIn cambia el HTML constantemente y sirve la interfaz en el idioma de la cuenta. El motor de formularios lee el nombre accesible de cada control (
aria-label,<label for>,legend...) y lo empareja contra un glosario bilingüe: pedirTitularencuentraHeadline, y al revés. Esto se ve funcionando en las postulaciones reales, donde una pregunta como «Confirm the name of the company where you work / Confirme o nome da empresa...» se resuelve sola con la respuesta guardada como «Current company».El contenedor del formulario se descubre, no se asume. Los editores de perfil dejaron de ser ventanas modales: ahora son páginas que ni siquiera cuelgan de
<main>, y el asistente de Solicitud sencilla tampoco es unrole="dialog". En vez de perseguir esa estructura, el motor parte del botón que cierra el paso (Guardar, Siguiente, Enviar) y sube hasta el primer ancestro que agrupa varios campos. Funcione donde funcione el formulario.Una sola pieza rellena todo. Editar el perfil y postular a un empleo son el mismo problema: un modal con campos. El mismo motor sirve para ambos, así que cualquier sección nueva que LinkedIn agregue ya está soportada sin tocar código.
Y hay una salida de emergencia: si algo se rompe, las herramientas
linkedin_browser_* dan control directo del navegador (radiografía de la
página, clic por referencia, escritura en campos) para terminar el trabajo a
mano sin editar el proyecto.
Related MCP server: LinkedIn MCP Server
Instalación
cd linkedin-pilot
npm install
npm run buildRequiere Node 20+. Usa el Chrome instalado en el sistema; si no lo encuentra prueba con Edge y luego con el Chromium de Playwright.
Registrarlo en Claude Code
Ya quedó registrado en el ámbito de usuario:
claude mcp add linkedin --scope user -- node "<ruta>/linkedin-pilot/dist/index.js"También hay un .mcp.json en la carpeta padre por si prefieres el ámbito de
proyecto. Comprueba con claude mcp list.
Puesta en marcha
npm run login # abre el navegador; inicia sesión a mano una sola vez
npm run doctor # diagnóstico: navegador, sesión, rutas, banco de respuestasTodo lo persistente vive en ~/.linkedin-pilot/:
Ruta | Qué guarda |
| Perfil de Chrome con las cookies de sesión |
| Postulaciones, interacciones y contadores diarios |
| Banco de respuestas reutilizables y ruta del CV |
| Capturas automáticas cuando algo falla |
| Registro diario en JSON |
Uso desde la terminal
linkedin-pilot status # ¿hay sesión?
linkedin-pilot profile # lee tu perfil completo
linkedin-pilot jobs "ingeniero de datos" # busca ofertas con Solicitud sencilla
linkedin-pilot job 4021234567 # detalle de una oferta
linkedin-pilot apply 4021234567 # SIMULA la postulación
linkedin-pilot apply 4021234567 --send # postula de verdad
linkedin-pilot applications # historial localHerramientas MCP
Sesión
Herramienta | Qué hace |
| Estado de la sesión y consumo del día. Empieza siempre por aquí. |
| Abre el navegador para que inicies sesión a mano. |
| Exporta o importa cookies ( |
| Cierra el navegador; la sesión queda guardada. |
Perfil
Herramienta | Qué hace |
| Lee un perfil completo (el tuyo o el de otra persona). |
| Lista las secciones editables y sus campos habituales. |
| Abre el editor y devuelve los campos reales sin guardar nada. |
| Rellena cualquier sección por etiqueta y guarda si se lo pides. |
| Atajo para el titular. |
| Atajo para "Acerca de". |
| Sube foto de perfil o portada. |
| Configura "Abierto a trabajar". |
| Cambia la URL personalizada. |
Secciones disponibles en linkedin_profile_edit, con sus rutas verificadas
contra LinkedIn el 2026-09-01: intro, about, experience, education,
skill, certification, project, language, course, honor,
publication, organization, patent, contactInfo, openToWork.
Flujo recomendado la primera vez que tocas una sección:
1. linkedin_profile_inspect_form { "section": "experience" }
→ te dice exactamente qué campos existen hoy y cuáles son obligatorios
2. linkedin_profile_edit { "section": "experience", "values": {...}, "save": false }
→ los rellena y te muestra qué quedó; revisas en pantalla
3. linkedin_profile_edit { ..., "save": true }Personas y contenido
Herramienta | Qué hace |
| Busca personas con filtros de grado de contacto. |
| Invitación a conectar, con nota opcional. |
| Mensaje directo. |
| Seguir o dejar de seguir. |
| Validar aptitudes. |
| Listar, aceptar, ignorar o retirar invitaciones. |
| Publicaciones del feed o de un perfil. |
| Reaccionar ( |
| Comentar. |
| Publicar en el feed. |
| Leer notificaciones. |
Empleos
Herramienta | Qué hace |
| Búsqueda con filtros de fecha, experiencia, modalidad y tipo. |
| Detalle completo de una oferta. |
| Solicitud sencilla paso a paso. Simula por defecto. |
| Guardar o quitar de guardados. |
| Ofertas guardadas o solicitudes según LinkedIn. |
| Historial local con las respuestas que diste. |
Soporte
Herramienta | Qué hace |
| Consulta y edita las respuestas reutilizables y el CV por defecto. |
| Consumo frente a los topes diarios. |
| Radiografía de la página: enlaces, botones y campos con referencia. |
| Control manual del navegador. |
| Llamada directa a la API interna de LinkedIn. |
Cómo funciona la postulación
linkedin_job_apply simula por defecto. Recorre el asistente completo,
rellena lo que sabe y se detiene justo antes de enviar:
{ "job": "4021234567" }Si el formulario pide algo que no sabe, no inventa: devuelve
status: "needs-answers" con la lista exacta de preguntas, sus opciones y una
captura. Se las pasas y vuelve a intentar:
{
"job": "4021234567",
"answers": { "Años de experiencia en Python": "5" },
"dryRun": false,
"confirm": true
}Las respuestas quedan guardadas en el banco, así que la siguiente oferta que pregunte lo mismo (aunque lo redacte distinto o en otro idioma) ya no se atasca. Cuanto más completo el banco, menos intervención necesitas.
Detalles que importan:
Las ofertas que no son Solicitud sencilla devuelven
status: "external"con el enlace de la empresa. No se puede completar desde LinkedIn."Seguir a la empresa" viene marcado por defecto en LinkedIn; aquí se desmarca salvo que pidas
followCompany: true.Cada postulación queda registrada, así que no repites ofertas.
El CV (
resumePath, o el del banco) se sube en cada postulación con el botón "Cargar currículum". LinkedIn solo lo guarda en tu cuenta cuando la solicitud se envía: si se descarta, desaparece, así que no sirve subirlo una vez y luego elegirlo de la lista. En la pantalla de revisión se comprueba que el CV adjunto es el pedido; si no lo es, no se envía.Un desplegable que LinkedIn trae ya elegido (el correo de contacto, por ejemplo) se cambia si el banco tiene un dato explícito distinto. El correo tiene que estar registrado en tu cuenta de LinkedIn para aparecer.
Si el asistente no avanza de un paso, se detiene con
status: "failed", la pregunta que LinkedIn marca como obligatoria y la captura, en vez de repetir "Siguiente" hasta el límite.
Cuidados con la cuenta
Automatizar LinkedIn va contra sus condiciones de uso y las cuentas que se pasan de volumen terminan restringidas. El proyecto está construido para quedarse muy por debajo del umbral:
Toda acción visible para terceros exige
confirm: true. Invitaciones, mensajes, comentarios, publicaciones y postulaciones no salen por accidente.Topes diarios conservadores, con contador persistente:
Acción
Tope
Variable de entorno
Invitaciones enviadas
20
LINKEDIN_PILOT_MAX_INVITATIONSRespuestas a invitaciones
100
LINKEDIN_PILOT_MAX_INVITATION_RESPONSESValidaciones de aptitudes
20
LINKEDIN_PILOT_MAX_ENDORSEMENTSMensajes
25
LINKEDIN_PILOT_MAX_MESSAGESPostulaciones
20
LINKEDIN_PILOT_MAX_APPLICATIONSReacciones
50
LINKEDIN_PILOT_MAX_REACTIONSComentarios
15
LINKEDIN_PILOT_MAX_COMMENTSSeguimientos
30
LINKEDIN_PILOT_MAX_FOLLOWSPublicaciones
3
LINKEDIN_PILOT_MAX_POSTSRitmo humano: pausas con variación aleatoria, escritura con cadencia irregular y desplazamiento por pasos.
Un navegador normal: Chrome real, ventana visible, sin el marcador
navigator.webdriver.
Subir los topes es tu decisión, pero los valores por defecto son lo que mantiene la cuenta sana.
Configuración
Variable | Por defecto | Para qué |
|
| Carpeta de datos |
|
| Ocultar la ventana (no recomendado) |
|
|
|
|
| Idioma del navegador |
|
| Zona horaria |
|
| Exigir confirmación explícita |
|
| Rango de pausa entre acciones (ms) |
|
| Diagnóstico detallado en stderr |
Pruebas
npm test # emparejado de etiquetas + arranque del servidor MCP
npm run test:forms # motor de formularios contra el HTML real de LinkedIn
npm run test:live # editores de perfil, empleos y personas con tu sesióntest:matching cubre lo más delicado: que pedir un campo no escriba en otro,
que el glosario funcione en los dos idiomas y que el banco de respuestas no se
invente una respuesta para una pregunta que no conoce.
test:live necesita sesión iniciada. Abre los editores de perfil para
comprobar que exponen sus campos, y hace una búsqueda de empleos y otra de
personas. No guarda ni envía nada. Es lo que hay que correr cuando algo
deje de funcionar: dice en qué punto se rompió.
Cuando LinkedIn cambie algo
Pasará. El orden para arreglarlo, de menos a más esfuerzo:
linkedin_profile_inspect_formolinkedin_browser_snapshotpara ver qué campos y botones hay ahora.Terminar la tarea con
linkedin_browser_clickylinkedin_browser_type.Si el cambio es permanente, ajustar la ruta en
SECTIONS(src/tools/profile.ts) o añadir el término nuevo al glosario (src/text.ts). Casi nunca hace falta más.
Available Tools
39 toolslinkedin_answers_bankC
Consulta o edita el banco de respuestas que se reutiliza al postular (datos de contacto, años de experiencia, disponibilidad, CV por defecto...). Cuanto más completo, menos se atascan las postulaciones.
Inputs: action (required), label, value, entries.
linkedin_applications_logC
Historial local de postulaciones hechas con esta herramienta, con su estado y las respuestas dadas.
Inputs: limit.
linkedin_browser_clickB
Pulsa un elemento por su ref (de un snapshot previo) o por su texto visible.
Inputs: ref, text.
linkedin_browser_screenshotC
Guarda una captura de la pantalla actual y devuelve la ruta.
Inputs: name.
linkedin_browser_scrollC
Desplaza la página para cargar contenido diferido.
Inputs: steps.
linkedin_browser_snapshotB
Radiografía de la página actual: enlaces, botones y campos con una referencia para pulsarlos o rellenarlos. Es la salida de emergencia cuando una herramienta de alto nivel no encuentra algo.
Inputs: textLimit, scopeSelector.
linkedin_browser_typeC
Escribe en un campo identificado por ref.
Inputs: ref (required), text (required), submit.
linkedin_close_browserA
Cierra el navegador. La sesión sigue guardada en disco: la próxima herramienta lo vuelve a abrir.
Inputs: no named parameters.
linkedin_connectA
Envía una invitación a conectar, con nota opcional (máx. 300 caracteres). Acción visible para la otra persona: exige confirm=true.
Inputs: target (required), note, confirm.
linkedin_endorseC
Valida aptitudes en el perfil de otra persona. Exige confirm=true.
Inputs: skills (required), target (required), confirm.
linkedin_followB
Sigue o deja de seguir un perfil. Exige confirm=true.
Inputs: target (required), follow, confirm.
linkedin_invitationsC
Lista invitaciones pendientes (recibidas o enviadas), y permite aceptar, ignorar o retirar.
Inputs: action (required), confirm, personName.
linkedin_job_applyA
Postula a una oferta con Solicitud sencilla. POR DEFECTO SIMULA: recorre todo el formulario, lo rellena y se detiene antes de enviar, devolviendo qué preguntas faltan por responder. Para enviar de verdad hay que pasar dryRun=false Y confirm=true. Las respuestas nuevas se guardan para reutilizarlas en las siguientes ofertas.
Inputs: job (required), dryRun, answers, confirm, +4 more.
linkedin_job_detailC
Trae el detalle completo de una oferta: descripción, empresa, ubicación, número de solicitantes y si admite Solicitud sencilla.
Inputs: job (required).
linkedin_job_saveC
Guarda o quita una oferta de la lista de guardados.
Inputs: job (required), save.
linkedin_jobs_searchC
Busca ofertas de empleo con los filtros de LinkedIn. Marca cuáles admiten Solicitud sencilla y cuáles ya tienes registradas como postuladas.
Inputs: keywords (required), limit, start, sortBy, +6 more.
linkedin_loginA
Abre una ventana de navegador en la pantalla de inicio de sesión y espera a que el usuario entre a mano (contraseña, verificación en dos pasos, captcha). La sesión queda guardada en disco y se reutiliza en llamadas futuras. No automatiza el login a propósito: hacerlo es lo que dispara los bloqueos de LinkedIn.
Inputs: timeoutSeconds.
linkedin_messageC
Envía un mensaje directo a un contacto. Exige confirm=true.
Inputs: text (required), target (required), confirm.
linkedin_my_jobsB
Lista tus ofertas guardadas o tus solicitudes enviadas según LinkedIn ("Mis empleos").
Inputs: tab.
linkedin_notificationsC
Lee las notificaciones recientes.
Inputs: limit.
linkedin_people_searchC
Busca personas por palabras clave, con filtros de grado de contacto.
Inputs: keywords (required), page, limit, connectionDegree.
linkedin_post_commentC
Comenta una publicación. Exige confirm=true.
Inputs: text (required), postUrl (required), confirm.
linkedin_post_createB
Publica en el feed. Exige confirm=true.
Inputs: text (required), confirm, imagePath, visibility.
linkedin_post_reactC
Reacciona a una publicación. Exige confirm=true.
Inputs: postUrl (required), confirm, reaction.
linkedin_posts_readC
Lee publicaciones del feed ("feed") o la actividad reciente de un perfil.
Inputs: limit, source.
linkedin_profile_aboutC
Reescribe la sección "Acerca de".
Inputs: text (required), save.
linkedin_profile_custom_urlC
Cambia la URL personalizada del perfil (linkedin.com/in/loquesea).
Inputs: vanity (required).
linkedin_profile_editA
Rellena una sección del perfil y opcionalmente la guarda. Los campos se identifican por su etiqueta visible (admite coincidencia parcial). Con save=false deja el formulario abierto y relleno para que lo revises: es lo recomendado la primera vez.
Inputs: values (required), section (required), save.
linkedin_profile_headlineC
Cambia el titular del perfil (la línea bajo el nombre).
Inputs: headline (required), save.
linkedin_profile_imageC
Sube la foto de perfil o la imagen de portada.
Inputs: kind (required), filePath (required).
linkedin_profile_inspect_formA
Abre el editor de una sección y devuelve EXACTAMENTE los campos que LinkedIn muestra ahora mismo (etiqueta, tipo, si es obligatorio, opciones disponibles) sin guardar nada. Úsalo antes de editar una sección por primera vez: así los nombres de campo que pases después coinciden con los reales, aunque LinkedIn los haya cambiado.
Inputs: section (required).
linkedin_profile_open_to_workC
Configura "Abierto a trabajar": cargos, ubicaciones, tipos de empleo y quién puede verlo.
Inputs: values (required), save.
linkedin_profile_readA
Lee un perfil completo (el propio por defecto): titular, acerca de, experiencia, educación, aptitudes, certificaciones e idiomas.
Inputs: target.
linkedin_profile_sectionsA
Lista las secciones del perfil que se pueden editar, con los campos habituales de cada una.
Inputs: no named parameters.
linkedin_session_cookiesA
Exporta las cookies de la sesión a un archivo, o importa un li_at/JSESSIONID obtenido del navegador personal. Útil para respaldar la sesión o para arrancar sin pasar por el login.
Inputs: action (required), liAt, filePath, jsessionid.
linkedin_session_statusA
Comprueba si hay sesión de LinkedIn activa en el navegador persistente. Devuelve el nombre, el identificador público y cuándo caduca la cookie. Llama a esto antes que nada.
Inputs: no named parameters.
linkedin_usageB
Muestra cuántas acciones llevas hoy frente a los topes diarios, y el registro de interacciones.
Inputs: showOutreach.
linkedin_voyager_requestA
Llamada directa a la API interna de LinkedIn (Voyager) reutilizando la sesión del navegador. Atajo avanzado para leer datos que la interfaz no expone cómodamente. No es una API pública: las rutas cambian sin aviso, así que trata los fallos como normales y usa las otras herramientas.
Inputs: path (required), body, method.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 39 tools
Most tools have clearly distinct resource+action purposes, and the high-level vs. browser-primitive vs. Voyager boundaries are usually clear. However, the generic profile_edit overlaps with specific wrappers like profile_headline, profile_about, profile_image, and profile_open_to_work, so an agent could reasonably choose either path for the same outcome.
All tools use snake_case with a consistent linkedin_ prefix, making the set predictable overall. Minor deviations exist, such as linkedin_posts_read (plural) versus linkedin_post_create/react/comment (singular), and linkedin_jobs_search versus linkedin_job_detail/apply/save.
With 39 tools, the set is well beyond the 25+ threshold that typically signals excessive surface area. While the domain is broad, several convenience wrappers and low-level browser primitives could be consolidated or exposed through fewer generic tools without losing core capability.
Core workflows are well covered: session management, profile editing, people search/connect/message, post interaction, job search/apply/save, usage monitoring, and low-level browser fallbacks. The notable gap is reading or managing the message inbox/conversations, though browser_snapshot/navigate and voyager_request provide workarounds.
Maintenance
Related MCP Connectors
LinkedIn jobs, companies and people for AI agents, plus messages and invites via your own account.
LinkedIn for AI agents: search people, read profiles, posts and connections via a connected account
Give AI agents the LinkedIn tools to find, qualify, engage, and follow up with prospects.
LinkedIn for AI agents: inbox, invitations, Sales Navigator search, posts, jobs, quotas, webhooks.
Related MCP Servers
- AlicenseAqualityBmaintenanceEnables AI assistants to interact with LinkedIn by scraping profiles, companies, job postings, and getting personalized job recommendations using authenticated browser automation.1713,039 PyPI4,163Apache 2.0
- AlicenseAqualityCmaintenanceLets an AI assistant operate LinkedIn through an authenticated browser session, enabling profile management, posting, networking, messaging, job search, and automated applications.10039 npm1MIT
- AlicenseBqualityBmaintenanceEnables an AI agent to fully operate a LinkedIn account—posting, messaging, profile edits, and network management—with self-healing selectors, human-like pacing, and approval-based planning to avoid breakage or lockouts.393 npmMIT
- AlicenseAqualityBmaintenanceControls the user's LinkedIn account through a logged-in browser session, enabling post publishing, profile viewing and editing, job searching, and Easy Apply submissions from chat.111MIT