Skip to content

Commit 7c1df91

Browse files
authored
Merge pull request Stack-Cairn#143 from 24baigei/feat/mcp-hub-local-import
feat(mcp-hub): add local import from Claude Code / Codex / Claude Des…
2 parents 11a9834 + 414c9e3 commit 7c1df91

15 files changed

Lines changed: 1492 additions & 8 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/agent-gateway/web/src/i18n/config.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1503,6 +1503,20 @@ export const translations: Record<Locale, Record<string, string>> = {
15031503
"mcpHub.add": "添加",
15041504
"mcpHub.tabInstalled": "已配置",
15051505
"mcpHub.tabStore": "MCP Store",
1506+
"mcpHub.tabImport": "本地导入",
1507+
"mcpHub.importRescan": "重新扫描",
1508+
"mcpHub.importButton": "导入",
1509+
"mcpHub.importScanning": "正在扫描本机其它工具的 MCP 配置…",
1510+
"mcpHub.importScanFailed": "扫描失败",
1511+
"mcpHub.importNotDetected": "未检测到",
1512+
"mcpHub.importEmpty": "该工具没有配置 MCP Server",
1513+
"mcpHub.importAlreadyImported": "已导入",
1514+
"mcpHub.importSelectAll": "全选",
1515+
"mcpHub.importDeselectAll": "取消全选",
1516+
"mcpHub.importSelectedCount": "已选 {selected} / {total}",
1517+
"mcpHub.importDone": "已导入 {count} 个 MCP Server",
1518+
"mcpHub.importOriginProject": "项目级",
1519+
"mcpHub.importUnparsable": "{count} 条配置无法解析",
15061520
"mcpHub.statusReady": "MCP 已就绪",
15071521
"mcpHub.statusEmpty": "暂未配置 MCP",
15081522
"mcpHub.statusEmptyDesc": "添加本地 MCP 或从 Store 一键安装来扩展能力",
@@ -3359,6 +3373,20 @@ export const translations: Record<Locale, Record<string, string>> = {
33593373
"mcpHub.add": "Add",
33603374
"mcpHub.tabInstalled": "Installed",
33613375
"mcpHub.tabStore": "MCP Store",
3376+
"mcpHub.tabImport": "Local Import",
3377+
"mcpHub.importRescan": "Rescan",
3378+
"mcpHub.importButton": "Import",
3379+
"mcpHub.importScanning": "Scanning MCP configs from other local tools…",
3380+
"mcpHub.importScanFailed": "Scan failed",
3381+
"mcpHub.importNotDetected": "Not detected",
3382+
"mcpHub.importEmpty": "No MCP servers configured for this tool",
3383+
"mcpHub.importAlreadyImported": "Imported",
3384+
"mcpHub.importSelectAll": "Select all",
3385+
"mcpHub.importDeselectAll": "Deselect all",
3386+
"mcpHub.importSelectedCount": "Selected {selected} / {total}",
3387+
"mcpHub.importDone": "Imported {count} MCP servers",
3388+
"mcpHub.importOriginProject": "Project",
3389+
"mcpHub.importUnparsable": "{count} entries could not be parsed",
33623390
"mcpHub.statusReady": "MCP ready",
33633391
"mcpHub.statusEmpty": "No MCP configured",
33643392
"mcpHub.statusEmptyDesc": "Add a local MCP or install from the Store to extend capabilities",

crates/agent-gateway/web/src/lib/skills/index.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ type SystemManageSkillResponse = {
149149
clawhubSlug?: string | null;
150150
clawhubDownloadUrl?: string | null;
151151
external?: ExternalToolScan[] | null;
152+
externalMcp?: ExternalMcpToolScan[] | null;
152153
};
153154

154155
export type ExternalSkillEntry = {
@@ -167,6 +168,28 @@ export type ExternalToolScan = {
167168
errors: string[];
168169
};
169170

171+
export type ExternalMcpServerEntry = {
172+
id: string;
173+
transport: "stdio" | "http" | "sse";
174+
command: string;
175+
args: string[];
176+
url: string;
177+
env: Record<string, string>;
178+
headers: Record<string, string>;
179+
cwd?: string | null;
180+
timeoutMs?: number | null;
181+
/** 来源作用域:"user" 或项目路径(Claude Code 的项目级配置) */
182+
origin: string;
183+
};
184+
185+
export type ExternalMcpToolScan = {
186+
tool: string;
187+
configPath: string;
188+
exists: boolean;
189+
servers: ExternalMcpServerEntry[];
190+
errors: string[];
191+
};
192+
170193
type DiscoverSkillsOptions = {
171194
force?: boolean;
172195
};
@@ -509,6 +532,11 @@ export async function scanExternalSkills(): Promise<ExternalToolScan[]> {
509532
return response.external ?? [];
510533
}
511534

535+
export async function scanExternalMcpServers(): Promise<ExternalMcpToolScan[]> {
536+
const response = await manageSkill({ action: "scan_external_mcp" });
537+
return response.externalMcp ?? [];
538+
}
539+
512540
export async function startSkillInstallJob(
513541
params: Record<string, unknown>,
514542
): Promise<SkillInstallJobSnapshot> {

crates/agent-gateway/web/src/pages/mcp-hub/McpHubPage.tsx

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { useState } from "react";
22
import { HubBackdrop, HubHeader } from "../../components/hub/HubChrome";
3-
import { Cable, Cloud, Plug, Plus, Server, Sparkles } from "../../components/icons";
3+
import { Cable, Cloud, Download, Plug, Plus, Server, Sparkles } from "../../components/icons";
44
import { Button } from "../../components/ui/button";
55
import { useLocale } from "../../i18n";
66
import { type AppSettings, type McpServerConfig, updateMcp } from "../../lib/settings";
77
import { cn } from "../../lib/shared/utils";
8+
import { McpImportView } from "./McpImportView";
89
import { McpRegistryBrowser } from "./McpRegistryBrowser";
910
import { McpServerEditModal, McpServersForm } from "./McpServersForm";
1011

@@ -16,7 +17,7 @@ type McpHubPageProps = {
1617
onOpenSidebar: () => void;
1718
};
1819

19-
type McpHubView = "installed" | "store";
20+
type McpHubView = "installed" | "store" | "import";
2021

2122
type EditingState = { mode: "add" } | { mode: "edit"; idx: number; server: McpServerConfig };
2223

@@ -151,6 +152,12 @@ export function McpHubPage(props: McpHubPageProps) {
151152
icon: Cloud,
152153
count: null,
153154
},
155+
{
156+
value: "import" as const,
157+
label: t("mcpHub.tabImport"),
158+
icon: Download,
159+
count: null,
160+
},
154161
].map((item) => {
155162
const Icon = item.icon;
156163
const active = view === item.value;
@@ -202,8 +209,10 @@ export function McpHubPage(props: McpHubPageProps) {
202209
onAddServer={openAdd}
203210
onEditServer={openEdit}
204211
/>
205-
) : (
212+
) : view === "store" ? (
206213
<McpRegistryBrowser settings={settings} setSettings={setSettings} />
214+
) : (
215+
<McpImportView settings={settings} setSettings={setSettings} />
207216
)}
208217
</div>
209218
</div>

0 commit comments

Comments
 (0)