linkedin-poster
linkedin-poster
Публикуйте в свою ленту LinkedIn из Claude Code, из оболочки или по cron. Один Cloudflare Worker, без зависимостей, три поверхности: MCP-сервер, чтобы агент мог публиковать напрямую, HTTP API для скриптов и стилистический линтер, который отказывается публиковать текст с признаками машинной прозы.
Создан, потому что хороший пост стоит автоматизировать, а плохое длинное тире не стоит публиковать. В этом README тоже нет длинных тире, в этом и суть.
Claude Code ──MCP──┐
├──> Worker ──> LinkedIn Posts API ──> your feed
curl / CI ──HTTP───┘ │
├──> KV (one 60-day token) + daily cron
└──> Telegram group (what happened, and what broke)Чем это не является
Это публикует от имени одного участника: вас. Это не SaaS для планирования, не мультитенантный инструмент и не затрагивает чужие аккаунты. Всё необходимое настраивается самостоятельно; никакая партнёрская программа LinkedIn не задействована.
Related MCP server: LinkedIn MCP Server
Ограничение, определяющее всё
Токены доступа LinkedIn живут 60 дней, а программные refresh-токены доступны только одобренным партнёрам Marketing Developer Platform. Самостоятельно настраиваемое приложение их не получает. Обойти это невозможно, и любое руководство, обещающее настройку LinkedIn-автоматизации «один раз и навсегда», ошибочно.
Что есть: пока ваш текущий токен действителен и вы вошли в LinkedIn, повторный запрос к endpoint авторизации пропускает экран согласия и просто перенаправляет. Так что продление — это один клик каждые семь недель, если успеть до истечения токена. Упустите окно — и снова появится экран согласия, то есть два клика вместо одного.
Именно поэтому сервис поставляется с cron-триггером. Начиная за 14 дней до истечения, он каждое утро выводит напоминание о продлении в начало ежедневной сводки, пока бесшумное продление ещё работает. См. Уведомления.
Настройка
1. Сторона LinkedIn (вручную, около десяти минут)
Вам нужна страница LinkedIn. Портал разработчика требует привязать приложение к ней и подтвердить её администратором.
Создайте приложение на linkedin.com/developers. Запишите Client ID и Client Secret.
Вкладка Products, запросите оба разрешения (это Open Permissions, одобряются мгновенно):
Sign In with LinkedIn using OpenID Connect →
openid,profileShare on LinkedIn →
w_member_social
Вкладка Auth → добавьте redirect URL. Он должен быть HTTPS, абсолютным и совпадать с
REDIRECT_URIсимвол в символ:https://your-worker.example.com/auth/callback
2. Сторона 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
npx wrangler secret put TELEGRAM_BOT_TOKEN # optional, see Notifications below
npx wrangler secret put TELEGRAM_CHAT_ID
npm run deploy3. Подключите аккаунт
Откройте https://your-worker.example.com/auth/start?key=<SETUP_KEY> в браузере,
один раз подтвердите, готово. Страница покажет дату истечения.
SETUP_KEY — не для вида. Без него любой, кто найдёт URL, сможет привязать
свой аккаунт LinkedIn к вашему Worker и перезаписать сохранённый токен.
Использование из Claude Code
claude mcp add --transport http linkedin https://your-worker.example.com/mcp \
--header "Authorization: Bearer $API_TOKEN"Три инструмента:
Tool | Что делает |
| Проверяет линтером, затем публикует. Отказывает при ошибках, если не указано |
| Проверяет линтером без публикации. Используйте при подготовке черновика. |
| От чьего имени публикует и сколько дней осталось у токена. |
Затем в сессии: «проверь этот черновик линтером, затем опубликуй».
Использование из оболочки
# 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 возвращает 201 с URN поста и его публичным URL, 422, когда линтер
блокирует публикацию, 503, когда токен отсутствует или недействителен.
Уведомления
Без этого сервис отказывает так же, как любой сервис без присмотра: тихо, и вы узнаёте об этом в день, когда пост не вышел. Группа в Telegram решает эту проблему ценой одного бота.
# 1. @BotFather in Telegram, /newbot, copy the token
npx wrangler secret put TELEGRAM_BOT_TOKEN
# 2. make a group, add the bot, send /start@yourbot in it
# (a bot with privacy mode on sees only messages that mention it)
# 3. read the group id back, then store it
open "https://your-worker.example.com/telegram/chatid?key=<SETUP_KEY>"
npx wrangler secret put TELEGRAM_CHAT_ID
# 4. prove it works
open "https://your-worker.example.com/telegram/test?key=<SETUP_KEY>"Что приходит:
Событие | Когда |
Ежедневная сводка | каждый запуск cron, включая тихие дни |
Напоминание о продлении | начиная за 14 дней, поверх сводки за этот день |
Переподключение | сохранён новый токен, с новой датой истечения |
Опубликовано | каждый опубликованный пост, со ссылкой |
Заблокировано | линтер отклонил черновик, с указанием сработавших правил |
Отклонено | LinkedIn отклонил пост, с предположением о причине |
Нет рабочего токена | попытка публикации обнаружила, что токен отсутствует или недействителен |
Квота | за день превышено 120 из 150 запросов, разрешённых участнику LinkedIn |
Два проектных решения, о которых стоит знать, прежде чем что-то менять:
Ежедневная сводка — это сердцебиение. Она уходит, даже если ничего не произошло, поэтому её отсутствие само по себе является сигналом тревоги, и никому не нужно следить за наблюдателем. Именно поэтому напоминание о продлении приходит поверх сводки, а не отдельным сообщением: ровно одно сообщение утром, иначе вы приучите себя просматривать их мельком.
Ссылка на продление содержит одноразовый nonce, а не ключ настройки. Ссылка
с SETUP_KEY навсегда оставила бы долгоживущий секрет в логе чата. Вместо этого
cron создаёт nonce, действительный семь дней, заменяемый следующим напоминанием
и удаляемый в момент сохранения токена. Предпросмотр ссылок отключён во всех
сообщениях, чтобы Telegram не мог израсходовать nonce предварительной загрузкой.
Если ничего не настроить, сервис ведёт себя ровно как раньше: NOTIFY_WEBHOOK,
если он у вас есть, и лог, если нет.
GET /telegram/preview?key=<SETUP_KEY>&kind=daily отображает любое сообщение без
отправки — так можно править формулировки, не засоряя группу. Добавьте
&send=1, чтобы увидеть его на телефоне.
Транспорт Bot API протестирован на локальной заглушке, включая миграцию в супергруппу, которая незаметно ломает Telegram-ботов спустя месяцы после настройки:
npm run test:telegramЛинтер
Ошибки блокируют публикацию; предупреждения — нет.
Rule | Severity | Why |
| error | Самый явный признак сгенерированного текста. Запятая или точка работают всегда. |
| error | LinkedIn отклоняет комментарии длиннее 3000 символов. |
| error | Очевидно, но легко пропустить при передаче из файла. |
| warning | LinkedIn не отображает ни одно из этих форматирований. Звёздочки и решётки показываются буквально. |
Дефисы не помечаются никогда. read-only tier, two-day sprint и
per-client limits — корректны и должны оставаться. Ошибками являются только
U+2014 и U+2013.
Редактирование src/lint.ts — это предусмотренный способ сделать проект своим.
Правила кодируют писательские предпочтения одного человека, а не универсальный
стандарт.
Что вас удивит
Posts API не извлекает URL, но LinkedIn всё равно превращает их в ссылки. Проверено на живом посте: голый URL сокращается до
lnkd.in/...и становится кликабельным. Чего вы не получите — это карточки предпросмотра с изображением и заголовком. Для этого нужна миниатюра, загруженная через Images API, плюс блокcontent.article. Здесь пока не реализовано.LinkedIn-Versionобязателен, и версии выводятся из эксплуатации.202508перестал работать 17 августа 2026 года. Относитесь к значению вwrangler.jsoncкак к пункту, требующему обслуживания./v2/ugcPostsустарел. Здесь используется/rest/posts, который заменил его.Изменение запрашиваемых областей доступа аннулирует все существующие токены. Вам придётся авторизоваться заново.
150 запросов на участника в день. На участника, а не на приложение.
Структура
Файл | Содержимое |
| Маршруты, OAuth-поток, cron-напоминание |
| Вызовы OAuth и Posts API, все endpoint'ы в одном месте |
| MCP-сервер, самописный JSON-RPC, без состояния |
| Стилистический линтер |
| Запись токена в KV, расчёт срока действия, безопасное по времени сравнение секретов |
| Какие события доходят до группы и в каких формулировках |
| Транспорт Bot API, повторы, миграция в супергруппу |
| Счётчики дня, которые читает сводка |
Локальная разработка
cp .dev.vars.example .dev.vars # fill in, never commit
npm run types # regenerate Env after editing wrangler.jsonc
npm run typecheck
npm run devwrangler dev --local даёт вам локальное KV, так что весь процесс, кроме реальных
вызовов LinkedIn, можно проверить без учётных данных.
Заметки из реальной настройки
docs/2026-08-27-postavljanje-i-zamke.md
описывает, чего на самом деле стоила настройка с нуля: портал отклонял любое имя
приложения, содержащее «LinkedIn», необратимая привязка к Page, OAuth-скоупы,
которые остаются пустыми, пока не обновишь страницу, %20 против + в параметре
scope, отрицательный DNS-кэш, из-за которого работающее развёртывание выглядело
мёртвым, и как обрабатывались секреты, чтобы ни один из них не прошёл через терминал.
docs/2026-08-27-telegram-obavijesti.md
описывает слой уведомлений: миграцию в супергруппу, которая незаметно ломает
Telegram-ботов, почему сердцебиение — это сводка, а не пинг, и почему ссылка на
продление содержит nonce.
Лицензия
MIT. Правила в src/lint.ts — мои; механизм можете забирать.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
No tool schema history has been recorded yet.
This server cannot be installed
Maintenance
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
Write LinkedIn posts in your own voice. Drafts only, ego never publishes for you.
Draft, reshape and schedule LinkedIn posts in the writer's own voice, not a generic AI one.
1Write LinkedIn posts in your voice: ideas, drafts, scheduling, analytics from your personal AI.
Give AI agents the LinkedIn tools to find, qualify, engage, and follow up with prospects.
Related MCP Servers
- AlicenseAqualityAmaintenanceEnables AI agents to publish posts, images, comments, and reactions to LinkedIn as the authenticated user, with built-in safety features like daily budgets and deduplication.929Apache 2.0
- AlicenseBqualityCmaintenanceEnables drafting, formatting, analyzing, and publishing LinkedIn posts directly from MCP-compatible clients like Claude.5214MIT
- AlicenseAqualityBmaintenanceEnables AI agents to publish posts, images, videos, and articles to LinkedIn.10MIT
- FlicenseNot gradedqualityBmaintenanceEnables AI agents to draft, format, and manage LinkedIn posts through a review pipeline, with human approval via a web UI before publication.-
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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