feishu-user-plugin 1.3.11 → 1.3.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/.claude-plugin/plugin.json +2 -2
  2. package/.cursor-plugin/plugin.json +2 -2
  3. package/.mcpb/manifest.json +3 -3
  4. package/CHANGELOG.md +159 -8
  5. package/README.en.md +130 -413
  6. package/README.md +69 -259
  7. package/package.json +2 -2
  8. package/scripts/check-description-drift.js +73 -0
  9. package/scripts/check-docs-sync.js +7 -16
  10. package/scripts/check-scopes.js +99 -0
  11. package/scripts/check-tool-count.js +4 -3
  12. package/scripts/sync-claude-md.sh +3 -4
  13. package/scripts/verify-app-name.js +64 -0
  14. package/skills/feishu-user-plugin/SKILL.md +3 -3
  15. package/skills/feishu-user-plugin/references/search.md +3 -3
  16. package/src/auth/credentials-monitor.js +185 -0
  17. package/src/auth/identity-state.js +209 -0
  18. package/src/auth/uat.js +49 -35
  19. package/src/cli.js +87 -0
  20. package/src/clients/official/base.js +170 -14
  21. package/src/clients/official/calendar.js +3 -1
  22. package/src/clients/official/im.js +76 -2
  23. package/src/clients/official/okr.js +2 -1
  24. package/src/error-codes.js +40 -0
  25. package/src/events/lockfile.js +40 -4
  26. package/src/events/owner.js +11 -2
  27. package/src/index.js +1 -1
  28. package/src/logger.js +11 -5
  29. package/src/oauth.js +65 -14
  30. package/src/server.js +76 -37
  31. package/src/test-all.js +41 -0
  32. package/src/test-cli-tool.js +87 -0
  33. package/src/test-credentials-monitor.js +124 -0
  34. package/src/test-display-label.js +88 -0
  35. package/src/test-error-codes.js +85 -0
  36. package/src/test-identity-state.js +177 -0
  37. package/src/test-lark-desktop.js +1 -0
  38. package/src/test-lockfile-pid.js +90 -0
  39. package/src/test-lru-cache.js +145 -0
  40. package/src/test-negative-cache.js +85 -0
  41. package/src/test-populate-sender-names.js +98 -0
  42. package/src/test-search-messages.js +101 -0
  43. package/src/test-send-shape.js +115 -0
  44. package/src/test-via-user.js +94 -0
  45. package/src/test-with-uat-retry.js +135 -0
  46. package/src/tools/_registry.js +24 -1
  47. package/src/tools/calendar.js +5 -5
  48. package/src/tools/im-read.js +52 -4
  49. package/src/tools/messaging-user.js +1 -1
  50. package/src/utils.js +83 -0
  51. package/skills/feishu-user-plugin/references/CLAUDE.md +0 -524
package/README.en.md CHANGED
@@ -1,189 +1,102 @@
1
- # feishu-user-plugin
1
+ # feishu-user-plugin — Feishu MCP server + CLI tool
2
2
 
