143 lines
3.5 KiB
TypeScript
143 lines
3.5 KiB
TypeScript
|
|
import { PostMessageble } from '../adapter';
|
|
import { connect, MCPClient, type MCPOptions } from './connect';
|
|
import { lookupEnvVarHandler } from './env-var';
|
|
import { callTool, getPrompt, getServerVersion, listPrompts, listResources, listResourceTemplates, listTools, readResource } from './handler';
|
|
import { chatCompletionHandler } from './llm';
|
|
import { panelLoadHandler, panelSaveHandler } from './panel';
|
|
import { settingLoadHandler, settingSaveHandler } from './setting';
|
|
import { ping } from './util';
|
|
|
|
import { spawnSync } from 'node:child_process';
|
|
|
|
|
|
// TODO: 支持更多的 client
|
|
export let client: MCPClient | undefined = undefined;
|
|
|
|
function tryGetRunCommandError(command: string, args: string[] = [], cwd?: string): string | null {
|
|
try {
|
|
console.log('current command', command);
|
|
console.log('current args', args);
|
|
|
|
const result = spawnSync(command, args, {
|
|
cwd: cwd || process.cwd(),
|
|
stdio: 'pipe',
|
|
encoding: 'utf-8'
|
|
});
|
|
|
|
if (result.error) {
|
|
return result.error.message;
|
|
}
|
|
if (result.status !== 0) {
|
|
return result.stderr || `Command failed with code ${result.status}`;
|
|
}
|
|
return null;
|
|
} catch (error) {
|
|
return error instanceof Error ? error.message : String(error);
|
|
}
|
|
}
|
|
|
|
async function connectHandler(option: MCPOptions, webview: PostMessageble) {
|
|
try {
|
|
console.log('ready to connect', option);
|
|
|
|
client = await connect(option);
|
|
const connectResult = {
|
|
code: 200,
|
|
msg: 'Connect to OpenMCP successfully\nWelcome back, Kirigaya'
|
|
};
|
|
webview.postMessage({ command: 'connect', data: connectResult });
|
|
} catch (error) {
|
|
|
|
// TODO: 这边获取到的 error 不够精致,如何才能获取到更加精准的错误
|
|
// 比如 error: Failed to spawn: `server.py`
|
|
// Caused by: No such file or directory (os error 2)
|
|
|
|
let errorMsg = '';
|
|
|
|
if (option.command) {
|
|
errorMsg += tryGetRunCommandError(option.command, option.args, option.cwd);
|
|
}
|
|
|
|
errorMsg += (error as any).toString();
|
|
|
|
const connectResult = {
|
|
code: 500,
|
|
msg: errorMsg
|
|
};
|
|
webview.postMessage({ command: 'connect', data: connectResult });
|
|
}
|
|
}
|
|
|
|
|
|
export function messageController(command: string, data: any, webview: PostMessageble) {
|
|
switch (command) {
|
|
case 'connect':
|
|
connectHandler(data, webview);
|
|
break;
|
|
|
|
case 'server/version':
|
|
getServerVersion(client, webview);
|
|
break;
|
|
|
|
case 'prompts/list':
|
|
listPrompts(client, webview);
|
|
break;
|
|
|
|
case 'prompts/get':
|
|
getPrompt(client, data, webview);
|
|
break;
|
|
|
|
case 'resources/list':
|
|
listResources(client, webview);
|
|
break;
|
|
|
|
|
|
case 'resources/templates/list':
|
|
listResourceTemplates(client, webview);
|
|
break;
|
|
|
|
case 'resources/read':
|
|
readResource(client, data, webview);
|
|
break;
|
|
|
|
case 'tools/list':
|
|
listTools(client, webview);
|
|
break;
|
|
|
|
case 'tools/call':
|
|
callTool(client, data, webview);
|
|
break;
|
|
|
|
case 'ping':
|
|
ping(client, webview);
|
|
break;
|
|
|
|
case 'setting/save':
|
|
settingSaveHandler(client, data, webview);
|
|
break;
|
|
|
|
case 'setting/load':
|
|
settingLoadHandler(client, webview);
|
|
break;
|
|
|
|
case 'panel/save':
|
|
panelSaveHandler(client, data, webview);
|
|
break;
|
|
|
|
case 'panel/load':
|
|
panelLoadHandler(client, webview);
|
|
break;
|
|
|
|
case 'llm/chat/completions':
|
|
chatCompletionHandler(client, data, webview);
|
|
break;
|
|
|
|
case 'lookup-env-var':
|
|
lookupEnvVarHandler(client, data, webview);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
} |