first commit
This commit is contained in:
318
web/test-client.html
Normal file
318
web/test-client.html
Normal file
@@ -0,0 +1,318 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>MCP 客户端测试</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 20px;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
.container {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
background: white;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
}
|
||||
.status {
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
margin: 10px 0;
|
||||
}
|
||||
.success { background: #d4edda; color: #155724; border: 1px solid #c3e6cb; }
|
||||
.error { background: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; }
|
||||
button {
|
||||
background: #007bff;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 8px 16px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
margin: 5px;
|
||||
}
|
||||
button:hover { background: #0056b3; }
|
||||
.form-group {
|
||||
margin: 15px 0;
|
||||
}
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
font-weight: bold;
|
||||
}
|
||||
input, select {
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.server-list {
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
margin: 15px 0;
|
||||
}
|
||||
.server-item {
|
||||
padding: 15px;
|
||||
border-bottom: 1px solid #eee;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
.server-item:last-child { border-bottom: none; }
|
||||
.server-info h3 { margin: 0 0 5px 0; }
|
||||
.server-info p { margin: 0; color: #666; font-size: 14px; }
|
||||
.tools-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
|
||||
gap: 15px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
.tool-card {
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
padding: 15px;
|
||||
background: #f9f9f9;
|
||||
}
|
||||
.tool-card h4 { margin: 0 0 10px 0; color: #333; }
|
||||
.tool-card p { margin: 0 0 10px 0; color: #666; font-size: 14px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>🚀 MCP Vue 客户端</h1>
|
||||
<p>Model Context Protocol 客户端 - 支持 HTTP 和 SSE 传输</p>
|
||||
|
||||
<div id="status" class="status success">
|
||||
✅ 客户端已加载
|
||||
</div>
|
||||
|
||||
<!-- 添加服务器表单 -->
|
||||
<div class="form-section">
|
||||
<h2>添加 MCP 服务器</h2>
|
||||
<div class="form-group">
|
||||
<label>服务器名称:</label>
|
||||
<input type="text" id="serverName" placeholder="例如: xhslogin" value="xhslogin">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>服务器 URL:</label>
|
||||
<input type="text" id="serverUrl" placeholder="http://127.0.0.1:3100/mcp" value="http://127.0.0.1:3100/mcp">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>传输类型:</label>
|
||||
<select id="transportType">
|
||||
<option value="http">HTTP</option>
|
||||
<option value="sse">Server-Sent Events</option>
|
||||
</select>
|
||||
</div>
|
||||
<button onclick="addServer()">添加并连接服务器</button>
|
||||
</div>
|
||||
|
||||
<!-- 服务器列表 -->
|
||||
<div class="servers-section">
|
||||
<h2>已连接的服务器</h2>
|
||||
<div id="serverList" class="server-list">
|
||||
<div class="server-item">
|
||||
<div class="server-info">
|
||||
<p>暂无服务器</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 工具列表 -->
|
||||
<div class="tools-section">
|
||||
<h2>可用工具</h2>
|
||||
<div id="toolsList" class="tools-grid">
|
||||
<div class="tool-card">
|
||||
<p>请先添加并连接 MCP 服务器</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="module">
|
||||
// 模拟 MCP 客户端功能
|
||||
let servers = [];
|
||||
let tools = [];
|
||||
|
||||
// 模拟添加服务器
|
||||
async function addServer() {
|
||||
const name = document.getElementById('serverName').value;
|
||||
const url = document.getElementById('serverUrl').value;
|
||||
const type = document.getElementById('transportType').value;
|
||||
|
||||
if (!name || !url) {
|
||||
updateStatus('请填写服务器名称和URL', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
updateStatus('正在连接服务器...', 'success');
|
||||
|
||||
try {
|
||||
// 测试连接
|
||||
const response = await fetch(url.replace('/mcp', '/health'));
|
||||
|
||||
if (response.ok) {
|
||||
// 模拟成功连接
|
||||
const server = {
|
||||
id: Date.now().toString(),
|
||||
name,
|
||||
url,
|
||||
type,
|
||||
status: 'connected'
|
||||
};
|
||||
|
||||
servers.push(server);
|
||||
updateServerList();
|
||||
|
||||
// 模拟获取工具列表
|
||||
await loadTools(server);
|
||||
|
||||
updateStatus(`✅ 成功连接到 ${name}`, 'success');
|
||||
} else {
|
||||
throw new Error(`服务器响应错误: ${response.status}`);
|
||||
}
|
||||
} catch (error) {
|
||||
updateStatus(`❌ 连接失败: ${error.message}`, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// 模拟加载工具
|
||||
async function loadTools(server) {
|
||||
// 这里应该调用真正的 MCP 协议
|
||||
const mockTools = [
|
||||
{
|
||||
name: 'get_account',
|
||||
description: '获取账户信息',
|
||||
serverId: server.id,
|
||||
serverName: server.name
|
||||
},
|
||||
{
|
||||
name: 'check_login_status',
|
||||
description: '检查登录状态',
|
||||
serverId: server.id,
|
||||
serverName: server.name
|
||||
},
|
||||
{
|
||||
name: 'publish_content',
|
||||
description: '发布内容到小红书',
|
||||
serverId: server.id,
|
||||
serverName: server.name
|
||||
}
|
||||
];
|
||||
|
||||
tools = tools.concat(mockTools);
|
||||
updateToolsList();
|
||||
}
|
||||
|
||||
// 更新状态显示
|
||||
function updateStatus(message, type = 'success') {
|
||||
const statusEl = document.getElementById('status');
|
||||
statusEl.textContent = message;
|
||||
statusEl.className = `status ${type}`;
|
||||
}
|
||||
|
||||
// 更新服务器列表
|
||||
function updateServerList() {
|
||||
const listEl = document.getElementById('serverList');
|
||||
|
||||
if (servers.length === 0) {
|
||||
listEl.innerHTML = '<div class="server-item"><div class="server-info"><p>暂无服务器</p></div></div>';
|
||||
return;
|
||||
}
|
||||
|
||||
listEl.innerHTML = servers.map(server => `
|
||||
<div class="server-item">
|
||||
<div class="server-info">
|
||||
<h3>${server.name}</h3>
|
||||
<p>${server.url} (${server.type.toUpperCase()})</p>
|
||||
</div>
|
||||
<div class="server-actions">
|
||||
<span style="color: green;">✅ 已连接</span>
|
||||
<button onclick="removeServer('${server.id}')" style="background: #dc3545;">删除</button>
|
||||
</div>
|
||||
</div>
|
||||
`).join('');
|
||||
}
|
||||
|
||||
// 更新工具列表
|
||||
function updateToolsList() {
|
||||
const listEl = document.getElementById('toolsList');
|
||||
|
||||
if (tools.length === 0) {
|
||||
listEl.innerHTML = '<div class="tool-card"><p>请先添加并连接 MCP 服务器</p></div>';
|
||||
return;
|
||||
}
|
||||
|
||||
listEl.innerHTML = tools.map(tool => `
|
||||
<div class="tool-card">
|
||||
<h4>🔧 ${tool.name}</h4>
|
||||
<p>${tool.description}</p>
|
||||
<p><small>来自: ${tool.serverName}</small></p>
|
||||
<button onclick="callTool('${tool.serverId}', '${tool.name}')">调用工具</button>
|
||||
</div>
|
||||
`).join('');
|
||||
}
|
||||
|
||||
// 删除服务器
|
||||
function removeServer(serverId) {
|
||||
servers = servers.filter(s => s.id !== serverId);
|
||||
tools = tools.filter(t => t.serverId !== serverId);
|
||||
updateServerList();
|
||||
updateToolsList();
|
||||
updateStatus('服务器已删除', 'success');
|
||||
}
|
||||
|
||||
// 调用工具
|
||||
async function callTool(serverId, toolName) {
|
||||
const server = servers.find(s => s.id === serverId);
|
||||
if (!server) return;
|
||||
|
||||
try {
|
||||
updateStatus(`正在调用工具: ${toolName}...`, 'success');
|
||||
|
||||
// 这里应该调用真正的 MCP 工具
|
||||
const response = await fetch(server.url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json, text/event-stream'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
jsonrpc: '2.0',
|
||||
id: Date.now().toString(),
|
||||
method: 'tools/call',
|
||||
params: {
|
||||
name: toolName,
|
||||
arguments: {}
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const result = await response.json();
|
||||
updateStatus(`✅ 工具 ${toolName} 调用成功`, 'success');
|
||||
console.log('工具调用结果:', result);
|
||||
alert(`工具调用成功!\n${JSON.stringify(result, null, 2)}`);
|
||||
} else {
|
||||
throw new Error(`HTTP ${response.status}`);
|
||||
}
|
||||
} catch (error) {
|
||||
updateStatus(`❌ 工具调用失败: ${error.message}`, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// 暴露函数到全局作用域
|
||||
window.addServer = addServer;
|
||||
window.removeServer = removeServer;
|
||||
window.callTool = callTool;
|
||||
|
||||
// 页面加载完成
|
||||
updateStatus('🚀 MCP 客户端已就绪,可以开始添加服务器', 'success');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user