Merge pull request #20 from LSTM-Kirigaya/main

sync
This commit is contained in:
Li Yaning 2025-05-26 21:40:31 +08:00 committed by GitHub
commit fc68a12b30
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 52 additions and 24 deletions

View File

@ -1,5 +1,11 @@
# Change Log # Change Log
## [main] 0.1.1
- 修复 SSH 连接 Ubuntu 的情况下的部分 bug
- 修复 python 项目点击 openmcp 进行连接时,初始化参数错误的问题
- 取消 service 底层的 mcp 连接复用技术,防止无法刷新
- 修复连接后,可能无法在欢迎界面选择调试选项的 bug
## [main] 0.1.0 ## [main] 0.1.0
- 新特性:支持同时连入多个 mcp server - 新特性:支持同时连入多个 mcp server
- 新特性:更新协议内容,支持 streamable http 协议,未来将逐步取代 SSE 的连接方式 - 新特性:更新协议内容,支持 streamable http 协议,未来将逐步取代 SSE 的连接方式

View File

@ -9,6 +9,8 @@
<a href="https://discord.gg/af5cfB9a" target="_blank" style="display: inline-block; padding: 8px 16px; background-color: rgb(84, 176, 84); color: white; border-radius: .5em; text-decoration: none;"> 加入 OpenMCP Discord频道</a> <a href="https://discord.gg/af5cfB9a" target="_blank" style="display: inline-block; padding: 8px 16px; background-color: rgb(84, 176, 84); color: white; border-radius: .5em; text-decoration: none;"> 加入 OpenMCP Discord频道</a>
<a href="https://github.com/LSTM-Kirigaya/openmcp-document" target="_blank" style="display: inline-block; padding: 8px 16px; background-color: rgb(84, 176, 84); color: white; border-radius: .5em; text-decoration: none;"> 📄OpenMCP 文档仓库</a>
</div> </div>
@ -17,6 +19,7 @@
一款用于 MCP 服务端调试的一体化 vscode/trae/cursor 插件。 一款用于 MCP 服务端调试的一体化 vscode/trae/cursor 插件。
<video src="https://github.com/user-attachments/assets/ab214d58-b77c-4bd3-8b6e-55552f4036ff" width="100%"></video> <video src="https://github.com/user-attachments/assets/ab214d58-b77c-4bd3-8b6e-55552f4036ff" width="100%"></video>
<video src="https://github.com/user-attachments/assets/c17a4ad7-83b4-47ff-8627-85b57ad18940" width="100%"></video> <video src="https://github.com/user-attachments/assets/c17a4ad7-83b4-47ff-8627-85b57ad18940" width="100%"></video>

View File

