mguttmann/linkedin-internal-api

GitHub: mguttmann/linkedin-internal-api

该项目逆向工程了 LinkedIn 私有 Web API 并提供 MCP Server,让 AI 助手能够以编程方式读写 LinkedIn 账号数据。

Stars: 0 | Forks: 0

# 🔗 LinkedIn 内部 API — 参考与 MCP Server **一个逆向工程且如实记录文档的 LinkedIn 私有 Web API 客户端 —— 外加一个即插即用的 MCP server,让 AI 助手为你读写 LinkedIn。** `Voyager + SDUI` · `130 个 endpoint(141 条原始抓取)` · `26 个 MCP tool` · `browserless-first` · `每个 ✅ 均抓取自真实流量`
## 🎯 这是什么? LinkedIn 的*官方* API 无法编辑你的个人资料、发送消息、管理你的人脉网络,或完整阅读 你自己发布的帖子。但 **LinkedIn 网站**却能完成所有这些操作 —— 它通过调用两个私有 后端 API 来实现。本项目从真实的已登录流量中**对那些 API 进行了逆向工程**,如实记录了 每一个 endpoint(已验证 ✅ vs. 已发现 🔍 vs. 推测 🔩),并发布了一个 **Model Context Protocol (MCP) server**,以便像 Claude 这样的工具可以通过编程方式驱动 LinkedIn 账号。 **范围:**控制账号**所有者自己**的个人资料 —— 包括编辑、帖子、消息传递、评论、 人脉网络。**代码库中绝不存储身份信息** —— 你需要通过环境变量来提供。 ## 🗺️ 两个 API 世界 LinkedIn 的前端与**两个平行的后端**通信。许多功能仅存在于其中一个 —— 你必须 同时了解这两者。 ``` flowchart TD B["🌐 Browser (logged in)
cookies: li_at + JSESSIONID"] B --> V["VOYAGER
/voyager/api/…
REST.li + GraphQL
established · broad"] B --> S["SDUI (rsc-action)
/flagship-web/rsc-action/…
Server-Driven UI · protobuf-JSON
newer · growing"] V --> V1["reads · like · create-post
follow-company · connect · all messaging"] S --> S1["unlike · delete-post · comments
all profile edits · endorse · remove-connection"] style B fill:#0a66c2,color:#fff style V fill:#e8f0fe,color:#000 style S fill:#fef7e8,color:#000 ``` **经验法则:**如果能在 Voyager 上运行,就使用它(稳定,无需浏览器)。只有在 Voyager 失败时才回退到 SDUI。请注意混合模式 —— *创建帖子 = Voyager,删除帖子 = SDUI;点赞 = Voyager,取消点赞 = SDUI。* ## 🔌 Browserless-first 关键发现:**大多数操作不需要浏览器。**通过最新的 session cookie,纯 Python `requests` 即可直接请求 Voyager。隐形浏览器仅作为**session 来源**,以及作为少数需要页面绑定上下文的 SDUI 写入操作的后备方案。 ``` sequenceDiagram participant U as You (once) participant SB as Stealth Browser participant C as Client (requests) participant LI as LinkedIn API U->>SB: log in once SB->>SB: persist session (survives restarts) SB-->>C: dump cookies (li_at, JSESSIONID) Note over C,LI: from here on — no browser C->>LI: GET /voyager/api/… (reads) LI-->>C: 200 JSON C->>LI: POST … (like · post · message · follow) LI-->>C: 200 / 201 Note over C,SB: only SDUI writes needing
currentActor fall back to the browser ``` **为什么需要隐形?**普通的自动化 Chrome 很快就会被登出。而一个持久的 patchright 上下文 (`navigator.webdriver = false`) 则能在崩溃后保持登录状态 —— 你只需登录**一次**。 ## 🧩 `states[]` 突破 SDUI 个人资料表单看起来无法重放 —— 其字段值是不透明的 `MemoryNamespace` state-refs。但它们会将每个值发送**两次**:同时作为真实的字面量存在于顶层的 `states[]` 数组中。这使得它们可以使用纯 `requests` 进行重放。一个 `saveProfileLanguageForm` 的创建操作 通过自行生成的 uuid + `states[]` 值进行了重放 → **HTTP 200,个人资料发生了实时更改。** → `docs/BROWSERLESS-REPLAY.md`。 ## 🤖 MCP server(26 个 tool) `mcp/` 是一个 [FastMCP](https://github.com/jlowin/fastmcp) server,将 API 暴露为任何 MCP 客户端(Claude Desktop、Cursor 等)都可以调用的 tool。 ``` flowchart LR AI["🤖 Claude / Cursor"] -->|MCP| SRV["server.py
26 @mcp.tool"] SRV --> CL["client.py
requests-first"] CL -->|browserless| LI["LinkedIn Voyager"] CL -. fallback .-> BR["stealth browser"] BR -.-> LI style AI fill:#0a66c2,color:#fff style SRV fill:#e8f0fe,color:#000 ``` | 领域 | Tool | |---|---| | **读取**(browserless) | `get_me` · `get_my_posts` · `get_profile` · `get_notifications` · `get_conversations` · `get_connections_summary` · `get_post_comments` · `get_link_preview` | | **帖子** | `create_post` (+poll) · `edit_post` · `delete_post` · `create_poll` · `save_post` · `repost` · `delete_repost` | | **互动** | `like` (browserless) · `unlike` (browser) | | **消息传递** | `send_dm` · `recall_message` · `react_to_message` | | **人脉网络** | `follow_company` · `connect` · `endorse_skill` · `remove_connection` | | **Session** | `session_status` · `refresh_session` | 🔒 **护栏机制:**面向他人的/破坏性的 tool(`create_post`、`edit_post`、`delete_post`、 `send_dm`、`recall_message`、`repost`、`delete_repost`、`connect`、`remove_connection`)需要 设置 `confirm=True`。 ### 运行 ``` cd mcp uv venv .venv --python 3.11 uv pip install --python .venv/bin/python fastmcp patchright requests .venv/bin/patchright install chromium # 你的身份来自环境——repo 中没有任何硬编码: export LI_OWNER_URN="urn:li:fsd_profile:" export LI_OWNER_VANITY="" .venv/bin/python tests/test_server.py # offline → 4/4 .venv/bin/python tests/test_client.py # offline → 19/19 .venv/bin/python bootstrap_login.py # first run: log in once in the stealth window .venv/bin/python server.py # stdio (Claude Desktop / Cursor / Hermes) ``` ## 🔬 方法:点击并记录 你无法猜测写入 endpoint —— 请求体嵌套极深且与特定部署相关。 唯一可靠的方法是:**执行真实操作,记录其触发的确切请求。** ``` flowchart LR A["do the action
(e.g. click 'Like')"] --> B["capture the
network request"] B --> C["extract endpoint
+ body + IDs"] C --> D["replay via requests"] D --> E{"browserless?"} E -->|yes| F["✅ document + tool"] E -->|500| G["browser fallback
+ honest note"] ``` 读取 endpoint 由自动探索的爬虫发现;写入 endpoint 则通过点击并记录的方式发现。→ `docs/05-VERIFICATION.md`, `CAPTURE-PLAYBOOK.md` 中有可复用的流程。 ## ✅ 覆盖范围 - **个人资料编辑** — 16 个部分已**记录文档**(逆向工程出的 `saveProfileForm` 模式)。持久化的抓取产物支撑了其中一部分:5 个支持完全的添加/编辑/删除,3 个仅支持添加, 1 个仅支持删除 —— 每个部分的文档(`docs/09`–`21`)都说明了其确切状态。*(参考 文档 —— 个人资料编辑未作为 MCP tool 暴露;这 26 个 tool 均为读取/帖子/消息传递/人脉网络操作。)* - **帖子** — 创建、编辑、删除、投票、媒体、@提及、保存/取消保存、转发、链接预览 - **消息传递** — 发送、撤回、回应、列出对话(全部为 browserless) - **互动** — 点赞 (browserless),取消点赞 (browser) - **人脉网络** — 连接 (+附言)、认可技能、移除连接、关注公司 - **读取** — 个人资料、*完整文本阅读*自己的帖子(填补了 Composio 无法弥补的空白)、通知、收件箱 - **联系信息** — 已抓取保存的 endpoint **未覆盖(已如实记录):**关注话题标签、个人资料语言、照片/封面上传、职位、 设置、推荐、引用转发。 ## 📚 文档地图 | 从这里开始 | 内容 | |---|---| | **[`docs/00-OVERVIEW.md`](docs/00-OVERVIEW.md)** | 两个 API 世界、决策规则 | | **[`docs/COVERAGE-MAP.md`](docs/COVERAGE-MAP.md)** | 每个功能 → endpoint → 状态(实时清单) | | **[`docs/ENDPOINTS.md`](docs/ENDPOINTS.md)** | 所有 endpoint 的扁平列表(130 个不同 / 141 个原始)+ 已验证的写入表 | | `docs/01` · `02` · `03` | 身份验证/Cookie · Voyager 深度解析 · SDUI 深度解析 | | `docs/04-WRITE-OPERATIONS.md` · `docs/05` | 每个已验证的写入及请求体 · 信息流/读取发现 | | `docs/06` · `07` · `08` | 消息传递 · 评论 · 人脉网络 | | `docs/09`–`22` | 个人资料编辑(16 个部分 + 联系信息 + 关于 + 求职意向) | | `docs/10` · `23` | 帖子互动(点赞/保存/转发) · 读取与发现 endpoint | | `docs/24` · `25` | 高级帖子(编辑/投票/媒体/提及) · 人脉网络与联系操作 | | `docs/BROWSERLESS-REPLAY.md` | 关于 `states[]` 发现的深入解析 | | `docs/MCP-DESIGN.md` | 为什么 server 要这样构建 | ## ⚠️ 注意事项 - **代码库中无个人身份信息。**所有者的 URN / 自定义名称来源于 `LI_OWNER_URN` / `LI_OWNER_VANITY`;文档中的个人标识符均为占位符(`OWNER_PROFILE_ID`、 `alex-rivera`、`SECTION_ITEM_ID`、`COMPANY_ID` 等)。少数结构性常量在公开且非个人的情况下保留为真实 值(例如测试中 Microsoft 的公司 ID `1035`, GraphQL 的 `queryId` 哈希值,LinkedIn 的 URN 类型名称)。 - **服务条款。**根据 LinkedIn 的 ToS,自动化操作 LinkedIn 属于灰色地带。这是一个针对用户**自己**账号的研究 / 个人自动化项目。请负责任地使用,风险自负。 - **无保证。**LinkedIn 在每次部署时会轮换 GraphQL 的 query-id 哈希值;当调用开始 返回 404 时,请重新抓取当前的哈希值(文档中指出了其位置)。
标签:AI助手, API逆向, LinkedIn, MCP服务器, 网络请求, 网络调试, 自动化, 逆向工具