linkedin-poster
linkedin-poster
从 Claude Code、shell 或 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 时,再次访问授权端点会跳过同意页面,直接重定向。因此,只要在令牌失效前操作,续期就是每七周点一次。错过窗口期,同意页面就会重新出现,变成点两次而不是一次。
这就是为什么这个服务自带 cron 触发器。从到期前 14 天开始,它会在每天早上的每日摘要顶部放一条续期提醒,此时静默续期仍然有效。参见通知。
设置
1. LinkedIn 侧(手动操作,约十分钟)
你需要一个 LinkedIn 主页。开发者门户要求你把应用关联到一个主页,并由主页管理员验证。
在 linkedin.com/developers 创建应用。 记下 Client ID 和 Client Secret。
在 Products 标签页,请求这两项(它们都是开放权限,会立即批准):
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"三个工具:
工具 | 作用 |
| 先检查,再发布。有错误时拒绝发布,除非 |
| 只检查,不发布。起草时使用。 |
| 以谁的身份发布,以及令牌还剩多少天。 |
然后,在会话中:"用检查器检查这篇草稿,然后发布它。"
从 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 返回 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 拒绝了帖子,附带对原因的猜测 |
无可用令牌 | 发布尝试发现令牌缺失或失效 |
配额 | 当天用掉了 LinkedIn 允许成员的 150 次请求中的 120 次 |
有两个设计决策,在改动之前值得了解:
每日摘要就是心跳。 即使什么都没发生它也会发出,所以它的缺席本身就是警报,不需要什么东西去监控监控者。这也是为什么续期提醒搭载在摘要之上,而不是作为第二条消息单独到达:每天早上恰好一条消息,否则你会训练自己只看一眼。
续期链接携带一次性 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检查器
错误会阻止发布;警告不会。
规则 | 严重程度 | 原因 |
| 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已于 2026 年 8 月 17 日失效。把wrangler.jsonc里的这个值当作一项维护事项。/v2/ugcPosts已弃用。 这里使用的是取代它的/rest/posts。更改请求的 scope 会使所有现有令牌失效。 你将需要重新授权。
每个成员每天 150 次请求。 是每个成员,不是每个应用。
目录结构
文件 | 内容 |
| 路由、OAuth 流程、cron 提醒 |
| OAuth 和 Posts API 调用,所有端点集中在一处 |
| 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" 的应用名称,不可逆的主页关联,刷新页面之前一直为空的 OAuth scope,
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.-