feishu-bridge

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.

Category
Visit Server

README

Feishu Bridge

A PoC exploring how collaboration tools should be redesigned for the AI Agent era.

demo

One core. Two surfaces (CLI + MCP). Real Feishu data, real meeting brief — in 30 seconds.

status license

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 formfeishu-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

  1. 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)
  2. Errors carry structured recovery hints (error_code, recovery_hint, is_retryable, plus actor-tagged recovery_hints[]) so the LLM can self-correct or surface the dev-side fix
  3. Composite operations over fine-grained APIsfeishu_user_recent_work is one call that internally fans out across Bitable / (future) Docx / IM
  4. Tools collaborate — each description explicitly names the next tool to chain into (search_events → get_attendees → user_recent_work)
  5. Graceful degradation with self-explanation — when the bot lacks visibility, source_diagnostics and recovery_hints tell the LLM exactly why and what to try next, instead of returning events: []

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, expanded
  • GAPS.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

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured