@bigbrain-work/mcp-connect 1.2.2 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Bigbrain Work
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,80 +1,54 @@
1
1
  # @bigbrain-work/mcp-connect
2
2
 
3
- 石榴 AI MCP 一键配置工具。用于将石榴 AI 的远程 MCP 服务接入 Codex、Claude Code 或 Cursor。
3
+ 石榴 AI 官方命令行工具。它负责验证当前凭据、配置常见 Agent、检查远程 MCP、读取实时工具清单,并为只支持 stdio 的客户端提供桥接。
4
4
 
5
- 客户不需要指定版本号。`npx` 会从 npm 获取 `latest` 对应的最新版:
6
-
7
- ## 使用
8
-
9
- 先在石榴 AI 页面复制当前账户的 API Key。推荐直接运行智能一键配置,安装器会检测本机已有的 Codex、Claude Code 和 Cursor:
5
+ ## 命令
10
6
 
11
7
  ```bash
12
- npx -y @bigbrain-work/mcp-connect
13
- ```
8
+ # 微信扫码登录;令牌进入操作系统凭据库
9
+ npx -y @bigbrain-work/mcp-connect login
14
10
 
15
- 连接完成后,Agent 可通过同一个 MCP 地址调用 `get_openstoryline_installer`,获取 Windows 或 macOS 本地 AI 剪辑工具的短期安装地址。
11
+ # Agent/无头环境:先创建会话并立即返回,再按返回的 poll_command 继续
12
+ npx -y @bigbrain-work/mcp-connect login --no-wait --json
13
+ npx -y @bigbrain-work/mcp-connect login poll --session <会话号> --wait --json
16
14
 
17
- 也可以明确指定客户端:
18
-
19
- ```bash
20
- npx -y @bigbrain-work/mcp-connect --agent codex
21
- npx -y @bigbrain-work/mcp-connect --agent claude
22
- npx -y @bigbrain-work/mcp-connect --agent cursor
23
- ```
15
+ # 自动检测并配置已安装的 Agent
16
+ npx -y @bigbrain-work/mcp-connect install
24
17
 
25
- 其他 Agent 也可以使用任意名称,例如:
18
+ # 只配置一个 Agent
19
+ npx -y @bigbrain-work/mcp-connect install --agent codex
26
20
 
27
- ```bash
28
- npx -y @bigbrain-work/mcp-connect --agent openclaw
29
- npx -y @bigbrain-work/mcp-connect --agent workbuddy
30
- ```
21
+ # 检查本地配置、远程连接和 tools/list
22
+ npx -y @bigbrain-work/mcp-connect status
31
23
 
32
- 对于尚未内置配置适配器的 Agent,安装器不会猜测其私有配置文件,而是输出一份标准 stdio MCP 配置。该配置统一运行:
24
+ # 显示服务实时返回的工具
25
+ npx -y @bigbrain-work/mcp-connect tools
33
26
 
34
- ```bash
35
- npx -y @bigbrain-work/mcp-connect proxy
27
+ # 撤销刷新令牌并清除本机凭据
28
+ npx -y @bigbrain-work/mcp-connect logout
36
29
  ```
37
30
 
38
- 桥接器从本机安全存储读取 `SHILIU_AI_API_KEY`,再连接远程 HTTP MCP。这样 WorkBuddy、OpenClaw 以及后续其他支持 stdio MCP 的 Agent 不需要分别开发认证头适配器。支持远程 HTTP MCP 和自定义认证头的客户端仍可直接连接服务地址。
31
+ 安装后也可使用 `shiliu` 命令。原有 `mcp-connect` 命令保持兼容。
32
+
33
+ `--url` 和 `--auth-url` 默认只接受石榴 AI 正式服务地址。开发者如需连接
34
+ `127.0.0.1`、`localhost` 或 `::1` 上的测试服务,必须显式添加
35
+ `--allow-localhost`;该开关不会放行局域网或公网第三方地址。
39
36
 
40
- 安装器会隐藏输入 API Key。配置完成后,重启对应客户端并检查连接:
37
+ ## 通用 Agent
41
38
 
42
39
  ```bash
43
- npx -y @bigbrain-work/mcp-connect status
40
+ npx -y @bigbrain-work/mcp-connect install --agent openclaw
44
41
  ```
45
42
 
46
- 如已设置 `SHILIU_AI_API_KEY` 环境变量,安装器会直接使用该变量,不再提示输入。
47
-
48
- ## 安全说明
49
-
50
- - npm 包源码中不包含任何用户 API Key。
51
- - Codex、Claude Code 和 Cursor 的 MCP 配置只保存环境变量引用,不保存真实 API Key。
52
- - Windows 上,安装器通过标准输入将 API Key 写入当前用户环境变量,避免进入终端历史和子进程命令行。
53
- - macOS/Linux 上,API Key 保存在权限为 `0600` 的 `~/.config/shiliu-ai/env`,并由用户登录配置加载。
54
- - `status` 命令只显示“已设置/未设置”,不会输出 API Key。
55
- - 通用 `proxy` 的 stdout 只承载 MCP 协议数据,不会输出 API Key。
43
+ 对未内置适配器的 Agent,CLI 会输出标准 stdio MCP 配置。名称只用于提示,不要求我们枚举所有 Agent。
56
44
 
