DSH Plugins Marketplace

DSH Plugins

Plugins

/

Terminal & Clients

/

dsh-feishu

d

dsh-feishu

Manifest valid

Deep Feishu / Lark integration for DeepSeek Harness: create Bitable apps, docs, sheets, wiki nodes, uploads and messages in the user's own cloud workspace, plus a user OAuth flow.

UI (client)hasBundlePatch

dsh-feishu

English | 中文

Deep Feishu / Lark integration for DeepSeek Harness.

It gives the agent eight tools that act on a real Feishu tenant (and a browser panel that shows what it did and fixes authorization in one click):

ToolWhat it does
feishu_bitableCreate Bitable (多维表格) apps with their tables and fields in one call; list tables and fields; insert, search, update, and delete records in batches
feishu_dashboardCreate dashboards and chart blocks inside a Bitable (柱状图 / 折线图 / 饼图 / 排行榜 / 指标卡 / NPS … 15 types), position them, and read a chart's computed numbers
feishu_queryRun a grouped, aggregated query over a table (group by, sum / avg / min / max / count / distinct_count, filter, sort, top-N) with the aggregation done server-side
feishu_docCreate documents; append Markdown (converted to native blocks), append raw blocks, read plain text, or import a local Markdown/Word/Excel/PowerPoint/PDF file as a new cloud document
feishu_sheetCreate spreadsheets; add sheets; read, write, and append ranges
feishu_driveBrowse folders, create folders, upload and download files, move, delete, read metadata
feishu_wikiList wiki spaces and nodes, resolve a wiki token to its document, create and move nodes
feishu_messageSend text, interactive cards, rich posts, files, and images; reply in a thread; post through a custom-bot webhook
feishu_authDiagnose authorization, produce the authorization URL, complete a manual code exchange, refresh, and log out
feishu_apiCall any documented Feishu open-platform path, with the same auth, retry, and error mapping

New content lands in the user's own cloud drive because the tools act as the authorized user, not as the app. When no user grant is stored they fall back to the app identity and say so in a warning rather than silently filing documents into a space the user cannot see.


Quick start

1. Create a Feishu app

  1. Open the Feishu Open Platform (or Lark) and create a custom app.

  2. Under 凭证与基础信息, note the App ID and App Secret.

  3. Under 安全设置 → 重定向 URL, add the callback this plugin serves:

    http://127.0.0.1:19387/api/feishu/oauth/callback
    

    The port is whatever DeepSeek Harness serves on (the plugin reads it from the host and reports the exact URI in feishu_auth action status).

  4. Under 权限管理, add the scopes below, then publish a version — scopes only apply after the version is released:

    ScopeNeeded for
    offline_accessRequired — without it Feishu returns no refresh token and the user must re-authorize every couple of hours
    bitable:appBitable
    docx:documentDocuments
    drive:driveDrive, imports, uploads
    sheets:spreadsheetSpreadsheets
    wiki:wikiWiki
    im:message, im:resourceMessages and file/image sending
    contact:user.base:readonlyReading the authorized user's name

2. Enable the plugin

See Install below, then restart DeepSeek Harness.

3. Configure it in the GUI

Open 设置 → 飞书 / Feishu. Everything is editable there — no YAML by hand:

  • 应用凭据 — the App ID, the App Secret (write-only), the credential reference name, and the brand (飞书 / Lark).
  • 默认落点与身份 — the folder new content lands in, and which identity the tools use by default.
  • 功能开关 — whether the tools register, whether the HTTP routes mount, whether the floating panel shows, and the tool-name prefix.
  • 授权 — the scopes to request and the redirect URL to register.
  • 高级 — endpoint overrides and the page-size caps.

Saving writes only this plugin's entry in the profile's cordis.patch.yml, which the harness hot-reloads, so most changes apply without a restart. The App Secret is never written to that file: it goes straight into the credential store under the reference name, and the page only ever shows whether it is set.

4. Authorize

Press 授权飞书 on the settings page, or ask the agent to run feishu_auth with action authorize_url. The browser lands on the callback, the grant is stored, and every later call acts as that user. The same form shows the redirect URL to register on the Feishu app and lists the scopes to grant.

Host without a reachable browser callback (a remote or headless session)? Open the URL anywhere, then pass the code query parameter to feishu_auth with action complete.


Install

Two ways, and they are alternatives — do not do both. Each creates a loader entry with id feishu, and the loader rejects a composition that defines one id twice with duplicate loader entry id.

As a bundle (recommended)

The package declares a dsh.bundle patch, so a bundle-aware CLI installs and mounts it in one step:

