记录一次mcp server的PR
https://github.com/larksuite/lark-openapi-mcp/pull/70
scope 就是包名前面 @ 开头的命名空间,用来区分包属于哪个组织
1 | |
配置.npmrc
有全局和项目.npmrc
1 | |
1 | |
npm命令解析
下载依赖
1 | |
把 package.json 里 dependencies 和 devDependencies 列的包全部下载到本地 node_modules/,不编译、不执行、不改代码。
prepare 是 npm 的生命周期钩子,npm install 的时候会自动触发,不是 npm run build 触发的。
1 | |
npm run build 直接执行 scripts.build,跟 prepare 没关系,所以单独跑 npm run build 不会有问题。
之前报 yarn: command not found 就是 npm install 时 prepare 钩子触发导致的。
编译
1 | |
执行 package.json 里 scripts.build 定义的命令
1 | |
就两步:
rm -rf dist— 删旧的编译产物tsc— 把src/下的 TypeScript 编译成 JavaScript 输出到dist/
npx 执行流程
-
检查本地有没有装过,没有就从 registry 下载到临时目录
- 相当于
npm install @tiangong/lark-mcp --prefix ~/.npm/_npx/<hash>/
- 相当于
-
找到 package.json 里 bin 字段对应的文件执行
-
1
2
3"bin": { "lark-mcp": "dist/cli.js" // ← npx 找这个 }
-
-
执行完不删除,下次同版本直接用缓存 , 可以用
npm cache clean --force清除
执行编译,测试
1 | |
push tgz 到私有源
1 | |
不指定源,在 package.json 里加 publishConfig,以后直接 npm publish 就行
1 | |
callback 流程
sequenceDiagram
participant User as 用户浏览器
participant CLI as lark-mcp CLI
participant Store as AuthStore (本地文件)
participant Feishu as 飞书开放平台
Note over CLI,Store: === 1. login 登录流程 ===
CLI->>CLI: handleLogin() 启动 express server<br/>绑定 0.0.0.0:3000 (bindHost)
CLI->>Store: registerClient(client_id_for_local_auth)
CLI->>CLI: generatePKCEPair() 生成 codeVerifier + codeChallenge
CLI->>Store: storeCodeVerifier(codeVerifier)
CLI->>User: 打印 authorizeUrl<br/>http://localhost:3000/authorize?...redirect_uri=https://callbackHost/callback
User->>CLI: GET /authorize
CLI->>Feishu: 302 跳转飞书授权页
User->>Feishu: 用户点击同意授权
Feishu->>CLI: GET /callback?code=xxx
CLI->>Store: getCodeVerifier()
CLI->>Feishu: exchangeAuthorizationCode(code, codeVerifier)
Feishu-->>CLI: 返回 access_token + refresh_token
CLI->>Store: storeLocalAccessToken(access_token, appId)<br/>storeToken(AuthInfo含refreshToken)
CLI->>User: 返回 "success, you can close this page"
CLI->>CLI: checkTokenWithTimeout() 检测到token存在
CLI->>CLI: ✅ 登录成功 process.exit(0)
Note over CLI,Store: === 2. token 使用流程 ===
CLI->>Store: getLocalAccessToken(appId)
Store-->>CLI: 返回 access_token
CLI->>Feishu: API请求 withUserAccessToken(access_token)<br/>例如 docx.builtin.search
Note over CLI,Store: === 3. token 过期刷新流程 ===
CLI->>Store: getToken(access_token)
Store-->>CLI: 返回 AuthInfo (含 refreshToken + expiresAt)
CLI->>CLI: isTokenExpired() 检查是否过期
CLI->>Feishu: exchangeRefreshToken(refreshToken)
Feishu-->>CLI: 返回新 access_token + refresh_token
CLI->>Store: removeToken(旧token)
CLI->>Store: storeLocalAccessToken(新token, appId)
Note over CLI,Store: === 4. token 存储结构 ===
Note over Store: 本地文件 storage.json<br/>{<br/> tokens: { "access_token_xxx": AuthInfo },<br/> localTokens: { "appId": "access_token_xxx" },<br/> clients: { "client_id_for_local_auth": ClientInfo }<br/>}