57
- ## 服务信息
45
+ ## 凭据安全
58
46
 
59
- - MCP 地址:`https://api.bigbrain.work/shiliu/mcp`
60
- - MCP 地址是 Agent 连接服务所用的完整 HTTP 接口地址,不需要另配其他域名。
61
- - 认证方式:`Authorization: Bearer <API_KEY>`
62
- - 配置名称:`shiliu_mcp`
47
+ - 不支持 `--api-key` 参数,避免密钥进入 shell 历史。
48
+ - 默认微信扫码后获得短期访问令牌;过期前使用可轮换刷新令牌自动更新。
49
+ - 令牌保存在 Windows Credential Manager、macOS Keychain 或 Linux Secret Service,不写入 Agent 的 MCP 配置。
50
+ - 登录后先以新访问令牌调用一次 `tools/list`,验证成功后才保存。
51
+ - 非阻塞登录只把设备码暂存在系统凭据库,JSON 输出不包含设备码或访问令牌。
52
+ - `status --json` 与 `tools --json` 不输出任何令牌。
63
53
 
64
- ## 发布
65
-
66
- 首次发布前,确认 npm 账号属于 `bigbrain-work` organization,并启用双重验证:
67
-
68
- ```bash
69
- npm login
70
- npm whoami
71
- npm pack --dry-run
72
- npm publish --access public
73
- ```
74
-
75
- 后续版本先更新 `package.json` 版本号,再发布:
76
-
77
- ```bash
78
- npm version patch
79
- npm publish --access public
80
- ```
54
+ 迁移期如确需使用现有 API Key,可显式运行 `login --legacy-api-key`;此入口将在设备登录稳定后移除。
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { runCli } from '../src/cli.js'
3
+ import { runCli } from "../src/cli.js";
4
4
 
5
5
  runCli().catch((error) => {
6
- console.error(`安装失败:${error.message}`)
7
- process.exitCode = 1
8
- })
6
+ console.error(`错误:${error.message}`);
7
+ process.exitCode = 1;
8
+ });
package/bin/shiliu.js ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { runCli } from "../src/cli.js";
4
+
5
+ runCli().catch((error) => {
6
+ console.error(`错误:${error.message}`);
7
+ process.exitCode = 1;
8
+ });
package/package.json CHANGED
@@ -1,15 +1,17 @@
1
1
  {
2
2
  "name": "@bigbrain-work/mcp-connect",
3
- "version": "1.2.2",
4
- "description": "石榴 AI MCP 智能配置工具,支持自动检测、通用 HTTP MCP 接入和本地 AI 剪辑工具安装。",
3
+ "version": "1.3.0",
4
+ "description": "石榴 AI 官方 CLI:登录、配置 Agent、检查 MCP 状态并桥接远程工具。",
5
5
  "type": "module",
6
6
  "bin": {
7
- "mcp-connect": "bin/mcp-connect.js"
7
+ "mcp-connect": "bin/mcp-connect.js",
8
+ "shiliu": "bin/shiliu.js"
8
9
  },
9
10
  "files": [
10
11
  "bin",
11
12
  "src",
12
- "README.md"
13
+ "README.md",
14
+ "LICENSE"
13
15
  ],
14
16
  "scripts": {
15
17
  "test": "node --test",
@@ -30,7 +32,9 @@
30
32
  },
31
33
  "dependencies": {
32
34
  "@modelcontextprotocol/sdk": "1.29.0",
35
+ "@napi-rs/keyring": "2.0.0",
36
+ "qrcode": "1.5.4",
33
37
  "zod": "^3.25.0"
34
38
  },
35
- "license": "UNLICENSED"
39
+ "license": "MIT"
36
40
  }
package/src/arguments.js CHANGED
@@ -1,4 +1,15 @@
1
- import { parseArgs } from 'node:util'
1
+ import { parseArgs } from "node:util";
2
+
3
+ const COMMANDS = new Set([
4
+ "install",
5
+ "login",
6
+ "logout",
7
+ "status",
8
+ "tools",
9
+ "mcp",
10
+ "proxy",
11
+ "update",
12
+ ]);
2
13
 
