Skip to main content
Glama
stepanic

linkedin-poster

by stepanic

linkedin-poster

Publica en tu propio feed de LinkedIn desde Claude Code, una shell o un cron job. Un Cloudflare Worker, sin dependencias, tres superficies: un servidor MCP para que un agente publique directamente, una API HTTP para scripts y un linter de voz que se niega a publicar texto que delate prosa generada por máquina.

Creado porque una buena publicación merece automatización y una mala raya em no merece publicarse. Este README tampoco tiene rayas em, que es el punto.

Claude Code ──MCP──┐
                   ├──> Worker ──> LinkedIn Posts API ──> your feed
curl / CI ──HTTP───┘      │
                          └──> KV (one 60-day token) + daily cron reminder

Lo que no es

Esto publica como un miembro: tú. No es un SaaS de programación, no es una herramienta multiinquilino y no toca la cuenta de nadie más. Todo lo que necesita es autogestionado; no implica ningún programa de socios de LinkedIn.

La restricción que lo condiciona todo

Los tokens de acceso de LinkedIn duran 60 días y los tokens de actualización programáticos están limitados a socios aprobados del Marketing Developer Platform. Una aplicación autogestionada nunca obtiene uno. No hay forma de evitarlo, y cualquier guía que prometa automatización de LinkedIn de configurar y olvidar está equivocada.

Lo que hay: mientras tu token actual siga siendo válido y tengas la sesión iniciada en LinkedIn, volver a acceder al endpoint de autorización omite la pantalla de consentimiento y simplemente redirige. Así que la renovación es un clic cada siete semanas, siempre que lo hagas antes de que el token expire. Si pierdes la ventana, vuelves a ver la pantalla de consentimiento, que son dos clics en lugar de uno.

Por eso este servicio incluye un disparador cron. Cuenta los días hacia atrás y te avisa a 14, 7, 3 y 1 día, mientras la renovación silenciosa sigue funcionando.

Configuración

1. Lado de LinkedIn (manual, unos diez minutos)

  1. Necesitas una Página de LinkedIn. El portal para desarrolladores te obliga a asociar la aplicación a una y a que un administrador de la página la verifique.

  2. Crea la aplicación en linkedin.com/developers. Anota el Client ID y el Client Secret.

  3. Pestaña Products, solicita ambos (son Open Permissions y se aprueban al instante):

    • Sign In with LinkedIn using OpenID Connectopenid, profile

    • Share on LinkedInw_member_social

  4. Pestaña Auth → añade la URL de redirección. Debe ser HTTPS, absoluta y coincidir con REDIRECT_URI carácter por carácter: https://your-worker.example.com/auth/callback

2. Lado del Worker

git clone https://github.com/stepanic/linkedin-poster.git
cd linkedin-poster
npm install

# KV to hold the token
npx wrangler kv namespace create TOKENS
npx wrangler kv namespace create TOKENS --preview
# paste both ids into wrangler.jsonc

# edit wrangler.jsonc: name, routes, REDIRECT_URI, account_id

npx wrangler secret put LINKEDIN_CLIENT_ID
npx wrangler secret put LINKEDIN_CLIENT_SECRET
npx wrangler secret put API_TOKEN     # openssl rand -hex 32, guards /post and /mcp
npx wrangler secret put SETUP_KEY     # openssl rand -hex 32, guards /auth/start
npx wrangler secret put NOTIFY_WEBHOOK  # optional, any URL taking a JSON POST

npm run deploy

3. Conecta tu cuenta

Abre https://your-worker.example.com/auth/start?key=<SETUP_KEY> en un navegador, aprueba una vez, listo. La página te indica la fecha de caducidad.

SETUP_KEY no es decoración. Sin él, cualquiera que encontrara la URL podría vincular su cuenta de LinkedIn a tu Worker y sobrescribir tu token almacenado.

Usarlo desde Claude Code

claude mcp add --transport http linkedin https://your-worker.example.com/mcp \
  --header "Authorization: Bearer $API_TOKEN"

