Skip to content

Commit fc886ab

Browse files
author
Gauge Developer
committed
feat: improve MCP page with interactive tool testing
- Add MCPToolTester component for real-time MCP tool testing - Add tool selector with problem_id and limit inputs - Display formatted JSON responses with status codes - Add error handling and user feedback via antd message
1 parent 7c6f4da commit fc886ab

File tree

1 file changed

+153
-5
lines changed

1 file changed

+153
-5
lines changed

frontend/src/components/MCP.tsx

Lines changed: 153 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,155 @@
1-
import React from 'react';
2-
import { Card, Typography, Space, Tag, Divider, Alert, Steps, Button, Tooltip } from 'antd';
3-
import { CloudOutlined, CodeOutlined, ThunderboltOutlined, CheckCircleOutlined, DatabaseOutlined, CopyOutlined } from '@ant-design/icons';
1+
import React, { useState } from 'react';
2+
import { Card, Typography, Space, Tag, Divider, Alert, Steps, Button, Tooltip, Input, message, Collapse } from 'antd';
3+
import { CloudOutlined, CodeOutlined, ThunderboltOutlined, CheckCircleOutlined, DatabaseOutlined, CopyOutlined, PlayCircleOutlined } from '@ant-design/icons';
44

55
const { Title, Paragraph, Text } = Typography;
66
const { Step } = Steps;
7+
const { Panel } = Collapse;
78

8-
// JSON 高亮组件
9+
// MCP Tool Tester Component
10+
const MCPToolTester: React.FC = () => {
11+
const [selectedTool, setSelectedTool] = useState<string>('get_hot100_online_count');
12+
const [problemId, setProblemId] = useState<string>('1');
13+
const [limit, setLimit] = useState<number>(10);
14+
const [loading, setLoading] = useState<boolean>(false);
15+
const [result, setResult] = useState<any>(null);
16+
const [error, setError] = useState<string>('');
17+
18+
const tools = [
19+
{ key: 'get_hot100_online_count', name: '获取Hot100在线人数', desc: '获取所有Hot 100题目的实时在线人数' },
20+
{ key: 'get_problem_online_count', name: '获取单题在线人数', desc: '根据题目ID获取单个题目的在线人数' },
21+
{ key: 'get_problem_history', name: '获取题目历史数据', desc: '获取题目的历史在线人数记录' },
22+
];
23+
24+
const handleTest = async () => {
25+
setLoading(true);
26+
setError('');
27+
setResult(null);
28+
29+
try {
30+
const params: any = {};
31+
if (selectedTool === 'get_problem_online_count' || selectedTool === 'get_problem_history') {
32+
params.problem_id = problemId;
33+
}
34+
if (selectedTool === 'get_problem_history') {
35+
params.limit = limit;
36+
}
37+
38+
const response = await fetch('/mcp', {
39+
method: 'POST',
40+
headers: { 'Content-Type': 'application/json' },
41+
body: JSON.stringify({
42+
name: selectedTool,
43+
parameters: params
44+
})
45+
});
46+
47+
const data = await response.json();
48+
setResult(data);
49+
50+
if (data.code === 200) {
51+
message.success('测试成功!');
52+
} else {
53+
setError(data.msg || '请求失败');
54+
message.error(data.msg || '请求失败');
55+
}
56+
} catch (err) {
57+
const errorMsg = err instanceof Error ? err.message : '网络请求失败';
58+
setError(errorMsg);
59+
message.error(errorMsg);
60+
} finally {
61+
setLoading(false);
62+
}
63+
};
64+
65+
return (
66+
<Space direction="vertical" style={{ width: '100%' }} size="middle">
67+
<Alert
68+
message="实时测试 MCP 工具"
69+
description="选择工具并输入参数,直接测试 MCP 服务器是否正常工作"
70+
type="info"
71+
showIcon
72+
/>
73+
74+
<div>
75+
<Text strong>选择工具:</Text>
76+
<div style={{ marginTop: 8 }}>
77+
{tools.map(tool => (
78+
<Tag
79+
key={tool.key}
80+
color={selectedTool === tool.key ? 'blue' : 'default'}
81+
style={{ cursor: 'pointer', marginBottom: 8, padding: '4px 12px' }}
82+
onClick={() => setSelectedTool(tool.key)}
83+
>
84+
{tool.name}
85+
</Tag>
86+
))}
87+
</div>
88+
<Text type="secondary" style={{ fontSize: 12 }}>
89+
{tools.find(t => t.key === selectedTool)?.desc}
90+
</Text>
91+
</div>
92+
93+
{(selectedTool === 'get_problem_online_count' || selectedTool === 'get_problem_history') && (
94+
<div>
95+
<Text strong>题目ID:</Text>
96+
<Input
97+
placeholder="输入题目ID (如: 1 或 two-sum)"
98+
value={problemId}
99+
onChange={(e) => setProblemId(e.target.value)}
100+
style={{ width: '100%', marginTop: 8 }}
101+
/>
102+
<Text type="secondary" style={{ fontSize: 12 }}>支持数字ID或英文slug</Text>
103+
</div>
104+
)}
105+
106+
{selectedTool === 'get_problem_history' && (
107+
<div>
108+
<Text strong>返回记录数:</Text>
109+
<Input
110+
type="number"
111+
placeholder="默认10条"
112+
value={limit}
113+
onChange={(e) => setLimit(parseInt(e.target.value) || 10)}
114+
style={{ width: '100%', marginTop: 8 }}
115+
/>
116+
</div>
117+
)}
118+
119+
<Button
120+
type="primary"
121+
icon={<PlayCircleOutlined />}
122+
onClick={handleTest}
123+
loading={loading}
124+
block
125+
>
126+
执行测试
127+
</Button>
128+
129+
{error && (
130+
<Alert
131+
message="错误"
132+
description={error}
133+
type="error"
134+
showIcon
135+
/>
136+
)}
137+
138+
{result && (
139+
<div>
140+
<Divider style={{ margin: '16px 0' }} />
141+
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 8 }}>
142+
<Text strong>响应结果:</Text>
143+
<Tag color={result.code === 200 ? 'success' : 'error'}>
144+
Code: {result.code}
145+
</Tag>
146+
</div>
147+
<JsonBlock data={result.data || result} />
148+
</div>
149+
)}
150+
</Space>
151+
);
152+
};
9153
const JsonBlock: React.FC<{ data: any }> = ({ data }) => {
10154
const jsonStr = JSON.stringify(data, null, 2);
11155
return (
@@ -322,7 +466,11 @@ const MCP: React.FC = () => {
322466
/>
323467
</Card>
324468

325-
<Card title={<><CheckCircleOutlined /> 支持的客户端</>}>
469+
<Card title={<><PlayCircleOutlined /> 在线测试工具</>}>
470+
<MCPToolTester />
471+
</Card>
472+
473+
<Card title={<><CheckCircleOutlined /> 支持的客户端</>}>>
326474
<Space wrap>
327475
<Tag color="purple">Claude Desktop</Tag>
328476
<Tag color="blue">Cursor</Tag>

0 commit comments

Comments
 (0)