feishu-bridge
MCP server that enables AI agents to interact with Feishu (Lark) for calendar events, attendees, and user recent work via structured tools with graceful degradation and recovery hints.
README
Feishu Bridge
A PoC exploring how collaboration tools should be redesigned for the AI Agent era.

One core. Two surfaces (CLI + MCP). Real Feishu data, real meeting brief — in 30 seconds.
What is this
A small TypeScript library that lets AI tools (Claude Desktop, Cursor, Claude Code...) use Feishu in a natural way.
Same business core, two surfaces:
- CLI form —
feishu-bridge ..., callable from any AI that can spawn a shell - MCP form — exposes the same capabilities as MCP tools
Both share the same AI Friendly design philosophy.
Why two forms
I was using Claude Code and noticed something: even when GitHub MCP exists, Claude often falls back to invoking gh CLI for GitHub tasks. CLI was already installed, already authenticated, zero config.
That reframed my mental model of AI Friendly:
AI Friendly is not about which protocol you pick. It's about whether AI can use your product smoothly — through whatever surface is available.
So this PoC implements the same capabilities twice — as a CLI and as an MCP server — to prove the underlying design philosophy is what matters, not the protocol.
The full demo narrative
The user types into Claude Desktop:
"Help me prepare for this week's team meeting."
Behind the scenes:
Step 1 — feishu_search_events(query="周会")
Claude calls the search-events tool. The bot's tenant_access_token can only see the bot's own primary calendar (empty) — but search-events gracefully degrades: it queries /calendar/v4/freebusy/list for the user's busy windows (which tenant_access_token CAN read), and returns a composite payload:
{
"events": [], // bot doesn't have detail access
"busy_windows": [ // …but it can see WHEN the user is busy
{ "human_label": "周三 14:00-14:30", "duration_minutes": 30, ... },
{ "human_label": "周四 15:00-16:00", "duration_minutes": 60, ... },
{ "human_label": "周五 16:00-17:00", "duration_minutes": 60, ... }
],
"source_diagnostics": {
"root_cause": "app_identity_vs_user_identity: bot is authenticated as
application identity ou_6687… and sees only its OWN primary calendar
via tenant_access_token. The user has 10 busy windows visible via
/freebusy/list, but Feishu's freebusy protocol intentionally omits
summaries. Detailed event read requires either (a) the bot is added
as an attendee, (b) the user shares the calendar via ACL, or (c) the
app uses user_access_token (OAuth) instead."
},
"recovery_hints": [
{ "id": "use_busy_windows", "actor": "mcp-caller", ... },
{ "id": "switch_to_user_access_token", "actor": "app-developer", ... }
]
}
Claude reads the description contract ("don't fabricate titles when only busy_windows are present") and responds:
"I see you're busy 周三 14:00-14:30 and 周四 15:00-16:00. Which one did you mean?"
Step 2 — feishu_user_recent_work(user_id="ou_3de3...")
Once the user confirms, Claude calls the recent-work aggregator. One composite call pulls all 5 project-tracker rows from a real Bitable, normalizes the schema (Feishu Bitable encodes person fields as arrays of {name, email}, dates as ms timestamps, etc.), and returns:
{
"user": { "open_id": "ou_3de3…", "name": "胡奕舟" },
"bitable_updates": [
{ "title": "权限模块设计", "status": "进行中", "updated_at_human": "2026-05-23", ... },
{ "title": "登录组件重构", "status": "已完成", "updated_at_human": "2026-05-22", ... },
{ "title": "移动端适配", "status": "进行中", "updated_at_human": "2026-05-20", ... },
{ "title": "监控大盘搭建", "status": "阻塞", "updated_at_human": "2026-05-18", ... },
{ "title": "文档同步工具", "status": "已完成", "updated_at_human": "2026-05-15", ... }
],
"source_diagnostics": { "docx": "Skipped: drive scope not yet granted — see OBSERVATIONS.md" }
}
Step 3 — Claude composes the brief
Claude reads the JSON and writes:
# 前端团队周会 预读
## 本周完成 (2)
- ✅ 登录组件重构 (2026-05-22) — OAuth 2.1 改造,接入 Device Flow
- ✅ 文档同步工具 (2026-05-15) — 已上线 v1.0,日均同步 2000+ 文档
## 本周进行中 (2)
- 🔄 权限模块设计 (2026-05-23) — RBAC 方案评审中,本周完成 PRD
- 🔄 移动端适配 (2026-05-20) — iOS/Android/H5 三端兼容验证
## 风险项 (1)
- 🚧 监控大盘搭建 【阻塞】(2026-05-18) — 等运维资源
A task that takes a human ~1 hour. AI does it in ~10 seconds.
See examples-meeting-brief.md for the actual generated output.
Five AI Friendly principles this PoC embodies
- Tool descriptions are written for the LLM, not for human developers — see how
feishu_search_events's description explicitly says "DO NOT invent event titles — say 'the user has a 30-min block at 周三 14:00'" (src/mcp/server.ts) - Errors carry structured recovery hints (
error_code,recovery_hint,is_retryable, plus actor-taggedrecovery_hints[]) so the LLM can self-correct or surface the dev-side fix - Composite operations over fine-grained APIs —
feishu_user_recent_workis one call that internally fans out across Bitable / (future) Docx / IM - Tools collaborate — each description explicitly names the next tool to chain into (
search_events → get_attendees → user_recent_work) - Graceful degradation with self-explanation — when the bot lacks visibility,
source_diagnosticsandrecovery_hintstell the LLM exactly why and what to try next, instead of returningevents: []
Repository layout
src/
core/
client.ts # Feishu API client (token cache + freebusy + calendar + bitable)
load-env.ts # zero-dep .env loader (auto-loaded by CLI and MCP)
types.ts
tools/ # the 3 capability functions, single source of truth
search-events.ts # composite: bot events + user freebusy + diagnostics
user-recent-work.ts# composite: bitable rows + (future) docx
get-attendees.ts # event attendees enriched with user profile
cli/index.ts # CLI surface (commander)
mcp/server.ts # MCP surface (@modelcontextprotocol/sdk)
assets/
demo.gif # the 30-second demo GIF
demo.tape # vhs source — `vhs assets/demo.tape` to re-record
Quick start
# 1. install
npm install
# 2. configure (one-time) — auto-loaded by both CLI and MCP
cp .env.example .env
# Fill in:
# FEISHU_APP_ID
# FEISHU_APP_SECRET
# FEISHU_PROJECT_BITABLE_APP_TOKEN (required for user-recent-work)
# FEISHU_PROJECT_BITABLE_TABLE_ID
# FEISHU_USER_OPEN_ID (optional — fallback for search-events)
# 3. build
npm run build
# 4. smoke test
node dist/cli/index.js ping
# => {"ok":true,"message":"feishu-bridge CLI is alive","version":"0.2.0"}
# 5. real query — composite call returns 5 bitable rows
node dist/cli/index.js user-recent-work --user-id ou_xxxxxxxxxxxxxxxx --days 14
# 6. search-events with freebusy fallback — see source_diagnostics
node dist/cli/index.js search-events --query 周会 --user-id ou_xxxxxxxxxxxxxxxx
Wire up to Claude Desktop (MCP)
Add to ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"feishu-bridge": {
"command": "node",
"args": ["/absolute/path/to/feishu-bridge-poc/dist/mcp/server.js"],
"env": {
"FEISHU_APP_ID": "cli_xxxxxxxxxxxxxxxx",
"FEISHU_APP_SECRET": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"FEISHU_PROJECT_BITABLE_APP_TOKEN": "xxxxxxxxxxxxxxxxxx",
"FEISHU_PROJECT_BITABLE_TABLE_ID": "tblxxxxxxxxxxxxxxx"
}
}
}
}
Restart Claude Desktop. You should see feishu_search_events, feishu_get_attendees, feishu_user_recent_work, and feishu_ping available.
Status (v0.2.0)
| Surface | What works today |
|---|---|
| Core | token cache · 7 verified endpoints · zero-dep .env loader |
| CLI | ping · whoami · search-events · get-attendees · user-recent-work |
| MCP | tools/list · all 4 tools callable · structured error envelope with recovery_hint |
| End-to-end | Bitable: ✅ 5 real records · Calendar: ✅ 10 real freebusy windows via fallback |
What this PoC is intentionally not
See ROADMAP.md → "Explicitly out of scope". Notably: docx writeback, full Feishu API surface coverage, OAuth/user_access_token (would unlock event titles — captured as a recovery_hint).
Companion docs
DESIGN_PHILOSOPHY.md— the five principles, expandedGAPS.md— 7 concrete OpenAPI-level gaps observed while building this PoC (with workarounds and production fixes)OBSERVATIONS.md— ecosystem-level notes on the Feishu AI Friendly landscape (lark-cli / lark-openapi-mcp / peer MCP servers / MCP spec)ROADMAP.md— stages, exit criteria, out-of-scope list
License
MIT
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。