修复 vscode/trae 下 tab 恢复的问题
This commit is contained in:
parent
e306388f14
commit
a0968902f4
@ -1,5 +1,12 @@
|
|||||||
# Change Log
|
# Change Log
|
||||||
|
|
||||||
|
## [main] 0.0.2
|
||||||
|
|
||||||
|
- 优化页面布局
|
||||||
|
- 解决更新标签页后打开无法显示的 bug
|
||||||
|
- 解决不如输入组件按下回车直接黑屏的 bug
|
||||||
|
- 更加完整方便的开发脚本
|
||||||
|
|
||||||
## [main] 0.0.1
|
## [main] 0.0.1
|
||||||
|
|
||||||
- 完成 openmcp 的基础 inspector 功能
|
- 完成 openmcp 的基础 inspector 功能
|
||||||
|
39
README.md
39
README.md
@ -13,13 +13,23 @@
|
|||||||
|
|
||||||
## OpenMCP
|
## OpenMCP
|
||||||
|
|
||||||
一款用于 MCP 服务端调试的一体化 vscode 插件。
|
一款用于 MCP 服务端调试的一体化 vscode/trae 插件。
|
||||||
|
|
||||||

|
集成 Inspector + MCP 客户端基础功能,开发测试一体化。
|
||||||
|
|
||||||
- 包含原版 Inpsector 的所有功能
|

