优化 web 端开发的隐私保护
This commit is contained in:
parent
2b1c0c30dd
commit
0bea084c35
@ -25,4 +25,9 @@ $serviceJob = Start-Job -ScriptBlock {
|
||||
$rendererJob | Wait-Job | Receive-Job
|
||||
$serviceJob | Wait-Job | Receive-Job
|
||||
|
||||
# 将 resources 目录复制到 software/resources
|
||||
New-Item -ItemType Directory -Path ./software/resources -Force
|
||||
Remove-Item -Recurse -Force ./software/resources/* -ErrorAction SilentlyContinue
|
||||
Copy-Item -Recurse -Path ./resources -Destination ./software/ -Force
|
||||
|
||||
Write-Output "finish building services in ./resources"
|
||||
|
1320
package-lock.json
generated
1320
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
8
renderer/package-lock.json
generated
8
renderer/package-lock.json
generated
@ -11,7 +11,6 @@
|
||||
"core-js": "^3.8.3",
|
||||
"element-plus": "^2.9.7",
|
||||
"katex": "^0.16.21",
|
||||
"loadash": "^1.0.0",
|
||||
"lodash": "^4.17.21",
|
||||
"markdown-it": "^14.1.0",
|
||||
"markdown-it-katex": "^2.0.3",
|
||||
@ -8623,13 +8622,6 @@
|
||||
"uc.micro": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/loadash": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/loadash/-/loadash-1.0.0.tgz",
|
||||
"integrity": "sha512-xlX5HBsXB3KG0FJbJJG/3kYWCfsCyCSus3T+uHVu6QL6YxAdggmm3QeyLgn54N2yi5/UE6xxL5ZWJAAiHzHYEg==",
|
||||
"deprecated": "Package is unsupport. Please use the lodash package instead.",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/loader-runner": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmmirror.com/loader-runner/-/loader-runner-4.3.0.tgz",
|
||||
|
@ -15,7 +15,7 @@ import MainPanel from '@/components/main-panel/index.vue';
|
||||
import { setDefaultCss } from './hook/css';
|
||||
import { greenLog, pinkLog } from './views/setting/util';
|
||||
import { acquireVsCodeApi, useMessageBridge } from './api/message-bridge';
|
||||
import { connectionArgs, connectionMethods, doConnect, launchConnect, loadEnvVar } from './views/connect/connection';
|
||||
import { connectionArgs, connectionMethods, doWebConnect, doVscodeConnect, loadEnvVar } from './views/connect/connection';
|
||||
import { loadSetting } from './hook/setting';
|
||||
import { loadPanels } from './hook/panel';
|
||||
|
||||
@ -29,11 +29,6 @@ bridge.addCommandListener('hello', data => {
|
||||
|
||||
|
||||
function initDebug() {
|
||||
connectionArgs.commandString = 'node /Users/bytedance/projects/mcp/servers/src/puppeteer/dist/index.js';
|
||||
// connectionArgs.commandString = 'node C:/Users/K/code/servers/src/puppeteer/dist/index.js';
|
||||
// connectionArgs.commandString = 'uv run mcp run bing-picture.py';
|
||||
connectionArgs.cwd = '../servers';
|
||||
connectionMethods.current = 'STDIO';
|
||||
|
||||
setTimeout(async () => {
|
||||
// 初始化 设置
|
||||
@ -43,7 +38,7 @@ function initDebug() {
|
||||
loadEnvVar();
|
||||
|
||||
// 尝试连接
|
||||
await doConnect();
|
||||
await doWebConnect();
|
||||
|
||||
// 初始化 tab
|
||||
loadPanels();
|
||||
@ -66,7 +61,7 @@ async function initProduce() {
|
||||
loadEnvVar();
|
||||
|
||||
// 尝试连接
|
||||
await launchConnect();
|
||||
await doVscodeConnect();
|
||||
|
||||
// 初始化 tab
|
||||
await loadPanels();
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { useMessageBridge } from '@/api/message-bridge';
|
||||
import { reactive } from 'vue';
|
||||
import { pinkLog } from '../setting/util';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { arrowMiddleware, ElMessage } from 'element-plus';
|
||||
import { ILaunchSigature } from '@/hook/type';
|
||||
|
||||
export const connectionMethods = reactive({
|
||||
@ -69,121 +69,79 @@ export interface McpOptions {
|
||||
clientVersion?: string;
|
||||
}
|
||||
|
||||
export function doConnect() {
|
||||
let connectOption: McpOptions;
|
||||
const bridge = useMessageBridge();
|
||||
const env = makeEnv();
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
// 监听 connect
|
||||
bridge.addCommandListener('connect', async data => {
|
||||
const { code, msg } = data;
|
||||
connectionResult.success = (code === 200);
|
||||
|
||||
if (code === 200) {
|
||||
const res = await getServerVersion() as { name: string, version: string };
|
||||
connectionResult.serverInfo.name = res.name || '';
|
||||
connectionResult.serverInfo.version = res.version || '';
|
||||
connectionResult.logString.push({
|
||||
type: 'info',
|
||||
message: msg
|
||||
});
|
||||
|
||||
} else {
|
||||
ElMessage({
|
||||
type: 'error',
|
||||
message: msg
|
||||
});
|
||||
connectionResult.logString.push({
|
||||
type: 'error',
|
||||
message: msg
|
||||
});
|
||||
}
|
||||
|
||||
resolve(void 0);
|
||||
}, { once: true });
|
||||
|
||||
if (connectionMethods.current === 'STDIO') {
|
||||
|
||||
if (connectionArgs.commandString.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const commandComponents = connectionArgs.commandString.split(/\s+/g);
|
||||
const command = commandComponents[0];
|
||||
commandComponents.shift();
|
||||
|
||||
connectOption = {
|
||||
connectionType: 'STDIO',
|
||||
command: command,
|
||||
cwd: connectionArgs.cwd,
|
||||
args: commandComponents,
|
||||
env: env,
|
||||
clientName: 'openmcp.connect.stdio',
|
||||
clientVersion: '0.0.1'
|
||||
}
|
||||
|
||||
} else {
|
||||
const url = connectionArgs.urlString;
|
||||
|
||||
if (url.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
connectOption = {
|
||||
connectionType: 'SSE',
|
||||
url: url,
|
||||
env: env,
|
||||
clientName: 'openmcp.connect.sse',
|
||||
clientVersion: '0.0.1'
|
||||
}
|
||||
}
|
||||
|
||||
bridge.postMessage({
|
||||
command: 'connect',
|
||||
data: connectOption
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description vscode 中初始化启动
|
||||
*/
|
||||
export async function launchConnect(option: { updateCommandString?: boolean } = {}) {
|
||||
// 本地开发只用 IPC 进行启动
|
||||
// 后续需要考虑到不同的连接方式
|
||||
|
||||
export async function doWebConnect(option: { updateCommandString?: boolean } = {}) {
|
||||
const {
|
||||
// updateCommandString 为 true 代表是初始化阶段
|
||||
updateCommandString = true
|
||||
} = option;
|
||||
|
||||
connectionMethods.current = 'STDIO';
|
||||
|
||||
pinkLog('请求启动参数');
|
||||
const connectionItem = await getLaunchSignature();
|
||||
|
||||
if (connectionItem.type === 'stdio') {
|
||||
if (updateCommandString) {
|
||||
pinkLog('请求启动参数');
|
||||
const connectionItem = await getLaunchSignature('web/launch-signature');
|
||||
|
||||
if (connectionItem.type ==='stdio') {
|
||||
connectionMethods.current = 'STDIO';
|
||||
connectionArgs.commandString = connectionItem.commandString;
|
||||
connectionArgs.cwd = connectionItem.cwd;
|
||||
|
||||
if (connectionArgs.commandString.length === 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
await launchStdio();
|
||||
|
||||
} else {
|
||||
if (updateCommandString) {
|
||||
connectionMethods.current = 'SSE';
|
||||
connectionArgs.urlString = connectionItem.url;
|
||||
|
||||
if (connectionArgs.urlString.length === 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (connectionMethods.current === 'STDIO') {
|
||||
await launchStdio();
|
||||
} else {
|
||||
await launchSSE();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description vscode 中初始化启动
|
||||
*/
|
||||
export async function doVscodeConnect(option: { updateCommandString?: boolean } = {}) {
|
||||
// 本地开发只用 IPC 进行启动
|
||||
// 后续需要考虑到不同的连接方式
|
||||
|
||||
const {
|
||||
// updateCommandString 为 true 代表是初始化阶段
|
||||
updateCommandString = true
|
||||
} = option;
|
||||
|
||||
if (updateCommandString) {
|
||||
pinkLog('请求启动参数');
|
||||
const connectionItem = await getLaunchSignature('vscode/launch-signature');
|
||||
|
||||
if (connectionItem.type ==='stdio') {
|
||||
connectionMethods.current = 'STDIO';
|
||||
connectionArgs.commandString = connectionItem.commandString;
|
||||
connectionArgs.cwd = connectionItem.cwd;
|
||||
|
||||
if (connectionArgs.commandString.length === 0) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
connectionMethods.current = 'SSE';
|
||||
connectionArgs.urlString = connectionItem.url;
|
||||
|
||||
if (connectionArgs.urlString.length === 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (connectionMethods.current === 'STDIO') {
|
||||
await launchStdio();
|
||||
} else {
|
||||
await launchSSE();
|
||||
}
|
||||
}
|
||||
|
||||
@ -191,10 +149,22 @@ async function launchStdio() {
|
||||
const bridge = useMessageBridge();
|
||||
const env = makeEnv();
|
||||
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
// 监听 connect
|
||||
bridge.addCommandListener('connect', async data => {
|
||||
const { code, msg } = data;
|
||||
const commandComponents = connectionArgs.commandString.split(/\s+/g);
|
||||
const command = commandComponents[0];
|
||||
commandComponents.shift();
|
||||
|
||||
const connectOption = {
|
||||
connectionType: 'STDIO',
|
||||
command: command,
|
||||
args: commandComponents,
|
||||
cwd: connectionArgs.cwd,
|
||||
clientName: 'openmcp.connect.stdio',
|
||||
clientVersion: '0.0.1',
|
||||
env
|
||||
};
|
||||
|
||||
const { code, msg } = await bridge.commandRequest('connect', connectOption);
|
||||
|
||||
connectionResult.success = (code === 200);
|
||||
|
||||
if (code === 200) {
|
||||
@ -238,40 +208,22 @@ async function launchStdio() {
|
||||
message: msg
|
||||
});
|
||||
}
|
||||
|
||||
resolve(void 0);
|
||||
}, { once: true });
|
||||
|
||||
|
||||
const commandComponents = connectionArgs.commandString.split(/\s+/g);
|
||||
const command = commandComponents[0];
|
||||
commandComponents.shift();
|
||||
|
||||
const connectOption = {
|
||||
connectionType: 'STDIO',
|
||||
command: command,
|
||||
args: commandComponents,
|
||||
cwd: connectionArgs.cwd,
|
||||
clientName: 'openmcp.connect.stdio',
|
||||
clientVersion: '0.0.1',
|
||||
env
|
||||
};
|
||||
|
||||
bridge.postMessage({
|
||||
command: 'connect',
|
||||
data: connectOption
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function launchSSE() {
|
||||
const bridge = useMessageBridge();
|
||||
const env = makeEnv();
|
||||
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
// 监听 connect
|
||||
bridge.addCommandListener('connect', async data => {
|
||||
const { code, msg } = data;
|
||||
const connectOption: McpOptions = {
|
||||
connectionType: 'SSE',
|
||||
url: connectionArgs.urlString,
|
||||
clientName: 'openmcp.connect.sse',
|
||||
clientVersion: '0.0.1',
|
||||
env
|
||||
};
|
||||
|
||||
const { code, msg } = await bridge.commandRequest('connect', connectOption);
|
||||
|
||||
connectionResult.success = (code === 200);
|
||||
|
||||
if (code === 200) {
|
||||
@ -293,6 +245,7 @@ async function launchSSE() {
|
||||
oauth: connectionArgs.oauth,
|
||||
env: env
|
||||
};
|
||||
|
||||
bridge.postMessage({
|
||||
command: 'vscode/update-connection-sigature',
|
||||
data: JSON.parse(JSON.stringify(clientSseConnectionItem))
|
||||
@ -309,40 +262,23 @@ async function launchSSE() {
|
||||
message: msg
|
||||
});
|
||||
}
|
||||
|
||||
resolve(void 0);
|
||||
}, { once: true });
|
||||
|
||||
const connectOption: McpOptions = {
|
||||
connectionType: 'SSE',
|
||||
url: connectionArgs.urlString,
|
||||
clientName: 'openmcp.connect.sse',
|
||||
clientVersion: '0.0.1',
|
||||
env
|
||||
};
|
||||
|
||||
bridge.postMessage({
|
||||
command: 'connect',
|
||||
data: connectOption
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
function getLaunchSignature() {
|
||||
function getLaunchSignature(signatureName: string) {
|
||||
return new Promise<ILaunchSigature>((resolve, reject) => {
|
||||
// 与 vscode 进行同步
|
||||
const bridge = useMessageBridge();
|
||||
|
||||
bridge.addCommandListener('vscode/launch-signature', data => {
|
||||
bridge.addCommandListener(signatureName, data => {
|
||||
pinkLog('收到启动参数');
|
||||
resolve(data.msg);
|
||||
|
||||
}, { once: true });
|
||||
|
||||
bridge.postMessage({
|
||||
command: 'vscode/launch-signature',
|
||||
command: signatureName,
|
||||
data: {}
|
||||
});
|
||||
})
|
||||
|
@ -29,7 +29,7 @@ import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
import { connectionResult, doConnect, launchConnect } from './connection';
|
||||
import { connectionResult, doWebConnect, doVscodeConnect } from './connection';
|
||||
|
||||
import ConnectionMethod from './connection-method.vue';
|
||||
import ConnectionArgs from './connection-args.vue';
|
||||
@ -47,9 +47,9 @@ async function suitableConnect() {
|
||||
isLoading.value = true;
|
||||
|
||||
if (acquireVsCodeApi === undefined) {
|
||||
await doConnect();
|
||||
await doWebConnect({ updateCommandString: false });
|
||||
} else {
|
||||
await launchConnect({ updateCommandString: false });
|
||||
await doVscodeConnect({ updateCommandString: false });
|
||||
}
|
||||
|
||||
isLoading.value = false;
|
||||
|
1
service/.gitignore
vendored
1
service/.gitignore
vendored
@ -26,3 +26,4 @@ setting.json
|
||||
|
||||
tabs.example-servers/puppeteer.json
|
||||
*.traineddata
|
||||
.env
|
@ -3,6 +3,8 @@ import pino from 'pino';
|
||||
|
||||
import { routeMessage } from './common/router';
|
||||
import { VSCodeWebViewLike } from './hook/adapter';
|
||||
import path from 'node:path';
|
||||
import * as fs from 'node:fs';
|
||||
|
||||
export interface VSCodeMessage {
|
||||
command: string;
|
||||
@ -25,6 +27,73 @@ const logger = pino({
|
||||
export type MessageHandler = (message: VSCodeMessage) => void;
|
||||
const wss = new (WebSocket as any).Server({ port: 8080 });
|
||||
|
||||
interface IStdioLaunchSignature {
|
||||
type: 'stdio';
|
||||
commandString: string;
|
||||
cwd: string;
|
||||
}
|
||||
|
||||
interface ISSELaunchSignature {
|
||||
type:'sse';
|
||||
url: string;
|
||||
oauth: string;
|
||||
}
|
||||
|
||||
export type ILaunchSigature = IStdioLaunchSignature | ISSELaunchSignature;
|
||||
|
||||
function refreshConnectionOption(envPath: string) {
|
||||
const defaultOption = {
|
||||
type:'stdio',
|
||||
command: 'mcp',
|
||||
args: ['run', 'main.py'],
|
||||
cwd: '../server'
|
||||
};
|
||||
|
||||
fs.writeFileSync(envPath, JSON.stringify(defaultOption, null, 4));
|
||||
|
||||
return defaultOption;
|
||||
}
|
||||
|
||||
function getInitConnectionOption() {
|
||||
const envPath = path.join(__dirname, '..', '.env');
|
||||
|
||||
if (!fs.existsSync(envPath)) {
|
||||
return refreshConnectionOption(envPath);
|
||||
}
|
||||
|
||||
try {
|
||||
const option = JSON.parse(fs.readFileSync(envPath, 'utf-8'));
|
||||
return option;
|
||||
|
||||
} catch (error) {
|
||||
logger.error('读取 .env 配置文件');
|
||||
return refreshConnectionOption(envPath);
|
||||
}
|
||||
}
|
||||
|
||||
function updateConnectionOption(data: any) {
|
||||
const envPath = path.join(__dirname, '..', '.env');
|
||||
|
||||
if (data.connectionType === 'STDIO') {
|
||||
const connectionItem = {
|
||||
type: 'stdio',
|
||||
command: data.command,
|
||||
args: data.args,
|
||||
cwd: data.cwd.replace(/\\/g, '/')
|
||||
};
|
||||
|
||||
fs.writeFileSync(envPath, JSON.stringify(connectionItem, null, 4));
|
||||
} else {
|
||||
const connectionItem = {
|
||||
type: 'sse',
|
||||
url: data.url,
|
||||
oauth: data.oauth
|
||||
};
|
||||
|
||||
fs.writeFileSync(envPath, JSON.stringify(connectionItem, null, 4));
|
||||
}
|
||||
}
|
||||
|
||||
wss.on('connection', ws => {
|
||||
|
||||
// 仿造 webview 进行统一接口访问
|
||||
@ -39,11 +108,47 @@ wss.on('connection', ws => {
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
const option = getInitConnectionOption();
|
||||
|
||||
// 注册消息接受的管线
|
||||
webview.onDidReceiveMessage(message => {
|
||||
logger.info(`command: [${message.command || 'No Command'}]`);
|
||||
|
||||
const { command, data } = message;
|
||||
|
||||
switch (command) {
|
||||
case 'web/launch-signature':
|
||||
const launchResultMessage: ILaunchSigature = option.type === 'stdio' ?
|
||||
{
|
||||
type: 'stdio',
|
||||
commandString: option.command + ' ' + option.args.join(' '),
|
||||
cwd: option.cwd || ''
|
||||
} :
|
||||
{
|
||||
type: 'sse',
|
||||
url: option.url,
|
||||
oauth: option.oauth || ''
|
||||
};
|
||||
|
||||
const launchResult = {
|
||||
code: 200,
|
||||
msg: launchResultMessage
|
||||
};
|
||||
|
||||
webview.postMessage({
|
||||
command: 'web/launch-signature',
|
||||
data: launchResult
|
||||
});
|
||||
|
||||
break;
|
||||
|
||||
case 'web/update-connection-sigature':
|
||||
updateConnectionOption(data);
|
||||
break;
|
||||
|
||||
default:
|
||||
routeMessage(command, data, webview);
|
||||
break;
|
||||
}
|
||||
});
|
||||
});
|
1
software/.gitignore
vendored
1
software/.gitignore
vendored
@ -13,4 +13,5 @@ resources
|
||||
setting.json
|
||||
*.traineddata
|
||||
release
|
||||
tabs.*
|
||||
tabs.example-servers/puppeteer.json
|
@ -1,8 +0,0 @@
|
||||
Remove-Item -Recurse -Force dist
|
||||
|
||||
tsc
|
||||
|
||||
electron-builder
|
||||
|
||||
$dmgFile = Get-ChildItem -Path dist -Filter "OpenMCP-0.0.1.exe"
|
||||
$dmgFile | ForEach-Object { Write-Host "$($_.FullName) size: $([math]::Round($_.Length / 1MB, 2)) MB" }
|
Loading…
x
Reference in New Issue
Block a user