dsh plugin add github:2048lr/dsh-feishu

That appends dsh-feishu to dsh.profile.bundles and profile boot merges cordis.patch.yml, which inserts the plugin row. Nothing else needs editing.

The settings page is aware of this: when the profile mounts the bundle, it writes an id-targeted config override rather than a second insert, so saving from the GUI never breaks the composition.

By hand (no CLI)

The plugin must be resolvable from the profile's node_modules, so it is copied there:

# from the repository root
pwsh -File scripts/install.ps1

The script copies the package into the profile's node_modules and inserts the entry into cordis.patch.yml:

- insert:
    - id: feishu
      name: dsh-feishu
      config:
        appId: cli_xxxxxxxxxxxx
        # appSecretRef: FEISHU_APP_SECRET
        # brand: feishu          # or lark
        # defaultFolderToken: fldcnxxxxxxxx

Restart DeepSeek Harness. The host half is a Node module cached in-process, so a reload alone does not pick it up. The browser half reloads with the page.

After that first restart, use 设置 → 飞书 / Feishu instead of editing the YAML: the page rewrites the block the installer added and the harness hot-reloads it.

Why the package avoids @deepseek-ai/* imports

A third-party plugin is loaded from a junction or a copied directory inside the profile, where a bare @deepseek-ai/dsh-tools specifier resolves to whichever DSH installation is reachable — which may not be the running host. The host half therefore imports only Node builtins and hand-writes its tool definitions and its configuration validation. The test suite checks every generated schema against the real SDK validator, so the hand-written form cannot drift from what the registry accepts.


Configuration

All fields are optional except appId.

FieldDefaultMeaning
appId—The Feishu app id. Required.
appSecretRefFEISHU_APP_SECRETCredential reference resolved through the harness credential store, then the environment.
appSecret''Literal fallback. Discouraged: it puts a secret in configuration.
brandfeishufeishu (open.feishu.cn) or lark (open.larksuite.com).
apiBaseUrl / accountsBaseUrlper brandOverride the endpoints (for a proxy or a private gateway).
defaultFolderToken''Where new documents, sheets, Bitable apps, and uploads go when a call omits a folder.
defaultIdentityautoauto, user, or app. auto uses the user when authorized and otherwise the app, reporting the fallback.
toolPrefixfeishu_Rename the tools (for example fs_).
requestTimeoutMs30000Per-attempt timeout.
maxRetries2Total attempts for rate-limited or transient failures (capped at 6).
enableToolstrueRegister the model-facing tools.
enableOAuthtrueMount the /api/feishu/* routes (status, activity, config, OAuth).
enableUitrueShow the floating panel.
oauthRedirectUriautoOverride the callback. Empty means "use the host webserver's loopback address".
oauthScopesrecommended setScopes requested by the authorization flow.
registerSystemPrompttrueAppend the Feishu guidance section to the system prompt.
activityLogSize50Entries retained for the browser panel.
maxRecordsPerPage500Page-size cap for paginated Feishu reads.
patchFilePathautoThe profile patch file the settings page edits. Not writable from the browser.
userAccessToken''Static user token for headless use; skips OAuth entirely.

Environment fallbacks: FEISHU_APP_ID, FEISHU_APP_SECRET, FEISHU_BRAND, FEISHU_FOLDER_TOKEN, FEISHU_USER_ACCESS_TOKEN.


The two Bitable API generations

The plugin uses both, deliberately:

  • V1 (/bitable/v1/apps/...) for apps, tables, fields, and records. It is the documented public API, and it is what the official Lark/Feishu SDK ships.
  • V3 (/base/v3/bases/...) for the two capabilities V1 does not have at all: dashboards with charts, and server-side aggregation. Note the resource is bases, not apps — the V1 and V3 paths are not interchangeable, and asking the wrong one answers a plain-text 404 page not found, not a business error.

V3 is newer than the published SDK, so it is not discoverable from the SDK's typings; the shapes here were taken from the official Lark CLI and verified against the live API.

V1V3
Field typesnumbers (1 = text)strings ("text")
Recordsrow objects {record_id, fields}columnar data matrix + field_id_list
Batch writes{records: [{fields}]}record_id_list / by_filter + patch
AggregationnonePOST .../data/query, a DSL naming tables and fields
Chartsnonedashboards + dashboards/{id}/blocks

A chart block is described by one data_config object, which names a table and its fields rather than addressing them by id:

{
  "table_name": "订单表",
  "series": [{ "field_name": "金额", "rollup": "SUM" }],
  "group_by": [{ "field_name": "类别", "mode": "integrated", "sort": { "type": "value", "order": "desc" } }],
  "filter": { "conjunction": "and", "conditions": [{ "field_name": "状态", "operator": "is", "value": "已完成" }] }
}

Use count_all: true instead of series to count rows, and {"text": "…"} for a text block. Aggregations live in feishu_query rather than here, so a question like "which region sold most" is one call instead of a table scan.

How it works

lib/
  index.js        composition root: config, identity, client, tools, routes
  config.js       normalization, brand endpoints, defaults
  identity.js     app credentials, tenant/app tokens, user grant, OAuth, refresh
  http.js         one HTTP request: timeout, bounded retries, byte ceiling
  client.js       the Feishu wire contract: envelope, auth, multipart, pagination
  errors.js       failure shaping and per-code remediation hints
  local-file.js   path resolution against the session workspace, upload/download
  activity.js     bounded in-memory record for the panel
  entry-config.js safe reader/writer for this plugin's own loader entry
  routes.js       /api/feishu/{status,activity,config,oauth/*}
  tools/
    kit.js        JSON-Schema-subset validator, definition helper, result envelope
    auth.js  bitable.js  docx.js  sheet.js  drive.js  wiki.js  im.js  raw.js
    index.js      assembly, prefixing, activity tracing
  ui/client.js    browser half: the floating panel and the settings page

The settings page

The page is self-contained: it talks to this plugin's own /api/feishu/config endpoint rather than the harness settings service, so the plugin keeps importing nothing from the SDK. A save does three things:

  1. validates every field against the table in routes.js — the redirect URL and the API base URLs must be http(s)://, the brand and identity are enumerations, the numeric fields are range-checked, and patchFilePath is not writable from the browser at all;
  2. rewrites only this plugin's entry in the profile patch file, which the harness hot-reloads. entry-config.js accepts only a path shaped like .../profiles/<name>/cordis.patch.yml, locates the block by its markers (or by a structural scan for the entry that names the plugin), carries over any key the page does not manage verbatim, writes atomically, and keeps one backup;
  3. stores the App Secret through ctx.credentials.set, so the secret never reaches the file and is never returned by any endpoint.

A field submitted as null is removed from the entry, which is how the page resets a value to the plugin default.

Token custody

  • App secret — resolved through the credential store, then the environment, then literal configuration. It never leaves the host and is never returned by the status endpoints.
  • Tenant / app access tokens — minted on demand, cached in memory, re-minted two minutes before expiry, single-flight so concurrent calls do not race.
  • User access token — a durable grant, so it lives in the credential store as the record dsh-feishu/user-token, together with its refresh token, and survives restarts. It is refreshed lazily when it nears expiry, and once more if Feishu rejects it mid-call.

Failure handling

Feishu reports business failures as HTTP 200 with a non-zero code. The client unwraps both shapes into a FeishuError carrying the code, the HTTP status, the path, any permission_violations, and a remediation hint. A token-expiry code earns exactly one automatic refresh-and-retry; everything else is surfaced with the hint attached, because "the app lacks a scope" and "the user never authorized" need different fixes.

Identity

Every tool takes an identity argument (auto, user, app). user puts new documents in the authorized person's drive and is the default; app acts as the application. auto prefers the user and, when none is stored, uses the app and reports the fallback as a warning, so a document never quietly ends up in the wrong drive.


Development

npm test          # or: node test/run-tests.mjs

The suite runs without the harness. It drives a mock Feishu tenant through a fake fetch, and it validates two things against the real DSH SDK rather than a local reimplementation:

  • every tool parameter and output schema passes the SDK's assertSupportedJsonSchema;
  • every parameter schema renders through jsonSchemaToTs, so PTC mode keeps working.

The SDK is deliberately not a dependency, so the suite looks for the real @deepseek-ai/dsh-tools in the usual profile and global locations and skips those two checks when it cannot find it (which is what happens in CI). Point DSH_TOOLS_PATH at dsh-tools/lib/index.js to force a specific copy.


Security notes

  • The app secret is read by reference and never returned over HTTP; the status endpoint reports only whether it is set and where it came from.
  • The OAuth routes are loopback-only and same-origin. The callback validates the state it issued and refuses a mismatch.
  • Bearer tokens are never logged, and the activity ring stores summaries and URLs, not credentials.
  • feishu_api is a full escape hatch by design. Register it only in compositions where the agent is trusted with the app's scopes.

Uninstall

pwsh -File scripts/uninstall.ps1

Then restart DeepSeek Harness and delete the stored grant if you want the user authorization gone as well.

Related projects

Feishu / Lark integrations are a crowded space, so it is worth being precise about what this plugin is and is not. Everything below is a point-in-time description; follow the links for the current state.

Official

  • larksuite/lark-openapi-mcp (MIT, npm @larksuiteoapi/lark-mcp) — the official Model Context Protocol server, and by far the broadest option: it wraps the published OpenAPI as MCP tools with presets, spanning IM, calendar, contacts, approval, drive, and more. Two caveats matter for document work, and both come from its own README and tool list: editing Feishu cloud-document content is stated as unsupported (import and read only), and its Bitable coverage is the V1 surface, where a dashboard appears only as list and copy — no creating or updating a dashboard or a chart block, and no aggregation.
  • larksuite/cli — the official CLI, with lark-base skills and reference documents. This plugin's V3 endpoint shapes and its data_config schema were taken from here and then verified against the live API.

Community Feishu MCP servers

Other DeepSeek Harness plugins

The DSH plugin market lists well over a hundred Feishu/Lark plugins, but the overwhelming majority are IM bridges — talk to your agent from Feishu, approval cards, notifications — which is a different job from this one. The closest in kind are:

What is different here

This plugin is deliberately narrow and deep. Where it goes beyond the alternatives above:

  • Writing, not just reading — Markdown converted into native document blocks, local files imported server-side, spreadsheet writes, Bitable records.
  • Charts and dashboards through the V3 API, including reading back a chart's computed numbers.
  • Server-side aggregation (feishu_query), so "top N by …" is one call instead of a table scan.
  • User-identity OAuth with an auto-refreshing grant, so new content lands in the user's own drive rather than the app's space.
  • A visual settings page, and errors carrying a per-code remediation hint.

For anything outside that list — calendar, approval, contacts, IM — reach for the official MCP or the official CLI, or use the feishu_api escape hatch.


License

MIT © 2026 Run Liu

Feishu, Lark, and 飞书 are trademarks of their respective owners. This project is an independent integration and is not affiliated with or endorsed by them.

Comments

Loading…

From the same category

dsh-TUI

by ccch1mneyyy

DSH 官方公众号收录的 TUI 补位插件:Claude Code 风,鲸鱼顶栏/实时状态/流式思考/双击 Esc 回滚/上下文进度+TPS。npm 一键装。 DSH official WeChat featured TUI plugin — Claude Code style: whale bar, live status, streaming thoughts, double-Esc rol

Terminal & ClientsManifest valid

★ 4.6k

↓ 11.9k/wk

MIT

TypeScript

Oct 16, 2026

dsh plugin --profile terminal add @deepseek-harness-tui/dsh-tui

by strukto-ai

The World's First Virtual Terminal for AI Agents

Terminal & ClientsManifest valid

★ 3.7k

↓ 374/wk

Apache-2.0

TypeScript

Oct 16, 2026

dsh plugin --profile agent add @struktoai/mirage-dsh

by bowenliang123

The best DeepSeek Harness plugin for context insight and management, with context dashboard / browser / sidebar and context command, for context statistics, composition, breakdown, evolution details,

Tools & CapabilitiesUI & ExperienceTerminal & ClientsManifest valid

★ 2.2k

↓ 52.1k/wk

Apache-2.0

TypeScript

Oct 16, 2026

dsh plugin --profile web add dsh-context

by huiliyi37

官方 DeepSeek Harness 的交互式终端 UI 插件:自研 ANSI 极简交互渲染、流式 Markdown/工具卡、16+ 主题、slash 命令与选择器、输入历史与本地偏好持久化、LSP 诊断、memory记忆,很丝滑的开发体验。

Terminal & ClientsManifest valid

★ 286

↓ 486/wk

Apache-2.0

TypeScript

Sep 30, 2026

dsh plugin --profile terminal add @huiliyi37/dsh-tianshu-tui

by Hilbert-beinghappy

面向 DeepSeek Harness 的 Claude Code 风格终端界面,支持 Windows、macOS 与 Linux,兼容透明终端、VS Code 主题和自定义配色。

Terminal & ClientsManifest valid

★ 196

↓ 108/wk

MIT

TypeScript

Oct 13, 2026

dsh plugin --profile web add seektty

by c3cvld7aag

富江DSH完美破甲|富江破甲 DSH 本地插件,内置提示词规则,支持 Windows 一键安装、环境自动准备与一键卸载,全中文使用说明。

Terminal & ClientsManifest valid

★ 94

JavaScript

Oct 3, 2026

dsh plugin --profile web add fujiang-armor