linkedin-poster
linkedin-poster
Claude Code, 셸, 또는 cron 작업에서 여러분 자신의 LinkedIn 피드에 게시하세요. 의존성 없는 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: mcp-server-linkedin
모든 것을 결정짓는 제약
LinkedIn 액세스 토큰은 60일 동안 유효하며, 프로그래매틱 리프레시 토큰은 승인된 Marketing Developer Platform 파트너에게만 제한됩니다. 셀프 서비스 앱은 절대 받을 수 없습니다. 이 제약을 우회할 방법은 없으며, 설정해두고 잊는 LinkedIn 자동화를 약속하는 어떤 가이드도 틀렸습니다.
있는 것은 이것입니다. 현재 토큰이 아직 유효하고 LinkedIn에 로그인된 상태에서 인증 엔드포인트를 다시 호출하면 동의 화면을 건너뛰고 그냥 리디렉션됩니다. 따라서 토큰이 죽기 전에만 하면 7주마다 한 번의 클릭으로 갱신됩니다. 그 기간을 놓치면 동의 화면이 다시 나타나는데, 그때는 클릭이 두 번입니다.
그래서 이 서비스에는 cron 트리거가 포함되어 있습니다. 14일 전부터 매일 아침, 자동 갱신이 아직 작동하는 동안 일일 요약 맨 위에 갱신 알림을 올려줍니다. 알림을 참조하세요.
설정
1. LinkedIn 쪽 (수동, 약 10분)
LinkedIn Page가 필요합니다. 개발자 포털에서 앱을 페이지에 연결하고 페이지 관리자가 검증하도록 해야 합니다.
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 탭에서 리디렉션 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"세 가지 도구:
도구 | 기능 |
| 린트 후 게시합니다. 오류가 있으면 |
| 게시하지 않고 린트만 합니다. 초안 작성 중에 사용하세요. |
| 게시 주체와 토큰의 남은 일수를 알려줍니다. |
그런 다음 세션에서: "이 초안을 린터에 검사한 다음 게시해."
셸에서 사용하기
# 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는 게시물 URN과 공개 URL과 함께 201을 반환하고, 린터가 차단하면 422, 토큰이 없거나 만료되었으면 503을 반환합니다.
알림
이것이 없으면 이 서비스는 모든 무인 서비스가 실패하는 방식으로 실패합니다. 조용히, 그리고 게시물이 나가지 않는 날에야 알게 됩니다. 텔레그램 그룹 하나면 봇 하나를 만드는 비용으로 그 문제를 해결합니다.
# 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이 게시물을 거부했고, 추정 사유가 포함됨 |
사용 가능한 토큰 없음 | 게시 시도에서 토큰이 없거나 만료된 것을 발견함 |
할당량 | 하루 요청이 LinkedIn이 회원에게 허용하는 150회 중 120회를 넘어섬 |
무언가를 바꾸기 전에 알아둘 만한 설계 결정 두 가지:
일일 요약이 하트비트입니다. 아무 일이 없어도 발송되므로, 요약이 오지 않는 것 자체가 알람이며, 모니터를 모니터링할 필요가 없습니다. 그래서 갱신 알림도 두 번째 메시지로 따로 오지 않고 요약 위에 얹혀 옵니다. 아침에 정확히 한 통이어야 합니다. 그렇지 않으면 훑어보는 데 익숙해질 테니까요.
갱신 링크에는 설정 키가 아니라 일회용 nonce가 담깁니다. SETUP_KEY가 들어간 링크는 오래 사는 비밀을 채팅 로그에 영구히 남겨 둡니다. 대신 cron이 nonce를 발급합니다. 이 nonce는 7일간 유효하며, 다음 알림으로 교체되고, 토큰이 저장되는 순간 삭제됩니다. 모든 메시지에서 링크 미리보기가 비활성화되어 있어, 텔레그램이 프리페치로 nonce를 소진하지 못합니다.
아무것도 설정하지 않으면 서비스는 이전과 똑같이 동작합니다. NOTIFY_WEBHOOK가 있으면 그쪽으로, 없으면 로그로 남깁니다.
GET /telegram/preview?key=<SETUP_KEY>&kind=daily는 메시지를 보내지 않고 렌더링합니다. 그룹에 스팸을 보내지 않고 문구를 편집하는 방법입니다. &send=1을 추가하면 휴대폰에서 확인할 수 있습니다.
Bot API 전송 계층은 로컬 스텁으로 테스트됩니다. 여기에는 설정 몇 달 후 텔레그램 봇을 조용히 망가뜨리는 슈퍼그룹 마이그레이션도 포함됩니다.
npm run test:telegram린터
오류는 게시를 차단하고, 경고는 차단하지 않습니다.
규칙 | 심각도 | 이유 |
| 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을 링크로 만들어 줍니다. 실제 게시물로 확인했습니다. 베어 URL은
lnkd.in/...으로 단축되고 클릭할 수 있습니다. 다만 이미지와 제목이 있는 미리보기 카드는 얻을 수 없습니다. 그게 필요하면 Images API로 썸네일을 업로드하고content.article블록을 추가해야 합니다. 아직 여기에는 구현되지 않았습니다.LinkedIn-Version은 필수이며, 버전은 지원 종료됩니다.202508은 2026년 8월 17일에 서비스가 중단되었습니다.wrangler.jsonc의 값을 유지보수 항목으로 취급하세요./v2/ugcPosts는 더 이상 사용되지 않습니다. 이 서비스는 그것을 대체한/rest/posts를 사용합니다.요청 범위(scope)를 변경하면 기존의 모든 토큰이 무효화됩니다. 다시 인증해야 합니다.
회원당 하루 150회 요청. 앱당이 아니라 회원당입니다.
구성
파일 | 내용 |
| 라우트, OAuth 흐름, cron 알림 |
| OAuth 및 Posts API 호출, 모든 엔드포인트를 한곳에 |
| MCP 서버, 직접 구현한 JSON-RPC, 무상태(stateless) |
| 문체 린터 |
| 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 범위, scope 매개변수의 %20과 +의 차이, 정상적으로 배포된 것을 죽은 것처럼 보이게 만든 네거티브 DNS 캐시, 그리고 어떤 비밀도 터미널을 거치지 않도록 처리한 방법이 담겨 있습니다.
docs/2026-08-27-telegram-obavijesti.md는 알림 계층을 다룹니다. 텔레그램 봇을 조용히 망가뜨리는 슈퍼그룹 마이그레이션, 하트비트가 핑이 아니라 요약인 이유, 갱신 링크에 nonce가 담기는 이유를 설명합니다.
라이선스
MIT. src/lint.ts의 규칙은 제 것이고, 메커니즘은 여러분이 가져다 쓸 수 있습니다.
This server cannot be deployed
Maintenance
Related MCP Connectors
Schedule and publish LinkedIn posts to profiles and company pages from AI agents.
Draft LinkedIn posts in your voice, then schedule or publish them through LinkedIn's official API.
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.
Related MCP Servers
- AlicenseAqualityCmaintenanceEnables 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.912 npmApache 2.0
- 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.-
- FlicenseNot gradedqualityBmaintenanceEnables AI assistants to publish public text posts to an authenticated LinkedIn profile via the Model Context Protocol.-