|
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'; |
4 | 4 |
|
5 | 5 | const { Title, Paragraph, Text } = Typography; |
6 | 6 | const { Step } = Steps; |
| 7 | +const { Panel } = Collapse; |
7 | 8 |
|
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 | +}; |
9 | 153 | const JsonBlock: React.FC<{ data: any }> = ({ data }) => { |
10 | 154 | const jsonStr = JSON.stringify(data, null, 2); |
11 | 155 | return ( |
@@ -322,7 +466,11 @@ const MCP: React.FC = () => { |
322 | 466 | /> |
323 | 467 | </Card> |
324 | 468 |
|
325 | | - <Card title={<><CheckCircleOutlined /> 支持的客户端</>}> |
| 469 | + <Card title={<><PlayCircleOutlined /> 在线测试工具</>}> |
| 470 | + <MCPToolTester /> |
| 471 | + </Card> |
| 472 | + |
| 473 | + <Card title={<><CheckCircleOutlined /> 支持的客户端</>}>> |
326 | 474 | <Space wrap> |
327 | 475 | <Tag color="purple">Claude Desktop</Tag> |
328 | 476 | <Tag color="blue">Cursor</Tag> |
|
0 commit comments