3
14
  export function parseCliArguments(args) {
4
15
  const parsed = parseArgs({
@@ -7,49 +18,94 @@ export function parseCliArguments(args) {
7
18
  strict: true,
8
19
  options: {
9
20
  agent: {
10
- type: 'string',
11
- short: 'a',
21
+ type: "string",
22
+ short: "a",
12
23
  },
13
- 'dry-run': {
14
- type: 'boolean',
24
+ "dry-run": {
25
+ type: "boolean",
15
26
  default: false,
16
27
  },
17
28
  home: {
18
- type: 'string',
29
+ type: "string",
19
30
  },
20
31
  url: {
21
- type: 'string',
32
+ type: "string",
33
+ },
34
+ "auth-url": {
35
+ type: "string",
36
+ },
37
+ "allow-localhost": {
38
+ type: "boolean",
39
+ default: false,
40
+ },
41
+ "legacy-api-key": {
42
+ type: "boolean",
43
+ default: false,
44
+ },
45
+ "no-wait": {
46
+ type: "boolean",
47
+ default: false,
48
+ },
49
+ wait: {
50
+ type: "boolean",
51
+ default: false,
52
+ },
53
+ session: {
54
+ type: "string",
55
+ },
56
+ json: {
57
+ type: "boolean",
58
+ default: false,
22
59
  },
23
60
  help: {
24
- type: 'boolean',
25
- short: 'h',
61
+ type: "boolean",
62
+ short: "h",
26
63
  default: false,
27
64
  },
28
65
  version: {
29
- type: 'boolean',
30
- short: 'v',
66
+ type: "boolean",
67
+ short: "v",
31
68
  default: false,
32
69
  },
33
70
  },
34
- })
71
+ });
35
72
 
36
- const command = parsed.positionals[0] || 'install'
37
- if (!['install', 'proxy', 'status'].includes(command)) {
38
- throw new Error(`不支持的命令:${command}`)
73
+ const command = parsed.positionals[0] || "install";
74
+ if (!COMMANDS.has(command)) {
75
+ throw new Error(`不支持的命令:${command}`);
76
+ }
77
+ const subcommand = parsed.positionals[1];
78
+ if (
79
+ parsed.positionals.length > 2 ||
80
+ (subcommand && !(command === "login" && subcommand === "poll"))
81
+ ) {
82
+ throw new Error(`无法识别的参数:${parsed.positionals.slice(1).join(" ")}`);
39
83
  }
40
84
 
41
- const agent = parsed.values.agent?.toLowerCase()
85
+ const agent = parsed.values.agent?.toLowerCase();
42
86
  if (agent && !/^[a-z0-9][a-z0-9_-]{0,63}$/u.test(agent)) {
43
- throw new Error('客户端名称只能包含小写字母、数字、下划线和连字符')
87
+ throw new Error("客户端名称只能包含小写字母、数字、下划线和连字符");
88
+ }
89
+ const session = parsed.values.session;
90
+ if (session && !/^[A-HJ-NP-Z2-9]{4}-[A-HJ-NP-Z2-9]{4}$/u.test(session)) {
91
+ throw new Error("登录会话编号格式无效");
44
92
  }
45
93
 
46
94
  return {
47
95
  command,
96
+ subcommand,
48
97
  agent,
49
- dryRun: parsed.values['dry-run'],
98
+ dryRun: parsed.values["dry-run"],
50
99
  home: parsed.values.home,
51
100
  url: parsed.values.url,
101
+ authUrl: parsed.values["auth-url"],
102
+ allowLocalhost: parsed.values["allow-localhost"],
103
+ legacyApiKey: parsed.values["legacy-api-key"],
104
+ noWait: parsed.values["no-wait"],
105
+ wait: parsed.values.wait,
106
+ session,
107
+ json: parsed.values.json,
52
108
  help: parsed.values.help,
53
109
  version: parsed.values.version,
54
- }
110
+ };
55
111
  }
@@ -0,0 +1,49 @@
1
+ import { AUTH_URL } from "./constants.js";
2
+ import { readPersistedApiKey } from "./credentials.js";
3
+ import {
4
+ DeviceAuthClient,
5
+ normalizeTokenResponse,
6
+ } from "./device-auth-client.js";
7
+ import { TokenStore } from "./token-store.js";
8
+
9
+ const REFRESH_WINDOW_MS = 60_000;
10
+
11
+ export async function resolveAuthorization({
12
+ home,
13
+ platform = process.platform,
14
+ env = process.env,
15
+ authUrl = AUTH_URL,
16
+ tokenStore = new TokenStore(),
17
+ authClient = new DeviceAuthClient({ baseUrl: authUrl }),
18
+ now = Date.now,
19
+ } = {}) {
20
+ let tokenSet;
21
+ try {
22
+ tokenSet = await tokenStore.load();
23
+ } catch (error) {
24
+ const legacyApiKey = readPersistedApiKey({ home, platform, env })?.trim();
25
+ if (legacyApiKey) {
26
+ return {
27
+ token: legacyApiKey,
28
+ source: "legacy_api_key",
29
+ warning: error.message,
30
+ };
31
+ }
32
+ throw error;
33
+ }
34
+ if (tokenSet) {
35
+ if (tokenSet.expiresAt > now() + REFRESH_WINDOW_MS) {
36
+ return { token: tokenSet.accessToken, source: "device" };
37
+ }
38
+ const refreshed = normalizeTokenResponse(
39
+ await authClient.refresh(tokenSet.refreshToken),
40
+ now(),
41
+ );
42
+ await tokenStore.save(refreshed);
43
+ return { token: refreshed.accessToken, source: "device" };
44
+ }
45
+
46
+ const legacyApiKey = readPersistedApiKey({ home, platform, env })?.trim();
47
+ if (legacyApiKey) return { token: legacyApiKey, source: "legacy_api_key" };
48
+ return { token: "", source: "none" };
49
+ }