feishu-user-plugin 1.0.0 → 1.0.1
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.
- package/.env.example +3 -3
- package/.mcp.json.example +3 -1
- package/README.md +24 -14
- package/package.json +1 -1
- package/skills/feishu-user-plugin/SKILL.md +2 -1
- package/skills/feishu-user-plugin/references/CLAUDE.md +65 -27
- package/src/index.js +11 -2
package/.env.example
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# === User Identity (reverse-engineered protocol) ===
|
|
2
2
|
# Required for: send_as_user, send_to_user, send_to_group, search_contacts, etc.
|
|
3
|
-
# How to get: Login to feishu.cn → Playwright context.cookies() or DevTools
|
|
3
|
+
# How to get: Login to feishu.cn → Playwright context.cookies() or DevTools Network tab
|
|
4
4
|
LARK_COOKIE=
|
|
5
5
|
|
|
6
6
|
# === Official API (Feishu Open Platform) ===
|
|
@@ -9,9 +9,9 @@ LARK_COOKIE=
|
|
|
9
9
|
LARK_APP_ID=
|
|
10
10
|
LARK_APP_SECRET=
|
|
11
11
|
|
|
12
|
-
# === User OAuth UAT (
|
|
12
|
+
# === User OAuth UAT (required for P2P chat reading) ===
|
|
13
13
|
# Required for: read_p2p_messages, list_user_chats
|
|
14
|
-
# How to get: Run "node src/oauth.js" after configuring App ID/Secret above
|
|
14
|
+
# How to get: Run "node src/oauth.js" after configuring Cookie + App ID/Secret above
|
|
15
15
|
# These are auto-populated by the OAuth flow and auto-refreshed at runtime
|
|
16
16
|
LARK_USER_ACCESS_TOKEN=
|
|
17
17
|
LARK_USER_REFRESH_TOKEN=
|
package/.mcp.json.example
CHANGED
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
"env": {
|
|
7
7
|
"LARK_COOKIE": "YOUR_FEISHU_COOKIE_HERE",
|
|
8
8
|
"LARK_APP_ID": "YOUR_APP_ID_HERE",
|
|
9
|
-
"LARK_APP_SECRET": "YOUR_APP_SECRET_HERE"
|
|
9
|
+
"LARK_APP_SECRET": "YOUR_APP_SECRET_HERE",
|
|
10
|
+
"LARK_USER_ACCESS_TOKEN": "YOUR_UAT_HERE",
|
|
11
|
+
"LARK_USER_REFRESH_TOKEN": "YOUR_REFRESH_TOKEN_HERE"
|
|
10
12
|
}
|
|
11
13
|
}
|
|
12
14
|
}
|
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@ The only MCP server that lets you send messages as your **personal identity** (n
|
|
|
15
15
|
- **Send as yourself** -- Messages show your real name, not a bot. Supports text, rich text, images, files, stickers, and audio.
|
|
16
16
|
- **Read everything** -- Group chats via bot API, P2P (direct messages) via OAuth UAT.
|
|
17
17
|
- **Full Feishu suite** -- Docs, Bitable (spreadsheets), Wiki, Drive, Contacts -- all in one plugin.
|
|
18
|
-
- **3 auth layers** -- Cookie-based user identity, app credentials (Official API), and OAuth UAT (P2P reading).
|
|
18
|
+
- **3 auth layers** -- Cookie-based user identity, app credentials (Official API), and OAuth UAT (P2P reading). All three are needed for full functionality.
|
|
19
19
|
- **8 slash commands** for Claude Code -- `/send`, `/reply`, `/search`, `/digest`, `/doc`, `/table`, `/wiki`, `/status`
|
|
20
20
|
- **Auto session management** -- Cookie heartbeat every 4h, UAT auto-refresh with token rotation.
|
|
21
21
|
- **Chat name resolution** -- Pass a group name instead of `oc_xxx` ID; it resolves automatically.
|
|
@@ -110,11 +110,9 @@ Add your bot to the group chats where you want it to read messages. The bot can
|
|
|
110
110
|
| `LARK_APP_ID` | Official API tools | App ID from Feishu Open Platform. Needed for `read_messages`, docs, tables, wiki, drive. |
|
|
111
111
|
| `LARK_APP_SECRET` | Official API tools | App Secret from Feishu Open Platform. Used together with `LARK_APP_ID`. |
|
|
112
112
|
| `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`. |
|
|
113
|
+
| `LARK_USER_REFRESH_TOKEN` | UAT auto-refresh | Refresh token for automatic UAT renewal. Obtained together with UAT via OAuth flow. |
|
|
113
114
|
|
|
114
|
-
|
|
115
|
-
- **Cookie only** -- for sending messages as yourself
|
|
116
|
-
- **App credentials only** -- for reading docs, tables, wiki, group chats
|
|
117
|
-
- **All three** -- for the full feature set
|
|
115
|
+
All five variables are required for full functionality. Configure all of them during setup.
|
|
118
116
|
|
|
119
117
|
## How to Get Your Cookie
|
|
120
118
|
|
|
@@ -147,9 +145,9 @@ Claude Code will automatically:
|
|
|
147
145
|
|
|
148
146
|
> The server automatically refreshes the session via heartbeat every 4 hours. The `sl_session` cookie has a 12-hour max-age.
|
|
149
147
|
|
|
150
|
-
##
|
|
148
|
+
## Set Up OAuth (Required for P2P Chat Reading)
|
|
151
149
|
|
|
152
|
-
To
|
|
150
|
+
To enable `read_p2p_messages` and `list_user_chats`:
|
|
153
151
|
|
|
154
152
|
1. Your Feishu app must be a **Custom App** (自建应用), NOT marketplace/third-party
|
|
155
153
|
2. Add scopes: `im:message`, `im:message:readonly`, `im:chat:readonly`
|
|
@@ -166,7 +164,7 @@ cd $(npm root -g)/feishu-user-plugin && node src/oauth.js
|
|
|
166
164
|
# Or clone the repo just for the OAuth step, then use npx for daily use
|
|
167
165
|
```
|
|
168
166
|
|
|
169
|
-
A browser window will open for OAuth consent. The token is saved to `.env` automatically and auto-refreshes at runtime. Add
|
|
167
|
+
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.
|
|
170
168
|
|
|
171
169
|
## MCP Client Configuration
|
|
172
170
|
|
|
@@ -185,7 +183,9 @@ Add to your project's `.mcp.json` (or `~/.claude/.mcp.json` for global):
|
|
|
185
183
|
"env": {
|
|
186
184
|
"LARK_COOKIE": "your-cookie-string",
|
|
187
185
|
"LARK_APP_ID": "cli_xxxxxxxxxxxx",
|
|
188
|
-
"LARK_APP_SECRET": "your-app-secret"
|
|
186
|
+
"LARK_APP_SECRET": "your-app-secret",
|
|
187
|
+
"LARK_USER_ACCESS_TOKEN": "your-uat",
|
|
188
|
+
"LARK_USER_REFRESH_TOKEN": "your-refresh-token"
|
|
189
189
|
}
|
|
190
190
|
}
|
|
191
191
|
}
|
|
@@ -203,7 +203,9 @@ Add to your project's `.mcp.json` (or `~/.claude/.mcp.json` for global):
|
|
|
203
203
|
"env": {
|
|
204
204
|
"LARK_COOKIE": "your-cookie-string",
|
|
205
205
|
"LARK_APP_ID": "cli_xxxxxxxxxxxx",
|
|
206
|
-
"LARK_APP_SECRET": "your-app-secret"
|
|
206
|
+
"LARK_APP_SECRET": "your-app-secret",
|
|
207
|
+
"LARK_USER_ACCESS_TOKEN": "your-uat",
|
|
208
|
+
"LARK_USER_REFRESH_TOKEN": "your-refresh-token"
|
|
207
209
|
}
|
|
208
210
|
}
|
|
209
211
|
}
|
|
@@ -228,7 +230,9 @@ Add to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS)
|
|
|
228
230
|
"env": {
|
|
229
231
|
"LARK_COOKIE": "your-cookie-string",
|
|
230
232
|
"LARK_APP_ID": "cli_xxxxxxxxxxxx",
|
|
231
|
-
"LARK_APP_SECRET": "your-app-secret"
|
|
233
|
+
"LARK_APP_SECRET": "your-app-secret",
|
|
234
|
+
"LARK_USER_ACCESS_TOKEN": "your-uat",
|
|
235
|
+
"LARK_USER_REFRESH_TOKEN": "your-refresh-token"
|
|
232
236
|
}
|
|
233
237
|
}
|
|
234
238
|
}
|
|
@@ -248,7 +252,9 @@ Add to `.cursor/mcp.json` in your project:
|
|
|
248
252
|
"env": {
|
|
249
253
|
"LARK_COOKIE": "your-cookie-string",
|
|
250
254
|
"LARK_APP_ID": "cli_xxxxxxxxxxxx",
|
|
251
|
-
"LARK_APP_SECRET": "your-app-secret"
|
|
255
|
+
"LARK_APP_SECRET": "your-app-secret",
|
|
256
|
+
"LARK_USER_ACCESS_TOKEN": "your-uat",
|
|
257
|
+
"LARK_USER_REFRESH_TOKEN": "your-refresh-token"
|
|
252
258
|
}
|
|
253
259
|
}
|
|
254
260
|
}
|
|
@@ -269,7 +275,9 @@ Add to `.vscode/mcp.json` in your project:
|
|
|
269
275
|
"env": {
|
|
270
276
|
"LARK_COOKIE": "your-cookie-string",
|
|
271
277
|
"LARK_APP_ID": "cli_xxxxxxxxxxxx",
|
|
272
|
-
"LARK_APP_SECRET": "your-app-secret"
|
|
278
|
+
"LARK_APP_SECRET": "your-app-secret",
|
|
279
|
+
"LARK_USER_ACCESS_TOKEN": "your-uat",
|
|
280
|
+
"LARK_USER_REFRESH_TOKEN": "your-refresh-token"
|
|
273
281
|
}
|
|
274
282
|
}
|
|
275
283
|
}
|
|
@@ -289,7 +297,9 @@ Add to `~/.codeium/windsurf/mcp_config.json`:
|
|
|
289
297
|
"env": {
|
|
290
298
|
"LARK_COOKIE": "your-cookie-string",
|
|
291
299
|
"LARK_APP_ID": "cli_xxxxxxxxxxxx",
|
|
292
|
-
"LARK_APP_SECRET": "your-app-secret"
|
|
300
|
+
"LARK_APP_SECRET": "your-app-secret",
|
|
301
|
+
"LARK_USER_ACCESS_TOKEN": "your-uat",
|
|
302
|
+
"LARK_USER_REFRESH_TOKEN": "your-refresh-token"
|
|
293
303
|
}
|
|
294
304
|
}
|
|
295
305
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "feishu-user-plugin",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "All-in-one Feishu plugin for Claude Code — send messages as yourself, read chats, manage docs/tables/wiki. 33 tools + 8 skills, 3 auth layers.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -61,7 +61,8 @@ Check cookie / app credentials / UAT — all three auth layers at once.
|
|
|
61
61
|
| LARK_COOKIE | **You** | Send messages as yourself | Yes (for messaging) |
|
|
62
62
|
| LARK_APP_ID | **You** (create a Feishu app) | Official API access | Yes |
|
|
63
63
|
| LARK_APP_SECRET | **You** (from your Feishu app) | Official API access | Yes |
|
|
64
|
-
| LARK_USER_ACCESS_TOKEN | **You** (OAuth flow
|
|
64
|
+
| LARK_USER_ACCESS_TOKEN | **You** (OAuth flow) | Read P2P chat history | Yes (for P2P reading) |
|
|
65
|
+
| LARK_USER_REFRESH_TOKEN | **You** (OAuth flow) | UAT auto-refresh | Yes (for P2P reading) |
|
|
65
66
|
|
|
66
67
|
### Getting Your Cookie (Automated via Playwright)
|
|
67
68
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
All-in-one Feishu plugin for Claude Code with three auth layers:
|
|
5
5
|
- **User Identity** (cookie auth): Send messages (text, image, file, post, sticker, audio) as yourself
|
|
6
6
|
- **Official API** (app credentials): Read group messages, docs, tables, wiki, drive, contacts
|
|
7
|
-
- **User OAuth UAT** (user_access_token): Read P2P chat history
|
|
7
|
+
- **User OAuth UAT** (user_access_token): Read P2P chat history, list all user's chats
|
|
8
8
|
|
|
9
9
|
## Tool Categories
|
|
10
10
|
|
|
@@ -26,7 +26,7 @@ All-in-one Feishu plugin for Claude Code with three auth layers:
|
|
|
26
26
|
- `get_login_status` — Check cookie, app, and UAT status
|
|
27
27
|
|
|
28
28
|
### User OAuth UAT Tools (P2P chat reading)
|
|
29
|
-
- `read_p2p_messages` — Read P2P (direct message) chat history.
|
|
29
|
+
- `read_p2p_messages` — Read P2P (direct message) chat history. chat_id accepts both numeric IDs (from create_p2p_chat) and oc_xxx format.
|
|
30
30
|
- `list_user_chats` — List group chats the user is in. Note: API only returns groups, not P2P. For P2P, use: `search_contacts` → `create_p2p_chat` → `read_p2p_messages`.
|
|
31
31
|
|
|
32
32
|
### Official API Tools (app credentials)
|
|
@@ -43,7 +43,7 @@ All-in-one Feishu plugin for Claude Code with three auth layers:
|
|
|
43
43
|
- Send text as yourself → `send_to_user` or `send_to_group`
|
|
44
44
|
- Send rich content → `send_post_as_user` (formatted text), `send_image_as_user` (images)
|
|
45
45
|
- Read group chat history → `read_messages` with chat name or oc_ ID
|
|
46
|
-
- Read P2P chat history → `search_contacts` → `create_p2p_chat` → `read_p2p_messages`
|
|
46
|
+
- Read P2P chat history → `search_contacts` → `create_p2p_chat` → `read_p2p_messages`
|
|
47
47
|
- Reply as user in thread → `send_as_user` with root_id
|
|
48
48
|
- Reply as bot → `reply_message` (official API, text messages only)
|
|
49
49
|
- Diagnose issues → `get_login_status` first
|
|
@@ -51,44 +51,82 @@ All-in-one Feishu plugin for Claude Code with three auth layers:
|
|
|
51
51
|
## Auth & Session
|
|
52
52
|
- **LARK_COOKIE**: Required for user identity tools. Session auto-refreshed every 4h via heartbeat.
|
|
53
53
|
- **LARK_APP_ID + LARK_APP_SECRET**: Required for official API tools.
|
|
54
|
-
- **LARK_USER_ACCESS_TOKEN**: Required for P2P reading.
|
|
54
|
+
- **LARK_USER_ACCESS_TOKEN + LARK_USER_REFRESH_TOKEN**: Required for P2P reading. Auto-refreshed via refresh_token.
|
|
55
55
|
|
|
56
56
|
## Automated Cookie Setup via Playwright
|
|
57
57
|
|
|
58
|
-
When LARK_COOKIE is missing or expired,
|
|
59
|
-
Do NOT ask the user to manually copy cookies from DevTools.
|
|
58
|
+
When LARK_COOKIE is missing or expired, obtain it using Playwright MCP.
|
|
60
59
|
|
|
61
60
|
### Prerequisites
|
|
62
|
-
Playwright MCP must be available. If not
|
|
61
|
+
Playwright MCP must be available. If not:
|
|
63
62
|
> Run: `npx @anthropic-ai/claude-code mcp add playwright -- npx @anthropic-ai/mcp-server-playwright`
|
|
64
63
|
> Then restart Claude Code.
|
|
65
64
|
|
|
66
|
-
### Automated Flow
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
65
|
+
### Automated Flow — FOLLOW EXACTLY
|
|
66
|
+
|
|
67
|
+
**Step 1: Clear cookies first** (Playwright uses persistent browser profile that may have a DIFFERENT account cached):
|
|
68
|
+
```
|
|
69
|
+
browser_run_code: await context.clearCookies();
|
|
70
|
+
browser_navigate: https://www.feishu.cn/messenger/
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**Step 2: Show QR code and wait for login**:
|
|
74
|
+
```
|
|
75
|
+
browser_take_screenshot
|
|
76
|
+
```
|
|
77
|
+
Poll `browser_snapshot` every 5s until URL changes from `/accounts/`.
|
|
78
|
+
|
|
79
|
+
**Step 3: Extract cookie — TWO-STEP approach** (NEVER use browser_run_code output directly as cookie):
|
|
80
|
+
|
|
81
|
+
Step 3a via `browser_run_code`:
|
|
82
|
+
```js
|
|
83
|
+
const cookies = await page.context().cookies('https://www.feishu.cn');
|
|
84
|
+
const str = cookies.map(c => c.name + '=' + c.value).join('; ');
|
|
85
|
+
await page.evaluate(s => { window.__COOKIE__ = s; }, str);
|
|
86
|
+
return 'Stored ' + cookies.length + ' cookies, length=' + str.length;
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Step 3b via `browser_evaluate`:
|
|
90
|
+
```js
|
|
91
|
+
window.__COOKIE__
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
**Step 4: Validate** — Must be pure ASCII, contain `session=` and `sl_session=`, length 500-5000. If >10000, it's contaminated.
|
|
95
|
+
|
|
96
|
+
**Step 5: Write config** using exact format (NO `"type": "stdio"`):
|
|
97
|
+
```json
|
|
98
|
+
{
|
|
99
|
+
"feishu-user-plugin": {
|
|
100
|
+
"command": "npx",
|
|
101
|
+
"args": ["-y", "feishu-user-plugin"],
|
|
102
|
+
"env": {
|
|
103
|
+
"LARK_COOKIE": "<cookie>",
|
|
104
|
+
"LARK_APP_ID": "<id>",
|
|
105
|
+
"LARK_APP_SECRET": "<secret>",
|
|
106
|
+
"LARK_USER_ACCESS_TOKEN": "<uat>",
|
|
107
|
+
"LARK_USER_REFRESH_TOKEN": "<refresh>"
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
81
112
|
|
|
82
113
|
## Troubleshooting
|
|
83
114
|
|
|
84
115
|
### If cookie authentication fails
|
|
85
|
-
- **Best method**: Playwright
|
|
86
|
-
- **Manual fallback**: Network tab →
|
|
116
|
+
- **Best method**: Playwright two-step extraction (see above)
|
|
117
|
+
- **Manual fallback**: Network tab → first request → Request Headers → Cookie → Copy value
|
|
87
118
|
- Do NOT use `document.cookie` or Application → Cookies (misses HttpOnly cookies)
|
|
88
119
|
|
|
120
|
+
### If Playwright logs into the wrong account
|
|
121
|
+
- Always `context.clearCookies()` BEFORE navigating to feishu.cn
|
|
122
|
+
- Verify account by checking URL domain after login
|
|
123
|
+
|
|
124
|
+
### If UAT refresh fails with "invalid_grant" (error 28003/20003/20005)
|
|
125
|
+
- Refresh token expired — re-run `node src/oauth.js` (needs LARK_APP_ID + LARK_APP_SECRET in `.env`)
|
|
126
|
+
- Copy new UAT + refresh token from `.env` to MCP config, then restart Claude Code
|
|
127
|
+
|
|
89
128
|
### If list_user_chats doesn't return P2P chats
|
|
90
|
-
-
|
|
91
|
-
- Use the P2P flow: `search_contacts` → `create_p2p_chat` → `read_p2p_messages`.
|
|
129
|
+
- Expected — API only returns groups. Use: `search_contacts` → `create_p2p_chat` → `read_p2p_messages`.
|
|
92
130
|
|
|
93
131
|
### If reply_message fails with error 230054
|
|
94
|
-
-
|
|
132
|
+
- Only text messages can be replied to via this API.
|
package/src/index.js
CHANGED
|
@@ -255,7 +255,7 @@ const TOOLS = [
|
|
|
255
255
|
inputSchema: {
|
|
256
256
|
type: 'object',
|
|
257
257
|
properties: {
|
|
258
|
-
chat_id: { type: 'string', description: 'Chat ID (oc_xxx
|
|
258
|
+
chat_id: { type: 'string', description: 'Chat ID (numeric from create_p2p_chat, or oc_xxx from list_user_chats). Both formats work.' },
|
|
259
259
|
page_size: { type: 'number', description: 'Messages to fetch (default 20, max 50)' },
|
|
260
260
|
start_time: { type: 'string', description: 'Start timestamp in seconds (optional)' },
|
|
261
261
|
end_time: { type: 'string', description: 'End timestamp in seconds (optional)' },
|
|
@@ -691,7 +691,16 @@ async function handleTool(name, args) {
|
|
|
691
691
|
async function main() {
|
|
692
692
|
const transport = new StdioServerTransport();
|
|
693
693
|
await server.connect(transport);
|
|
694
|
-
|
|
694
|
+
|
|
695
|
+
// Startup diagnostics
|
|
696
|
+
const hasCookie = !!process.env.LARK_COOKIE;
|
|
697
|
+
const hasApp = !!(process.env.LARK_APP_ID && process.env.LARK_APP_SECRET);
|
|
698
|
+
const hasUAT = !!process.env.LARK_USER_ACCESS_TOKEN;
|
|
699
|
+
console.error(`[feishu-user-plugin] MCP Server v1.0.1 — ${TOOLS.length} tools`);
|
|
700
|
+
console.error(`[feishu-user-plugin] Auth: Cookie=${hasCookie ? 'YES' : 'NO'} App=${hasApp ? 'YES' : 'NO'} UAT=${hasUAT ? 'YES' : 'NO'}`);
|
|
701
|
+
if (!hasCookie) console.error('[feishu-user-plugin] WARNING: LARK_COOKIE not set — user identity tools (send_to_user, etc.) will fail');
|
|
702
|
+
if (!hasApp) console.error('[feishu-user-plugin] WARNING: LARK_APP_ID/SECRET not set — official API tools (read_messages, docs, etc.) will fail');
|
|
703
|
+
if (!hasUAT) console.error('[feishu-user-plugin] WARNING: LARK_USER_ACCESS_TOKEN not set — P2P chat reading (read_p2p_messages) will fail');
|
|
695
704
|
}
|
|
696
705
|
|
|
697
706
|
main().catch(console.error);
|