feat: mcp测试版

This commit is contained in:
ageer
2025-04-14 23:10:17 +08:00
parent 188dc1e55e
commit a4314dbbde
14 changed files with 455 additions and 452 deletions

View File

@@ -0,0 +1,16 @@
server:
port: 9999
spring:
ai:
openai:
api-key: sk-xXe1WMPjhlVb1aiI1b4c6c8934D8463f9e4b67Ed8718B772
base-url: https://api.pandarobot.chat/
mcp:
client:
enabled: true
name: call-mcp-server
sse:
connections:
server1:
url: http://127.0.0.1:6040

View File

@@ -0,0 +1,40 @@
{
"mcpServers": {
"fileSystem": {
"command": "D:\\software\\nodeJs\\npx.cmd",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"D:\\software\\sqlite"
]
},
"sqlLite": {
"command": "D:\\Program Files\\python3.12.3\\Scripts\\uvx.exe",
"args": [
"mcp-server-sqlite",
"--db-path",
"D:\\work-space-study\\spring-ai-mcp-demo\\mcp-client\\src\\main\\resources\\test.db"
]
},
"fetch": {
"command": "D:\\Program Files\\python3.12.3\\Scripts\\uvx.exe",
"args": [
"mcp-server-fetch"
]
},
"baidu-map": {
"command": "D:\\Program Files\\python3.12.3\\Scripts\\uvx.exe",
"args": [
"run",
"--with",
"mcp[cli]",
"mcp",
"run",
"D:\\work-space-python\\python-baidu-map\\baidu_map_mcp_server\\map.py"
],
"env": {
"BAIDU_MAPS_API_KEY": "{百度地图API-KEY}"
}
}
}
}

View File

@@ -0,0 +1,20 @@
{
"mcpServers": {
"fileSystem": {
"command": "D:\\software\\nodeJs\\npx.cmd",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"D:\\software\\sqlite"
]
},
"sqlLite": {
"command": "D:\\Program Files\\python3.12.3\\Scripts\\uvx.exe",
"args": [
"mcp-server-sqlite",
"--db-path",
"D:\\work-space-study\\spring-ai-mcp-demo\\mcp-client\\src\\main\\resources\\test.db"
]
}
}
}

View File

@@ -0,0 +1,148 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AI 对话助手</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-gray-100 min-h-screen">
<div class="container mx-auto p-4 max-w-3xl">
<!-- 标题 -->
<div class="text-center mb-8">
<h1 class="text-3xl font-bold text-gray-800">AI 对话助手</h1>
<p class="text-gray-600 mt-2">基于 Spring AI 的流式对话系统 By AhuCodingBeast</p>
</div>
<!-- 聊天容器 -->
<div id="chat-container" class="bg-white rounded-xl shadow-lg p-4 mb-4 h-[500px] overflow-y-auto space-y-4">
<!-- 初始欢迎消息 -->
<div class="ai-message flex items-start gap-3">
<div class="bg-green-100 p-3 rounded-lg max-w-[85%]">
<span class="text-gray-800">您好我是AI助手有什么可以帮您</span>
</div>
</div>
</div>
<!-- 输入区域 -->
<div class="flex gap-2">
<input type="text" id="message-input"
class="flex-1 border border-gray-300 rounded-xl px-4 py-3 focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder="输入您的问题...">
<button id="send-button"
class="bg-blue-500 text-white px-6 py-3 rounded-xl hover:bg-blue-600 transition-colors flex items-center">
<span>发送</span>
<svg id="loading-spinner" class="hidden w-4 h-4 ml-2 animate-spin" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"></path>
</svg>
</button>
</div>
</div>
<script>
const chatContainer = document.getElementById('chat-container');
const messageInput = document.getElementById('message-input');
const sendButton = document.getElementById('send-button');
const loadingSpinner = document.getElementById('loading-spinner');
// 发送消息处理
function handleSend() {
const message = messageInput.value.trim();
if (!message) return;
// 添加用户消息
addMessage(message, 'user');
messageInput.value = '';
// 构建API URL
const apiUrl = new URL('http://localhost:9999/dashscope/chat-client/generate_stream');
apiUrl.searchParams.append('id', '01');
apiUrl.searchParams.append('prompt', message);
// 显示加载状态
sendButton.disabled = true;
loadingSpinner.classList.remove('hidden');
// 创建EventSource连接
const eventSource = new EventSource(apiUrl);
let aiMessageElement = null;
eventSource.onmessage = (event) => {
try {
const data = JSON.parse(event.data);
console.log(data);
const content = data.result?.output?.text || '';
const finishReason = data.result?.metadata?.finishReason;
// 创建消息容器(如果不存在)
if (!aiMessageElement) {
aiMessageElement = addMessage('', 'ai');
}
// 追加内容
if (content) {
aiMessageElement.querySelector('.message-content').textContent += content;
autoScroll();
}
// 处理结束
if (finishReason === 'STOP') {
eventSource.close();
sendButton.disabled = false;
loadingSpinner.classList.add('hidden');
}
} catch (error) {
console.error('解析错误:', error);
}
};
eventSource.onerror = (error) => {
console.error('连接错误:', error);
eventSource.close();
sendButton.disabled = false;
loadingSpinner.classList.add('hidden');
addMessage('对话连接异常,请重试', 'ai', true);
};
}
// 添加消息到容器
function addMessage(content, type, isError = false) {
const messageDiv = document.createElement('div');
messageDiv.className = `${type}-message flex items-start gap-3`;
const bubble = document.createElement('div');
bubble.className = `p-3 rounded-lg max-w-[85%] ${
type === 'user'
? 'bg-blue-500 text-white ml-auto'
: `bg-green-100 ${isError ? 'text-red-500' : 'text-gray-800'}`
}`;
const contentSpan = document.createElement('span');
contentSpan.className = 'message-content';
contentSpan.textContent = content;
bubble.appendChild(contentSpan);
messageDiv.appendChild(bubble);
chatContainer.appendChild(messageDiv);
autoScroll();
return bubble;
}
// 自动滚动到底部
function autoScroll() {
chatContainer.scrollTop = chatContainer.scrollHeight;
}
// 事件监听
sendButton.addEventListener('click', handleSend);
messageInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
handleSend();
}
});
</script>
</body>
</html>