first commit
This commit is contained in:
282
web/public/blank-page-debug.html
Normal file
282
web/public/blank-page-debug.html
Normal file
@@ -0,0 +1,282 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>编辑按钮问题诊断</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||
padding: 20px;
|
||||
max-width: 1000px;
|
||||
margin: 0 auto;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
.section {
|
||||
background: white;
|
||||
padding: 20px;
|
||||
margin: 20px 0;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||||
}
|
||||
h1 { color: #333; }
|
||||
h2 { color: #666; margin-top: 0; }
|
||||
.step {
|
||||
background: #f8f9fa;
|
||||
padding: 15px;
|
||||
margin: 10px 0;
|
||||
border-left: 4px solid #18a058;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.code {
|
||||
background: #1e1e1e;
|
||||
color: #d4d4d4;
|
||||
padding: 15px;
|
||||
border-radius: 4px;
|
||||
font-family: monospace;
|
||||
font-size: 12px;
|
||||
overflow-x: auto;
|
||||
margin: 10px 0;
|
||||
}
|
||||
.success { color: #4ade80; }
|
||||
.error { color: #f87171; }
|
||||
.warning { color: #fbbf24; }
|
||||
.info { color: #60a5fa; }
|
||||
.button {
|
||||
background: #18a058;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 10px 20px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
margin-right: 10px;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
}
|
||||
.button:hover { background: #16955d; }
|
||||
ul { line-height: 2; }
|
||||
.checklist { list-style: none; padding: 0; }
|
||||
.checklist li { padding: 8px 0; }
|
||||
.checklist input { margin-right: 10px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>🔍 编辑按钮空白页面诊断</h1>
|
||||
|
||||
<div class="section">
|
||||
<h2>❓ 问题描述</h2>
|
||||
<p>点击"MCP 设置" → "已配置的服务器" → "编辑"按钮后,弹出的对话框显示空白。</p>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2>🛠️ 已实施的修复</h2>
|
||||
<div class="step">
|
||||
<strong>修复 1: 调整 Modal 样式</strong>
|
||||
<p>修改了 modal 和 card 的样式配置,确保内容能正确显示:</p>
|
||||
<div class="code">
|
||||
<n-modal v-model:show="showServerDetail">
|
||||
<n-card style="width: 90vw; max-width: 1200px; max-height: 90vh; overflow: auto;">
|
||||
<MCPServerDetail .../>
|
||||
</n-card>
|
||||
</n-modal>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="step">
|
||||
<strong>修复 2: 调整组件高度</strong>
|
||||
<p>将 MCPServerDetail 组件的 height: 100% 改为 min-height: 500px</p>
|
||||
<div class="code">
|
||||
.mcp-server-detail {
|
||||
min-height: 500px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="step">
|
||||
<strong>修复 3: 添加详细调试日志</strong>
|
||||
<p>在组件加载、数据更新等关键位置添加了console.log</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2>📋 测试步骤</h2>
|
||||
|
||||
<div class="step">
|
||||
<strong>步骤 1: 刷新页面</strong>
|
||||
<p>强制刷新浏览器页面以加载最新代码</p>
|
||||
<ul>
|
||||
<li>Mac: <code>Cmd + Shift + R</code></li>
|
||||
<li>Windows/Linux: <code>Ctrl + Shift + R</code></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="step">
|
||||
<strong>步骤 2: 打开开发者工具</strong>
|
||||
<p>打开浏览器的开发者工具并切换到 Console 标签</p>
|
||||
<ul>
|
||||
<li>Mac: <code>Cmd + Option + I</code></li>
|
||||
<li>Windows/Linux: <code>F12</code></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="step">
|
||||
<strong>步骤 3: 点击编辑按钮</strong>
|
||||
<p>在 MCP 设置页面,点击任意服务器的"编辑"按钮</p>
|
||||
</div>
|
||||
|
||||
<div class="step">
|
||||
<strong>步骤 4: 观察控制台输出</strong>
|
||||
<p>应该看到以下日志序列:</p>
|
||||
<div class="code">
|
||||
<span class="info">🔍 [1] 打开服务器详情被调用</span>
|
||||
<span class="info">🔍 [2] 服务器数据: {...}</span>
|
||||
<span class="info">🔍 [3] 当前 showServerDetail 值: false</span>
|
||||
<span class="info">🔍 [4] editingServer 设置完成: {...}</span>
|
||||
<span class="success">✅ [5] showServerDetail 设置为 true</span>
|
||||
<span class="success">✅ [6] 最终状态检查 - showServerDetail: true</span>
|
||||
<span class="info">🎯 MCPServerDetail 组件加载</span>
|
||||
<span class="info">📦 接收到的 server prop: {...}</span>
|
||||
<span class="info">👀 MCPServerDetail watch 触发, newServer: {...}</span>
|
||||
<span class="info">📝 更新表单数据: {...}</span>
|
||||
<span class="success">✅ formData 更新完成: {...}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2>🐛 问题排查清单</h2>
|
||||
|
||||
<h3>情况 A: Modal 弹出但完全空白</h3>
|
||||
<ul>
|
||||
<li><strong>检查</strong>: Elements 标签中搜索 "mcp-server-detail"</li>
|
||||
<li><strong>检查</strong>: 该元素的 computed styles,特别是 height, display, visibility</li>
|
||||
<li><strong>可能原因</strong>: CSS 样式问题导致内容不可见</li>
|
||||
</ul>
|
||||
<p><strong>临时解决方案 - 在控制台执行</strong>:</p>
|
||||
<div class="code">
|
||||
const detail = document.querySelector('.mcp-server-detail')
|
||||
if (detail) {
|
||||
console.log('找到组件元素:', detail)
|
||||
console.log('元素尺寸:', detail.getBoundingClientRect())
|
||||
console.log('Computed styles:', window.getComputedStyle(detail))
|
||||
|
||||
// 强制设置可见
|
||||
detail.style.minHeight = '600px'
|
||||
detail.style.display = 'flex'
|
||||
detail.style.visibility = 'visible'
|
||||
console.log('✅ 已尝试强制显示')
|
||||
} else {
|
||||
console.error('❌ 未找到 .mcp-server-detail 元素')
|
||||
}
|
||||
</div>
|
||||
|
||||
<h3>情况 B: Modal 没有弹出</h3>
|
||||
<ul>
|
||||
<li><strong>检查</strong>: 控制台是否有 "showServerDetail 设置为 true" 的日志</li>
|
||||
<li><strong>检查</strong>: Elements 标签中搜索 "n-modal",看元素是否存在</li>
|
||||
<li><strong>可能原因</strong>: Modal 组件渲染问题或 z-index 太低</li>
|
||||
</ul>
|
||||
|
||||
<h3>情况 C: 有日志但没有组件加载日志</h3>
|
||||
<ul>
|
||||
<li><strong>意味着</strong>: MCPServerDetail 组件根本没有被创建</li>
|
||||
<li><strong>检查</strong>: editingServer 的值是否为 null 或 undefined</li>
|
||||
<li><strong>检查</strong>: 控制台是否有组件导入或编译错误</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2>🔧 快速诊断脚本</h2>
|
||||
<p>在浏览器控制台执行以下代码进行全面诊断:</p>
|
||||
<div class="code">
|
||||
// 诊断脚本
|
||||
console.log('=== MCP Modal 诊断开始 ===')
|
||||
|
||||
// 1. 检查 Modal 元素
|
||||
const modals = document.querySelectorAll('.n-modal')
|
||||
console.log('1️⃣ Modal 元素数量:', modals.length)
|
||||
modals.forEach((m, i) => {
|
||||
console.log(` Modal ${i}:`, {
|
||||
display: m.style.display || window.getComputedStyle(m).display,
|
||||
opacity: window.getComputedStyle(m).opacity,
|
||||
zIndex: window.getComputedStyle(m).zIndex
|
||||
})
|
||||
})
|
||||
|
||||
// 2. 检查 Card 元素
|
||||
const cards = document.querySelectorAll('.n-card')
|
||||
console.log('2️⃣ Card 元素数量:', cards.length)
|
||||
|
||||
// 3. 检查 MCPServerDetail 组件
|
||||
const detail = document.querySelector('.mcp-server-detail')
|
||||
console.log('3️⃣ MCPServerDetail 元素:', detail ? '✅ 存在' : '❌ 不存在')
|
||||
if (detail) {
|
||||
const rect = detail.getBoundingClientRect()
|
||||
const styles = window.getComputedStyle(detail)
|
||||
console.log(' 尺寸:', {
|
||||
width: rect.width,
|
||||
height: rect.height,
|
||||
minHeight: styles.minHeight,
|
||||
display: styles.display
|
||||
})
|
||||
}
|
||||
|
||||
// 4. 检查 tabs
|
||||
const tabs = document.querySelectorAll('.n-tabs')
|
||||
console.log('4️⃣ Tabs 元素数量:', tabs.length)
|
||||
|
||||
console.log('=== 诊断结束 ===')
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2>✅ 验证清单</h2>
|
||||
<ul class="checklist">
|
||||
<li><input type="checkbox" id="c1"><label for="c1">开发服务器运行在 http://localhost:5173</label></li>
|
||||
<li><input type="checkbox" id="c2"><label for="c2">页面已强制刷新 (Cmd+Shift+R)</label></li>
|
||||
<li><input type="checkbox" id="c3"><label for="c3">浏览器开发者工具已打开</label></li>
|
||||
<li><input type="checkbox" id="c4"><label for="c4">Console 标签已选中</label></li>
|
||||
<li><input type="checkbox" id="c5"><label for="c5">点击编辑按钮能看到日志</label></li>
|
||||
<li><input type="checkbox" id="c6"><label for="c6">看到 "MCPServerDetail 组件加载" 日志</label></li>
|
||||
<li><input type="checkbox" id="c7"><label for="c7">Modal 对话框成功弹出</label></li>
|
||||
<li><input type="checkbox" id="c8"><label for="c8">可以看到服务器详情内容</label></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2>📸 需要提供的信息</h2>
|
||||
<p>如果问题依然存在,请提供以下信息的截图:</p>
|
||||
<ol>
|
||||
<li><strong>Console 标签</strong>: 点击编辑后的所有日志输出</li>
|
||||
<li><strong>Elements 标签</strong>: 搜索 "mcp-server-detail" 的结果</li>
|
||||
<li><strong>Network 标签</strong>: 是否有加载失败的资源</li>
|
||||
<li><strong>控制台诊断脚本输出</strong>: 运行上面的诊断脚本后的输出</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2>🚀 快速操作</h2>
|
||||
<a href="http://localhost:5173" class="button" target="_blank">打开 MCP Client</a>
|
||||
<a href="#" class="button" onclick="window.location.reload(); return false;">刷新本页</a>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 检查清单进度
|
||||
document.querySelectorAll('.checklist input').forEach(cb => {
|
||||
cb.addEventListener('change', () => {
|
||||
const total = document.querySelectorAll('.checklist input').length
|
||||
const checked = document.querySelectorAll('.checklist input:checked').length
|
||||
if (checked === total) {
|
||||
alert('🎉 太棒了!所有检查项都完成了!\n\n如果问题仍然存在,请提供控制台截图。')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
console.log('📋 诊断页面已加载')
|
||||
console.log('💡 提示: 在主应用中打开控制台进行调试')
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
441
web/public/debug.html
Normal file
441
web/public/debug.html
Normal file
@@ -0,0 +1,441 @@
|
||||
<!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: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
h1 {
|
||||
color: #333;
|
||||
border-bottom: 2px solid #4CAF50;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
.section {
|
||||
background: white;
|
||||
padding: 20px;
|
||||
margin: 20px 0;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
}
|
||||
.button {
|
||||
background: #4CAF50;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 10px 20px;
|
||||
margin: 5px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
}
|
||||
.button:hover {
|
||||
background: #45a049;
|
||||
}
|
||||
.button:disabled {
|
||||
background: #ccc;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.output {
|
||||
background: #f9f9f9;
|
||||
border: 1px solid #ddd;
|
||||
padding: 15px;
|
||||
margin-top: 10px;
|
||||
border-radius: 4px;
|
||||
font-family: 'Courier New', monospace;
|
||||
font-size: 13px;
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
.success { color: #4CAF50; }
|
||||
.error { color: #f44336; }
|
||||
.info { color: #2196F3; }
|
||||
.status {
|
||||
display: inline-block;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
margin-right: 8px;
|
||||
}
|
||||
.status.connected { background: #4CAF50; }
|
||||
.status.disconnected { background: #9e9e9e; }
|
||||
.status.connecting { background: #2196F3; }
|
||||
.status.error { background: #f44336; }
|
||||
input, select {
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
margin: 5px 0;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
label {
|
||||
display: block;
|
||||
margin-top: 10px;
|
||||
font-weight: bold;
|
||||
color: #555;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>🔧 MCP 客户端调试工具</h1>
|
||||
|
||||
<div class="section">
|
||||
<h2>📊 系统状态</h2>
|
||||
<p><strong>前端:</strong> <span id="frontendStatus">检查中...</span></p>
|
||||
<p><strong>MCP HTTP服务器:</strong> <span id="httpServerStatus">检查中...</span></p>
|
||||
<p><strong>MCP SSE服务器:</strong> <span id="sseServerStatus">检查中...</span></p>
|
||||
<button class="button" onclick="checkSystemStatus()">🔄 刷新状态</button>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2>🧪 测试 MCP 协议</h2>
|
||||
|
||||
<label>服务器URL:</label>
|
||||
<input type="text" id="testServerUrl" value="http://localhost:3100/mcp" placeholder="http://localhost:3100/mcp">
|
||||
|
||||
<label>传输类型:</label>
|
||||
<select id="testTransportType">
|
||||
<option value="http">HTTP</option>
|
||||
<option value="sse">SSE</option>
|
||||
</select>
|
||||
|
||||
<div style="margin-top: 15px;">
|
||||
<button class="button" onclick="testInitialize()">1️⃣ 测试 Initialize</button>
|
||||
<button class="button" onclick="testListTools()">2️⃣ 测试 List Tools</button>
|
||||
<button class="button" onclick="testCallTool()">3️⃣ 测试 Call Tool</button>
|
||||
</div>
|
||||
|
||||
<div class="output" id="protocolOutput">等待测试...</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2>🎯 测试前端功能</h2>
|
||||
|
||||
<p><strong>提示:</strong> 请在浏览器中打开 <a href="http://localhost:5173" target="_blank">http://localhost:5173</a></p>
|
||||
|
||||
<h3>编辑按钮测试清单:</h3>
|
||||
<ol>
|
||||
<li>打开控制台 (F12 或 Cmd+Option+I)</li>
|
||||
<li>切换到 Console 标签</li>
|
||||
<li>点击任意服务器的"编辑"按钮</li>
|
||||
<li>查看是否有以下日志输出:
|
||||
<ul>
|
||||
<li><code class="info">🔍 打开服务器详情: {...}</code></li>
|
||||
<li><code class="info">✅ 详情页状态: true {...}</code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>检查是否弹出服务器详情对话框</li>
|
||||
</ol>
|
||||
|
||||
<h3>连接测试清单:</h3>
|
||||
<ol>
|
||||
<li>确保MCP服务器正在运行 (见上方系统状态)</li>
|
||||
<li>添加新服务器或选择现有服务器</li>
|
||||
<li>服务器状态应该是 <span class="status disconnected"></span> 断开连接</li>
|
||||
<li>点击"连接"按钮</li>
|
||||
<li>查看控制台日志:
|
||||
<ul>
|
||||
<li><code class="info">🔌 开始连接服务器: xxx</code></li>
|
||||
<li><code class="info">📡 正在连接 xxx...</code></li>
|
||||
<li><code class="success">✅ 连接成功: xxx</code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>状态应该变为 <span class="status connected"></span> 已连接</li>
|
||||
<li>点击"断开"按钮测试断开连接</li>
|
||||
<li>再次点击"连接"测试重新连接 (这是修复的关键!)</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2>📝 调试信息收集</h2>
|
||||
<button class="button" onclick="collectDebugInfo()">🔍 收集调试信息</button>
|
||||
<div class="output" id="debugOutput">点击按钮收集调试信息...</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 输出辅助函数
|
||||
function log(element, message, type = 'info') {
|
||||
const output = document.getElementById(element);
|
||||
const timestamp = new Date().toLocaleTimeString();
|
||||
const className = type === 'success' ? 'success' : type === 'error' ? 'error' : 'info';
|
||||
output.innerHTML += `<span class="${className}">[${timestamp}] ${message}</span>\n`;
|
||||
output.scrollTop = output.scrollHeight;
|
||||
}
|
||||
|
||||
function clearLog(element) {
|
||||
document.getElementById(element).innerHTML = '';
|
||||
}
|
||||
|
||||
// 检查系统状态
|
||||
async function checkSystemStatus() {
|
||||
// 检查前端
|
||||
try {
|
||||
const frontendResp = await fetch('http://localhost:5173');
|
||||
document.getElementById('frontendStatus').innerHTML =
|
||||
'<span class="success">✅ 运行中</span>';
|
||||
} catch (e) {
|
||||
document.getElementById('frontendStatus').innerHTML =
|
||||
'<span class="error">❌ 未运行</span>';
|
||||
}
|
||||
|
||||
// 检查 HTTP MCP 服务器
|
||||
try {
|
||||
const httpResp = await fetch('http://localhost:3100/mcp', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
jsonrpc: '2.0',
|
||||
id: 1,
|
||||
method: 'initialize',
|
||||
params: {
|
||||
protocolVersion: '2024-11-05',
|
||||
clientInfo: { name: 'debug-tool', version: '1.0.0' }
|
||||
}
|
||||
})
|
||||
});
|
||||
const data = await httpResp.json();
|
||||
if (data.result) {
|
||||
document.getElementById('httpServerStatus').innerHTML =
|
||||
`<span class="success">✅ 运行中 (${data.result.serverInfo?.name})</span>`;
|
||||
} else {
|
||||
throw new Error('Invalid response');
|
||||
}
|
||||
} catch (e) {
|
||||
document.getElementById('httpServerStatus').innerHTML =
|
||||
'<span class="error">❌ 未运行或无响应</span>';
|
||||
}
|
||||
|
||||
// 检查 SSE MCP 服务器
|
||||
try {
|
||||
const sseResp = await fetch('http://localhost:3200/sse');
|
||||
if (sseResp.ok) {
|
||||
document.getElementById('sseServerStatus').innerHTML =
|
||||
'<span class="success">✅ 运行中</span>';
|
||||
} else {
|
||||
throw new Error('Invalid response');
|
||||
}
|
||||
} catch (e) {
|
||||
document.getElementById('sseServerStatus').innerHTML =
|
||||
'<span class="error">❌ 未运行或无响应</span>';
|
||||
}
|
||||
}
|
||||
|
||||
// 测试 Initialize
|
||||
async function testInitialize() {
|
||||
clearLog('protocolOutput');
|
||||
const url = document.getElementById('testServerUrl').value;
|
||||
const type = document.getElementById('testTransportType').value;
|
||||
|
||||
log('protocolOutput', `开始测试 initialize 方法...`);
|
||||
log('protocolOutput', `服务器: ${url}`);
|
||||
log('protocolOutput', `传输类型: ${type}`);
|
||||
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
jsonrpc: '2.0',
|
||||
id: 1,
|
||||
method: 'initialize',
|
||||
params: {
|
||||
protocolVersion: '2024-11-05',
|
||||
clientInfo: {
|
||||
name: 'mcp-debug-tool',
|
||||
version: '1.0.0'
|
||||
},
|
||||
capabilities: {}
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
log('protocolOutput', '响应:', 'success');
|
||||
log('protocolOutput', JSON.stringify(data, null, 2), 'success');
|
||||
|
||||
if (data.result) {
|
||||
log('protocolOutput', `✅ 服务器: ${data.result.serverInfo?.name} v${data.result.serverInfo?.version}`, 'success');
|
||||
log('protocolOutput', `✅ 协议版本: ${data.result.protocolVersion}`, 'success');
|
||||
} else if (data.error) {
|
||||
log('protocolOutput', `❌ 错误: ${data.error.message}`, 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
log('protocolOutput', `❌ 请求失败: ${error.message}`, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// 测试 List Tools
|
||||
async function testListTools() {
|
||||
clearLog('protocolOutput');
|
||||
const url = document.getElementById('testServerUrl').value;
|
||||
|
||||
log('protocolOutput', `开始测试 tools/list 方法...`);
|
||||
|
||||
try {
|
||||
// 先 initialize
|
||||
const initResp = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
jsonrpc: '2.0',
|
||||
id: 1,
|
||||
method: 'initialize',
|
||||
params: {
|
||||
protocolVersion: '2024-11-05',
|
||||
clientInfo: { name: 'mcp-debug-tool', version: '1.0.0' },
|
||||
capabilities: {}
|
||||
}
|
||||
})
|
||||
});
|
||||
await initResp.json();
|
||||
|
||||
// 然后列出工具
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
jsonrpc: '2.0',
|
||||
id: 2,
|
||||
method: 'tools/list',
|
||||
params: {}
|
||||
})
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
log('protocolOutput', '响应:', 'success');
|
||||
log('protocolOutput', JSON.stringify(data, null, 2), 'success');
|
||||
|
||||
if (data.result?.tools) {
|
||||
log('protocolOutput', `✅ 找到 ${data.result.tools.length} 个工具`, 'success');
|
||||
data.result.tools.forEach((tool, index) => {
|
||||
log('protocolOutput', ` ${index + 1}. ${tool.name} - ${tool.description}`, 'info');
|
||||
});
|
||||
} else if (data.error) {
|
||||
log('protocolOutput', `❌ 错误: ${data.error.message}`, 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
log('protocolOutput', `❌ 请求失败: ${error.message}`, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// 测试 Call Tool
|
||||
async function testCallTool() {
|
||||
clearLog('protocolOutput');
|
||||
const url = document.getElementById('testServerUrl').value;
|
||||
|
||||
log('protocolOutput', `开始测试 tools/call 方法...`);
|
||||
log('protocolOutput', `将调用 get_account 工具...`);
|
||||
|
||||
try {
|
||||
// 先 initialize
|
||||
const initResp = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
jsonrpc: '2.0',
|
||||
id: 1,
|
||||
method: 'initialize',
|
||||
params: {
|
||||
protocolVersion: '2024-11-05',
|
||||
clientInfo: { name: 'mcp-debug-tool', version: '1.0.0' },
|
||||
capabilities: {}
|
||||
}
|
||||
})
|
||||
});
|
||||
await initResp.json();
|
||||
|
||||
// 调用工具
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
jsonrpc: '2.0',
|
||||
id: 3,
|
||||
method: 'tools/call',
|
||||
params: {
|
||||
name: 'get_account',
|
||||
arguments: {}
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
log('protocolOutput', '响应:', 'success');
|
||||
log('protocolOutput', JSON.stringify(data, null, 2), 'success');
|
||||
|
||||
if (data.result) {
|
||||
log('protocolOutput', `✅ 工具调用成功`, 'success');
|
||||
} else if (data.error) {
|
||||
log('protocolOutput', `❌ 错误: ${data.error.message}`, 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
log('protocolOutput', `❌ 请求失败: ${error.message}`, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// 收集调试信息
|
||||
async function collectDebugInfo() {
|
||||
clearLog('debugOutput');
|
||||
|
||||
log('debugOutput', '=== 系统信息 ===');
|
||||
log('debugOutput', `浏览器: ${navigator.userAgent}`);
|
||||
log('debugOutput', `时间: ${new Date().toLocaleString()}`);
|
||||
log('debugOutput', '');
|
||||
|
||||
log('debugOutput', '=== 服务状态检查 ===');
|
||||
|
||||
// 检查前端
|
||||
try {
|
||||
const frontendResp = await fetch('http://localhost:5173');
|
||||
log('debugOutput', '✅ 前端服务: 运行中', 'success');
|
||||
} catch (e) {
|
||||
log('debugOutput', '❌ 前端服务: 未运行', 'error');
|
||||
}
|
||||
|
||||
// 检查 HTTP MCP
|
||||
try {
|
||||
const httpResp = await fetch('http://localhost:3100/mcp', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
jsonrpc: '2.0',
|
||||
id: 1,
|
||||
method: 'initialize',
|
||||
params: {
|
||||
protocolVersion: '2024-11-05',
|
||||
clientInfo: { name: 'debug', version: '1.0.0' }
|
||||
}
|
||||
})
|
||||
});
|
||||
const data = await httpResp.json();
|
||||
log('debugOutput', `✅ HTTP MCP服务: ${data.result?.serverInfo?.name} v${data.result?.serverInfo?.version}`, 'success');
|
||||
} catch (e) {
|
||||
log('debugOutput', `❌ HTTP MCP服务: ${e.message}`, 'error');
|
||||
}
|
||||
|
||||
log('debugOutput', '');
|
||||
log('debugOutput', '=== 建议操作 ===');
|
||||
log('debugOutput', '1. 如果MCP服务未运行,请执行:');
|
||||
log('debugOutput', ' cd /Users/gavin/xhs/mcp_client/xhsLoginMCP && node server.js');
|
||||
log('debugOutput', '');
|
||||
log('debugOutput', '2. 如果前端未运行,请执行:');
|
||||
log('debugOutput', ' cd /Users/gavin/xhs/mcp_client/mcp-client-vue/web && npm run dev');
|
||||
log('debugOutput', '');
|
||||
log('debugOutput', '3. 打开前端应用: http://localhost:5173');
|
||||
log('debugOutput', '4. 打开浏览器控制台查看日志');
|
||||
log('debugOutput', '5. 测试编辑按钮和连接功能');
|
||||
}
|
||||
|
||||
// 页面加载时检查状态
|
||||
window.addEventListener('load', checkSystemStatus);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
54
web/public/diagnose-edit-button.js
Normal file
54
web/public/diagnose-edit-button.js
Normal file
@@ -0,0 +1,54 @@
|
||||
// 在浏览器控制台执行此脚本来诊断问题
|
||||
|
||||
console.log('=== 开始诊断 ===')
|
||||
|
||||
// 1. 检查编辑按钮是否存在
|
||||
const editButtons = document.querySelectorAll('button')
|
||||
let editButton = null
|
||||
editButtons.forEach(btn => {
|
||||
if (btn.textContent.includes('编辑')) {
|
||||
editButton = btn
|
||||
}
|
||||
})
|
||||
console.log('1️⃣ 编辑按钮:', editButton ? '✅ 找到' : '❌ 未找到')
|
||||
|
||||
// 2. 检查 Vue 应用实例
|
||||
const app = document.querySelector('#app')
|
||||
if (app && app.__vueParentComponent) {
|
||||
console.log('2️⃣ Vue 应用:', '✅ 存在')
|
||||
|
||||
// 尝试访问 setup 状态
|
||||
const instance = app.__vueParentComponent
|
||||
if (instance.setupState) {
|
||||
console.log('3️⃣ showServerDetail:', instance.setupState.showServerDetail)
|
||||
console.log('3️⃣ editingServer:', instance.setupState.editingServer)
|
||||
}
|
||||
} else {
|
||||
console.log('2️⃣ Vue 应用:', '❌ 未找到')
|
||||
}
|
||||
|
||||
// 3. 检查 Modal 元素
|
||||
const modals = document.querySelectorAll('.n-modal')
|
||||
console.log('4️⃣ Modal 元素数量:', modals.length)
|
||||
if (modals.length > 0) {
|
||||
modals.forEach((modal, i) => {
|
||||
const styles = window.getComputedStyle(modal)
|
||||
console.log(` Modal ${i}:`, {
|
||||
display: styles.display,
|
||||
opacity: styles.opacity,
|
||||
visibility: styles.visibility
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// 4. 手动触发点击(如果找到按钮)
|
||||
if (editButton) {
|
||||
console.log('5️⃣ 尝试手动点击编辑按钮...')
|
||||
editButton.click()
|
||||
setTimeout(() => {
|
||||
const modalsAfter = document.querySelectorAll('.n-modal')
|
||||
console.log('6️⃣ 点击后 Modal 数量:', modalsAfter.length)
|
||||
}, 500)
|
||||
}
|
||||
|
||||
console.log('=== 诊断结束 ===')
|
||||
271
web/public/modal-debug.html
Normal file
271
web/public/modal-debug.html
Normal file
@@ -0,0 +1,271 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>MCP Modal 调试</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
||||
padding: 20px;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
.debug-section {
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
margin-bottom: 20px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||||
}
|
||||
h2 {
|
||||
margin-top: 0;
|
||||
color: #333;
|
||||
}
|
||||
.button {
|
||||
background: #18a058;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 10px 20px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.button:hover {
|
||||
background: #16955d;
|
||||
}
|
||||
.button.secondary {
|
||||
background: #666;
|
||||
}
|
||||
.button.secondary:hover {
|
||||
background: #555;
|
||||
}
|
||||
.log-area {
|
||||
background: #1e1e1e;
|
||||
color: #d4d4d4;
|
||||
padding: 15px;
|
||||
border-radius: 4px;
|
||||
font-family: 'Monaco', 'Menlo', 'Courier New', monospace;
|
||||
font-size: 12px;
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
margin-top: 10px;
|
||||
}
|
||||
.log-entry {
|
||||
margin: 4px 0;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.log-success { color: #4ade80; }
|
||||
.log-error { color: #f87171; }
|
||||
.log-warning { color: #fbbf24; }
|
||||
.log-info { color: #60a5fa; }
|
||||
.status-indicator {
|
||||
display: inline-block;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
margin-right: 8px;
|
||||
}
|
||||
.status-connected { background: #4ade80; }
|
||||
.status-disconnected { background: #94a3b8; }
|
||||
.status-error { background: #f87171; }
|
||||
.test-result {
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
.test-result.success {
|
||||
background: #d1fae5;
|
||||
border: 1px solid #4ade80;
|
||||
color: #065f46;
|
||||
}
|
||||
.test-result.error {
|
||||
background: #fee2e2;
|
||||
border: 1px solid #f87171;
|
||||
color: #991b1b;
|
||||
}
|
||||
.code-block {
|
||||
background: #f3f4f6;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
font-family: monospace;
|
||||
font-size: 12px;
|
||||
overflow-x: auto;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>🔍 MCP Modal 调试工具</h1>
|
||||
|
||||
<div class="debug-section">
|
||||
<h2>📋 调试步骤</h2>
|
||||
<ol>
|
||||
<li>打开浏览器开发者工具 (F12 或 Cmd+Option+I)</li>
|
||||
<li>切换到 <strong>Console</strong> 标签</li>
|
||||
<li>回到主应用 (<a href="http://localhost:5173" target="_blank">http://localhost:5173</a>)</li>
|
||||
<li>点击任意 MCP 服务器的 <strong>"编辑"</strong> 按钮</li>
|
||||
<li>在 Console 中查找以下日志</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<div class="debug-section">
|
||||
<h2>🔎 预期的控制台输出</h2>
|
||||
<div class="log-area">
|
||||
<div class="log-entry log-info">🔍 [1] 打开服务器详情被调用</div>
|
||||
<div class="log-entry log-info">🔍 [2] 服务器数据: { id: "...", name: "test", url: "...", ... }</div>
|
||||
<div class="log-entry log-info">🔍 [3] 当前 showServerDetail 值: false</div>
|
||||
<div class="log-entry log-info">🔍 [4] editingServer 设置完成: { id: "...", name: "test", ... }</div>
|
||||
<div class="log-entry log-success">✅ [5] showServerDetail 设置为 true</div>
|
||||
<div class="log-entry log-success">✅ [6] 最终状态检查 - showServerDetail: true editingServer: {...}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="debug-section">
|
||||
<h2>🐛 可能的问题和解决方案</h2>
|
||||
|
||||
<h3>问题 1: 点击"编辑"按钮后,控制台完全没有日志</h3>
|
||||
<div class="test-result error">
|
||||
<strong>原因</strong>: 按钮的点击事件没有被触发
|
||||
<br><br>
|
||||
<strong>检查</strong>:
|
||||
<ul>
|
||||
<li>检查按钮是否被其他元素遮挡</li>
|
||||
<li>检查是否有 JavaScript 错误阻止了事件处理</li>
|
||||
<li>在 Elements 标签中检查按钮的 DOM 结构</li>
|
||||
</ul>
|
||||
<strong>解决方案</strong>: 刷新页面后重试,或清除浏览器缓存
|
||||
</div>
|
||||
|
||||
<h3>问题 2: 有日志输出,但 modal 不显示</h3>
|
||||
<div class="test-result error">
|
||||
<strong>原因</strong>: Modal 组件渲染或样式问题
|
||||
<br><br>
|
||||
<strong>检查</strong>:
|
||||
<ul>
|
||||
<li>在 Elements 标签中搜索 "n-modal",查看元素是否存在</li>
|
||||
<li>检查 modal 的 CSS 样式(display、opacity、z-index等)</li>
|
||||
<li>查看是否有 Vue 组件渲染错误</li>
|
||||
</ul>
|
||||
<strong>在控制台执行此代码</strong>:
|
||||
<div class="code-block">
|
||||
const modal = document.querySelector('.n-modal')<br>
|
||||
console.log('Modal 元素:', modal)<br>
|
||||
console.log('Modal 样式:', modal ? window.getComputedStyle(modal) : 'Not found')
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3>问题 3: 日志显示 showServerDetail 为 true,但看不到 modal</h3>
|
||||
<div class="test-result error">
|
||||
<strong>原因</strong>: Modal 可能被渲染在错误的位置或 z-index 太低
|
||||
<br><br>
|
||||
<strong>临时解决方案</strong>:
|
||||
<div class="code-block">
|
||||
// 在控制台执行,强制显示 modal<br>
|
||||
const modals = document.querySelectorAll('.n-modal')<br>
|
||||
modals.forEach(m => {<br>
|
||||
m.style.display = 'flex'<br>
|
||||
m.style.opacity = '1'<br>
|
||||
m.style.zIndex = '9999'<br>
|
||||
})
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="debug-section">
|
||||
<h2>✅ 测试清单</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<input type="checkbox" id="check1">
|
||||
<label for="check1">开发服务器运行在 http://localhost:5173</label>
|
||||
</li>
|
||||
<li>
|
||||
<input type="checkbox" id="check2">
|
||||
<label for="check2">浏览器开发者工具已打开</label>
|
||||
</li>
|
||||
<li>
|
||||
<input type="checkbox" id="check3">
|
||||
<label for="check3">Console 标签已选中</label>
|
||||
</li>
|
||||
<li>
|
||||
<input type="checkbox" id="check4">
|
||||
<label for="check4">可以看到至少一个 MCP 服务器卡片</label>
|
||||
</li>
|
||||
<li>
|
||||
<input type="checkbox" id="check5">
|
||||
<label for="check5">点击"编辑"按钮后看到控制台日志</label>
|
||||
</li>
|
||||
<li>
|
||||
<input type="checkbox" id="check6">
|
||||
<label for="check6">Modal 对话框成功显示</label>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="debug-section">
|
||||
<h2>🔧 快速修复脚本</h2>
|
||||
<p>如果 modal 不显示,在浏览器控制台执行以下代码:</p>
|
||||
|
||||
<h3>检查 Vue 应用状态</h3>
|
||||
<div class="code-block">
|
||||
// 检查 showServerDetail 的值<br>
|
||||
const app = document.querySelector('#app')<br>
|
||||
const vueInstance = app?.__vueParentComponent<br>
|
||||
console.log('Vue 实例:', vueInstance)<br>
|
||||
<br>
|
||||
// 如果能访问到 setupState<br>
|
||||
console.log('showServerDetail:', vueInstance?.setupState?.showServerDetail)<br>
|
||||
console.log('editingServer:', vueInstance?.setupState?.editingServer)
|
||||
</div>
|
||||
|
||||
<h3>强制触发 modal 显示</h3>
|
||||
<div class="code-block">
|
||||
// 在控制台直接设置状态(需要 Vue Devtools)<br>
|
||||
// 或者尝试直接修改 DOM<br>
|
||||
const backdrop = document.querySelector('.n-modal-container')<br>
|
||||
if (backdrop) {<br>
|
||||
backdrop.style.display = 'block'<br>
|
||||
backdrop.style.opacity = '1'<br>
|
||||
console.log('✅ Modal backdrop 已强制显示')<br>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="debug-section">
|
||||
<h2>📞 需要报告的信息</h2>
|
||||
<p>如果问题持续,请提供以下信息:</p>
|
||||
<ol>
|
||||
<li>点击"编辑"后控制台的完整输出(截图)</li>
|
||||
<li>浏览器的 Elements 标签中搜索 "n-modal" 的结果(截图)</li>
|
||||
<li>Console 中是否有任何红色错误信息</li>
|
||||
<li>浏览器类型和版本</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<div class="debug-section">
|
||||
<h2>🚀 返回主应用</h2>
|
||||
<button class="button" onclick="window.location.href='http://localhost:5173'">
|
||||
打开 MCP Client (http://localhost:5173)
|
||||
</button>
|
||||
<button class="button secondary" onclick="window.location.reload()">
|
||||
刷新此页面
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 添加一些交互功能
|
||||
document.querySelectorAll('input[type="checkbox"]').forEach(checkbox => {
|
||||
checkbox.addEventListener('change', () => {
|
||||
const allChecked = Array.from(document.querySelectorAll('input[type="checkbox"]')).every(c => c.checked)
|
||||
if (allChecked) {
|
||||
alert('🎉 太棒了!所有步骤都完成了!')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
console.log('📋 调试页面已加载')
|
||||
console.log('📍 请访问 http://localhost:5173 进行测试')
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user