3
3
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
4
4
  [![Node.js](https://img.shields.io/badge/Node.js-%3E%3D18-green.svg)](https://nodejs.org)
5
5
  [![MCP](https://img.shields.io/badge/MCP-Compatible-purple.svg)](https://modelcontextprotocol.io)
6
- [![Tools](https://img.shields.io/badge/Tools-84-orange.svg)](#tools)
6
+ [![Tools](https://img.shields.io/badge/Tools-85-orange.svg)](docs/TOOLS.md)
7
+ [![npm](https://img.shields.io/npm/v/feishu-user-plugin.svg)](https://www.npmjs.com/package/feishu-user-plugin)
7
8
  [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](CONTRIBUTING.md)
8
9
 
9
- **All-in-one Feishu/Lark MCP Server -- 84 tools, 9 skills, 3 auth layers for messaging, docs, bitable, calendar, tasks, drive, OKR, and more.**
10
+ [中文](README.md) · **English** · [Docs](https://ethanqc.github.io/feishu-user-plugin/en) · [CHANGELOG](CHANGELOG.md) · [npm](https://www.npmjs.com/package/feishu-user-plugin)
10
11
 
11
- > [中文 README](README.md) is the primary version. This English README mirrors it.
12
+ Feishu / Lark MCP server covering IM, docs, bitable, wiki, drive, calendar, tasks v2, OKR, and realtime events. **85 tools · 3 auth layers · 9 MCP prompts · MIT licensed · Node ≥18**.
12
13
 
13
- The only MCP server that lets you send messages as your **personal identity** (not a bot), while also integrating the full official Feishu API. Works with Claude Code, Cursor, Windsurf, OpenClaw, and any MCP-compatible client.
14
+ Works with Claude Code, Codex, Cursor, Windsurf, VS Code, Claude Desktop, OpenClaw, and any MCP-compatible client.
14
15
 
15
- ## Highlights
16
+ There are two paths to user-identity messaging: **Feishu's official OAuth scope `im:message.send_as_user`** (requires creating a self-built app + admin approval), or this repo's **cookie + protobuf path** (zero app barrier — capture cookie and you're ready). This repo is no longer architecturally exclusive, but it remains the simpler option for "individual developers / no admin access / want to try quickly" scenarios.
16
17
 
17
- - **Send as yourself** -- Messages show your real name, not a bot. Supports text, rich text, images, files, stickers, and audio.
18
- - **Read everything** -- Group chats via bot API, P2P (direct messages) via OAuth UAT.
19
- - **Full Feishu suite** -- Docs, Bitable, Wiki, Drive, Calendar, Tasks, Contacts -- all in one plugin.
20
- - **3 auth layers** -- Cookie-based user identity, app credentials (Official API), and OAuth UAT (P2P reading).
21
- - **Group management** -- Create groups, add/remove members, pin messages, emoji reactions.
22
- - **Document editing** -- Not just read/create, but insert/update/delete content blocks.
23
- - **Calendar & Tasks** -- Create events, check free/busy, manage tasks.
24
- - **9 slash commands** for Claude Code -- `/send`, `/reply`, `/search`, `/digest`, `/doc`, `/table`, `/wiki`, `/drive`, `/status`
25
- - **Auto session management** -- Cookie heartbeat every 4h, UAT auto-refresh with token rotation.
26
- - **Real-time events** (v1.3.9) -- Machine-level WS: one owner process writes to `~/.feishu-user-plugin/events.jsonl`, all harnesses drain from a shared cursor — every event delivered exactly once across all MCP processes. `manage_ws_status` to diagnose/control. WS auto-starts on boot.
27
- - **Multi-platform** -- Claude Code, Cursor, Windsurf, VS Code, OpenClaw.
18
+ ## vs the official Feishu/Lark tools (released 2026)
28
19
 
29
- ## Why This Exists
20
+ - [`larksuite/lark-openapi-mcp`](https://github.com/larksuite/lark-openapi-mcp) official OpenAPI MCP, **⚠ Beta**, last updated 2025-08 (9 months stale). Their README explicitly states "File upload/download not yet supported" and "Direct document editing not supported"; 1271 endpoint tools but preset.default only enables ~20, the rest "not undergone compatibility testing".
21
+ - [`larksuite/cli`](https://github.com/larksuite/cli) — official CLI (9.9k stars, actively maintained), 17 business domains, 200+ commands + 24 AI Agent Skills. **Now supports `+messages-send --as user`** via OAuth scope `im:message.send_as_user`. But it's a **CLI, not an MCP server**. Codex / Cursor / Windsurf etc would have to shell out to it.
30
22
 
31
- Feishu's official API has a hard limitation: **there is no `send_as_user` scope**. Even with `user_access_token` (OAuth), messages still show `sender_type: "app"`.
23
+ **When to use this repo**:
32
24
 
33
- This project combines three auth layers into one plugin:
25
+ - You want user-identity messaging / P2P chat reading but **can't / don't want to create a Feishu self-built app** (individual developer / no admin access) — the cookie path has zero barrier
26
+ - You use MCP protocol (Codex / Cursor / Windsurf / VS Code etc) and don't need mail / approval / HR / meeting-minutes domains that this repo doesn't cover
27
+ - You run multiple MCP clients simultaneously and need "every event delivered exactly once across the entire machine" (v1.3.9+ machine-level WS SSOT)
34
28
 
35
- ```
36
- User Identity (cookie): You -> Protobuf -> Feishu (messages appear as YOU)
37
- Official API (app token): You -> REST API -> Feishu (docs, tables, wiki, drive)
38
- User OAuth (UAT): You -> REST API -> Feishu (read P2P chats, list all chats)
39
- ```
40
-
41
- **One plugin. Everything Feishu. No other MCP needed.**
29
+ **When to use the official**: you need mail / approval / attendance / HR / hiring / meeting-minutes business-system domains; or you already have a Feishu app + admin-approved OAuth scopes and prefer the officially-maintained long-term path.
42
30
 
43
- ## Quick Start
31
+ Full honest comparison: [docs/COMPARISON.md](docs/COMPARISON.md).
44
32
 
45
- ### Option 1: npx (recommended)
33
+ ## Quick example
46
34
 
47
- ```bash
48
- npx feishu-user-plugin
49
35
  ```
50
-
51
- No installation needed. The package runs directly via npx.
52
-
53
- ### Option 2: Clone and run locally
54
-
55
- ```bash
56
- git clone https://github.com/EthanQC/feishu-user-plugin.git
57
- cd feishu-user-plugin
58
- npm install
59
- npm start
36
+ You: send Wang Xiao Ming a message as me: "finished the code review, 3 nits"
37
+ Claude: [calls send_to_user] Sent
60
38
  ```
61
39
 
62
- ## Create Your Feishu App
63
-
64
- To use the Official API tools (docs, tables, wiki, drive, bot messaging), you need to create a Feishu app:
65
-
66
- ### Step 1: Create the App
67
-
68
- 1. Go to [Feishu Open Platform](https://open.feishu.cn/app) and log in
69
- 2. Click **Create Custom App** (创建自建应用) -- you must choose **Custom App** (自建应用), NOT marketplace/third-party types
70
- 3. Fill in the app name and description, then create it
71
-
72
- ### Step 2: Enable Bot Capability
73
-
74
- 1. In your app settings, go to **Add Capabilities** (添加应用能力)
75
- 2. Enable **Bot** (机器人)
76
-
77
- ### Step 3: Add Permissions (Scopes)
78
-
79
- Go to **Permissions & Scopes** (权限管理) and add the following scopes:
80
-
81
- | Scope | Purpose |
82
- |-------|---------|
83
- | `im:message` | Send messages as bot |
84
- | `im:message:readonly` | Read message history |
85
- | `im:chat:readonly` | List and read chats |
86
- | `docx:document` | Read and create documents |
87
- | `docx:document:readonly` | Read documents |
88
- | `bitable:record` | Read and write Bitable records |
89
- | `wiki:wiki:readonly` | Read wiki spaces and nodes |
90
- | `drive:drive:readonly` | List Drive files and folders |
91
- | `contact:user.base:readonly` | Look up users by email/mobile |
92
-
93
- > Add more scopes as needed depending on which tools you use.
94
-
95
- ### Step 4: Get App Credentials
96
-
97
- 1. Go to **Credentials & Basic Info** (凭证与基础信息)
98
- 2. Copy the **App ID** (`cli_xxxxxxxxxxxx`) and **App Secret**
99
- 3. Set them as `LARK_APP_ID` and `LARK_APP_SECRET` in your environment
100
-
101
- ### Step 5: Publish and Approve
102
-
103
- 1. **Create a version** and submit it for review (创建版本)
104
- 2. Have your organization admin approve the app (管理员审核)
105
- 3. After approval, the app is live
106
-
107
- ### Step 6: Add Bot to Group Chats
108
-
109
- Add your bot to the group chats where you want it to read messages. The bot can only access chats it has been added to.
110
-
111
- ## Environment Variables
112
-
113
- | Variable | Required For | Description |
114
- |----------|-------------|-------------|
115
- | `LARK_COOKIE` | User identity tools | Feishu web session cookie string. Needed for `send_to_user`, `send_to_group`, `search_contacts`, etc. |
116
- | `LARK_APP_ID` | Official API tools | App ID from Feishu Open Platform. Needed for `read_messages`, docs, tables, wiki, drive. |
117
- | `LARK_APP_SECRET` | Official API tools | App Secret from Feishu Open Platform. Used together with `LARK_APP_ID`. |
118
- | `LARK_USER_ACCESS_TOKEN` | P2P chat reading | OAuth user token. Needed for `read_p2p_messages` and `list_user_chats`. Obtained via `node src/oauth.js`. |
119
- | `LARK_USER_REFRESH_TOKEN` | UAT auto-refresh | Refresh token for automatic UAT renewal. Obtained together with UAT via OAuth flow. |
120
-
121
- All five variables are required for full functionality. Configure all of them during setup.
122
-
123
- ## How to Get Your Cookie
40
+ ```
41
+ You: summarize today's discussion in the engineering group after 9am, post a daily digest to #daily
42
+ Claude: [read_messages summarize send_to_group] Sent
43
+ ```
124
44
 
125
- **Option A: Automated via Playwright MCP (recommended, zero manual copying)**
45
+ ## Quick start
126
46
 
127
- First, install Playwright MCP if you don't have it:
128
47
  ```bash
129
- npx @anthropic-ai/claude-code mcp add playwright -- npx @anthropic-ai/mcp-server-playwright
48
+ npx feishu-user-plugin setup --app-id <APP_ID> --app-secret <APP_SECRET>
49
+ npx feishu-user-plugin oauth # OAuth UAT
50
+ # restart Claude Code / Codex
130
51
  ```
131
52
 
132
- Then just tell Claude Code: **"Help me set up my Feishu cookie"**
133
-
134
- Claude Code will automatically:
135
- 1. Open feishu.cn in a browser via Playwright
136
- 2. Show you the QR code — scan it with Feishu mobile app
137
- 3. Extract the full cookie (including HttpOnly) via `context.cookies()`
138
- 4. Write it to your `.mcp.json` LARK_COOKIE field
139
- 5. Prompt you to restart Claude Code
53
+ Cookie capture (Playwright auto-QR / DevTools manual), Feishu app creation, per-client config — see [docs/AUTH-SETUP.md](docs/AUTH-SETUP.md).
140
54
 
141
- **Option B: Manual (via Network tab)**
55
+ ## Three auth layers
142
56
 
143
- 1. Open [feishu.cn/messenger](https://www.feishu.cn/messenger/) in your browser and log in
144
- 2. Open DevTools (`F12` or `Cmd+Option+I`)
145
- 3. Go to the **Network** tab check **Disable cache** press `Cmd+R` to reload
146
- 4. Click the first request in the list (usually the page itself)
147
- 5. In the right panel, find **Request Headers** **Cookie:** right-click **Copy value**
148
- 6. Set it as `LARK_COOKIE` in your environment
57
+ | Layer | Credentials | Capabilities | Tools |
58
+ |---|---|---|---|
59
+ | User identity (cookie + protobuf) | `LARK_COOKIE` | Send text / image / file / post / @ / batch as the user | 8 |
60
+ | Official API (bot) | `LARK_APP_ID` + `LARK_APP_SECRET` | Group messages, docs, bitable, wiki, drive, calendar, tasks v2, OKR, contacts, realtime WS | 70+ |
61
+ | User OAuth UAT | `LARK_USER_ACCESS_TOKEN` + `LARK_USER_REFRESH_TOKEN` | P2P chat reading, user chat list; resources owned by the user when creating | 2 explicit + UAT-first across the suite |
149
62
 
150
- > Do NOT use `document.cookie` in the Console or copy from Application → Cookies tab they miss HttpOnly cookies (`session`, `sl_session`) required for auth.
63
+ Layers are independentconfigure any subset.
151
64
 
152
- > The server automatically refreshes the session via heartbeat every 4 hours. The `sl_session` cookie has a 12-hour max-age.
65
+ ## Capabilities
153
66
 
154
- ## Set Up OAuth (Required for P2P Chat Reading)
67
+ - **Send messages as you** (8): text / image / file / rich-text post / cards / batch; differentiator — Feishu's official API has no `send_as_user`
68
+ - **Read groups & P2P chats** (17): group messages / P2P / `merge_forward` auto-expanded / URL + Feishu doc links auto-extracted / external groups auto-fallback to UAT
69
+ - **Document suite** (27): Feishu docs (with `read_doc_markdown` saving ~60% tokens) / bitable (batch up to 500) / wiki (full write CRUD) / drive
70
+ - **Productivity** (21): calendar (read+write) / tasks v2 (with member management) / OKR (read + progress records) / contacts
71
+ - **Realtime events** (2): machine-level SSOT WS, every event delivered exactly once across the entire machine
72
+ - **Diagnostics & multi-account** (4): N profiles auto-switched per call, writes never auto-switch (avoids accidental cross-account creates)
155
73
 
156
- To enable `read_p2p_messages` and `list_user_chats`:
74
+ Full tool list + cross-domain caveats + usage patterns: [docs/TOOLS.md](docs/TOOLS.md).
157
75
 
158
- 1. Your Feishu app must be a **Custom App** (自建应用), NOT marketplace/third-party
159
- 2. Add scopes: `im:message`, `im:message:readonly`, `im:chat:readonly`
160
- 3. In your app's **Security Settings** (安全设置), add the OAuth redirect URI: `http://127.0.0.1:9997/callback`
161
- 4. **Important**: Make sure "对外共享" (external sharing) is **disabled** in your app version settings — enabling it marks the app as b2c/b2b type, which blocks P2P chat access
162
- 5. Run the authorization flow:
76
+ ## 9 MCP prompts (slash commands)
163
77
 
164
- ```bash
165
- # If you cloned the repo:
166
- node src/oauth.js
167
-
168
- # If you installed via npx:
169
- cd $(npm root -g)/feishu-user-plugin && node src/oauth.js
170
- # Or clone the repo just for the OAuth step, then use npx for daily use
171
- ```
172
-
173
- A browser window will open for OAuth consent. The token is saved to `.env` automatically and auto-refreshes at runtime. Add both `LARK_USER_ACCESS_TOKEN` and `LARK_USER_REFRESH_TOKEN` from `.env` to your MCP config's `env` section.
78
+ | Prompt | Purpose |
79
+ |---|---|
80
+ | `/send` | Send a message as yourself |
81
+ | `/reply` | Read recent messages then reply |
82
+ | `/digest` | Summarise recent group / P2P messages |
83
+ | `/search` | Search contacts / groups |
84
+ | `/doc` | Search / read / create a Feishu doc |
85
+ | `/table` | Operate on a bitable |
86
+ | `/wiki` | Search wiki space |
87
+ | `/drive` | List drive files / create folder |
88
+ | `/status` | Check all three auth layers |
174
89
 
175
90
  ## MCP Client Configuration
176
91
 
177
92
  ### Claude Code
178
93
 
179
- Add to your project's `.mcp.json` (or `~/.claude/.mcp.json` for global):
180
-
181
- **Using npx:**
94
+ Add to `~/.claude.json` `mcpServers` (recommended global) or your project's `.mcp.json`:
182
95
 
183
96
  ```json
184
97
  {
185
98
  "mcpServers": {
186
- "feishu": {
99
+ "feishu-user-plugin": {
187
100
  "command": "npx",
188
101
  "args": ["-y", "feishu-user-plugin"],
189
102
  "env": {
@@ -198,30 +111,7 @@ Add to your project's `.mcp.json` (or `~/.claude/.mcp.json` for global):
198
111
  }
199
112
  ```
200
113
 
201
- **Using a local clone:**
202
-
203
- ```json
204
- {
205
- "mcpServers": {
206
- "feishu": {
207
- "command": "node",
208
- "args": ["/absolute/path/to/feishu-user-plugin/src/index.js"],
209
- "env": {
210
- "LARK_COOKIE": "your-cookie-string",
211
- "LARK_APP_ID": "cli_xxxxxxxxxxxx",
212
- "LARK_APP_SECRET": "your-app-secret",
213
- "LARK_USER_ACCESS_TOKEN": "your-uat",
214
- "LARK_USER_REFRESH_TOKEN": "your-refresh-token"
215
- }
216
- }
217
- }
218
- }
219
- ```
220
-
221
- Then just say things like:
222
- - "Send a message to Alice saying the meeting is at 3pm"
223
- - "What did the engineering group chat about today?"
224
- - "Search for docs about MCP"
114
+ Or via CLI: `npx feishu-user-plugin setup --app-id <APP_ID> --app-secret <APP_SECRET>`.
225
115
 
226
116
  ### Claude Desktop
227
117
 
@@ -245,6 +135,25 @@ Add to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS)
245
135
  }
246
136
  ```
247
137
 
138
+ ### Codex
139
+
140
+ Add to `~/.codex/config.toml`:
141
+
142
+ ```toml
143
+ [mcp_servers.feishu-user-plugin]
144
+ command = "npx"
145
+ args = ["-y", "feishu-user-plugin"]
146
+
147
+ [mcp_servers.feishu-user-plugin.env]
148
+ LARK_COOKIE = "your-cookie-string"
149
+ LARK_APP_ID = "cli_xxxxxxxxxxxx"
150
+ LARK_APP_SECRET = "your-app-secret"
151
+ LARK_USER_ACCESS_TOKEN = "your-uat"
152
+ LARK_USER_REFRESH_TOKEN = "your-refresh-token"
153
+ ```
154
+
155
+ Or via CLI: `npx feishu-user-plugin setup --client codex --app-id <APP_ID> --app-secret <APP_SECRET>`.
156
+
248
157
  ### Cursor
249
158
 
250
159
  Add to `.cursor/mcp.json` in your project:
@@ -269,7 +178,7 @@ Add to `.cursor/mcp.json` in your project:
269
178
 
270
179
  ### VS Code (Copilot)
271
180
 
272
- Add to `.vscode/mcp.json` in your project:
181
+ Add to `.vscode/mcp.json` in your project (note: top-level key is `servers`, not `mcpServers`):
273
182
 
274
183
  ```json
275
184
  {
@@ -314,9 +223,7 @@ Add to `~/.openclaw/openclaw.json` (note: key path is `mcp.servers`, not `mcpSer
314
223
  }
315
224
  ```
316
225
 
317
- Or via CLI: `openclaw mcp set feishu-user-plugin '{"command":"npx","args":["-y","feishu-user-plugin"],"env":{...}}'`
318
-
319
- > OpenClaw's built-in Feishu channel handles receiving messages (bot identity). This plugin adds user identity messaging + docs/bitable/calendar/tasks.
226
+ Or via CLI: `openclaw mcp set feishu-user-plugin '{"command":"npx","args":["-y","feishu-user-plugin"],"env":{...}}'`.
320
227
 
321
228
  ### Windsurf
322
229
 
@@ -340,264 +247,74 @@ Add to `~/.codeium/windsurf/mcp_config.json`:
340
247
  }
341
248
  ```
342
249
 
343
- ## Tools (80 total)
344
-
345
- ### User Identity -- Messaging (10 tools, cookie auth)
346
-
347
- | Tool | Description |
348
- |------|-------------|
349
- | `send_to_user` | Search user by name + send text -- one step |
350
- | `send_to_group` | Search group by name + send text -- one step |
351
- | `send_as_user` | Send text to any chat by ID, supports reply threading |
352
- | `send_image_as_user` | Send image (requires `image_key` from `upload_image`) |
353
- | `send_file_as_user` | Send file (requires `file_key` from `upload_file`) |
354
- | `send_post_as_user` | Send rich text with title + formatted paragraphs |
355
- | `batch_send` | Fan-out send to multiple targets in one call (text / image / file / post). v1.3.6 |
356
- | `send_card_as_user` | Send a Feishu interactive card via bot identity (Official API). User-identity card sending is server-side disabled at the Feishu cookie auth tier — confirmed in v1.3.9. |
357
-
358
- ### User Identity -- Contacts & Info (5 tools, cookie auth)
359
-
360
- | Tool | Description |
361
- |------|-------------|
362
- | `search_contacts` | Search users, bots, or group chats by name |
363
- | `create_p2p_chat` | Create/get P2P (direct message) chat |
364
- | `get_chat_info` | Group details (supports both oc_xxx and numeric ID) |
365
- | `get_user_info` | User display name lookup by user ID |
366
- | `get_login_status` | Check cookie, app credentials, and UAT status |
367
-
368
- ### User OAuth UAT -- P2P Chat Reading (2 tools)
369
-
370
- | Tool | Description |
371
- |------|-------------|
372
- | `read_p2p_messages` | Read P2P (direct message) history |
373
- | `list_user_chats` | List group chats the user is in |
374
-
375
- ### Official API -- IM (17 tools)
376
-
377
- | Tool | Description |
378
- |------|-------------|
379
- | `list_chats` | List all chats the bot has joined |
380
- | `read_messages` | Read message history (accepts chat name, oc_xxx, or numeric ID) |
381
- | `send_message_as_bot` | Send message as bot to any chat |
382
- | `reply_message` | Reply to a specific message (as bot) |
383
- | `forward_message` | Forward a message to another chat |
384
- | `delete_message` | Recall/delete a bot message |
385
- | `update_message` | Edit a sent bot message |
386
- | `add_reaction` | Add emoji reaction to a message |
387
- | `delete_reaction` | Remove emoji reaction |
388
- | `pin_message` | Pin a message in chat |
389
- | `unpin_message` | Unpin a message |
390
- | `create_group` | Create a new group chat |
391
- | `update_group` | Update group name/description |
392
- | `list_members` | List group members |
393
- | `add_members` | Add users to a group |
394
- | `remove_members` | Remove users from a group |
395
- | `upload_image` / `upload_file` | Upload image/file, returns key for sending |
396
- | `download_message_resource` | v1.3.7 (C2.4): download a message-attached image or file. Args: `message_id`, `key`, `kind=image|file`, `save_path?`. **Required save_path when bytes > 2 MiB** (Anthropic 5 MB inline cap). Replaces v1.3.6 download_image (message mode) + download_file. |
397
- | `download_doc_image` | v1.3.7 (C2.4): download an image embedded in a docx (image_token + optional doc_token). Same 2 MiB cap. Replaces v1.3.6 download_image (docx mode). |
398
-
399
- ### Wiki, OKR, and Calendar (v1.3.4)
400
-
401
- | Tool | Description |
402
- |------|-------------|
403
- | `get_wiki_node` | Resolve a Wiki node token to its underlying obj_type + obj_token + space_id |
404
- | `list_user_okrs` | List a user's OKRs (requires open_id; filter by period_ids) |
405
- | `get_okrs` | Batch-fetch full OKR details (objectives, key results, progress, alignments) |
406
- | `list_okr_periods` | List OKR periods (quarters / years) |
407
- | `list_calendars` | List the current user's calendars (primary + shared + subscribed) |
408
- | `list_calendar_events` | List events in a calendar within a time range |
409
- | `get_calendar_event` | Full event details (attendees, location, meeting link, attachments) |
410
-
411
- All docx / bitable tools' `document_id` / `app_token` parameter also accepts a Wiki node token or a full Feishu URL — the plugin resolves it transparently.
412
-
413
- ### Official API -- Documents (5 tools)
414
-
415
- | Tool | Description |
416
- |------|-------------|
417
- | `search_docs` | Search documents by keyword |
418
- | `read_doc` | Read raw text content |
419
- | `get_doc_blocks` | Get structured block tree |
420
- | `create_doc` | Create a new document |
421
- | `manage_doc_block` | Insert / update / delete blocks (`action=create|update|delete`). Supports generic `children`, image (`image_path`/`image_token`), and file (`file_path`/`file_token`) shortcuts. v1.3.7 consolidates the v1.3.6 trio create_doc_block / update_doc_block / delete_doc_blocks. |
422
-
423
- ### Official API -- Bitable (6 tools, v1.3.7 consolidation)
424
-
425
- | Tool | Actions | Description |
426
- |------|---------|-------------|
427
- | `manage_bitable_app` | create / copy / get_meta | App-level operations (v1.3.7 consolidates create_bitable / copy_bitable / get_bitable_meta) |
428
- | `manage_bitable_table` | list / create / update / delete | Table CRUD (rename via update) |
429
- | `manage_bitable_field` | list / create / update / delete | Field (column) management. `type` required for both create AND update. |
430
- | `manage_bitable_view` | list / create / delete | Views (grid, kanban, gallery, form, gantt, calendar) |
431
- | `manage_bitable_record` | search / get / create / update / delete | Record CRUD. create/update/delete accept arrays — single record or up to 500/call. |
432
- | `upload_bitable_attachment` | — | Upload a file into a Bitable Attachment-type field. Returns `file_token` to write into the field as `[{file_token}]`. v1.3.6 |
433
-
434
- ### Official API -- Calendar (8 tools, write tools v1.3.7)
435
-
436
- | Tool | Description |
437
- |------|-------------|
438
- | `list_calendars` | List accessible calendars |
439
- | `list_calendar_events` | List events in a calendar |
440
- | `get_calendar_event` | Full event details |
441
- | `create_calendar_event` | Create an event (v1.3.7). Requires `calendar:calendar.event:write`. |
442
- | `update_calendar_event` | Patch event fields (v1.3.7) |
443
- | `delete_calendar_event` | Delete an event, optionally dissolve its meeting chat (v1.3.7) |
444
- | `respond_calendar_event` | RSVP as accept / decline / tentative (v1.3.7) |
445
- | `get_freebusy` | Freebusy lookup for `user_ids` in a time range (v1.3.7) |
446
-
447
- ### Official API -- Tasks v2 (7 tools, v1.3.7 new domain)
448
-
449
- Identifier is `task_guid` (not v1's numeric `task_id`). Requires `task:task` scope.
450
-
451
- | Tool | Description |
452
- |------|-------------|
453
- | `list_tasks` | List the current user's tasks (filter by completed / type) |
454
- | `get_task` | Full task detail |
455
- | `create_task` | Create a task (summary required; due/members optional) |
456
- | `update_task` | Patch fields. **`update_fields` is required** — Feishu only updates the listed keys. |
457
- | `complete_task` | Mark complete (or uncomplete with `completed=false`) |
458
- | `delete_task` | Permanent delete |
459
- | `manage_task_members` | `action=add|remove`, members `[{id, role:"assignee"|"follower"}]` |
460
-
461
- ### Official API -- Drive (4 tools)
462
-
463
- | Tool | Description |
464
- |------|-------------|
465
- | `list_files` | List files in a folder |
466
- | `create_folder` | Create a new folder |
467
- | `manage_drive_file` | Copy / move / delete a Drive file (`action=copy|move|delete`, `type` required). v1.3.7 consolidates v1.3.6 copy_file / move_file / delete_file. |
468
- | `upload_drive_file` | Upload a local file into a Drive folder (`drive/v1/files/upload_all`). Optional `wiki_space_id` attaches the upload as a Wiki node atomically. v1.3.6 |
469
-
470
- ### Official API -- Wiki (8 tools)
471
-
472
- | Tool | Description |
473
- |------|-------------|
474
- | `list_wiki_spaces` / `search_wiki` / `list_wiki_nodes` / `get_wiki_node` | Wiki spaces, search, browse + resolve a wiki node to underlying obj_token |
475
- | `create_wiki_node` | Create a new wiki node (doc/sheet/bitable/mindnote/file/docx/slides) inside a space |
476
- | `update_wiki_node` | Rename a wiki node (title only — content edits via docx/bitable tools) |
477
- | `move_wiki_node` | Move a wiki node to a different parent or different space |
478
- | `copy_wiki_node` | Deep-copy a wiki node to a different location (optionally to a different space) |
479
-
480
- ### Plugin -- Profiles (3 tools, v1.3.6 + v1.3.8)
481
-
482
- | Tool | Description |
483
- |------|-------------|
484
- | `list_profiles` | List available identity profiles (default + extras from `LARK_PROFILES_JSON`) and the active one |
485
- | `switch_profile` | Hot-swap active profile; cached client instances rebuild against new credentials |
486
- | `manage_profile_hints` | Inspect/set/clear the resourceKey → profile cache used by the v1.3.8 auto-switch middleware |
487
-
488
- ### Multi-profile auto-switch (v1.3.8)
489
-
490
- When `~/.feishu-user-plugin/credentials.json` has more than one profile, the plugin auto-switches between them on **read** paths when the active profile gets a permission-denied error. The winning profile is cached per resource so subsequent calls go straight to the right account.
491
-
492
- **Whitelist** -- only `read_*`, `list_*`, `get_*`, `search_*`, `download_*` (and the read-action variants of `manage_bitable_*`) get auto-retry. Writes never auto-switch -- they fail loud so you don't accidentally create resources under the wrong account.
493
-
494
- **Triggers** -- error codes 91403, 1254301, 1254000, 99991672, HTTP 403, plus message patterns `access_denied / permission_denied / docx_no_permission / no permission / forbidden`.
250
+ ## Multi-account
495
251
 
496
- **Per-call override** -- pass `via_profile: "<name>"` in any tool call to pin to that profile (no auto-switch). Pass `via_profile: "auto"` to opt **into** auto-switch on a write call (escape hatch -- be careful).
252
+ `~/.feishu-user-plugin/credentials.json` supports multiple profiles (default + any number of additional), so one machine handles multiple Feishu accounts / multiple tenants.
497
253
 
498
- **Cache management** -- `manage_profile_hints(action="list" | "set" | "clear", resource_key?, profile?)` lets you inspect or edit the cache.
499
-
500
- Single-profile users (the vast majority): zero behaviour change -- the router short-circuits and `manage_profile_hints` is a no-op.
501
-
502
- ## Claude Code Slash Commands (9 skills)
254
+ ```bash
255
+ npx feishu-user-plugin list-profiles
256
+ npx feishu-user-plugin switch-profile <name>
257
+ npx feishu-user-plugin keepalive --all # cross-profile keepalive
258
+ ```
503
259
 
504
- This plugin includes 9 built-in skills in `skills/feishu-user-plugin/`:
260
+ Read-path tools auto-retry across profiles on errors `91403` / `1254301` / `1254000` / `99991672` / `HTTP 403`. Writes never auto-switch (avoids creating resources under the wrong account). Per-call override: pass `via_profile: "<name>"` to pin to a specific profile.
505
261
 
506
- | Skill | Usage | Description |
507
- |-------|-------|-------------|
508
- | `/send` | `/send Alice: meeting at 3pm` | Send message as yourself |
509
- | `/reply` | `/reply engineering-chat` | Read recent messages and reply |
510
- | `/digest` | `/digest engineering-chat 7` | Summarize recent chat messages |
511
- | `/search` | `/search engineering` | Search contacts and groups |
512
- | `/doc` | `/doc search MCP` | Search, read, or create documents |
513
- | `/table` | `/table query appXxx` | Query or create Bitable records |
514
- | `/wiki` | `/wiki search protocol` | Search and browse wiki |
515
- | `/drive` | `/drive list folderToken` | List files or create folders in Drive |
516
- | `/status` | `/status` | Check login and auth status |
262
+ Details: [docs/TOOLS.md "Multi-profile auto-switch"](docs/TOOLS.md#多-profile-auto-switchv138).
517
263
 
518
- Skills are automatically available when the plugin is installed.
264
+ ## Realtime events
519
265
 
520
- ## Architecture
266
+ A single MCP process per machine holds the WS owner lock. All MCP processes share `events.jsonl`, every event delivered exactly once across the entire machine.
521
267
 
268
+ ```bash
269
+ mcp call manage_ws_status --action info
270
+ mcp call manage_ws_status --action claim --force true
522
271
  ```
523
- Cookie + Proto ┌──────────────────────────────────────┐
524
- ────────────────── >│ internal-api-lark-api.feishu.cn │
525
- ┌──────────────┐ │ /im/gateway/ (Protobuf over HTTP) │
526
- │ MCP Client │ └──────────────────────────────────────┘
527
- │ (Claude, │ App Token (REST) ┌──────────────────────────────────────┐
528
- │ Cursor, │ ────────────────->│ open.feishu.cn/open-apis/ │
529
- │ VS Code) │ │ (Official REST API) │
530
- │ │ └──────────────────────────────────────┘
531
- │ │ User OAuth (REST)┌──────────────────────────────────────┐
532
- │ │ ────────────────->│ open.feishu.cn/open-apis/ │
533
- └──────────────┘ │ (UAT -- P2P chat reading) │
534
- └──────────────────────────────────────┘
535
- ```
536
-
537
- ## Session & Token Lifecycle
538
-
539
- | Auth Layer | Token | Lifetime | Refresh |
540
- |------------|-------|----------|---------|
541
- | Cookie | `sl_session` | 12h max-age | Auto-refreshed every 4h via heartbeat |
542
- | App Token | `tenant_access_token` | 2h | Auto-managed by SDK |
543
- | User OAuth | `user_access_token` | ~2h | Auto-refreshed via `refresh_token`, saved to MCP config |
544
272
 
545
- When the cookie expires (after ~12-24h without heartbeat), re-login at feishu.cn and update `LARK_COOKIE`. Use `get_login_status` to check health proactively.
273
+ Default subscriptions: `["im.message.receive_v1"]`. To subscribe to other events (approval / calendar / vc / etc.), edit `credentials.json::profiles[<active>].events`, then call `manage_ws_status(action=reconfig)` to apply without restart.
546
274
 
547
- If UAT refresh fails with `invalid_grant`, re-run `npx feishu-user-plugin oauth` and restart Claude Code / Codex. v1.3.5+ also re-reads the persisted MCP config before refreshing, so duplicate MCP processes can adopt a token already rotated by another process instead of retrying a stale refresh token.
548
-
549
- ## Project Structure
550
-
551
- ```
552
- feishu-user-plugin/
553
- ├── .claude-plugin/
554
- │ └── plugin.json # Plugin metadata
555
- ├── skills/
556
- │ └── feishu-user-plugin/
557
- │ ├── SKILL.md # Main skill definition (trigger, tools, auth)
558
- │ └── references/ # 8 skill reference docs + CLAUDE.md
559
- ├── src/
560
- │ ├── index.js # MCP server entry point (78 tools)
561
- │ ├── client.js # User identity client (Protobuf gateway)
562
- │ ├── official.js # Official API client (REST, UAT)
563
- │ ├── utils.js # ID generators, cookie parser
564
- │ ├── oauth.js # OAuth flow for user_access_token
565
- │ ├── test-send.js # Quick CLI test
566
- │ └── test-all.js # Full test suite
567
- ├── proto/
568
- │ └── lark.proto # Protobuf message definitions
569
- ├── .mcp.json.example # MCP server config template
570
- ├── server.json # MCP Registry manifest
571
- ├── .env.example # Configuration template
572
- └── package.json
573
- ```
275
+ Only `feishu.cn` is supported Lark international (`lark.com`) WSClient is not available.
574
276
 
575
277
  ## Limitations
576
278
 
577
- - Cookie-based auth requires periodic refresh (auto-heartbeat extends to ~12h; manual re-login needed after that)
578
- - Depends on Feishu's internal Protobuf protocol -- may break if Feishu updates their web client
579
- - Image/file/audio sending requires pre-uploaded keys (upload via Official API or external bridge)
580
- - No real-time message receiving (WebSocket push not yet implemented)
581
- - May violate Feishu's Terms of Service -- use at your own risk
279
+ - **Cookie lifetime**: 12-24 hours without heartbeat; re-login at feishu.cn to get a fresh cookie
280
+ - **Protocol drift**: cookie + protobuf path depends on Feishu web client protocol; Feishu updates may break user-identity messaging (bot capabilities unaffected)
281
+ - **Cards**: cookie path's card sending is server-disabled; bot path works
282
+ - **Lark international**: realtime events WS not supported
283
+ - **Not implemented**: `search_messages`, md wiki sync (see [ROADMAP.md](ROADMAP.md))
284
+
285
+ ## Documentation
286
+
287
+ | Document | Role |
288
+ |----------|------|
289
+ | [docs/TOOLS.md](docs/TOOLS.md) | Tool reference + cross-domain caveats + usage patterns |
290
+ | [docs/AUTH-SETUP.md](docs/AUTH-SETUP.md) | Install / 3 auth layers / cookie capture / OAuth scopes |
291
+ | [docs/TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md) | Error codes & diagnosis |
292
+ | [docs/RELEASING.md](docs/RELEASING.md) | Release flow + team-skills sync + announcement rules |
293
+ | [docs/REFACTOR-NOTES.md](docs/REFACTOR-NOTES.md) | File responsibility matrix |
294
+ | [docs/CREDENTIALS-FORMAT.md](docs/CREDENTIALS-FORMAT.md) | Credentials schema |
295
+ | [docs/TESTING-METHODOLOGY.md](docs/TESTING-METHODOLOGY.md) | Testing playbook |
296
+ | [CONTRIBUTING.md](CONTRIBUTING.md) | Contribution flow (bilingual) |
297
+ | [ROADMAP.md](ROADMAP.md) | Roadmap (forward-only) |
298
+ | [CHANGELOG.md](CHANGELOG.md) | Version history |
299
+
300
+ Full docs/ index: [docs/README.md](docs/README.md).
582
301
 
583
302
  ## Contributing
584
303
 
585
- Issues and PRs welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, code style, and submission guidelines.
586
-
587
- If Feishu updates their protocol and something breaks, please [open an issue](https://github.com/EthanQC/feishu-user-plugin/issues/new?template=bug_report.md) with the error details.
588
-
589
- ### Automated sync hooks
304
+ Issues / PRs welcome. Read [CONTRIBUTING.md](CONTRIBUTING.md) first.
590
305
 
591
- This repo uses husky to enforce several invariants on every commit:
306
+ If a Feishu protocol change breaks a tool open an issue with the error log.
592
307
 
593
- - **CLAUDE.md sync** — staging `CLAUDE.md` automatically regenerates `AGENTS.md` (identical body, different first line) and `skills/feishu-user-plugin/references/CLAUDE.md` (verbatim copy). Both are re-staged in the same commit.
594
- - **Version triangle** — if `package.json`, `.claude-plugin/plugin.json`, or `skills/feishu-user-plugin/SKILL.md` are staged, all three `version` fields must agree or the commit is rejected.
595
- - **Tool-count badge** — if `src/server.js` or any file under `src/tools/` is staged, the `N tools` badge in `README.md` must match the actual `TOOLS.length` exported by `src/server.js`.
596
- - **Smoke test** — any change under `src/` triggers `npm run smoke` to catch schema regressions before commit.
308
+ ## Privacy
597
309
 
598
- CI (`.github/workflows/validate.yml`) runs the same checks on every PR to `main`, so bypassing the local hook still gets caught.
310
+ A locally-run MCP server. Credentials stay on the user's machine; no telemetry, no phone-home. Full text: [PRIVACY.md](PRIVACY.md).
599
311
 
600
- On the maintainer's machine, a post-merge hook (`scripts/sync-team-skills.sh`) auto-opens a sync PR in the `~/team-skills` repo after every merge to main. The hook silently skips if `~/team-skills` is absent.
312
+ - **Collected**: nothing by the plugin itself; the five `LARK_*` envs are supplied by the user from their own Feishu / Lark account
313
+ - **Processed**: only the messages / docs / bitable / wiki / drive / calendar / tasks / OKR / contacts the user explicitly requests via MCP tool calls
314
+ - **Stored**: `~/.feishu-user-plugin/credentials.json` (mode 0600); optional event log at `~/.feishu-user-plugin/events.jsonl`
315
+ - **Third-party**: only the user's own Feishu tenant and the AI client the user runs (Claude Code / Codex / Cursor / etc.)
316
+ - **Retention**: entirely user-controlled; `rm -rf ~/.feishu-user-plugin && npm uninstall -g feishu-user-plugin` removes everything
317
+ - **Contact**: [GitHub Issues](https://github.com/EthanQC/feishu-user-plugin/issues); security disclosures with `[security]` prefix in the title
601
318
 
602
319
  ## License
603
320
 
@@ -605,6 +322,6 @@ On the maintainer's machine, a post-merge hook (`scripts/sync-team-skills.sh`) a
605
322
 
606
323
  ## Acknowledgments
607
324
 
608
- - [cv-cat/LarkAgentX](https://github.com/cv-cat/LarkAgentX) -- Early Feishu web protocol research (Python)
609
- - [cv-cat/OpenFeiShuApis](https://github.com/cv-cat/OpenFeiShuApis) -- Underlying API research
610
- - [Model Context Protocol](https://modelcontextprotocol.io) -- The MCP standard
325
+ - [cv-cat/LarkAgentX](https://github.com/cv-cat/LarkAgentX) early Feishu web protocol research (Python)
326
+ - [cv-cat/OpenFeiShuApis](https://github.com/cv-cat/OpenFeiShuApis) underlying API research
327
+ - [Model Context Protocol](https://modelcontextprotocol.io) MCP spec + Anthropic / PulseMCP / GitHub / Stacklok joint registry