feat: MCP Token 复制按钮 — 后台一键取回明文 Token 到剪贴板

This commit is contained in:
2026-09-11 15:10:57 +08:00
parent 861f132274
commit 8cf91aed9a
3 changed files with 43 additions and 0 deletions
+10
View File
@@ -797,6 +797,16 @@ func MCPStatus(c *gin.Context) {
})
}
// MCPGetToken 返回完整明文 Token(供后台「复制」按钮使用,需已登录后台会话)
func MCPGetToken(c *gin.Context) {
_, token := getMCPAuthState()
if token == "" {
c.JSON(http.StatusOK, gin.H{"success": false, "message": "Token 未生成,请先点「重新生成」"})
return
}
c.JSON(http.StatusOK, gin.H{"success": true, "token": token})
}
// MCPRegenerateToken 生成新随机 Token 并自动启用 MCP,返回完整新 Token(仅此一次明文展示)
func MCPRegenerateToken(c *gin.Context) {
b := make([]byte, 24)
+1
View File
@@ -72,6 +72,7 @@ func main() {
// MCP 管理(后台 UI)
admin.GET("/api/mcp/status", handlers.MCPStatus)
admin.GET("/api/mcp/token", handlers.MCPGetToken)
admin.POST("/api/mcp/token", handlers.MCPRegenerateToken)
admin.POST("/api/mcp/enabled", handlers.MCPSetEnabled)
}
+32
View File
@@ -139,6 +139,7 @@
<label style="font-size:12px; color:#666">Token</label>
<div style="display:flex; gap:8px; align-items:center">
<input type="text" id="cfg_mcp_token" class="input" readonly style="flex:1; background:#fff; color:#555">
<button class="btn btn-primary" onclick="copyMCPToken(this)" style="padding:8px 14px; white-space:nowrap">📋 复制</button>
<button class="btn btn-primary" onclick="regenMCPToken()" style="padding:8px 14px; white-space:nowrap">🔄 重新生成</button>
</div>
<div style="font-size:11px; color:#999; margin-top:6px">
@@ -200,6 +201,37 @@
});
}
async function copyMCPToken(btn) {
try {
const resp = await fetch('/admin/api/mcp/token');
const res = await resp.json();
if (!res.success) { alert('❌ ' + (res.message || 'Token 未生成')); return; }
const token = res.token;
let copied = false;
try {
await navigator.clipboard.writeText(token);
copied = true;
} catch (e) {
// 非 HTTPS/localhost 环境降级方案
const ta = document.createElement('textarea');
ta.value = token;
ta.style.position = 'fixed';
ta.style.opacity = '0';
document.body.appendChild(ta);
ta.focus(); ta.select();
try { copied = document.execCommand('copy'); } catch (e2) {}
document.body.removeChild(ta);
}
if (copied) {
const old = btn.textContent;
btn.textContent = '✅ 已复制';
setTimeout(() => { btn.textContent = old; }, 1500);
} else {
prompt('自动复制不可用,请手动复制 Token:', token);
}
} catch(e) { alert('获取 Token 失败'); }
}
async function regenMCPToken() {
if (!confirm('确定重新生成 Token?\n\n旧 Token 将立即失效,已接入的 AI 客户端需要更新为新 Token。')) return;
try {