♻️ refactor(ai): 拆分远程 MCP 快速配置面板

- 将 OpenClaw/Hermans 远程接入说明抽成独立展示组件

- 保留 schema-only、Bearer Token 和云端配置说明

- 补充远程快速配置渲染测试
This commit is contained in:
Syngnat
2026-06-11 19:28:38 +08:00
parent 8006844b9f
commit e6d2685521
3 changed files with 215 additions and 168 deletions

View File

@@ -7,10 +7,10 @@ import {
buildRemoteMCPClientQuickStart,
isMCPClientKey,
isRemoteMCPClientStatus,
REMOTE_MCP_PARAMETER_GUIDES,
type MCPClientKey,
} from '../../utils/mcpClientInstallStatus';
import type { OverlayWorkbenchTheme } from '../../utils/overlayWorkbenchTheme';
import AIMCPRemoteQuickStartPanel from './AIMCPRemoteQuickStartPanel';
import {
getMCPClientDetectionSummary,
getMCPClientInstallStateLabel,
@@ -296,173 +296,12 @@ const AIMCPClientInstallPanel: React.FC<AIMCPClientInstallPanelProps> = ({
</div>
)}
{remoteQuickStart && (
<div
style={{
padding: '12px 14px',
borderRadius: 12,
border: `1px solid ${darkMode ? 'rgba(56,189,248,0.2)' : 'rgba(14,165,233,0.18)'}`,
background: darkMode ? 'rgba(14,165,233,0.06)' : 'rgba(240,249,255,0.78)',
display: 'flex',
flexDirection: 'column',
gap: 10,
}}
>
<div style={{ fontWeight: 700, fontSize: 13, color: overlayTheme.titleText }}>
{remoteQuickStart.displayName} MCP
</div>
<div style={{ fontSize: 12, color: overlayTheme.mutedText, lineHeight: 1.7 }}>
Agent GUI/CLI Windows GoNavi 使 MCP URL Bearer Token schema-only
</div>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(210px, 1fr))', gap: 10 }}>
{REMOTE_MCP_PARAMETER_GUIDES.map((item) => (
<div
key={item.key}
style={{
padding: '10px 12px',
borderRadius: 10,
border: `1px solid ${cardBorder}`,
background: darkMode ? 'rgba(15,23,42,0.42)' : 'rgba(255,255,255,0.72)',
display: 'flex',
flexDirection: 'column',
gap: 5,
}}
>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8 }}>
<div style={{ fontWeight: 700, fontSize: 12, color: overlayTheme.titleText }}>
{item.title}
</div>
<span
style={{
padding: '2px 7px',
borderRadius: 999,
fontSize: 11,
color: item.required ? '#dc2626' : overlayTheme.mutedText,
background: item.required
? (darkMode ? 'rgba(248,113,113,0.12)' : 'rgba(254,226,226,0.7)')
: (darkMode ? 'rgba(255,255,255,0.06)' : 'rgba(15,23,42,0.05)'),
}}
>
{item.required ? '必填' : '可选'}
</span>
</div>
<div style={{ fontSize: 12, color: overlayTheme.titleText, lineHeight: 1.6 }}>
{item.fill}
</div>
<div style={{ fontSize: 12, color: overlayTheme.mutedText, lineHeight: 1.6 }}>
<code style={{ fontFamily: 'var(--gn-font-mono)' }}>{item.example}</code>
</div>
<div style={{ fontSize: 12, color: overlayTheme.mutedText, lineHeight: 1.6 }}>
{item.avoid}
</div>
</div>
))}
</div>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(260px, 1fr))', gap: 10 }}>
<div
style={{
padding: '10px 12px',
borderRadius: 10,
border: `1px solid ${cardBorder}`,
background: darkMode ? 'rgba(15,23,42,0.55)' : 'rgba(255,255,255,0.78)',
}}
>
<div style={{ fontWeight: 700, fontSize: 12, color: overlayTheme.titleText }}>
Agent
</div>
<code
style={{
display: 'block',
marginTop: 8,
fontFamily: 'var(--gn-font-mono)',
fontSize: 11,
color: overlayTheme.titleText,
whiteSpace: 'pre-wrap',
overflowWrap: 'anywhere',
}}
>
{remoteQuickStart.configJson}
</code>
</div>
<div
style={{
padding: '10px 12px',
borderRadius: 10,
border: `1px solid ${cardBorder}`,
background: darkMode ? 'rgba(15,23,42,0.55)' : 'rgba(255,255,255,0.78)',
}}
>
<div style={{ fontWeight: 700, fontSize: 12, color: overlayTheme.titleText }}>
GUI / CLI
</div>
<code
style={{
display: 'block',
marginTop: 8,
fontFamily: 'var(--gn-font-mono)',
fontSize: 11,
color: overlayTheme.titleText,
whiteSpace: 'pre-wrap',
overflowWrap: 'anywhere',
}}
>
{remoteQuickStart.configCommand}
</code>
<div style={{ marginTop: 8, fontSize: 12, color: overlayTheme.mutedText, lineHeight: 1.6 }}>
{remoteQuickStart.displayName} MCP
</div>
</div>
<div
style={{
padding: '10px 12px',
borderRadius: 10,
border: `1px solid ${cardBorder}`,
background: darkMode ? 'rgba(15,23,42,0.55)' : 'rgba(255,255,255,0.78)',
}}
>
<div style={{ fontWeight: 700, fontSize: 12, color: overlayTheme.titleText }}>
Windows GoNavi MCP HTTP
</div>
<code
style={{
display: 'block',
marginTop: 8,
fontFamily: 'var(--gn-font-mono)',
fontSize: 11,
color: overlayTheme.titleText,
whiteSpace: 'pre-wrap',
overflowWrap: 'anywhere',
}}
>
{remoteQuickStart.launchCommand}
</code>
<div style={{ marginTop: 8, fontSize: 12, color: overlayTheme.mutedText, lineHeight: 1.6 }}>
{remoteQuickStart.standaloneCommand}
</div>
</div>
</div>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: 10 }}>
<div>
<div style={{ fontWeight: 700, fontSize: 12, color: overlayTheme.titleText }}></div>
<div style={{ marginTop: 5, display: 'flex', flexDirection: 'column', gap: 4 }}>
{remoteQuickStart.verificationSteps.map((item) => (
<div key={item} style={{ fontSize: 12, color: overlayTheme.mutedText, lineHeight: 1.6 }}>
{item}
</div>
))}
</div>
</div>
<div>
<div style={{ fontWeight: 700, fontSize: 12, color: overlayTheme.titleText }}></div>
<div style={{ marginTop: 5, display: 'flex', flexDirection: 'column', gap: 4 }}>
{remoteQuickStart.securityNotes.map((item) => (
<div key={item} style={{ fontSize: 12, color: overlayTheme.mutedText, lineHeight: 1.6 }}>
{item}
</div>
))}
</div>
</div>
</div>
</div>
<AIMCPRemoteQuickStartPanel
quickStart={remoteQuickStart}
darkMode={darkMode}
overlayTheme={overlayTheme}
cardBorder={cardBorder}
/>
)}
<div style={{ fontSize: 12, color: overlayTheme.mutedText, lineHeight: 1.7 }}>
CLI {selectedIsRemoteClient

View File

@@ -0,0 +1,37 @@
import React from 'react';
import { renderToStaticMarkup } from 'react-dom/server';
import { describe, expect, it } from 'vitest';
import { buildRemoteMCPClientQuickStart } from '../../utils/mcpClientInstallStatus';
import { buildOverlayWorkbenchTheme } from '../../utils/overlayWorkbenchTheme';
import AIMCPRemoteQuickStartPanel from './AIMCPRemoteQuickStartPanel';
describe('AIMCPRemoteQuickStartPanel', () => {
it('renders remote MCP bridge parameters and safe launch snippets for cloud agents', () => {
const quickStart = buildRemoteMCPClientQuickStart({
client: 'openclaw',
displayName: 'OpenClaw',
});
const markup = renderToStaticMarkup(
<AIMCPRemoteQuickStartPanel
quickStart={quickStart}
darkMode={false}
overlayTheme={buildOverlayWorkbenchTheme(false)}
cardBorder="rgba(0,0,0,0.08)"
/>,
);
expect(markup).toContain('OpenClaw 远程 MCP 快速配置');
expect(markup).toContain('公网/隧道 URL');
expect(markup).toContain('Bearer Token');
expect(markup).toContain('配置到云端 Agent');
expect(markup).toContain('无 GUI / CLI 生成配置');
expect(markup).toContain('Windows 启动 GoNavi MCP HTTP');
expect(markup).toContain('&quot;type&quot;: &quot;streamable-http&quot;');
expect(markup).toContain('GoNavi.exe mcp-server remote-config --client openclaw');
expect(markup).toContain('gonavi-mcp-server http --addr 127.0.0.1:8765');
expect(markup).toContain('默认 --schema-only 不注册 execute_sql');
expect(markup).not.toContain('password');
});
});

View File

@@ -0,0 +1,171 @@
import React from 'react';
import {
REMOTE_MCP_PARAMETER_GUIDES,
type RemoteMCPClientQuickStart,
} from '../../utils/mcpClientInstallStatus';
import type { OverlayWorkbenchTheme } from '../../utils/overlayWorkbenchTheme';
interface AIMCPRemoteQuickStartPanelProps {
quickStart: RemoteMCPClientQuickStart;
darkMode: boolean;
overlayTheme: OverlayWorkbenchTheme;
cardBorder: string;
}
interface RemoteCommandCardProps {
title: string;
children: React.ReactNode;
darkMode: boolean;
overlayTheme: OverlayWorkbenchTheme;
cardBorder: string;
}
const remoteCodeStyle = (overlayTheme: OverlayWorkbenchTheme): React.CSSProperties => ({
display: 'block',
marginTop: 8,
fontFamily: 'var(--gn-font-mono)',
fontSize: 11,
color: overlayTheme.titleText,
whiteSpace: 'pre-wrap',
overflowWrap: 'anywhere',
});
const RemoteCommandCard: React.FC<RemoteCommandCardProps> = ({
title,
children,
darkMode,
overlayTheme,
cardBorder,
}) => (
<div
style={{
padding: '10px 12px',
borderRadius: 10,
border: `1px solid ${cardBorder}`,
background: darkMode ? 'rgba(15,23,42,0.55)' : 'rgba(255,255,255,0.78)',
}}
>
<div style={{ fontWeight: 700, fontSize: 12, color: overlayTheme.titleText }}>
{title}
</div>
{children}
</div>
);
const AIMCPRemoteQuickStartPanel: React.FC<AIMCPRemoteQuickStartPanelProps> = ({
quickStart,
darkMode,
overlayTheme,
cardBorder,
}) => (
<div
style={{
padding: '12px 14px',
borderRadius: 12,
border: `1px solid ${darkMode ? 'rgba(56,189,248,0.2)' : 'rgba(14,165,233,0.18)'}`,
background: darkMode ? 'rgba(14,165,233,0.06)' : 'rgba(240,249,255,0.78)',
display: 'flex',
flexDirection: 'column',
gap: 10,
}}
>
<div style={{ fontWeight: 700, fontSize: 13, color: overlayTheme.titleText }}>
{quickStart.displayName} MCP
</div>
<div style={{ fontSize: 12, color: overlayTheme.mutedText, lineHeight: 1.7 }}>
Agent GUI/CLI Windows GoNavi 使 MCP URL Bearer Token schema-only
</div>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(210px, 1fr))', gap: 10 }}>
{REMOTE_MCP_PARAMETER_GUIDES.map((item) => (
<div
key={item.key}
style={{
padding: '10px 12px',
borderRadius: 10,
border: `1px solid ${cardBorder}`,
background: darkMode ? 'rgba(15,23,42,0.42)' : 'rgba(255,255,255,0.72)',
display: 'flex',
flexDirection: 'column',
gap: 5,
}}
>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8 }}>
<div style={{ fontWeight: 700, fontSize: 12, color: overlayTheme.titleText }}>
{item.title}
</div>
<span
style={{
padding: '2px 7px',
borderRadius: 999,
fontSize: 11,
color: item.required ? '#dc2626' : overlayTheme.mutedText,
background: item.required
? (darkMode ? 'rgba(248,113,113,0.12)' : 'rgba(254,226,226,0.7)')
: (darkMode ? 'rgba(255,255,255,0.06)' : 'rgba(15,23,42,0.05)'),
}}
>
{item.required ? '必填' : '可选'}
</span>
</div>
<div style={{ fontSize: 12, color: overlayTheme.titleText, lineHeight: 1.6 }}>
{item.fill}
</div>
<div style={{ fontSize: 12, color: overlayTheme.mutedText, lineHeight: 1.6 }}>
<code style={{ fontFamily: 'var(--gn-font-mono)' }}>{item.example}</code>
</div>
<div style={{ fontSize: 12, color: overlayTheme.mutedText, lineHeight: 1.6 }}>
{item.avoid}
</div>
</div>
))}
</div>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(260px, 1fr))', gap: 10 }}>
<RemoteCommandCard title="配置到云端 Agent" darkMode={darkMode} overlayTheme={overlayTheme} cardBorder={cardBorder}>
<code style={remoteCodeStyle(overlayTheme)}>
{quickStart.configJson}
</code>
</RemoteCommandCard>
<RemoteCommandCard title="无 GUI / CLI 生成配置" darkMode={darkMode} overlayTheme={overlayTheme} cardBorder={cardBorder}>
<code style={remoteCodeStyle(overlayTheme)}>
{quickStart.configCommand}
</code>
<div style={{ marginTop: 8, fontSize: 12, color: overlayTheme.mutedText, lineHeight: 1.6 }}>
{quickStart.displayName} MCP
</div>
</RemoteCommandCard>
<RemoteCommandCard title="Windows 启动 GoNavi MCP HTTP" darkMode={darkMode} overlayTheme={overlayTheme} cardBorder={cardBorder}>
<code style={remoteCodeStyle(overlayTheme)}>
{quickStart.launchCommand}
</code>
<div style={{ marginTop: 8, fontSize: 12, color: overlayTheme.mutedText, lineHeight: 1.6 }}>
{quickStart.standaloneCommand}
</div>
</RemoteCommandCard>
</div>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: 10 }}>
<div>
<div style={{ fontWeight: 700, fontSize: 12, color: overlayTheme.titleText }}></div>
<div style={{ marginTop: 5, display: 'flex', flexDirection: 'column', gap: 4 }}>
{quickStart.verificationSteps.map((item) => (
<div key={item} style={{ fontSize: 12, color: overlayTheme.mutedText, lineHeight: 1.6 }}>
{item}
</div>
))}
</div>
</div>
<div>
<div style={{ fontWeight: 700, fontSize: 12, color: overlayTheme.titleText }}></div>
<div style={{ marginTop: 5, display: 'flex', flexDirection: 'column', gap: 4 }}>
{quickStart.securityNotes.map((item) => (
<div key={item} style={{ fontSize: 12, color: overlayTheme.mutedText, lineHeight: 1.6 }}>
{item}
</div>
))}
</div>
</div>
</div>
</div>
);
export default AIMCPRemoteQuickStartPanel;