Tres herramientas:

Herramienta

Qué hace

linkedin_post

Aplica el linter y luego publica. Se niega si hay errores salvo que force: true.

linkedin_check

Aplica el linter sin publicar. Úsalo mientras redactas.

linkedin_status

En nombre de quién publica y cuántos días le quedan al token.

Luego, en una sesión: "revisa este borrador con el linter y luego publícalo."

Usarlo desde una shell

# dry run: lint only, publish nothing
curl -s -X POST https://your-worker.example.com/post \
  -H "Authorization: Bearer $API_TOKEN" -H 'Content-Type: application/json' \
  -d '{"text":"…","dry_run":true}'

# publish
curl -s -X POST https://your-worker.example.com/post \
  -H "Authorization: Bearer $API_TOKEN" -H 'Content-Type: application/json' \
  -d '{"text":"…","visibility":"PUBLIC"}'

# token state
curl -s https://your-worker.example.com/status -H "Authorization: Bearer $API_TOKEN"

/post devuelve 201 con el URN de la publicación y su URL pública, 422 cuando el linter lo bloquea, 503 cuando el token falta o está caducado.

El linter

Los errores bloquean la publicación; las advertencias no.

Regla

Severidad

Por qué

no-em-dash, no-en-dash

error

La señal más clara de prosa generada. Una coma o un punto siempre funcionan.

max-length

error

LinkedIn rechaza comentarios de más de 3000 caracteres.

empty

error

Obvio, pero fácil de alcanzar al canalizar desde un archivo.

no-markdown-bold, no-markdown-link, no-markdown-heading, markdown-bullets

warning

LinkedIn no renderiza nada de eso. Los asteriscos y las almohadillas aparecen literalmente.

Los guiones nunca se marcan. read-only tier, two-day sprint y per-client limits son correctos y deben permanecer. Solo U+2014 y U+2013 son errores.

Editar src/lint.ts es la forma prevista de hacer esto tuyo. Las reglas codifican las convenciones de escritura de una persona, no un estándar universal.

Cosas que te sorprenderán

  • La API de Posts no extrae URLs. Un enlace en tu texto permanece como enlace simple. Una tarjeta de vista previa real necesita una miniatura subida mediante la API de Imágenes más un bloque content.article. Aún no implementado aquí.

  • LinkedIn-Version es obligatorio y las versiones se retiran. 202508 dejó de estar disponible el 17 de agosto de 2026. Trata el valor en wrangler.jsonc como un elemento de mantenimiento.

  • /v2/ugcPosts está obsoleto. Esto usa /rest/posts, que lo reemplazó.

  • Cambiar los ámbitos solicitados invalida todos los tokens existentes. Tendrás que volver a autorizar.

  • 150 solicitudes por miembro al día. Por miembro, no por aplicación.

Estructura

Archivo

Contenido

src/index.ts

Rutas, flujo OAuth, recordatorio cron

src/linkedin.ts

Llamadas a la API de OAuth y Posts, todos los endpoints en un solo lugar

src/mcp.ts

Servidor MCP, JSON-RPC hecho a mano, sin estado

src/lint.ts

El linter de voz

src/tokens.ts

Registro de token en KV, cálculos de caducidad, comparación de secretos a prueba de tiempos

Desarrollo local

cp .dev.vars.example .dev.vars   # fill in, never commit
npm run types                    # regenerate Env after editing wrangler.jsonc
npm run typecheck
npm run dev

wrangler dev --local te da un KV local, así que todo el flujo salvo las llamadas reales a LinkedIn se puede probar sin credenciales.

Licencia

MIT. Las reglas en src/lint.ts son mías; el mecanismo es tuyo para llevarlo.

-
license - not tested
Not graded
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

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

View all MCP Connectors

Latest Blog Posts

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/stepanic/linkedin-poster'

If you have feedback or need assistance with the MCP directory API, please join our Discord server