首页 Lark MCP Docker 集成方案
文章
取消

Lark MCP Docker 集成方案

概述

在 Docker 中运行 lark-mcp 作为 MCP 服务,供 opencode 调用 Lark API。核心需要解决两个问题:

  1. Token 持久化lark-mcp 通过 keytar → libsecret → D-Bus → gnome-keyring 存储 token,Docker 无桌面环境全链路不可用
  2. 端口映射 — OAuth 登录回调需要浏览器访问容器内的登录服务

相关文件

文件作用
Dockerfile镜像构建,安装所有依赖
scripts/entrypoint.sh容器启动时初始化 dbus + keyring
scripts/start.sh启动容器 + 执行 OAuth 登录
opencode.jsonopencode 的 MCP 配置

一、Token 持久化

依赖链

1
lark-mcp → keytar(Node.js) → libsecret(C) → D-Bus IPC → org.freedesktop.secrets(gnome-keyring)

Docker slim 镜像缺了三个环节:machine-iddbus-daemongnome-keyring

Dockerfile 安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# keytar 编译依赖
RUN apt-get update && apt-get install -y --no-install-recommends \
    pkg-config libsecret-1-dev libsecret-1-0 socat \
    && rm -rf /var/lib/apt/lists/*

# D-Bus + 密钥存储服务
RUN apt-get update && apt-get install -y --no-install-recommends \
    dbus-daemon dbus-session-bus-common gnome-keyring \
    && rm -rf /var/lib/apt/lists/*

# machine-id(dbus 启动必需)
RUN mkdir -p /var/lib/dbus && \
    echo "b9e7a32c5d8e4a2f9e6d1c3a7b5f8e2a" > /etc/machine-id && \
    ln -sf /etc/machine-id /var/lib/dbus/machine-id

安装 dbus-daemon 时需先 apt-get update,slim 镜像的 apt cache 中不包含这个包。

entrypoint.sh(容器启动时自动初始化)

1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/bash
set -e

# 启动 D-Bus session bus
dbus-daemon --session --address=unix:path=/tmp/dbus-session --fork || true
export DBUS_SESSION_BUS_ADDRESS=unix:path=/tmp/dbus-session

# 启动 gnome-keyring,空密码 unlock 创建默认 "login" collection
export GNOME_KEYRING_CONTROL=/root/.cache/keyring
echo "" | gnome-keyring-daemon --unlock --components=secrets >/dev/null 2>&1 || true

exec "$@"

ENTRYPOINT ["/entrypoint.sh"] 确保容器启动时自动执行上述初始化,环境变量传递给主进程。

二、端口映射(OAuth 登录回调)

问题

lark-mcp login 默认监听 127.0.0.1:3000。Docker 的 -p 将流量转发到容器 IP(如 172.17.0.x),而非 127.0.0.1,所以外部连不上。

如果用 --host 0.0.0.0 会触发 MCP SDK OAuth 库的 HTTPS 强制检查报错:Error: Issuer URL must be HTTPS

解决:不同端口 + socat 桥接

关键思路:宿主机和容器的端口号不同,避免冲突,同时让 lark-mcp login 保持在 127.0.0.1 上运行,不触发 HTTPS 检查。

1
2
3
4
5
6
7
8
9
用户浏览器 http://localhost:3000/authorize?...
     │
     │ Docker: -p 3000:3001(宿主机 3000 → 容器 3001)
     ▼
容器 0.0.0.0:3001
     │
     │ socat: TCP-LISTEN:3001 → TCP:127.0.0.1:3000
     ▼
容器 127.0.0.1:3000(lark-mcp login,默认端口,无 HTTPS 检查)

start.sh 实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 1. 暴露容器 3001 到宿主机 3000
docker run -d --restart unless-stopped \
    --name lark-bot \
    -p 3000:3001 \

# 2. socat 桥接:0.0.0.0:3001 → 127.0.0.1:3000
docker exec -d lark-bot socat TCP-LISTEN:3001,fork,reuseaddr TCP:127.0.0.1:3000

# 3. lark-mcp login 默认绑 127.0.0.1:3000(不需要 --port)
docker exec -e DBUS_SESSION_BUS_ADDRESS=unix:path=/tmp/dbus-session lark-bot \
    npx -y @larksuiteoapi/lark-mcp login -a "$APP_ID" -s "$APP_SECRET"

# 4. 验证 token 是否成功持久化:
docker exec -e DBUS_SESSION_BUS_ADDRESS=unix:path=/tmp/dbus-session lark-bot \
    sh -c 'npx -y @larksuiteoapi/lark-mcp whoami'

注意: docker exec 不会继承 entrypoint 中 export 的环境变量,所以所有 docker exec lark-mcp 命令都要显式传 -e DBUS_SESSION_BUS_ADDRESS=unix:path=/tmp/dbus-session

远程服务器的情况

如果 Docker 跑在远程服务器(如腾讯云)上,用户浏览器访问 http://localhost:3000 指向的是本地 Mac,不是远程服务器的 3000 端口。需要用 SSH 本地端口转发-L)把远程的 3000 端口映射到本地:

1
ssh -L 3000:localhost:3000 -i /path/to/key.pem root@<server-ip>

完整路径如下:

方向路径
用户浏览器 http://localhost:3000本地 Mac 3000 端口
SSH -L 3000:localhost:3000远程服务器 localhost:3000
Docker -p 3000:3001容器 0.0.0.0:3001
socat 桥接容器 127.0.0.1:3000
lark-mcp login← 收到 callback,登录完成

-L 的含义:-L 本地端口:目标主机:目标端口,将本地 Mac 的 3000 端口流量通过 SSH 隧道转发到远程服务器的 localhost:3000。

OAuth 回调完整流程

步骤说明
1浏览器打开 http://localhost:3000/authorize?...
2重定向到 Lark 授权页,用户登录授权
3Lark 将浏览器重定向回 http://localhost:3000/callback?code=...
4-p 3000:3001 → 容器内 0.0.0.0:3001
5socat → 127.0.0.1:3000
6lark-mcp login 收到 code,交换成 token,存入 gnome-keyring

三、AI Agent MCP 配置(以 opencode 为例)

opencode.json 中配置 lark-mcp 作为 MCP 服务端:

1
2
3
4
5
6
{
  "command": [
    "sh", "-c",
    "lark-mcp mcp -a \"$LARK_APP_ID\" -s \"$LARK_APP_SECRET\" --oauth --token-mode user_access_token --domain https://open.larksuite.com"
  ]
}

关键点:

  • 通过 sh -c 从环境变量读凭据,不硬编码到配置文件
  • --oauth 自动使用已存储的 user_access_token,过期时自动刷新
  • --token-mode user_access_token 使用用户级别的 token,可以访问用户自己的文档
  • 环境变量在 docker run --env-file .env 时注入

总结

在 Docker 中集成 lark-mcp 的核心挑战来自其 token 存储链路对桌面环境的依赖。通过安装 dbus-daemon + gnome-keyring + 手动注入 machine-id,结合 entrypoint 脚本自动初始化 session bus,可以在无桌面环境的容器中完整跑通 keytar → libsecret → D-Bus → gnome-keyring 链路。OAuth 登录回调则通过 socat 桥接不同端口绕过 HTTPS 检查限制。

效果图

本文由作者按照 CC BY 4.0 进行授权

CT Control Tower Guardrails 与原生 SCP 的分工原则

多云联邦 — AWS 登录 Aliyun