commit
fc68a12b30
@ -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 的连接方式
|
||||||
|
@ -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>
|
||||||
|
@ -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",
|
||||||
|
@ -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>
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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]);
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)) {
|
|
||||||
const client = await connect(option);
|
// if (!clientMap.has(uuid)) {
|
||||||
clientMap.set(uuid, client);
|
// const client = await connect(option);
|
||||||
}
|
// clientMap.set(uuid, client);
|
||||||
|
// }
|
||||||
|
// const client = clientMap.get(uuid)!;
|
||||||
|
|
||||||
const client = clientMap.get(uuid)!;
|
const client = await connect(option);
|
||||||
|
clientMap.set(uuid, client);
|
||||||
|
|
||||||
const versionInfo = client.getServerVersion();
|
const versionInfo = client.getServerVersion();
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"clientId": "83313e18-3e18-513e1883c06-813e1883c060a6b-60a6b641",
|
"clientId": "83313e18-3e18-513e1883c06-813e1883c060a6b-60a6b641",
|
||||||
"currentIndex": 1,
|
"currentIndex": 0,
|
||||||
"tabs": [
|
"tabs": [
|
||||||
{
|
{
|
||||||
"name": "交互测试",
|
"name": "交互测试",
|
||||||
|
@ -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');
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -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');
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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) {
|
||||||
|
@ -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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user