dsh-mcp-connector 0.2.28 → 0.2.30
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/CHANGELOG.md +27 -1
- package/CONTRIBUTING.md +5 -0
- package/README.en.md +8 -5
- package/README.md +8 -5
- package/docs/FIRST-CONTRIBUTION.md +31 -0
- package/docs/PLUGIN-UPDATE.md +3 -1
- package/docs/screenshots/01-market-overview.jpg +0 -0
- package/docs/screenshots/02-connector-detail.jpg +0 -0
- package/docs/screenshots/03-tool-discovery.jpg +0 -0
- package/docs/screenshots/04-json-import.jpg +0 -0
- package/docs/screenshots/README.md +35 -0
- package/docs/screenshots/assets.json +46 -0
- package/lib/client.js +79 -4
- package/package.json +12 -3
- package/screenshots.json +6 -0
- package/scripts/ui-harness.mjs +71 -8
- package/ui/index.html +35 -3
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,30 @@
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.2.30] - 2026-08-30
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- 新增营销元数据事实源与线上/离线漂移检查,统一 npm 描述与关键词、GitHub About/Topics、中英文首屏 CTA 和外部分发文案。
|
|
12
|
+
- 新增贡献模板、good first issue 入口、自然搜索/转化基线与发布前监控检查。
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
|
|
16
|
+
- 更新中英文产品介绍、npm 检索词与 GitHub Topics,突出 MCP Server 连接、Registry、OAuth 2.0 PKCE 与 stdio/HTTP 能力。
|
|
17
|
+
- 重新录制无真实凭据的市场截图与演示 GIF:实际两列卡片布局,企查查卡片不再展示“需重新授权”。
|
|
18
|
+
- 已安装但尚无连接时不再强制弹出转化引导;首次连接成功或存在历史连接后才展示,且每页面生命周期仅一次。
|
|
19
|
+
|
|
20
|
+
### Verification
|
|
21
|
+
|
|
22
|
+
- 152 项自动测试、lint、npm 发布包白名单/敏感内容扫描、商店素材哈希与尺寸校验通过。
|
|
23
|
+
|
|
24
|
+
## [0.2.29] - 2026-08-30
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
28
|
+
- 更新服务返回 `RELEASE_TOO_FRESH` 时明确提示“发布安全等待期”,不再误写为镜像同步;主动跳过等待的操作也改为“立即更新(跳过等待)”。
|
|
29
|
+
- DSH Desktop 或其他无兼容 Update Provider 的宿主直接展示精确版本升级命令,并支持一键复制与打开 npm 页面,不再只给出泛化的“查看更新方式”。
|
|
30
|
+
|
|
7
31
|
## [0.2.28] - 2026-08-29
|
|
8
32
|
|
|
9
33
|
### Documentation
|
|
@@ -449,7 +473,9 @@
|
|
|
449
473
|
- 外部 URL 与导入 Header 执行安全校验。
|
|
450
474
|
- iframe 消息校验同源和消息来源。
|
|
451
475
|
|
|
452
|
-
[Unreleased]: https://github.com/duhu2000/dsh-mcp-connector/compare/v0.2.
|
|
476
|
+
[Unreleased]: https://github.com/duhu2000/dsh-mcp-connector/compare/v0.2.30...HEAD
|
|
477
|
+
[0.2.30]: https://github.com/duhu2000/dsh-mcp-connector/compare/v0.2.29...v0.2.30
|
|
478
|
+
[0.2.29]: https://github.com/duhu2000/dsh-mcp-connector/compare/v0.2.28...v0.2.29
|
|
453
479
|
[0.2.28]: https://github.com/duhu2000/dsh-mcp-connector/compare/v0.2.27...v0.2.28
|
|
454
480
|
[0.2.27]: https://github.com/duhu2000/dsh-mcp-connector/compare/v0.2.26...v0.2.27
|
|
455
481
|
[0.2.26]: https://github.com/duhu2000/dsh-mcp-connector/compare/v0.2.25...v0.2.26
|
package/CONTRIBUTING.md
CHANGED
|
@@ -9,6 +9,7 @@ Thank you for contributing. Never put tokens, API keys, cookies, OAuth credentia
|
|
|
9
9
|
- 报告缺陷或提交功能建议:[GitHub Issues](https://github.com/duhu2000/dsh-mcp-connector/issues)
|
|
10
10
|
- 为公共市场增加连接器:阅读 [Connector onboarding](https://github.com/duhu2000/dsh-mcp-connector-registry/blob/main/docs/ONBOARDING.md),连接器描述与插件代码分仓管理。
|
|
11
11
|
- 修复插件或改进文档:Fork 本仓库,从最新 `main` 创建单一目的的分支并提交 PR。
|
|
12
|
+
- 第一次参与:从带有 [`good first issue`](https://github.com/duhu2000/dsh-mcp-connector/labels/good%20first%20issue) 标签的任务开始,并按[首次贡献路径](docs/FIRST-CONTRIBUTION.md)完成本地校验。
|
|
12
13
|
- 搭建私有目录:参考 [README 配置说明](README.md#配置) 和 [市场注册指南](docs/MARKET-REGISTRATION.md)。
|
|
13
14
|
|
|
14
15
|
## 本地开发
|
|
@@ -53,3 +54,7 @@ npm run check
|
|
|
53
54
|
```
|
|
54
55
|
|
|
55
56
|
提交时说明用户问题、解决方案、测试结果与必要的手工验收步骤。
|
|
57
|
+
|
|
58
|
+
## 维护者如何准备首次贡献任务
|
|
59
|
+
|
|
60
|
+
首次贡献任务应边界清楚、无需真实凭据或私有 DSH 环境,并在 Issue 中写明背景、建议修改文件、验收标准和验证命令。适合的范围包括文档示例、无凭据测试夹具、可访问性文案和小型校验器改进;涉及发布、OAuth 凭据、Registry 上架审批或大规模重构的工作不应标记为 `good first issue`。
|
package/README.en.md
CHANGED
|
@@ -8,7 +8,7 @@ Manage MCP connections from different providers in one place inside DeepSeek Har
|
|
|
8
8
|
|
|
9
9
|
[简体中文](README.md)
|
|
10
10
|
|
|
11
|
-
[Chinese user guide](docs/USER-GUIDE.md) · [Connector onboarding](https://github.com/duhu2000/dsh-mcp-connector-registry/blob/main/docs/ONBOARDING.md) · [Contributing](CONTRIBUTING.md) · [Issues](https://github.com/duhu2000/dsh-mcp-connector/issues)
|
|
11
|
+
[Chinese user guide](docs/USER-GUIDE.md) · [Connector onboarding](https://github.com/duhu2000/dsh-mcp-connector-registry/blob/main/docs/ONBOARDING.md) · [First contribution](docs/FIRST-CONTRIBUTION.md) · [Contributing](CONTRIBUTING.md) · [Issues](https://github.com/duhu2000/dsh-mcp-connector/issues)
|
|
12
12
|
|
|
13
13
|
[](https://github.com/duhu2000/dsh-mcp-connector/actions/workflows/ci.yml)
|
|
14
14
|
[](https://www.npmjs.com/package/dsh-mcp-connector)
|
|
@@ -30,7 +30,7 @@ Fully restart DeepSeek Harness Desktop or `dsh web` after installation or upgrad
|
|
|
30
30
|
|
|
31
31
|

|
|
32
32
|
|
|
33
|
-
If the plugin helps you connect an MCP server faster, consider [starring the repository](https://github.com/duhu2000/dsh-mcp-connector/stargazers)
|
|
33
|
+
If the plugin helps you connect an MCP server faster, consider [starring the repository](https://github.com/duhu2000/dsh-mcp-connector/stargazers), [submitting a connector](https://github.com/duhu2000/dsh-mcp-connector-registry/blob/main/docs/ONBOARDING.md), or [contributing a fix](CONTRIBUTING.md).
|
|
34
34
|
|
|
35
35
|
## Why use MCP Connector
|
|
36
36
|
|
|
@@ -72,7 +72,7 @@ As of 2026-08-27, the public Registry publishes 79 connector descriptors. After
|
|
|
72
72
|
| Tool discovery, descriptions, and scrolling | JSON import |
|
|
73
73
|
|  |  |
|
|
74
74
|
|
|
75
|
-
The assets are captured from a
|
|
75
|
+
The assets are captured from a credential-free UI acceptance harness that mirrors the real 800px product panel, producing two cards per desktop row. They show only public marketplace metadata, example prompts, and explicitly marked mock tool descriptions—never credentials, local paths, or query results. See [`docs/screenshots/README.md`](docs/screenshots/README.md) for provenance.
|
|
76
76
|
|
|
77
77
|
## Installation
|
|
78
78
|
|
|
@@ -107,7 +107,9 @@ The detailed [Chinese user guide](docs/USER-GUIDE.md) covers category browsing,
|
|
|
107
107
|
- [Plugin updates: version discovery, providers, and rollback](docs/PLUGIN-UPDATE.md)
|
|
108
108
|
- [Marketplace registration: local cards, the public Registry, and OAuth requirements](docs/MARKET-REGISTRATION.md)
|
|
109
109
|
- [Third-party connector onboarding](https://github.com/duhu2000/dsh-mcp-connector-registry/blob/main/docs/ONBOARDING.md)
|
|
110
|
+
- [First contribution: from a good first issue to your first PR](docs/FIRST-CONTRIBUTION.md)
|
|
110
111
|
- [Development, forks, and contributions](CONTRIBUTING.md)
|
|
112
|
+
- [Growth baseline and monthly review template](docs/GROWTH-BASELINE.md)
|
|
111
113
|
|
|
112
114
|
## Connector catalog
|
|
113
115
|
|
|
@@ -137,17 +139,18 @@ Set `catalogUrl` to an empty string for an explicitly offline/private setup. A c
|
|
|
137
139
|
|
|
138
140
|
```bash
|
|
139
141
|
npm run check
|
|
142
|
+
npm run marketing:check:live
|
|
140
143
|
npm run registry:build
|
|
141
144
|
npm run registry:validate
|
|
142
145
|
npm run market:check
|
|
143
146
|
npm run dev:ui
|
|
144
147
|
```
|
|
145
148
|
|
|
146
|
-
`npm run check`
|
|
149
|
+
`marketing/metadata.json` is the source of truth for the npm description/keywords, GitHub About/Topics, bilingual first-screen CTAs, and external listing copy. `npm run check` blocks repository drift offline; `npm run marketing:check:live` also compares the public GitHub and npm metadata for metadata changes and monthly reviews. `npm run market:check` tracks the external DSH marketplace PR and live directory. Tags matching `v*` trigger GitHub Actions; the tag must match `package.json`. npm releases use Trusted Publishing through GitHub OIDC and do not require a long-lived `NPM_TOKEN`.
|
|
147
150
|
|
|
148
151
|
Every Registry merge regenerates `catalog-stats.json`; an hourly workflow in this repository synchronizes the Chinese and English product copy plus a local stats snapshot. The static npm README updates with package releases, while the live badges above read the Registry directly and therefore stay current without another npm release.
|
|
149
152
|
|
|
150
|
-
The current public version is [`dsh-mcp-connector@0.2.
|
|
153
|
+
The current public version is [`dsh-mcp-connector@0.2.30`](https://www.npmjs.com/package/dsh-mcp-connector), with [GitHub Release v0.2.30](https://github.com/duhu2000/dsh-mcp-connector/releases/tag/v0.2.30).
|
|
151
154
|
|
|
152
155
|
See [CHANGELOG.md](CHANGELOG.md) for version history and [docs/DESKTOP-E2E.md](docs/DESKTOP-E2E.md) for the Desktop release checklist.
|
|
153
156
|
|
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
[English](README.en.md)
|
|
10
10
|
|
|
11
|
-
[用户手册](docs/USER-GUIDE.md) · [第三方连接器上架指南](https://github.com/duhu2000/dsh-mcp-connector-registry/blob/main/docs/ONBOARDING.md) · [参与贡献](CONTRIBUTING.md) · [问题反馈](https://github.com/duhu2000/dsh-mcp-connector/issues)
|
|
11
|
+
[用户手册](docs/USER-GUIDE.md) · [第三方连接器上架指南](https://github.com/duhu2000/dsh-mcp-connector-registry/blob/main/docs/ONBOARDING.md) · [首次贡献](docs/FIRST-CONTRIBUTION.md) · [参与贡献](CONTRIBUTING.md) · [问题反馈](https://github.com/duhu2000/dsh-mcp-connector/issues)
|
|
12
12
|
|
|
13
13
|
[](https://github.com/duhu2000/dsh-mcp-connector/actions/workflows/ci.yml)
|
|
14
14
|
[](https://www.npmjs.com/package/dsh-mcp-connector)
|
|
@@ -30,7 +30,7 @@ dsh plugin --profile web add dsh-mcp-connector
|
|
|
30
30
|
|
|
31
31
|

|
|
32
32
|
|
|
33
|
-
如果它帮你更快地接入 MCP Server
|
|
33
|
+
如果它帮你更快地接入 MCP Server,欢迎 [GitHub 点个 Star](https://github.com/duhu2000/dsh-mcp-connector/stargazers)、[提交新的连接器](https://github.com/duhu2000/dsh-mcp-connector-registry/blob/main/docs/ONBOARDING.md)或[参与贡献](CONTRIBUTING.md)。
|
|
34
34
|
|
|
35
35
|
## 为什么使用 MCP连接器
|
|
36
36
|
|
|
@@ -74,7 +74,7 @@ dsh plugin --profile web add dsh-mcp-connector
|
|
|
74
74
|
| 工具发现、描述与独立滚动 | JSON 导入 |
|
|
75
75
|
|  |  |
|
|
76
76
|
|
|
77
|
-
|
|
77
|
+
素材从复刻真实 800px 产品面板的无凭据 UI 验收环境采集,桌面端一行 2 张卡片;只展示公开市场元数据、示例 Prompt 和明确标识的 Mock 工具说明,不包含凭据、本机路径或查询结果。详见 [`docs/screenshots/README.md`](docs/screenshots/README.md)。
|
|
78
78
|
|
|
79
79
|
## 安装
|
|
80
80
|
|
|
@@ -109,7 +109,9 @@ bash <(curl -fsSL https://raw.githubusercontent.com/duhu2000/dsh-mcp-connector/m
|
|
|
109
109
|
- [插件更新:版本检测、Provider 与回滚](docs/PLUGIN-UPDATE.md)
|
|
110
110
|
- [市场注册:本地卡片、公共 Registry 与 OAuth 要求](docs/MARKET-REGISTRATION.md)
|
|
111
111
|
- [第三方连接器上架指南](https://github.com/duhu2000/dsh-mcp-connector-registry/blob/main/docs/ONBOARDING.md)
|
|
112
|
+
- [首次贡献:从 good first issue 到第一个 PR](docs/FIRST-CONTRIBUTION.md)
|
|
112
113
|
- [开发、Fork 与贡献指南](CONTRIBUTING.md)
|
|
114
|
+
- [增长基线与月度复盘模板](docs/GROWTH-BASELINE.md)
|
|
113
115
|
|
|
114
116
|
## 配置
|
|
115
117
|
|
|
@@ -132,17 +134,18 @@ Bundle 默认配置位于 `cordis.patch.yml`:
|
|
|
132
134
|
|
|
133
135
|
```bash
|
|
134
136
|
npm run check
|
|
137
|
+
npm run marketing:check:live
|
|
135
138
|
npm run registry:build
|
|
136
139
|
npm run registry:validate
|
|
137
140
|
npm run market:check
|
|
138
141
|
npm run dev:ui
|
|
139
142
|
```
|
|
140
143
|
|
|
141
|
-
`check`
|
|
144
|
+
`marketing/metadata.json` 是 npm 描述/关键词、GitHub About/Topics、中英文首屏 CTA 和外部分发文案的事实源。`check` 会离线阻断仓库内漂移;`marketing:check:live` 进一步核对线上 GitHub 与 npm,供元数据调整和月度复盘时执行。`market:check` 检查外部 DSH 市场 PR 与线上目录;`dev:ui` 启动不含真实凭据的本地 mock 市场。CI 使用 `--legacy-peer-deps` 安装显式测试依赖,DSH 运行期 peer 仍由 Host 提供。`v*` Tag 会触发 GitHub Actions;Tag 必须与 `package.json` 版本一致。Release 通过 npm Trusted Publishing (GitHub OIDC) 发布,不依赖长期 `NPM_TOKEN`。
|
|
142
145
|
|
|
143
146
|
公共 Registry 每次合并后会生成 `catalog-stats.json`;本仓库的定时工作流每小时同步中英文介绍和统计快照。npm 页面中的静态正文随版本发布更新,上方动态统计徽标则直接读取 Registry,可在不发布新 npm 版本时保持实时数量一致。
|
|
144
147
|
|
|
145
|
-
当前公开版本为 [`dsh-mcp-connector@0.2.
|
|
148
|
+
当前公开版本为 [`dsh-mcp-connector@0.2.30`](https://www.npmjs.com/package/dsh-mcp-connector),对应 [GitHub Release v0.2.30](https://github.com/duhu2000/dsh-mcp-connector/releases/tag/v0.2.30)。
|
|
146
149
|
|
|
147
150
|
版本能力与变更记录见 [CHANGELOG.md](CHANGELOG.md)。
|
|
148
151
|
Desktop 发版回归见 [docs/DESKTOP-E2E.md](docs/DESKTOP-E2E.md)。
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# 首次贡献 / First contribution
|
|
2
|
+
|
|
3
|
+
欢迎第一次参与 `dsh-mcp-connector`。优先选择带有 [`good first issue`](https://github.com/duhu2000/dsh-mcp-connector/labels/good%20first%20issue) 标签、且尚未被认领的任务;在 Issue 留言后再开始,避免重复劳动。
|
|
4
|
+
|
|
5
|
+
Welcome! Start with an unassigned [`good first issue`](https://github.com/duhu2000/dsh-mcp-connector/labels/good%20first%20issue). Leave a short comment before working on it so contributors do not duplicate effort.
|
|
6
|
+
|
|
7
|
+
## 适合第一次参与的范围
|
|
8
|
+
|
|
9
|
+
- 中英文文档示例、安装或故障排查说明。
|
|
10
|
+
- 不需要真实 Token、API Key 或私有服务的测试用例。
|
|
11
|
+
- 键盘操作、可访问性标签和小型界面文案改进。
|
|
12
|
+
- 元数据校验器与贡献者工具链的小改进。
|
|
13
|
+
|
|
14
|
+
新的公共连接器描述不提交到本仓库,请改走独立 Registry 的[连接器上架指南](https://github.com/duhu2000/dsh-mcp-connector-registry/blob/main/docs/ONBOARDING.md)。
|
|
15
|
+
|
|
16
|
+
## 从 Issue 到 PR
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
git switch main
|
|
20
|
+
git pull --ff-only
|
|
21
|
+
git switch -c docs/<short-purpose>
|
|
22
|
+
npm install --legacy-peer-deps
|
|
23
|
+
npm run check
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
1. 只处理 Issue 定义的单一问题;不提交真实凭据、业务数据或本机路径。
|
|
27
|
+
2. 中英文用户文案保持同步;行为变化需补测试。
|
|
28
|
+
3. PR 中链接对应 Issue,并写清问题、改动、验证结果和必要的手工检查。
|
|
29
|
+
4. 维护者确认验收标准后合并;版本发布由维护者统一安排。
|
|
30
|
+
|
|
31
|
+
如果任务描述不够清楚,请先在 Issue 提问。首次贡献不要求拥有 DSH 私有环境,也不要求发布 npm 包。
|
package/docs/PLUGIN-UPDATE.md
CHANGED
|
@@ -25,7 +25,9 @@ DSH Market 适配器从 `GET /dsh-market/api/v1/capabilities` 开始,要求 `s
|
|
|
25
25
|
5. 完整性校验通过后,按 Provider 返回的激活结论展示“刷新生效”或重启提示。Web 且 Provider 明确允许进程重启时才展示“立即重启”;Desktop 等由外壳管理生命周期的宿主只提示用户重启,不自行杀进程。
|
|
26
26
|
6. Provider 保留恢复点时展示“回滚”。回滚仍由 Provider 执行,MCP连接器不直接修改 profile、lockfile 或 `node_modules`。
|
|
27
27
|
|
|
28
|
-
失败结果使用稳定代码区分正在运行的 Agent
|
|
28
|
+
失败结果使用稳定代码区分正在运行的 Agent、其他安装任务占用、发布安全等待、镜像同步、版本未变化、超时和权限拒绝,以及 `DOWNGRADE_DETECTED`、`RESOLVED_VERSION_MISMATCH`、`INVALID_UPDATE_RESULT` 三类完整性故障。`RELEASE_TOO_FRESH` 明确显示为约 24 小时的发布安全等待期,并提供“立即更新(跳过等待)”;真正的镜像同步故障保留独立提示,不再混用同一文案。
|
|
29
|
+
|
|
30
|
+
当 DSH Desktop 或其他宿主没有兼容 Update Provider 时,标题区直接展示绑定 npm 精确版本的 CLI 命令,例如 `dsh plugin --profile web add --config.minimumReleaseAge=0 dsh-mcp-connector@<目标版本>`,并提供复制按钮与 npm 页面入口。运行时会把 `<目标版本>` 替换为 npm 已发布的确切版本;命令中的单次覆盖只用于用户主动跳过本次发布安全等待。Connector 仍不自行执行包管理器命令。
|
|
29
31
|
|
|
30
32
|
## 安全边界
|
|
31
33
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# UI 素材说明
|
|
2
|
+
|
|
3
|
+
本目录用于保存 `dsh-mcp-connector` 的公开界面截图。素材于 2026-08-30 从当前源码的
|
|
4
|
+
无凭据 UI harness 采集:外层浏览器视口为 1280×720,harness 复刻产品宿主在
|
|
5
|
+
`lib/client.js` 中定义的 800px 市场面板,因此桌面端稳定为一行 2 张卡片。公开 Registry
|
|
6
|
+
快照含 79 条描述,与 4 张随包唯一卡片合并后市场显示 83 张。画面只展示公开市场元数据、
|
|
7
|
+
示例 Prompt 和明确标识为 Mock 的工具数据,不包含 OAuth Token、API Key、本机路径、
|
|
8
|
+
用户会话或查询结果。
|
|
9
|
+
|
|
10
|
+
旧素材直接以 1280px 打开内部 iframe,绕过了真实产品的 800px 宿主面板,因此触发
|
|
11
|
+
`auto-fill/minmax(300px)` 的 3 列布局;这是采集 harness/视口过期,不是当前产品 CSS 漂移。
|
|
12
|
+
本次素材从浏览器中的真实页面状态直接截取,没有后期重排卡片或修改连接状态。
|
|
13
|
+
|
|
14
|
+
仓库根目录的 [`screenshots.json`](../../screenshots.json) 按市场总览、连接器详情、工具发现、
|
|
15
|
+
JSON 导入的顺序声明这 4 张图片,供 awesome-dsh-plugin 和 DSH Market 的 App Store 风格详情页
|
|
16
|
+
直接采集。根清单保持外部消费者兼容的路径数组;[`assets.json`](assets.json) 记录
|
|
17
|
+
1280×720 视口、800px 产品面板、2 列、无凭据状态,以及每张截图和 `demo.gif` 的
|
|
18
|
+
SHA-256、尺寸与 GIF 时长。
|
|
19
|
+
`npm run storefront:check` 会校验路径、顺序、格式、文件存在性、哈希、尺寸和采集约束;
|
|
20
|
+
`npm run check` 已包含该门禁。
|
|
21
|
+
|
|
22
|
+
| 文件 | 展示内容 |
|
|
23
|
+
|---|---|
|
|
24
|
+
| `01-market-overview.jpg` | 83 张合并市场卡片、桌面两列、推荐章节、9 分类和固定分类栏;企查查卡片均为未连接的“连接”状态 |
|
|
25
|
+
| `02-connector-detail.jpg` | Seedream 第三方服务说明、精选 Prompt 和未连接状态 |
|
|
26
|
+
| `03-tool-discovery.jpg` | Context7 无凭据 Mock 健康状态、Mock 工具数量/描述、搜索和独立滚动区 |
|
|
27
|
+
| `04-json-import.jpg` | Streamable HTTP / stdio JSON 导入与本机凭据提示 |
|
|
28
|
+
|
|
29
|
+
`../demo.gif` 由以上 4 个真实浏览器状态顺序编码,时长 16 秒,分辨率 960×540;编码只做
|
|
30
|
+
等比例缩放和 GIF 调色,不改变布局或状态。更新 UI 后应继续使用 1280×720 浏览器视口、
|
|
31
|
+
800px 产品面板和无凭据初始状态重新采集,并检查桌面两列、企查查卡片不出现
|
|
32
|
+
“需重新授权”,且画面不包含凭据、本机路径、真实会话、查询结果或其他不应公开的内容。
|
|
33
|
+
|
|
34
|
+
截图顶部“无凭据 Mock”标识和工具名中的 `mock_` 前缀用于明确区分验收数据与真实授权。
|
|
35
|
+
真实用户的已安装数量、授权状态和服务健康度会因本机环境而不同。
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"capture": {
|
|
4
|
+
"capturedOn": "2026-08-30",
|
|
5
|
+
"browserViewport": {
|
|
6
|
+
"width": 1280,
|
|
7
|
+
"height": 720
|
|
8
|
+
},
|
|
9
|
+
"productPanelWidth": 800,
|
|
10
|
+
"desktopCardColumns": 2,
|
|
11
|
+
"state": "credential-free-mock"
|
|
12
|
+
},
|
|
13
|
+
"screenshots": [
|
|
14
|
+
{
|
|
15
|
+
"path": "docs/screenshots/01-market-overview.jpg",
|
|
16
|
+
"sha256": "856dc020a285752f4cd4a1c1025df9ce68ace2cd90ee1aa06c6b0699c78763f6",
|
|
17
|
+
"width": 1280,
|
|
18
|
+
"height": 720
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"path": "docs/screenshots/02-connector-detail.jpg",
|
|
22
|
+
"sha256": "0e15a26bbd21f8587b6354174d6d3411a6487e7a2df45d20c89f396b26f2ef65",
|
|
23
|
+
"width": 1280,
|
|
24
|
+
"height": 720
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"path": "docs/screenshots/03-tool-discovery.jpg",
|
|
28
|
+
"sha256": "ca1eccf06506c829fc23212eee39306e64c5781da9c1eff959d4b597d5df2f97",
|
|
29
|
+
"width": 1280,
|
|
30
|
+
"height": 720
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"path": "docs/screenshots/04-json-import.jpg",
|
|
34
|
+
"sha256": "2619ae8ba8f5d40131c6dfa2a367ee5ee64b8fee7782e5f4eddebd2a1cc79934",
|
|
35
|
+
"width": 1280,
|
|
36
|
+
"height": 720
|
|
37
|
+
}
|
|
38
|
+
],
|
|
39
|
+
"demo": {
|
|
40
|
+
"path": "docs/demo.gif",
|
|
41
|
+
"sha256": "4fa49853df79faa1c53d28938d79dd43bde3603712ecdc2e3b62d93a4c219d9a",
|
|
42
|
+
"width": 960,
|
|
43
|
+
"height": 540,
|
|
44
|
+
"durationSeconds": 16
|
|
45
|
+
}
|
|
46
|
+
}
|
package/lib/client.js
CHANGED
|
@@ -135,6 +135,29 @@ window.__ModuleLoader__.load({
|
|
|
135
135
|
gap: 6px;
|
|
136
136
|
min-width: 0;
|
|
137
137
|
}
|
|
138
|
+
.mcpConnectorManualUpdate {
|
|
139
|
+
display: flex;
|
|
140
|
+
align-items: center;
|
|
141
|
+
gap: 6px;
|
|
142
|
+
min-width: 0;
|
|
143
|
+
flex: 1 1 360px;
|
|
144
|
+
}
|
|
145
|
+
.mcpConnectorManualCommand {
|
|
146
|
+
box-sizing: border-box;
|
|
147
|
+
min-width: 0;
|
|
148
|
+
max-width: 430px;
|
|
149
|
+
overflow-x: auto;
|
|
150
|
+
padding: 5px 8px;
|
|
151
|
+
color: #374151;
|
|
152
|
+
background: #f9fafb;
|
|
153
|
+
border: 1px solid #d1d5db;
|
|
154
|
+
border-radius: 8px;
|
|
155
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
|
156
|
+
font-size: 11px;
|
|
157
|
+
line-height: 1.35;
|
|
158
|
+
white-space: nowrap;
|
|
159
|
+
user-select: text;
|
|
160
|
+
}
|
|
138
161
|
.mcpConnectorUpdateStatus {
|
|
139
162
|
max-width: 240px;
|
|
140
163
|
overflow: hidden;
|
|
@@ -175,6 +198,7 @@ window.__ModuleLoader__.load({
|
|
|
175
198
|
.mcpConnectorUpdateButton:focus-visible { background: #3730a3; }
|
|
176
199
|
.mcpConnectorUpdateStatus { color: #bbf7d0; background: #14532d; }
|
|
177
200
|
.mcpConnectorUpdateStatus[data-tone="error"] { color: #fecaca; background: #7f1d1d; }
|
|
201
|
+
.mcpConnectorManualCommand { color: #e5e7eb; background: #111827; border-color: #4b5563; }
|
|
178
202
|
.mcpConnectorUpdateSecondary { color: #d1d5db; background: transparent; border-color: #4b5563; }
|
|
179
203
|
.mcpConnectorMarketClose { color: #c4c8d0; }
|
|
180
204
|
.mcpConnectorMarketClose:hover,
|
|
@@ -361,7 +385,8 @@ window.__ModuleLoader__.load({
|
|
|
361
385
|
const labels = {
|
|
362
386
|
AGENTS_RUNNING: "有任务正在运行,请结束后重试",
|
|
363
387
|
OPERATION_BUSY: "插件市场正在处理其他任务",
|
|
364
|
-
RELEASE_TOO_FRESH: "
|
|
388
|
+
RELEASE_TOO_FRESH: "新版本处于发布安全等待期(约 24 小时)",
|
|
389
|
+
MIRROR_SYNC_PENDING: "镜像尚未同步完整安装包",
|
|
365
390
|
VERSION_UNCHANGED: "下载后版本未变化",
|
|
366
391
|
DOWNGRADE_DETECTED: "已阻止版本降级",
|
|
367
392
|
RESOLVED_VERSION_MISMATCH: "下载版本与预期不一致",
|
|
@@ -373,6 +398,21 @@ window.__ModuleLoader__.load({
|
|
|
373
398
|
return labels[failure?.code] ?? failure?.message ?? "更新失败";
|
|
374
399
|
}
|
|
375
400
|
|
|
401
|
+
function manualUpgradeCommand(version) {
|
|
402
|
+
const parsed = parseClientVersion(version);
|
|
403
|
+
if (parsed === null) return null;
|
|
404
|
+
return `dsh plugin --profile web add --config.minimumReleaseAge=0 ${PLUGIN_PACKAGE_NAME}@${parsed.normalized}`;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
async function copyManualUpgradeCommand(command) {
|
|
408
|
+
if (typeof window.navigator?.clipboard?.writeText === "function") {
|
|
409
|
+
await window.navigator.clipboard.writeText(command);
|
|
410
|
+
return true;
|
|
411
|
+
}
|
|
412
|
+
window.prompt?.("请复制以下升级命令", command);
|
|
413
|
+
return false;
|
|
414
|
+
}
|
|
415
|
+
|
|
376
416
|
function parseClientVersion(value) {
|
|
377
417
|
if (typeof value !== "string") return null;
|
|
378
418
|
const normalized = value.trim().replace(/^v/i, "");
|
|
@@ -530,6 +570,7 @@ window.__ModuleLoader__.load({
|
|
|
530
570
|
const [updateStarting, setUpdateStarting] = (0, react.useState)(false);
|
|
531
571
|
const [rollbackRunning, setRollbackRunning] = (0, react.useState)(false);
|
|
532
572
|
const [restarting, setRestarting] = (0, react.useState)(false);
|
|
573
|
+
const [manualCommandCopied, setManualCommandCopied] = (0, react.useState)(false);
|
|
533
574
|
const frameRef = (0, react.useRef)(null);
|
|
534
575
|
const closeRef = (0, react.useRef)(null);
|
|
535
576
|
(0, react.useEffect)(() => {
|
|
@@ -600,6 +641,9 @@ window.__ModuleLoader__.load({
|
|
|
600
641
|
window.clearTimeout(pollTimer);
|
|
601
642
|
};
|
|
602
643
|
}, [open]);
|
|
644
|
+
(0, react.useEffect)(() => {
|
|
645
|
+
if (open) setManualCommandCopied(false);
|
|
646
|
+
}, [open, versionStatus?.latestVersion]);
|
|
603
647
|
(0, react.useEffect)(() => {
|
|
604
648
|
if (!open) return void 0;
|
|
605
649
|
let disposed = false;
|
|
@@ -788,7 +832,7 @@ window.__ModuleLoader__.load({
|
|
|
788
832
|
type: "button",
|
|
789
833
|
className: "mcpConnectorUpdateButton",
|
|
790
834
|
onClick: () => startUpdate(force),
|
|
791
|
-
children: force ? "强制重试" : "重试更新"
|
|
835
|
+
children: updateOperation.failure?.code === "RELEASE_TOO_FRESH" ? "立即更新(跳过等待)" : force ? "强制重试" : "重试更新"
|
|
792
836
|
}),
|
|
793
837
|
rollbackRunning && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
794
838
|
className: "mcpConnectorUpdateStatus",
|
|
@@ -887,12 +931,43 @@ window.__ModuleLoader__.load({
|
|
|
887
931
|
children: `一键更新到 v${providerUpdateCheck.latestVersion}`
|
|
888
932
|
});
|
|
889
933
|
}
|
|
934
|
+
const command = manualUpgradeCommand(versionStatus?.latestVersion);
|
|
935
|
+
if (command !== null) {
|
|
936
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
937
|
+
className: "mcpConnectorManualUpdate",
|
|
938
|
+
children: [
|
|
939
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
|
|
940
|
+
className: "mcpConnectorManualCommand",
|
|
941
|
+
title: command,
|
|
942
|
+
children: command
|
|
943
|
+
}),
|
|
944
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
945
|
+
type: "button",
|
|
946
|
+
className: "mcpConnectorUpdateButton",
|
|
947
|
+
onClick: () => {
|
|
948
|
+
copyManualUpgradeCommand(command).then((copied) => {
|
|
949
|
+
if (copied) setManualCommandCopied(true);
|
|
950
|
+
}, (error) => {
|
|
951
|
+
console.warn("[mcp-connector] copy upgrade command failed:", error);
|
|
952
|
+
window.prompt?.("请复制以下升级命令", command);
|
|
953
|
+
});
|
|
954
|
+
},
|
|
955
|
+
children: manualCommandCopied ? "已复制" : "复制升级命令"
|
|
956
|
+
}),
|
|
957
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
958
|
+
type: "button",
|
|
959
|
+
className: "mcpConnectorUpdateButton mcpConnectorUpdateSecondary",
|
|
960
|
+
onClick: () => window.open(NPM_PACKAGE_URL, "_blank", "noopener,noreferrer"),
|
|
961
|
+
children: "查看 npm"
|
|
962
|
+
})
|
|
963
|
+
]
|
|
964
|
+
});
|
|
965
|
+
}
|
|
890
966
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
891
967
|
type: "button",
|
|
892
968
|
className: "mcpConnectorUpdateButton",
|
|
893
|
-
title: `npm 已发布 v${versionStatus?.latestVersion}`,
|
|
894
969
|
onClick: () => openDshPluginMarket(actions),
|
|
895
|
-
children:
|
|
970
|
+
children: "查看更新方式"
|
|
896
971
|
});
|
|
897
972
|
};
|
|
898
973
|
const src = window.location.origin + "/mcp-connector/ui/";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-mcp-connector",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.30",
|
|
4
4
|
"description": "Connect and manage MCP servers in DeepSeek Harness — a universal MCP connector and marketplace with OAuth 2.0 PKCE, API keys, stdio/HTTP, mcpServers JSON import, tools, and prompts. Maintained by Qichacha/QCC.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -20,11 +20,14 @@
|
|
|
20
20
|
"docs/DESKTOP-E2E.md",
|
|
21
21
|
"docs/MARKET-REGISTRATION.md",
|
|
22
22
|
"docs/PLUGIN-UPDATE.md",
|
|
23
|
+
"docs/FIRST-CONTRIBUTION.md",
|
|
23
24
|
"docs/STDIO-SUPPORT.md",
|
|
24
25
|
"docs/USER-GUIDE.md",
|
|
26
|
+
"docs/screenshots",
|
|
25
27
|
"cordis.patch.yml",
|
|
26
28
|
"README.md",
|
|
27
29
|
"README.en.md",
|
|
30
|
+
"screenshots.json",
|
|
28
31
|
"CONTRIBUTING.md",
|
|
29
32
|
"CHANGELOG.md",
|
|
30
33
|
"LICENSE",
|
|
@@ -35,15 +38,20 @@
|
|
|
35
38
|
],
|
|
36
39
|
"scripts": {
|
|
37
40
|
"test": "node --test",
|
|
38
|
-
"lint": "node --check lib/index.js && node --check lib/web.js && node --check lib/client.js && node --check lib/version-status.js && node --check lib/schema.js && node --check lib/catalog.js && node --check lib/prompts.js && node --check lib/probe.js && node --check lib/mcp-validation.js && node --check lib/mcp-http.js && node --check lib/migration.js && node --check lib/stores.js && node --check lib/grant-journal.js && node --check lib/oauth.js && node --check lib/grant-lifecycle.js && node --check lib/callback-server.js && node --check lib/mcp-provision.js && node --check lib/util.js && node --check lib/constants.js && node --check lib/tools.js && node --check lib/connectors/oauth-connector.js && node --check lib/connectors/manual-connector.js && node --check lib/connectors/json-connector.js && node --check scripts/probe-connector.mjs && node --check scripts/build-registry.mjs && node --check scripts/ui-harness.mjs && node --check scripts/check-market-registration.mjs && node --check scripts/check-readme-version.mjs && node --check scripts/sync-registry-stats.mjs",
|
|
41
|
+
"lint": "node --check lib/index.js && node --check lib/web.js && node --check lib/client.js && node --check lib/version-status.js && node --check lib/schema.js && node --check lib/catalog.js && node --check lib/prompts.js && node --check lib/probe.js && node --check lib/mcp-validation.js && node --check lib/mcp-http.js && node --check lib/migration.js && node --check lib/stores.js && node --check lib/grant-journal.js && node --check lib/oauth.js && node --check lib/grant-lifecycle.js && node --check lib/callback-server.js && node --check lib/mcp-provision.js && node --check lib/util.js && node --check lib/constants.js && node --check lib/tools.js && node --check lib/connectors/oauth-connector.js && node --check lib/connectors/manual-connector.js && node --check lib/connectors/json-connector.js && node --check scripts/probe-connector.mjs && node --check scripts/build-registry.mjs && node --check scripts/ui-harness.mjs && node --check scripts/check-market-registration.mjs && node --check scripts/check-readme-version.mjs && node --check scripts/check-marketing-metadata.mjs && node --check scripts/check-storefront-screenshots.mjs && node --check scripts/sync-registry-stats.mjs",
|
|
39
42
|
"registry:build": "node scripts/build-registry.mjs",
|
|
40
43
|
"registry:validate": "node scripts/probe-connector.mjs catalog/catalog.json --validate-only",
|
|
41
44
|
"dev:ui": "node scripts/ui-harness.mjs",
|
|
42
45
|
"market:check": "node scripts/check-market-registration.mjs",
|
|
43
46
|
"registry:stats:sync": "node scripts/sync-registry-stats.mjs",
|
|
44
47
|
"docs:check": "node scripts/check-readme-version.mjs",
|
|
48
|
+
"marketing:check": "node scripts/check-marketing-metadata.mjs",
|
|
49
|
+
"marketing:check:github": "node scripts/check-marketing-metadata.mjs --live-github",
|
|
50
|
+
"marketing:check:npm": "node scripts/check-marketing-metadata.mjs --live-npm",
|
|
51
|
+
"marketing:check:live": "node scripts/check-marketing-metadata.mjs --live",
|
|
52
|
+
"storefront:check": "node scripts/check-storefront-screenshots.mjs",
|
|
45
53
|
"verify-pack": "node scripts/verify-pack.mjs",
|
|
46
|
-
"check": "npm run lint && npm run docs:check && npm test && npm run verify-pack",
|
|
54
|
+
"check": "npm run lint && npm run docs:check && npm run marketing:check && npm run storefront:check && npm test && npm run verify-pack",
|
|
47
55
|
"prepublishOnly": "npm run check"
|
|
48
56
|
},
|
|
49
57
|
"keywords": [
|
|
@@ -66,6 +74,7 @@
|
|
|
66
74
|
"mcp-store",
|
|
67
75
|
"remote-mcp",
|
|
68
76
|
"streamable-http",
|
|
77
|
+
"stdio",
|
|
69
78
|
"connector",
|
|
70
79
|
"connection",
|
|
71
80
|
"connection-manager",
|
package/screenshots.json
ADDED
package/scripts/ui-harness.mjs
CHANGED
|
@@ -5,12 +5,25 @@ import { readFile } from 'node:fs/promises';
|
|
|
5
5
|
import { dirname, join } from 'node:path';
|
|
6
6
|
import { fileURLToPath } from 'node:url';
|
|
7
7
|
import { normalizeConnectorDescriptor } from '../lib/schema.js';
|
|
8
|
+
import { auditDescriptor, auditRawDescriptor, mergeCatalog } from '../lib/catalog.js';
|
|
8
9
|
|
|
9
10
|
const root = join(dirname(fileURLToPath(import.meta.url)), '..');
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const
|
|
11
|
+
const packageJson = JSON.parse(await readFile(join(root, 'package.json'), 'utf8'));
|
|
12
|
+
|
|
13
|
+
async function loadCatalogFile(path) {
|
|
14
|
+
const document = JSON.parse(await readFile(path, 'utf8'));
|
|
15
|
+
const items = Array.isArray(document) ? document : document.connectors ?? [];
|
|
16
|
+
return items.map((item) => auditDescriptor(normalizeConnectorDescriptor(auditRawDescriptor(item))));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const catalogSources = [await loadCatalogFile(join(root, 'catalog/catalog.json'))];
|
|
20
|
+
if (process.env.MCP_CONNECTOR_UI_CATALOG_PATH) {
|
|
21
|
+
catalogSources.push(await loadCatalogFile(process.env.MCP_CONNECTOR_UI_CATALOG_PATH));
|
|
22
|
+
}
|
|
23
|
+
const catalog = mergeCatalog(catalogSources).filter((item) => item.published !== false);
|
|
24
|
+
|
|
25
|
+
// A fresh harness never claims a real authorization. Tests may connect to the mock API explicitly.
|
|
26
|
+
const connected = new Set();
|
|
14
27
|
const healthStates = new Map();
|
|
15
28
|
const bundledAssets = new Map([
|
|
16
29
|
['qcc-logo.svg', 'image/svg+xml'],
|
|
@@ -24,8 +37,40 @@ function json(res, value, status = 200) {
|
|
|
24
37
|
res.end(body);
|
|
25
38
|
}
|
|
26
39
|
|
|
40
|
+
function captureShell() {
|
|
41
|
+
return `<!doctype html>
|
|
42
|
+
<html lang="zh-CN">
|
|
43
|
+
<head>
|
|
44
|
+
<meta charset="utf-8" />
|
|
45
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
46
|
+
<title>MCP连接器 · 无凭据验收环境</title>
|
|
47
|
+
<style>
|
|
48
|
+
* { box-sizing: border-box; }
|
|
49
|
+
html, body { width: 100%; height: 100%; margin: 0; }
|
|
50
|
+
body { display: flex; align-items: center; justify-content: center; background: #e5e7eb; font: 14px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", sans-serif; }
|
|
51
|
+
.capture-panel { width: min(800px, 90vw); height: min(800px, 85vh); display: flex; flex-direction: column; overflow: hidden; border-radius: 16px; background: #fff; box-shadow: 0 20px 60px rgba(0,0,0,.18); }
|
|
52
|
+
.capture-header { min-height: 64px; display: flex; align-items: center; gap: 10px; padding: 16px 24px; border-bottom: 1px solid #e5e7eb; color: #111827; }
|
|
53
|
+
.capture-title { font-size: 18px; font-weight: 650; }
|
|
54
|
+
.capture-version, .capture-state { padding: 2px 8px; border-radius: 999px; background: #f3f4f6; color: #6b7280; font-size: 12px; font-weight: 600; }
|
|
55
|
+
.capture-state { margin-left: auto; color: #047857; background: #ecfdf5; }
|
|
56
|
+
iframe { flex: 1; width: 100%; min-height: 0; border: 0; background: transparent; }
|
|
57
|
+
</style>
|
|
58
|
+
</head>
|
|
59
|
+
<body>
|
|
60
|
+
<section class="capture-panel" aria-label="MCP连接器产品面板">
|
|
61
|
+
<header class="capture-header"><span aria-hidden="true">🧩</span><span class="capture-title">MCP连接器</span><span class="capture-version">v${packageJson.version}</span><span class="capture-state">无凭据 Mock</span></header>
|
|
62
|
+
<iframe src="/mcp-connector/ui/" title="MCP连接器"></iframe>
|
|
63
|
+
</section>
|
|
64
|
+
</body>
|
|
65
|
+
</html>`;
|
|
66
|
+
}
|
|
67
|
+
|
|
27
68
|
const server = createServer(async (req, res) => {
|
|
28
|
-
if (req.method === 'GET' &&
|
|
69
|
+
if (req.method === 'GET' && req.url === '/') {
|
|
70
|
+
const body = Buffer.from(captureShell());
|
|
71
|
+
res.writeHead(200, { 'content-type': 'text/html; charset=utf-8', 'content-length': body.byteLength }); res.end(body); return;
|
|
72
|
+
}
|
|
73
|
+
if (req.method === 'GET' && req.url === '/mcp-connector/ui/') {
|
|
29
74
|
const body = await readFile(join(root, 'ui/index.html'));
|
|
30
75
|
res.writeHead(200, { 'content-type': 'text/html; charset=utf-8' }); res.end(body); return;
|
|
31
76
|
}
|
|
@@ -52,12 +97,30 @@ const server = createServer(async (req, res) => {
|
|
|
52
97
|
connectionLabel: healthStates.get(item.id) === 'healthy' ? '已连接' : connected.has(item.id) ? '已配置' : '未连接',
|
|
53
98
|
})) } }); return;
|
|
54
99
|
}
|
|
55
|
-
if (method === 'status') {
|
|
100
|
+
if (method === 'status') {
|
|
101
|
+
const items = catalog.filter((item) => connected.has(item.id)).flatMap((item) => item.servers.map((server) => ({
|
|
102
|
+
key: `${item.id}:${server.serverKey}`,
|
|
103
|
+
connectorId: item.id,
|
|
104
|
+
name: item.name,
|
|
105
|
+
serverName: server.serverName,
|
|
106
|
+
endpoint: server.url || server.command || '本地 Mock',
|
|
107
|
+
authMode: item.auth.mode === 'oauth2-pkce' ? 'oauth' : item.auth.mode,
|
|
108
|
+
enabled: true,
|
|
109
|
+
connectionState: healthStates.get(item.id) ?? 'configured',
|
|
110
|
+
})));
|
|
111
|
+
json(res, { ok: true, detail: { items } }); return;
|
|
112
|
+
}
|
|
56
113
|
if (method === 'migrationPreview') { json(res, { ok: true, detail: { pendingCount: 0, items: [] } }); return; }
|
|
57
114
|
if (method === 'toolsList') {
|
|
58
|
-
const
|
|
115
|
+
const connector = catalog.find((item) => item.id === params.connectorId);
|
|
116
|
+
const server = connector?.servers?.[0] ?? { serverKey: 'mock', serverName: 'mock-server' };
|
|
117
|
+
const tools = Array.from({ length: 125 }, (_, index) => ({
|
|
118
|
+
name: `mock_tool_${String(index + 1).padStart(3, '0')}`,
|
|
119
|
+
title: `Mock 工具 ${index + 1}`,
|
|
120
|
+
description: `本地无凭据 UI 验收数据:用于验证分批渲染与搜索的第 ${index + 1} 个工具。`,
|
|
121
|
+
}));
|
|
59
122
|
healthStates.set(params.connectorId, 'healthy');
|
|
60
|
-
json(res, { ok: true, detail: { totalTools: tools.length, connectionState: 'healthy', servers: [{ serverKey:
|
|
123
|
+
json(res, { ok: true, detail: { totalTools: tools.length, connectionState: 'healthy', servers: [{ serverKey: server.serverKey, serverName: server.serverName, ok: true, tools }] } }); return;
|
|
61
124
|
}
|
|
62
125
|
if (method === 'healthCheck') {
|
|
63
126
|
const ids = params.connectorId ? [params.connectorId] : [...connected];
|
package/ui/index.html
CHANGED
|
@@ -133,7 +133,7 @@
|
|
|
133
133
|
.market-section-toggle { border: 0; background: transparent; color: var(--text-2); cursor: pointer; font: inherit; font-size: 12px; padding: 4px 0; }
|
|
134
134
|
.market-section-toggle:hover { color: var(--accent); }
|
|
135
135
|
|
|
136
|
-
/* Grid -
|
|
136
|
+
/* Grid - 产品 800px 面板为两列;更宽容器可自适应增加列数 */
|
|
137
137
|
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 12px; }
|
|
138
138
|
|
|
139
139
|
/* Card - TraeWork 风格:标题上移,描述 2 行 */
|
|
@@ -203,6 +203,13 @@
|
|
|
203
203
|
.migration-banner { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; padding: 12px 14px; border: 1px solid #fbbf24; background: var(--warn-bg); border-radius: 10px; color: var(--text-2); }
|
|
204
204
|
.migration-banner .copy { flex: 1; min-width: 0; font-size: 12px; }
|
|
205
205
|
.migration-banner strong { display: block; color: var(--text); font-size: 13px; }
|
|
206
|
+
.community-cta { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 16px; padding: 10px 12px; border: 1px solid var(--line); background: var(--card); border-radius: 10px; color: var(--muted); font-size: 12px; }
|
|
207
|
+
.community-cta .copy { flex: 1; min-width: 0; }
|
|
208
|
+
.community-cta a { color: var(--accent); text-decoration: none; white-space: nowrap; }
|
|
209
|
+
.community-cta a:hover { text-decoration: underline; }
|
|
210
|
+
.community-cta-close { border: 0; background: transparent; color: var(--muted); cursor: pointer; font: inherit; font-size: 16px; line-height: 1; padding: 2px 4px; }
|
|
211
|
+
.community-cta-close:hover { color: var(--text); }
|
|
212
|
+
.community-cta-close:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }
|
|
206
213
|
|
|
207
214
|
/* Detail Overlay */
|
|
208
215
|
.detail-overlay {
|
|
@@ -514,6 +521,8 @@
|
|
|
514
521
|
let promptRequestId = null;
|
|
515
522
|
let promptRequestTimer = null;
|
|
516
523
|
let initialHealthCheckStarted = false;
|
|
524
|
+
let communityCtaEligible = false;
|
|
525
|
+
let communityCtaDismissed = false;
|
|
517
526
|
|
|
518
527
|
async function call(method, params, { timeoutMs: timeoutOverride } = {}) {
|
|
519
528
|
const controller = new AbortController();
|
|
@@ -781,6 +790,21 @@
|
|
|
781
790
|
node.setAttribute('aria-label', Number.isFinite(count) ? `${count} 个` : '');
|
|
782
791
|
}
|
|
783
792
|
|
|
793
|
+
function communityCtaHtml() {
|
|
794
|
+
if (!communityCtaEligible || communityCtaDismissed) return '';
|
|
795
|
+
return `<aside class="community-cta" aria-label="MCP连接器社区入口"><span class="copy">连接顺利?如果 MCP连接器对你有帮助,欢迎支持或一起改进。</span><a href="https://github.com/duhu2000/dsh-mcp-connector/stargazers" target="_blank" rel="noopener noreferrer">Star</a><a href="https://github.com/duhu2000/dsh-mcp-connector-registry/blob/main/docs/ONBOARDING.md" target="_blank" rel="noopener noreferrer">提交连接器</a><a href="https://github.com/duhu2000/dsh-mcp-connector/blob/main/CONTRIBUTING.md" target="_blank" rel="noopener noreferrer">参与贡献</a><button class="community-cta-close" type="button" onclick="window.__mcp.dismissCommunityCta()" aria-label="关闭社区入口" title="本次不再显示">×</button></aside>`;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
function markCommunityCtaEligible() {
|
|
799
|
+
if (!communityCtaDismissed) communityCtaEligible = true;
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
function dismissCommunityCta() {
|
|
803
|
+
communityCtaDismissed = true;
|
|
804
|
+
communityCtaEligible = false;
|
|
805
|
+
document.querySelector('.community-cta')?.remove();
|
|
806
|
+
}
|
|
807
|
+
|
|
784
808
|
function marketSectionHtml(value, label, items) {
|
|
785
809
|
if (!items.length) return '';
|
|
786
810
|
const expanded = expandedMarketSections.has(value);
|
|
@@ -880,8 +904,9 @@
|
|
|
880
904
|
const pendingMigration = migration.ok ? migration.detail?.pendingCount || 0 : 0;
|
|
881
905
|
const migrationHtml = pendingMigration > 0 ? `<div class="migration-banner"><div class="copy"><strong>发现旧企查查 MCP 授权</strong>可安全复制 ${pendingMigration} 组授权到 MCP连接器;不会删除旧插件或原凭据。</div><button class="btn" type="button" onclick="window.__mcp.migrateLegacy()">迁移</button></div>` : '';
|
|
882
906
|
if (!items.length) { main.innerHTML = `${migrationHtml}<div class="stats"><span class="count">可从旧企查查 OAuth 插件复制已有授权</span><button class="btn ghost" type="button" onclick="window.__mcp.scanLegacy()">检测旧插件</button></div><div class="empty">还没有连接任何 MCP · 到「市场」里连接一个吧</div>`; return; }
|
|
907
|
+
markCommunityCtaEligible();
|
|
883
908
|
const filtered = items.filter(matchesSearch);
|
|
884
|
-
main.innerHTML = `${migrationHtml}<div class="stats"><span class="count">共 <strong>${filtered.length}</strong> 条连接${searchQuery ? ` · 搜索「${esc(searchQuery)}」` : ''} · 停用后工具立即下线,断开会撤销 OAuth 授权</span><button class="btn ghost" type="button" onclick="window.__mcp.scanLegacy()">检测旧插件</button></div><div class="rows">${filtered.map(rowHtml).join('')}</div
|
|
909
|
+
main.innerHTML = `${migrationHtml}<div class="stats"><span class="count">共 <strong>${filtered.length}</strong> 条连接${searchQuery ? ` · 搜索「${esc(searchQuery)}」` : ''} · 停用后工具立即下线,断开会撤销 OAuth 授权</span><button class="btn ghost" type="button" onclick="window.__mcp.scanLegacy()">检测旧插件</button></div><div class="rows">${filtered.map(rowHtml).join('')}</div>${communityCtaHtml()}`;
|
|
885
910
|
}
|
|
886
911
|
|
|
887
912
|
function rowHtml(r) {
|
|
@@ -1066,10 +1091,12 @@
|
|
|
1066
1091
|
const r = await call('connect', { connectorId }, { timeoutMs });
|
|
1067
1092
|
showToast(r.message, r.ok);
|
|
1068
1093
|
if (r.ok) {
|
|
1094
|
+
markCommunityCtaEligible();
|
|
1069
1095
|
await call('healthCheck', { connectorId });
|
|
1070
1096
|
await refresh();
|
|
1071
1097
|
}
|
|
1072
1098
|
},
|
|
1099
|
+
dismissCommunityCta() { dismissCommunityCta(); },
|
|
1073
1100
|
toggle(key, enabled) {
|
|
1074
1101
|
call('setEnabled', { key, enabled }).then((r) => showToast(r.message, r.ok));
|
|
1075
1102
|
},
|
|
@@ -1126,6 +1153,7 @@
|
|
|
1126
1153
|
const configuredFromDetail = detailConnector?.id === connectorId && $('#detail-overlay').classList.contains('active');
|
|
1127
1154
|
closeModal();
|
|
1128
1155
|
if (configuredFromDetail) closeDetail();
|
|
1156
|
+
markCommunityCtaEligible();
|
|
1129
1157
|
showToast(r.message, true); await refresh();
|
|
1130
1158
|
return;
|
|
1131
1159
|
}
|
|
@@ -1159,6 +1187,7 @@
|
|
|
1159
1187
|
});
|
|
1160
1188
|
setModalBusy(false);
|
|
1161
1189
|
if (!r.ok) { showModalError(r.message); return; }
|
|
1190
|
+
markCommunityCtaEligible();
|
|
1162
1191
|
closeModal(); showToast(r.message, true); await refresh();
|
|
1163
1192
|
},
|
|
1164
1193
|
async submitImport() {
|
|
@@ -1175,6 +1204,7 @@
|
|
|
1175
1204
|
const r = await call('importJson', { json });
|
|
1176
1205
|
setModalBusy(false);
|
|
1177
1206
|
if (!r.ok) { showModalError(r.message); return; }
|
|
1207
|
+
markCommunityCtaEligible();
|
|
1178
1208
|
closeModal(); showToast(r.message, true); view = 'installed'; syncTabs(); await refresh();
|
|
1179
1209
|
},
|
|
1180
1210
|
async submitUrl() {
|
|
@@ -1184,6 +1214,7 @@
|
|
|
1184
1214
|
const r = await call('installFromUrl', { url });
|
|
1185
1215
|
setModalBusy(false);
|
|
1186
1216
|
if (!r.ok) { showModalError(r.message); return; }
|
|
1217
|
+
markCommunityCtaEligible();
|
|
1187
1218
|
closeModal(); showToast(r.message, true); await refresh();
|
|
1188
1219
|
},
|
|
1189
1220
|
async migrateLegacy() {
|
|
@@ -1348,6 +1379,7 @@
|
|
|
1348
1379
|
const r = await call('connect', { connectorId: id }, { timeoutMs: 310_000 });
|
|
1349
1380
|
showToast(r.message, r.ok);
|
|
1350
1381
|
if (r.ok) {
|
|
1382
|
+
markCommunityCtaEligible();
|
|
1351
1383
|
await call('healthCheck', { connectorId: id });
|
|
1352
1384
|
closeDetail();
|
|
1353
1385
|
await refresh();
|
|
@@ -1367,7 +1399,7 @@
|
|
|
1367
1399
|
}
|
|
1368
1400
|
const r = await call('connect', { connectorId: id });
|
|
1369
1401
|
showToast(r.message, r.ok);
|
|
1370
|
-
if (r.ok) { closeDetail(); await refresh(); }
|
|
1402
|
+
if (r.ok) { markCommunityCtaEligible(); closeDetail(); await refresh(); }
|
|
1371
1403
|
return;
|
|
1372
1404
|
}
|
|
1373
1405
|
const prompt = detailPrompts[promptPage * PROMPT_PAGE_SIZE];
|