@ -2,7 +2,7 @@
"name": "openmcp", "name": "openmcp",
"displayName": "OpenMCP", "displayName": "OpenMCP",
"description": "An all in one MCP Client/TestTool", "description": "An all in one MCP Client/TestTool",
"version": "0.1.0", "version": "0.1.1",
"publisher": "kirigaya", "publisher": "kirigaya",
"author": { "author": {
"name": "kirigaya", "name": "kirigaya",

View File

@ -6,7 +6,7 @@
</span> </span>
<p> <p>
OpenMCP Client 0.1.0 OpenMCP@<a href="https://www.zhihu.com/people/can-meng-zhong-de-che-xian">锦恢</a> 开发 OpenMCP Client 0.1.1 OpenMCP@<a href="https://www.zhihu.com/people/can-meng-zhong-de-che-xian">锦恢</a> 开发
</p> </p>
<p> <p>

View File

@ -471,7 +471,8 @@ class McpClientAdapter {
for (const item of launchSignature) { for (const item of launchSignature) {
// 创建一个新的客户端 // 创建一个新的客户端
const client = reactive(new McpClient()); // const client = reactive(new McpClient());
const client = new McpClient();
// 同步连接参数 // 同步连接参数
await client.acquireConnectionSignature(item); await client.acquireConnectionSignature(item);
@ -562,6 +563,10 @@ class McpClientAdapter {
return msg; return msg;
} }
public get connected() {
return this.clients.length > 0 && this.clients[0].connectionResult.success;
}
public async loadPanels() { public async loadPanels() {
const masterNode = this.clients[0]; const masterNode = this.clients[0];
await loadPanels(masterNode); await loadPanels(masterNode);

View File

@ -62,11 +62,11 @@ function selectServer(index: number) {
} }
function addServer() { function addServer() {
const client = reactive(new McpClient()); // const client = reactive(new McpClient());
const client = new McpClient();
mcpClientAdapter.clients.push(client); mcpClientAdapter.clients.push(client);
mcpClientAdapter.currentClientIndex = mcpClientAdapter.clients.length - 1; mcpClientAdapter.currentClientIndex = mcpClientAdapter.clients.length - 1;
mcpClientAdapter.clients.at(-1)!.handleEnvSwitch(true);
client.handleEnvSwitch(true);
} }

View File

@ -7,7 +7,7 @@
<!-- TODO: 支持更多的 server --> <!-- TODO: 支持更多的 server -->
<span <span
class="debug-option" class="debug-option"
:class="{ 'disable': !client.connectionResult.success }" :class="{ 'disable': !mcpClientAdapter.connected }"
v-for="(option, index) of debugOptions" v-for="(option, index) of debugOptions"
:key="index" :key="index"
@click="chooseDebugMode(index)" @click="chooseDebugMode(index)"
@ -32,7 +32,6 @@ import { mcpClientAdapter } from '../connect/core';
defineComponent({ name: 'welcome' }); defineComponent({ name: 'welcome' });
const { t } = useI18n(); const { t } = useI18n();
const client = mcpClientAdapter.masterNode;
const debugOptions = [ const debugOptions = [
{ {
@ -60,7 +59,7 @@ const debugOptions = [
function chooseDebugMode(index: number) { function chooseDebugMode(index: number) {
// TODO: server // TODO: server
if (client.connectionResult.success) { if (mcpClientAdapter.connected) {
const activeTab = tabs.activeTab; const activeTab = tabs.activeTab;
activeTab.component = markRaw(debugModes[index]); activeTab.component = markRaw(debugModes[index]);

View File

@ -30,6 +30,7 @@ export async function routeMessage(command: string, data: any, webview: PostMess
webview.postMessage({ command, data: res }); webview.postMessage({ command, data: res });
} }
} catch (error) { } catch (error) {
console.error(error);
webview.postMessage({ webview.postMessage({
command, data: { command, data: {
code: 500, code: 500,

View File

@ -133,8 +133,12 @@ export class McpClient {
// 调用工具 // 调用工具
public async callTool(options: { name: string; arguments: Record<string, any>, callToolOption?: any }) { public async callTool(options: { name: string; arguments: Record<string, any>, callToolOption?: any }) {
const { callToolOption, ...methodArgs } = options; const { callToolOption, ...methodArgs } = options;
console.log('methodArgs', methodArgs);
console.log('callToolOption', callToolOption); console.log('callToolOption', callToolOption);
return await this.client.callTool(methodArgs, undefined, callToolOption); const res = await this.client.callTool(methodArgs, undefined, callToolOption);
console.log('callTool res', res);
return res;
} }
} }

View File

@ -249,12 +249,15 @@ export async function connectService(
const uuid = await deterministicUUID(JSON.stringify(option)); const uuid = await deterministicUUID(JSON.stringify(option));
const reuseConntion = clientMap.has(uuid); const reuseConntion = clientMap.has(uuid);
if (!clientMap.has(uuid)) {
// if (!clientMap.has(uuid)) {
// const client = await connect(option);
// clientMap.set(uuid, client);
// }
// const client = clientMap.get(uuid)!;
const client = await connect(option); const client = await connect(option);
clientMap.set(uuid, client); clientMap.set(uuid, client);
}
const client = clientMap.get(uuid)!;
const versionInfo = client.getServerVersion(); const versionInfo = client.getServerVersion();

View File

@ -1,6 +1,6 @@
{ {
"clientId": "83313e18-3e18-513e1883c06-813e1883c060a6b-60a6b641", "clientId": "83313e18-3e18-513e1883c06-813e1883c060a6b-60a6b641",
"currentIndex": 1, "currentIndex": 0,
"tabs": [ "tabs": [
{ {
"name": "交互测试", "name": "交互测试",

View File

@ -22,8 +22,8 @@ export class McpInstalledConnectProvider implements vscode.TreeDataProvider<Conn
const connection = getConnectionConfig(); const connection = getConnectionConfig();
const sidebarItems = connection.items.map((item, index) => { const sidebarItems = connection.items.map((item, index) => {
// 连接的名字 // 连接的名字
item = Array.isArray(item)? item[0] : item; const nItem = Array.isArray(item)? item[0] : item;
const itemName = `${item.name} (${item.type || item.connectionType})` const itemName = `${nItem.name} (${nItem.type || nItem.connectionType})`
return new ConnectionViewItem(itemName, vscode.TreeItemCollapsibleState.None, item, 'server'); return new ConnectionViewItem(itemName, vscode.TreeItemCollapsibleState.None, item, 'server');
}) })

View File

@ -22,8 +22,8 @@ export class McpWorkspaceConnectProvider implements vscode.TreeDataProvider<Conn
const connection = getWorkspaceConnectionConfig(); const connection = getWorkspaceConnectionConfig();
const sidebarItems = connection.items.map((item, index) => { const sidebarItems = connection.items.map((item, index) => {
// 连接的名字 // 连接的名字
item = Array.isArray(item) ? item[0] : item; const nItem = Array.isArray(item) ? item[0] : item;
const itemName = `${item.name} (${item.type || item.connectionType})` const itemName = `${nItem.name} (${nItem.type || nItem.connectionType})`
return new ConnectionViewItem(itemName, vscode.TreeItemCollapsibleState.None, item, 'server'); return new ConnectionViewItem(itemName, vscode.TreeItemCollapsibleState.None, item, 'server');
}) })

View File

@ -5,6 +5,9 @@ export async function deleteUserConnection(item: McpOptions[] | McpOptions) {
// 弹出确认对话框 // 弹出确认对话框
const masterNode = Array.isArray(item) ? item[0] : item; const masterNode = Array.isArray(item) ? item[0] : item;
const name = masterNode.name; const name = masterNode.name;
console.log('enter delete');
const confirm = await vscode.window.showWarningMessage( const confirm = await vscode.window.showWarningMessage(
`确定要删除连接 "${name}" 吗?`, `确定要删除连接 "${name}" 吗?`,
{ modal: true }, { modal: true },
@ -18,6 +21,10 @@ export async function deleteUserConnection(item: McpOptions[] | McpOptions) {
const workspaceConnectionConfig = getWorkspaceConnectionConfig(); const workspaceConnectionConfig = getWorkspaceConnectionConfig();
// 从配置中移除该连接项 // 从配置中移除该连接项
console.log(item);
console.log(workspaceConnectionConfig.items);
// TODO: 改成基于 path 进行搜索
const index = workspaceConnectionConfig.items.indexOf(item); const index = workspaceConnectionConfig.items.indexOf(item);
if (index !== -1) { if (index !== -1) {
workspaceConnectionConfig.items.splice(index, 1); workspaceConnectionConfig.items.splice(index, 1);

View File

@ -1,7 +1,8 @@
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import { RegisterCommand } from "../common"; import { RegisterCommand } from "../common";
import { getDefaultLanunchSignature, getLaunchCWD, revealOpenMcpWebviewPanel } from './webview.service'; import { getDefaultLanunchSignature, getWorkspacePath, revealOpenMcpWebviewPanel } from './webview.service';
import { getWorkspaceConnectionConfigItemByPath } from '../global'; import { getWorkspaceConnectionConfigItemByPath } from '../global';
import path from 'path';
export class WebviewController { export class WebviewController {
@RegisterCommand('openmcp.showOpenMCP') @RegisterCommand('openmcp.showOpenMCP')
@ -10,8 +11,7 @@ export class WebviewController {
if (!connectionItem) { if (!connectionItem) {
// 项目不存在连接信息 // 项目不存在连接信息
const cwd = getLaunchCWD(context, uri); const cwd = path.dirname(uri.fsPath);
const signature = getDefaultLanunchSignature(uri.fsPath, cwd); const signature = getDefaultLanunchSignature(uri.fsPath, cwd);
if (!signature) { if (!signature) {

View File

@ -24,7 +24,7 @@ export function getWebviewContent(context: vscode.ExtensionContext, panel: vscod
return html; return html;
} }
export function getLaunchCWD(context: vscode.ExtensionContext, uri: vscode.Uri) { export function getWorkspacePath(context: vscode.ExtensionContext, uri: vscode.Uri) {
// TODO: 启动上下文? // TODO: 启动上下文?
// 获取当前打开的项目的路径 // 获取当前打开的项目的路径
const workspaceFolder = vscode.workspace.getWorkspaceFolder(uri); const workspaceFolder = vscode.workspace.getWorkspaceFolder(uri);