|
||||||
- 包含一个简易的用于进行测试的大模型对话 & 执行窗口
|
|
||||||
- 支持多种大模型
|
进行资源协议、工具、Prompt 的 MCP 服务器测试。
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
测试完成的工具可以放入 「交互测试」 模块之间进行大模型交互测试。
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
支持多种大模型
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
@ -50,23 +60,22 @@ B <--mcp--> m(MCP Server)
|
|||||||
配置项目
|
配置项目
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
source configure.sh
|
## linux
|
||||||
|
./configure.sh
|
||||||
|
## windows
|
||||||
|
./configure.ps1
|
||||||
```
|
```
|
||||||
|
|
||||||
启动 dev server
|
启动 dev server
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd renderer
|
## linux
|
||||||
npm run serve
|
./dev.sh
|
||||||
```
|
## windows
|
||||||
|
./dev.ps1
|
||||||
启动 service
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd service
|
|
||||||
npm run serve
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> 端口占用: 8080 (renderer) + 8081 (service)
|
||||||
|
|
||||||
### Extention Dev
|
### Extention Dev
|
||||||
|
|
||||||
|
@ -1,23 +1,23 @@
|
|||||||
# Create resources directory if it doesn't exist
|
# 创建并清理资源目录
|
||||||
New-Item -ItemType Directory -Force -Path .\resources | Out-Null
|
New-Item -ItemType Directory -Path ./resources -Force
|
||||||
|
Remove-Item -Recurse -Force ./resources/*
|
||||||
|
New-Item -ItemType Directory -Path ./resources -Force
|
||||||
|
|
||||||
# Start both build tasks in parallel
|
# 并行构建 renderer 和 service
|
||||||
$jobs = @(
|
$rendererJob = Start-Job -ScriptBlock {
|
||||||
Start-Job -ScriptBlock {
|
cd ./renderer
|
||||||
Set-Location $using:PWD\renderer
|
|
||||||
npm run build
|
npm run build
|
||||||
Move-Item -Force -Path .\dist -Destination ..\resources\renderer
|
mv ./dist ../resources/renderer
|
||||||
}
|
}
|
||||||
Start-Job -ScriptBlock {
|
|
||||||
Set-Location $using:PWD\service
|
$serviceJob = Start-Job -ScriptBlock {
|
||||||
|
cd ./service
|
||||||
npm run build
|
npm run build
|
||||||
Move-Item -Force -Path .\dist -Destination ..\resources\service
|
mv ./dist ../resources/service
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
# Wait for all jobs to complete
|
# 等待任务完成
|
||||||
Wait-Job -Job $jobs | Out-Null
|
$rendererJob | Wait-Job | Receive-Job
|
||||||
Receive-Job -Job $jobs
|
$serviceJob | Wait-Job | Receive-Job
|
||||||
Remove-Job -Job $jobs
|
|
||||||
|
|
||||||
Write-Host "finish building services in ./resources"
|
Write-Output "finish building services in ./resources"
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
mkdir -p ./resources
|
mkdir -p ./resources
|
||||||
|
rm -rf ./resources/
|
||||||
|
mkdir -p ./resources
|
||||||
|
|
||||||
(cd ./renderer && npm run build && mv ./dist ../resources/renderer) &
|
(cd ./renderer && npm run build && mv ./dist ../resources/renderer) &
|
||||||
(cd ./service && npm run build && mv ./dist ../resources/service) &
|
(cd ./service && npm run build && mv ./dist ../resources/service) &
|
||||||
wait
|
wait
|
||||||
|
13
configure.ps1
Normal file
13
configure.ps1
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# 安装 renderer 依赖
|
||||||
|
Set-Location renderer
|
||||||
|
npm i
|
||||||
|
Set-Location ..
|
||||||
|
|
||||||
|
# 安装 service 依赖并打补丁
|
||||||
|
Set-Location service
|
||||||
|
npm i
|
||||||
|
node patch-mcp-sdk.js
|
||||||
|
Set-Location ..
|
||||||
|
|
||||||
|
# 安装根目录依赖
|
||||||
|
npm i
|
16
dev.ps1
Normal file
16
dev.ps1
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# 定义颜色变量
|
||||||
|
$PINK = "$([char]27)[33m"
|
||||||
|
$GREEN = "$([char]27)[32m"
|
||||||
|
$NC = "$([char]27)[0m"
|
||||||
|
|
||||||
|
Start-Job -ScriptBlock {
|
||||||
|
cd renderer
|
||||||
|
npm run serve | ForEach-Object { "$using:PINK[renderer]$using:NC $_" }
|
||||||
|
}
|
||||||
|
|
||||||
|
Start-Job -ScriptBlock {
|
||||||
|
cd service
|
||||||
|
npm run serve | ForEach-Object { "$using:GREEN[service]$using:NC $_" }
|
||||||
|
}
|
||||||
|
|
||||||
|
Get-Job | Wait-Job | Receive-Job -Wait
|
12
dev.sh
Executable file
12
dev.sh
Executable file
@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# 定义颜色变量(使用 -e 选项的 echo 时)
|
||||||
|
PINK=$'\033[33m'
|
||||||
|
GREEN=$'\033[32m'
|
||||||
|
NC=$'\033[0m'
|
||||||
|
|
||||||
|
(cd renderer && npm run serve | while read -r line; do echo -e "${PINK}[renderer]${NC} $line"; done) &
|
||||||
|
|
||||||
|
(cd service && npm run serve | while read -r line; do echo -e "${GREEN}[service]${NC} $line"; done) &
|
||||||
|
|
||||||
|
wait
|
BIN
icons/openmcp.chatbot.png
Normal file
BIN
icons/openmcp.chatbot.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 435 KiB |
BIN
icons/openmcp.resource.png
Normal file
BIN
icons/openmcp.resource.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 492 KiB |
BIN
icons/openmcp.support.llm.png
Normal file
BIN
icons/openmcp.support.llm.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 435 KiB |
BIN
icons/openmcp.welcome.png
Normal file
BIN
icons/openmcp.welcome.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 402 KiB |
Binary file not shown.
Before Width: | Height: | Size: 178 KiB |
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { onMounted } from 'vue';
|
import { onMounted } from 'vue';
|
||||||
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
import { Connection } from './components/sidebar/sidebar';
|
import { Connection } from './components/sidebar/sidebar';
|
||||||
|
|
||||||
import Sidebar from '@/components/sidebar/index.vue';
|
import Sidebar from '@/components/sidebar/index.vue';
|
||||||
@ -26,40 +27,28 @@ bridge.addCommandListener('hello', data => {
|
|||||||
greenLog(`version: ${data.version}`);
|
greenLog(`version: ${data.version}`);
|
||||||
}, { once: true });
|
}, { once: true });
|
||||||
|
|
||||||
// 监听 connect
|
|
||||||
bridge.addCommandListener('connect', async data => {
|
|
||||||
const { code, msg } = data;
|
|
||||||
connectionResult.success = (code === 200);
|
|
||||||
connectionResult.logString = msg;
|
|
||||||
|
|
||||||
const res = await getServerVersion() as { name: string, version: string };
|
|
||||||
connectionResult.serverInfo.name = res.name || '';
|
|
||||||
connectionResult.serverInfo.version = res.version || '';
|
|
||||||
|
|
||||||
}, { once: true });
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function initDebug() {
|
function initDebug() {
|
||||||
connectionArgs.commandString = 'mcp run ../servers/main.py';
|
connectionArgs.commandString = 'mcp run ../servers/main.py';
|
||||||
connectionMethods.current = 'STDIO';
|
connectionMethods.current = 'STDIO';
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(async () => {
|
||||||
// 初始化 设置
|
// 初始化 设置
|
||||||
loadSetting();
|
loadSetting();
|
||||||
|
|
||||||
|
// 尝试连接
|
||||||
|
await doConnect();
|
||||||
|
|
||||||
// 初始化 tab
|
// 初始化 tab
|
||||||
loadPanels();
|
loadPanels();
|
||||||
|
|
||||||
// 尝试连接
|
|
||||||
doConnect();
|
|
||||||
|
|
||||||
// 200 是我的电脑上的 ws 的连接时间,部署环境中不存在 ws 连接延时的问题,所以
|
|
||||||
// 可以直接不管
|
|
||||||
}, 200);
|
}, 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
function initProduce() {
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
async function initProduce() {
|
||||||
// TODO: get from vscode
|
// TODO: get from vscode
|
||||||
connectionArgs.commandString = 'mcp run ../servers/main.py';
|
connectionArgs.commandString = 'mcp run ../servers/main.py';
|
||||||
connectionMethods.current = 'STDIO';
|
connectionMethods.current = 'STDIO';
|
||||||
@ -67,10 +56,15 @@ function initProduce() {
|
|||||||
// 初始化 设置
|
// 初始化 设置
|
||||||
loadSetting();
|
loadSetting();
|
||||||
|
|
||||||
// 初始化 tab
|
// 尝试连接
|
||||||
loadPanels();
|
await launchConnect();
|
||||||
|
|
||||||
launchConnect();
|
// 初始化 tab
|
||||||
|
await loadPanels();
|
||||||
|
|
||||||
|
if (route.name !== 'debug') {
|
||||||
|
router.replace('/debug');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
import { addNewTab, tabs, closeTab } from './panel';
|
import { addNewTab, tabs, closeTab } from './panel';
|
||||||
|
import { panelLoaded } from '@/hook/panel';
|
||||||
|
|
||||||
defineComponent({ name: 'main-panel' });
|
defineComponent({ name: 'main-panel' });
|
||||||
|
|
||||||
|
@ -19,6 +19,8 @@ interface SaveTab {
|
|||||||
export const panelLoaded = ref(false);
|
export const panelLoaded = ref(false);
|
||||||
|
|
||||||
export function loadPanels() {
|
export function loadPanels() {
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
const bridge = useMessageBridge();
|
const bridge = useMessageBridge();
|
||||||
|
|
||||||
bridge.addCommandListener('panel/load', data => {
|
bridge.addCommandListener('panel/load', data => {
|
||||||
@ -51,17 +53,16 @@ export function loadPanels() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tabs.activeIndex = persistTab.currentIndex;
|
tabs.activeIndex = persistTab.currentIndex;
|
||||||
nextTick(() => {
|
|
||||||
tabs.activeIndex = persistTab.currentIndex;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
panelLoaded.value = true;
|
panelLoaded.value = true;
|
||||||
|
resolve(void 0);
|
||||||
}, { once: true });
|
}, { once: true });
|
||||||
|
|
||||||
bridge.postMessage({
|
bridge.postMessage({
|
||||||
command: 'panel/load'
|
command: 'panel/load'
|
||||||
});
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let debounceHandler: NodeJS.Timeout;
|
let debounceHandler: NodeJS.Timeout;
|
||||||
@ -74,10 +75,10 @@ export function safeSavePanels() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function savePanels(saveHandler?: () => void) {
|
export function savePanels(saveHandler?: () => void) {
|
||||||
// 没有完成 panel 加载就不保存
|
// // 没有完成 panel 加载就不保存
|
||||||
if (!panelLoaded.value) {
|
// if (!panelLoaded.value) {
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
const bridge = useMessageBridge();
|
const bridge = useMessageBridge();
|
||||||
|
|
||||||
|
@ -57,6 +57,20 @@ export interface MCPOptions {
|
|||||||
|
|
||||||
export function doConnect() {
|
export function doConnect() {
|
||||||
let connectOption: MCPOptions;
|
let connectOption: MCPOptions;
|
||||||
|
const bridge = useMessageBridge();
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
// 监听 connect
|
||||||
|
bridge.addCommandListener('connect', async data => {
|
||||||
|
const { code, msg } = data;
|
||||||
|
connectionResult.success = (code === 200);
|
||||||
|
connectionResult.logString = msg;
|
||||||
|
|
||||||
|
const res = await getServerVersion() as { name: string, version: string };
|
||||||
|
connectionResult.serverInfo.name = res.name || '';
|
||||||
|
connectionResult.serverInfo.version = res.version || '';
|
||||||
|
resolve(void 0);
|
||||||
|
}, { once: true });
|
||||||
|
|
||||||
if (connectionMethods.current === 'STDIO') {
|
if (connectionMethods.current === 'STDIO') {
|
||||||
|
|
||||||
@ -91,11 +105,11 @@ export function doConnect() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const bridge = useMessageBridge();
|
|
||||||
bridge.postMessage({
|
bridge.postMessage({
|
||||||
command: 'connect',
|
command: 'connect',
|
||||||
data: connectOption
|
data: connectOption
|
||||||
});
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -106,16 +120,30 @@ export async function launchConnect() {
|
|||||||
// 后续需要考虑到不同的连接方式
|
// 后续需要考虑到不同的连接方式
|
||||||
|
|
||||||
connectionMethods.current = 'STDIO';
|
connectionMethods.current = 'STDIO';
|
||||||
|
const bridge = useMessageBridge();
|
||||||
|
|
||||||
pinkLog('请求启动参数');
|
pinkLog('请求启动参数');
|
||||||
const { commandString, cwd } = await getLaunchCommand();
|
const { commandString, cwd } = await getLaunchCommand();
|
||||||
|
|
||||||
connectionArgs.commandString = commandString;
|
connectionArgs.commandString = commandString;
|
||||||
|
|
||||||
if (connectionArgs.commandString.length === 0) {
|
if (connectionArgs.commandString.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return new Promise<void>((resolve, reject) => {
|
||||||
|
// 监听 connect
|
||||||
|
bridge.addCommandListener('connect', async data => {
|
||||||
|
const { code, msg } = data;
|
||||||
|
connectionResult.success = (code === 200);
|
||||||
|
connectionResult.logString = msg;
|
||||||
|
|
||||||
|
const res = await getServerVersion() as { name: string, version: string };
|
||||||
|
connectionResult.serverInfo.name = res.name || '';
|
||||||
|
connectionResult.serverInfo.version = res.version || '';
|
||||||
|
resolve(void 0);
|
||||||
|
}, { once: true });
|
||||||
|
|
||||||
|
|
||||||
const commandComponents = connectionArgs.commandString.split(/\s+/g);
|
const commandComponents = connectionArgs.commandString.split(/\s+/g);
|
||||||
const command = commandComponents[0];
|
const command = commandComponents[0];
|
||||||
commandComponents.shift();
|
commandComponents.shift();
|
||||||
@ -129,11 +157,11 @@ export async function launchConnect() {
|
|||||||
clientVersion: '0.0.1'
|
clientVersion: '0.0.1'
|
||||||
};
|
};
|
||||||
|
|
||||||
const bridge = useMessageBridge();
|
|
||||||
bridge.postMessage({
|
bridge.postMessage({
|
||||||
command: 'connect',
|
command: 'connect',
|
||||||
data: connectOption
|
data: connectOption
|
||||||
});
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<Welcome v-show="!haveActiveTab"></Welcome>
|
<Welcome v-show="!haveActiveTab"></Welcome>
|
||||||
|
|
||||||
<!-- 如果存在激活标签页,则根据标签页进行渲染 -->
|
<!-- 如果存在激活标签页,则根据标签页进行渲染 -->
|
||||||
<div v-show="haveActiveTab" style="height: 100%;">
|
<div v-show="haveActiveTab" v-if="panelLoaded" style="height: 100%;">
|
||||||
<!-- vscode/trae 中,下面存在初始化问题 -->
|
<!-- vscode/trae 中,下面存在初始化问题 -->
|
||||||
<component
|
<component
|
||||||
v-show="tab === tabs.content[tabs.activeIndex]"
|
v-show="tab === tabs.content[tabs.activeIndex]"
|
||||||
|
@ -36,5 +36,8 @@ module.exports = defineConfig({
|
|||||||
},
|
},
|
||||||
css: {
|
css: {
|
||||||
extract: false
|
extract: false
|
||||||
|
},
|
||||||
|
devServer: {
|
||||||
|
port: 8081
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"currentIndex": 0,
|
"currentIndex": 1,
|
||||||
"tabs": [
|
"tabs": [
|
||||||
{
|
{
|
||||||
"name": "资源",
|
"name": "资源",
|
||||||
@ -7,54 +7,7 @@
|
|||||||
"type": "blank",
|
"type": "blank",
|
||||||
"componentIndex": 0,
|
"componentIndex": 0,
|
||||||
"storage": {
|
"storage": {
|
||||||
"currentResourceName": "greeting",
|
"currentResourceName": "greeting"
|
||||||
"lastResourceReadResponse": {
|
|
||||||
"contents": [
|
|
||||||
{
|
|
||||||
"uri": "greeting://12312",
|
|
||||||
"mimeType": "text/plain",
|
|
||||||
"text": "Hello, 12312!"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "交互测试",
|
|
||||||
"icon": "icon-robot",
|
|
||||||
"type": "blank",
|
|
||||||
"componentIndex": 3,
|
|
||||||
"storage": {
|
|
||||||
"messages": [],
|
|
||||||
"settings": {
|
|
||||||
"modelIndex": 0,
|
|
||||||
"enableTools": [
|
|
||||||
{
|
|
||||||
"name": "add",
|
|
||||||
"description": "对两个数字进行实数域的加法",
|
|
||||||
"enabled": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "multiply",
|
|
||||||
"description": "对两个数字进行实数域的乘法运算",
|
|
||||||
"enabled": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "is_even",
|
|
||||||
"description": "判断一个整数是否为偶数",
|
|
||||||
"enabled": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "capitalize",
|
|
||||||
"description": "将字符串首字母大写",
|
|
||||||
"enabled": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"enableWebSearch": false,
|
|
||||||
"temperature": 0.7,
|
|
||||||
"contextLength": 10,
|
|
||||||
"systemPrompt": ""
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user