finish config export
This commit is contained in:
parent
3e363c6dde
commit
d10c88f35e
@ -1,8 +1,8 @@
|
|||||||
@font-face {
|
@font-face {
|
||||||
font-family: "iconfont"; /* Project id 4870215 */
|
font-family: "iconfont"; /* Project id 4870215 */
|
||||||
src: url('iconfont.woff2?t=1750172161574') format('woff2'),
|
src: url('iconfont.woff2?t=1750532923458') format('woff2'),
|
||||||
url('iconfont.woff?t=1750172161574') format('woff'),
|
url('iconfont.woff?t=1750532923458') format('woff'),
|
||||||
url('iconfont.ttf?t=1750172161574') format('truetype');
|
url('iconfont.ttf?t=1750532923458') format('truetype');
|
||||||
}
|
}
|
||||||
|
|
||||||
.iconfont {
|
.iconfont {
|
||||||
@ -13,6 +13,10 @@
|
|||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.icon-deploy:before {
|
||||||
|
content: "\e614";
|
||||||
|
}
|
||||||
|
|
||||||
.icon-suffix-xml:before {
|
.icon-suffix-xml:before {
|
||||||
content: "\e653";
|
content: "\e653";
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
@ -0,0 +1,208 @@
|
|||||||
|
<template>
|
||||||
|
<el-tooltip :content="'导出 mcpconfig'" placement="top" effect="light">
|
||||||
|
<div class="setting-button" @click="toggleDialog">
|
||||||
|
<span class="iconfont icon-deploy">
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</el-tooltip>
|
||||||
|
|
||||||
|
<el-dialog v-model="showDialog" width="fit-content">
|
||||||
|
|
||||||
|
<template #header>
|
||||||
|
<div>
|
||||||
|
<div class="export-file-input">
|
||||||
|
<span>{{ t('export-filename') }}</span>
|
||||||
|
<el-input
|
||||||
|
v-model="exportFileName"
|
||||||
|
style="max-width: 300px"
|
||||||
|
>
|
||||||
|
<template #append>.json</template>
|
||||||
|
</el-input>
|
||||||
|
<span class="how-to-use"
|
||||||
|
@click="gotoHowtoUse"
|
||||||
|
>
|
||||||
|
<span class="iconfont icon-info"></span>
|
||||||
|
<span>{{ t('how-to-use') }}</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div class="tools-dialog-container">
|
||||||
|
<el-scrollbar height="400px" class="tools-list">
|
||||||
|
<div v-html="exportJson">
|
||||||
|
</div>
|
||||||
|
</el-scrollbar>
|
||||||
|
<!--
|
||||||
|
<el-scrollbar height="400px" class="tools-list">
|
||||||
|
<div v-html="exampleCode"></div>
|
||||||
|
</el-scrollbar> -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<el-button type="primary" @click="copyCode">{{ t('copy') }}</el-button>
|
||||||
|
<el-button type="primary" @click="exportCode">{{ t('export') }}</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, computed, inject, onMounted, watch } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { type ChatStorage, type EnableToolItem, getToolSchema } from '../chat';
|
||||||
|
import { markdownToHtml } from '@/components/main-panel/chat/markdown/markdown';
|
||||||
|
import { llmManager, llms } from '@/views/setting/llm';
|
||||||
|
import { mcpClientAdapter } from '@/views/connect/core';
|
||||||
|
import { ElMessage } from 'element-plus';
|
||||||
|
import { useMessageBridge } from '@/api/message-bridge';
|
||||||
|
|
||||||
|
const { t, locale } = useI18n();
|
||||||
|
|
||||||
|
const showDialog = ref(false);
|
||||||
|
const exportJson = ref('');
|
||||||
|
const exportFileName = ref('mcpconfig');
|
||||||
|
|
||||||
|
// 修改 toggleDialog 方法
|
||||||
|
const toggleDialog = () => {
|
||||||
|
showDialog.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const generateExportData = computed(() => {
|
||||||
|
const currentLLM = llms[llmManager.currentModelIndex];
|
||||||
|
|
||||||
|
const mcpServers = {} as any;
|
||||||
|
for (const client of mcpClientAdapter.clients) {
|
||||||
|
|
||||||
|
const option = client.connectOption;
|
||||||
|
const type = option.connectionType;
|
||||||
|
|
||||||
|
if (type === 'STDIO') {
|
||||||
|
mcpServers[client.name] = {
|
||||||
|
command: option.command,
|
||||||
|
args: option.args,
|
||||||
|
description: "",
|
||||||
|
}
|
||||||
|
} else if (type === 'SSE') {
|
||||||
|
mcpServers[client.name] = {
|
||||||
|
type: 'sse',
|
||||||
|
url: option.url,
|
||||||
|
description: "",
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mcpServers[client.name] = {
|
||||||
|
type: 'streamable_http',
|
||||||
|
url: option.url,
|
||||||
|
description: "",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mcpconfig = {
|
||||||
|
version: "0.0.1",
|
||||||
|
namespace: "openmcp",
|
||||||
|
mcpServers,
|
||||||
|
defaultLLM: {
|
||||||
|
baseURL: currentLLM.baseUrl,
|
||||||
|
apiToken: currentLLM.userToken,
|
||||||
|
model: currentLLM.userModel
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return JSON.stringify(mcpconfig, null, 2);
|
||||||
|
});
|
||||||
|
|
||||||
|
const innerMarkdownHtml = (code: string) => {
|
||||||
|
const rawCode = markdownToHtml(code);
|
||||||
|
const doc = new DOMParser().parseFromString(rawCode, 'text/html');
|
||||||
|
const pres = doc.querySelectorAll('pre');
|
||||||
|
|
||||||
|
if (pres.length < 2) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const inner = pres[1].outerHTML;
|
||||||
|
return inner;
|
||||||
|
}
|
||||||
|
|
||||||
|
const exampleCode = computed(() => {
|
||||||
|
return innerMarkdownHtml(
|
||||||
|
'```typescript\n' +
|
||||||
|
`import { OmAgent } from 'openmcp-sdk/service/sdk';
|
||||||
|
|
||||||
|
const agent = new OmAgent();
|
||||||
|
|
||||||
|
agent.loadMcpConfig('/path/to/${exportFileName.value}.json');
|
||||||
|
|
||||||
|
const prompt = await agent.getPrompt('hacknews', { topn: '5' });
|
||||||
|
const res = await agent.ainvoke({ messages: prompt });
|
||||||
|
|
||||||
|
console.log('⚙️ Agent Response', res);
|
||||||
|
` +
|
||||||
|
'\n```'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
const copyCode = async () => {
|
||||||
|
try {
|
||||||
|
await navigator.clipboard.writeText(generateExportData.value);
|
||||||
|
ElMessage.success(t('copy-success'));
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.error(t('copy-fail'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const exportCode = async () => {
|
||||||
|
const bridge = useMessageBridge();
|
||||||
|
bridge.postMessage({
|
||||||
|
command: 'export-file',
|
||||||
|
data: {
|
||||||
|
filename: exportFileName.value,
|
||||||
|
content: generateExportData.value
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const gotoHowtoUse = () => {
|
||||||
|
if (locale.value === 'zh') {
|
||||||
|
window.open('https://kirigaya.cn/openmcp/zh/sdk-tutorial/#%E4%BD%BF%E7%94%A8');
|
||||||
|
} else if (locale.value === 'ja') {
|
||||||
|
window.open('https://kirigaya.cn/openmcp/ja/sdk-tutorial/#%E4%BD%BF%E7%94%A8%E6%96%B9%E6%B3%95');
|
||||||
|
} else {
|
||||||
|
window.open('https://kirigaya.cn/openmcp/sdk-tutorial/#usage');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
exportJson.value = innerMarkdownHtml(
|
||||||
|
'```json\n' + generateExportData.value + '\n```'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
.export-file-input {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tools-list {
|
||||||
|
border-radius: .5em;
|
||||||
|
border: 1px solid var(--main-color);
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.how-to-use {
|
||||||
|
margin-left: 10px;
|
||||||
|
font-size: 15px;
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: var(--main-color);
|
||||||
|
color: #1e1e1e;
|
||||||
|
padding: 3px 5px;
|
||||||
|
border-radius: .3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
@ -9,6 +9,7 @@
|
|||||||
<Temperature />
|
<Temperature />
|
||||||
<ContextLength />
|
<ContextLength />
|
||||||
<XmlWrapper />
|
<XmlWrapper />
|
||||||
|
<Export />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -27,6 +28,7 @@ import ParallelToolCalls from './parallel-tool-calls.vue';
|
|||||||
import Temperature from './temperature.vue';
|
import Temperature from './temperature.vue';
|
||||||
import ContextLength from './context-length.vue';
|
import ContextLength from './context-length.vue';
|
||||||
import XmlWrapper from './xml-wrapper.vue';
|
import XmlWrapper from './xml-wrapper.vue';
|
||||||
|
import Export from './export.vue';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
modelValue: {
|
modelValue: {
|
||||||
|
@ -22,9 +22,6 @@ const props = defineProps({
|
|||||||
<style>
|
<style>
|
||||||
.chat-prompt-item {
|
.chat-prompt-item {
|
||||||
max-width: 80px;
|
max-width: 80px;
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
border-radius: .3em;
|
border-radius: .3em;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -34,9 +31,17 @@ const props = defineProps({
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
margin-left: 3px;
|
margin-left: 3px;
|
||||||
margin-right: 3px;
|
margin-right: 3px;
|
||||||
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat-prompt-item .iconfont {
|
.chat-prompt-item .iconfont {
|
||||||
margin-right: 4px;
|
margin-right: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.chat-prompt-item .real-text {
|
||||||
|
max-width: 60px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
<!-- body -->
|
<!-- body -->
|
||||||
<div class="tool-list-container-scrollbar">
|
<div class="tool-list-container-scrollbar">
|
||||||
<el-scrollbar height="500px">
|
<el-scrollbar height="fit-content">
|
||||||
<div class="tool-list-container">
|
<div class="tool-list-container">
|
||||||
<div class="item" :class="{ 'active': tabStorage.currentToolName === tool.name }"
|
<div class="item" :class="{ 'active': tabStorage.currentToolName === tool.name }"
|
||||||
v-for="tool of client.tools?.values()" :key="tool.name" @click="handleClick(tool)">
|
v-for="tool of client.tools?.values()" :key="tool.name" @click="handleClick(tool)">
|
||||||
@ -148,10 +148,9 @@ onMounted(async () => {
|
|||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
background-color: var(--main-color);
|
background-color: var(--main-color);
|
||||||
padding: 2px 5px;
|
padding: 2px 5px;
|
||||||
border-radius: .5em;
|
border-radius: .3em;
|
||||||
height: fit-content;
|
height: fit-content;
|
||||||
font-size: 10px;
|
font-size: 13px;
|
||||||
|
|
||||||
color: black;
|
color: black;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,5 +176,11 @@
|
|||||||
"tool-manage": "إدارة الأدوات",
|
"tool-manage": "إدارة الأدوات",
|
||||||
"enable-all-tools": "تفعيل جميع الأدوات",
|
"enable-all-tools": "تفعيل جميع الأدوات",
|
||||||
"disable-all-tools": "تعطيل جميع الأدوات",
|
"disable-all-tools": "تعطيل جميع الأدوات",
|
||||||
"using-tool": "جاري استخدام الأداة"
|
"using-tool": "جاري استخدام الأداة",
|
||||||
|
"copy-success": "تم النسخ بنجاح",
|
||||||
|
"copy-fail": "فشل النسخ",
|
||||||
|
"copy": "نسخ",
|
||||||
|
"export": "تصدير",
|
||||||
|
"export-filename": "اسم ملف التصدير",
|
||||||
|
"how-to-use": "كيفية الاستخدام؟"
|
||||||
}
|
}
|
@ -176,5 +176,11 @@
|
|||||||
"tool-manage": "Werkzeugverwaltung",
|
"tool-manage": "Werkzeugverwaltung",
|
||||||
"enable-all-tools": "Alle Tools aktivieren",
|
"enable-all-tools": "Alle Tools aktivieren",
|
||||||
"disable-all-tools": "Alle Tools deaktivieren",
|
"disable-all-tools": "Alle Tools deaktivieren",
|
||||||
"using-tool": "Werkzeug wird verwendet"
|
"using-tool": "Werkzeug wird verwendet",
|
||||||
|
"copy-success": "Erfolgreich kopiert",
|
||||||
|
"copy-fail": "Kopieren fehlgeschlagen",
|
||||||
|
"copy": "Kopieren",
|
||||||
|
"export": "Exportieren",
|
||||||
|
"export-filename": "Exportdateiname",
|
||||||
|
"how-to-use": "Wie benutzt man?"
|
||||||
}
|
}
|
@ -176,5 +176,11 @@
|
|||||||
"tool-manage": "Tool Management",
|
"tool-manage": "Tool Management",
|
||||||
"enable-all-tools": "Activate all tools",
|
"enable-all-tools": "Activate all tools",
|
||||||
"disable-all-tools": "Disable all tools",
|
"disable-all-tools": "Disable all tools",
|
||||||
"using-tool": "Using tool"
|
"using-tool": "Using tool",
|
||||||
|
"copy-success": "Copied successfully",
|
||||||
|
"copy-fail": "Copy failed",
|
||||||
|
"copy": "Copy",
|
||||||
|
"export": "Export",
|
||||||
|
"export-filename": "Export file name",
|
||||||
|
"how-to-use": "How to use?"
|
||||||
}
|
}
|
@ -176,5 +176,11 @@
|
|||||||
"tool-manage": "Gestion des outils",
|
"tool-manage": "Gestion des outils",
|
||||||
"enable-all-tools": "Activer tous les outils",
|
"enable-all-tools": "Activer tous les outils",
|
||||||
"disable-all-tools": "Désactiver tous les outils",
|
"disable-all-tools": "Désactiver tous les outils",
|
||||||
"using-tool": "Utilisation de l'outil"
|
"using-tool": "Utilisation de l'outil",
|
||||||
|
"copy-success": "Copié avec succès",
|
||||||
|
"copy-fail": "Échec de la copie",
|
||||||
|
"copy": "Copier",
|
||||||
|
"export": "Exporter",
|
||||||
|
"export-filename": "Nom du fichier d'exportation",
|
||||||
|
"how-to-use": "Comment utiliser ?"
|
||||||
}
|
}
|
@ -176,5 +176,11 @@
|
|||||||
"tool-manage": "ツール管理",
|
"tool-manage": "ツール管理",
|
||||||
"enable-all-tools": "すべてのツールを有効にする",
|
"enable-all-tools": "すべてのツールを有効にする",
|
||||||
"disable-all-tools": "すべてのツールを無効にする",
|
"disable-all-tools": "すべてのツールを無効にする",
|
||||||
"using-tool": "ツール使用中"
|
"using-tool": "ツール使用中",
|
||||||
|
"copy-success": "コピーしました",
|
||||||
|
"copy-fail": "コピーに失敗しました",
|
||||||
|
"copy": "コピー",
|
||||||
|
"export": "エクスポート",
|
||||||
|
"export-filename": "エクスポートファイル名",
|
||||||
|
"how-to-use": "使い方は?"
|
||||||
}
|
}
|
@ -176,5 +176,11 @@
|
|||||||
"tool-manage": "도구 관리",
|
"tool-manage": "도구 관리",
|
||||||
"enable-all-tools": "모든 도구 활성화",
|
"enable-all-tools": "모든 도구 활성화",
|
||||||
"disable-all-tools": "모든 도구 비활성화",
|
"disable-all-tools": "모든 도구 비활성화",
|
||||||
"using-tool": "도구 사용 중"
|
"using-tool": "도구 사용 중",
|
||||||
|
"copy-success": "성공적으로 복사되었습니다",
|
||||||
|
"copy-fail": "복사 실패",
|
||||||
|
"copy": "복사",
|
||||||
|
"export": "내보내기",
|
||||||
|
"export-filename": "내보내기 파일 이름",
|
||||||
|
"how-to-use": "사용 방법?"
|
||||||
}
|
}
|
@ -176,5 +176,11 @@
|
|||||||
"tool-manage": "Управление инструментами",
|
"tool-manage": "Управление инструментами",
|
||||||
"enable-all-tools": "Активировать все инструменты",
|
"enable-all-tools": "Активировать все инструменты",
|
||||||
"disable-all-tools": "Отключить все инструменты",
|
"disable-all-tools": "Отключить все инструменты",
|
||||||
"using-tool": "Использование инструмента"
|
"using-tool": "Использование инструмента",
|
||||||
|
"copy-success": "Скопировано успешно",
|
||||||
|
"copy-fail": "Ошибка копирования",
|
||||||
|
"copy": "Копировать",
|
||||||
|
"export": "Экспорт",
|
||||||
|
"export-filename": "Имя экспортируемого файла",
|
||||||
|
"how-to-use": "Как использовать?"
|
||||||
}
|
}
|
@ -176,5 +176,11 @@
|
|||||||
"tool-manage": "工具管理",
|
"tool-manage": "工具管理",
|
||||||
"enable-all-tools": "激活所有工具",
|
"enable-all-tools": "激活所有工具",
|
||||||
"disable-all-tools": "禁用所有工具",
|
"disable-all-tools": "禁用所有工具",
|
||||||
"using-tool": "正在使用工具"
|
"using-tool": "正在使用工具",
|
||||||
|
"copy-success": "复制成功",
|
||||||
|
"copy-fail": "复制失败",
|
||||||
|
"copy": "复制",
|
||||||
|
"export": "导出",
|
||||||
|
"export-filename": "导出文件名",
|
||||||
|
"how-to-use": "如何使用?"
|
||||||
}
|
}
|
@ -176,5 +176,11 @@
|
|||||||
"tool-manage": "工具管理",
|
"tool-manage": "工具管理",
|
||||||
"enable-all-tools": "啟用所有工具",
|
"enable-all-tools": "啟用所有工具",
|
||||||
"disable-all-tools": "禁用所有工具",
|
"disable-all-tools": "禁用所有工具",
|
||||||
"using-tool": "正在使用工具"
|
"using-tool": "正在使用工具",
|
||||||
|
"copy-success": "複製成功",
|
||||||
|
"copy-fail": "複製失敗",
|
||||||
|
"copy": "複製",
|
||||||
|
"export": "匯出",
|
||||||
|
"export-filename": "匯出檔案名稱",
|
||||||
|
"how-to-use": "如何使用?"
|
||||||
}
|
}
|
@ -506,7 +506,11 @@ class McpClientAdapter {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public platform: string
|
public platform: string
|
||||||
) {}
|
) {
|
||||||
|
if (platform !== 'nodejs') {
|
||||||
|
this.addConnectRefreshListener();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 获取连接参数签名
|
* @description 获取连接参数签名
|
||||||
@ -564,18 +568,23 @@ class McpClientAdapter {
|
|||||||
* @description register HMR
|
* @description register HMR
|
||||||
*/
|
*/
|
||||||
public addConnectRefreshListener() {
|
public addConnectRefreshListener() {
|
||||||
// 创建对于 connect/refresh 的监听
|
// 创建对于 connect/refresh 的监听
|
||||||
if (!this.connectrefreshListener) {
|
if (!this.connectrefreshListener) {
|
||||||
const bridge = useMessageBridge();
|
const bridge = useMessageBridge();
|
||||||
this.connectrefreshListener = bridge.addCommandListener('connect/refresh', async (message) => {
|
this.connectrefreshListener = bridge.addCommandListener('connect/refresh', async (message) => {
|
||||||
const { code, msg } = message;
|
const { code, msg } = message;
|
||||||
|
|
||||||
|
console.log('refresh');
|
||||||
|
|
||||||
|
|
||||||
if (code === 200) {
|
if (code === 200) {
|
||||||
// 查找目标客户端
|
// 查找目标客户端
|
||||||
const clientIndex = this.findClientIndexByUuid(msg.uuid);
|
const clientIndex = this.findClientIndexByUuid(msg.uuid);
|
||||||
|
|
||||||
if (clientIndex > -1) {
|
if (clientIndex > -1) {
|
||||||
// 刷新该客户端的所有资源
|
// 刷新该客户端的所有资源
|
||||||
|
console.log('clientIndex', clientIndex);
|
||||||
|
|
||||||
await this.clients[clientIndex].refreshAllResources();
|
await this.clients[clientIndex].refreshAllResources();
|
||||||
this.refreshSignal.value++;
|
this.refreshSignal.value++;
|
||||||
} else {
|
} else {
|
||||||
|
@ -22,7 +22,6 @@ export async function routeMessage(command: string, data: any, webview: PostMess
|
|||||||
const { handler, option = {} } = handlerStore;
|
const { handler, option = {} } = handlerStore;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// TODO: select client based on something
|
|
||||||
const res = await handler(data, webview);
|
const res = await handler(data, webview);
|
||||||
|
|
||||||
// res.code = -1 代表当前请求不需要返回发送
|
// res.code = -1 代表当前请求不需要返回发送
|
||||||
|
@ -57,6 +57,7 @@ export class VSCodeWebViewLike {
|
|||||||
* @param message - 包含 command 和 args 的消息
|
* @param message - 包含 command 和 args 的消息
|
||||||
*/
|
*/
|
||||||
postMessage(message: WebSocketMessage): void {
|
postMessage(message: WebSocketMessage): void {
|
||||||
|
|
||||||
if (this.ws.readyState === WebSocket.OPEN) {
|
if (this.ws.readyState === WebSocket.OPEN) {
|
||||||
this.ws.send(JSON.stringify(message));
|
this.ws.send(JSON.stringify(message));
|
||||||
} else {
|
} else {
|
||||||
|
@ -5,8 +5,7 @@ import { dirname, join } from 'path';
|
|||||||
import { routeMessage } from './common/router.js';
|
import { routeMessage } from './common/router.js';
|
||||||
import { VSCodeWebViewLike } from './hook/adapter.js';
|
import { VSCodeWebViewLike } from './hook/adapter.js';
|
||||||
import fs from 'fs/promises'; // 使用 Promise API 替代回调
|
import fs from 'fs/promises'; // 使用 Promise API 替代回调
|
||||||
import path from 'path';
|
import chalk from 'chalk';
|
||||||
import axios from 'axios';
|
|
||||||
|
|
||||||
export interface VSCodeMessage {
|
export interface VSCodeMessage {
|
||||||
command: string;
|
command: string;
|
||||||
@ -101,7 +100,10 @@ wss.on('connection', (ws) => {
|
|||||||
|
|
||||||
acquireConnectionOption().then(option => {
|
acquireConnectionOption().then(option => {
|
||||||
webview.onDidReceiveMessage(async (message) => {
|
webview.onDidReceiveMessage(async (message) => {
|
||||||
logger.info(`收到命令: [${message.command || '未定义'}]`);
|
console.log(
|
||||||
|
chalk.white('receive command') +
|
||||||
|
chalk.blue(` [${message.command || '未定义'}]`)
|
||||||
|
);
|
||||||
|
|
||||||
const { command, data } = message;
|
const { command, data } = message;
|
||||||
|
|
||||||
|
@ -4,6 +4,8 @@ import { PostMessageble } from '../hook/adapter.js';
|
|||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import { pino } from 'pino';
|
import { pino } from 'pino';
|
||||||
|
import chalk from 'chalk';
|
||||||
|
|
||||||
|
|
||||||
// 保留现有 logger 配置
|
// 保留现有 logger 配置
|
||||||
const logger = pino({
|
const logger = pino({
|
||||||
@ -59,15 +61,11 @@ export class McpServerConnectMonitor {
|
|||||||
debounceTime: 500,
|
debounceTime: 500,
|
||||||
duplicateCheckTime: 500,
|
duplicateCheckTime: 500,
|
||||||
onChange: async (curr, prev) => {
|
onChange: async (curr, prev) => {
|
||||||
// 使用 info 级别记录文件修改
|
|
||||||
logger.info({
|
|
||||||
uuid: this.uuid,
|
|
||||||
size: curr.size,
|
|
||||||
mtime: new Date(curr.mtime).toLocaleString()
|
|
||||||
}, 'File modified');
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await onchange(this.uuid, this.Options);
|
await onchange(this.uuid, this.Options);
|
||||||
|
|
||||||
|
console.log('send something');
|
||||||
|
|
||||||
this.sendWebviewMessage('connect/refresh', {
|
this.sendWebviewMessage('connect/refresh', {
|
||||||
code: 200,
|
code: 200,
|
||||||
msg: {
|
msg: {
|
||||||
@ -75,7 +73,11 @@ export class McpServerConnectMonitor {
|
|||||||
uuid: this.uuid,
|
uuid: this.uuid,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
logger.info({ uuid: this.uuid }, 'Connection refresh successful');
|
|
||||||
|
console.log(
|
||||||
|
chalk.green('Connection refresh successfully')
|
||||||
|
);
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.sendWebviewMessage('connect/refresh', {
|
this.sendWebviewMessage('connect/refresh', {
|
||||||
code: 500,
|
code: 500,
|
||||||
@ -122,4 +124,9 @@ export class McpServerConnectMonitor {
|
|||||||
// 发送消息到webview
|
// 发送消息到webview
|
||||||
this.webview?.postMessage({ command, data });
|
this.webview?.postMessage({ command, data });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public close() {
|
||||||
|
this.Monitor?.close();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ import path from 'node:path';
|
|||||||
import fs from 'node:fs';
|
import fs from 'node:fs';
|
||||||
import * as os from 'os';
|
import * as os from 'os';
|
||||||
import { PostMessageble } from '../hook/adapter.js';
|
import { PostMessageble } from '../hook/adapter.js';
|
||||||
import Table from 'cli-table3';
|
import chalk from 'chalk';
|
||||||
|
|
||||||
export const clientMap: Map<string, RequestClientType> = new Map();
|
export const clientMap: Map<string, RequestClientType> = new Map();
|
||||||
export function getClient(clientId?: string): RequestClientType | undefined {
|
export function getClient(clientId?: string): RequestClientType | undefined {
|
||||||
@ -21,7 +21,10 @@ export async function updateClientMap(uuid: string, options: McpOptions): Promis
|
|||||||
const client = await connect(options);
|
const client = await connect(options);
|
||||||
clientMap.set(uuid, client);
|
clientMap.set(uuid, client);
|
||||||
const tools = await client.listTools();
|
const tools = await client.listTools();
|
||||||
console.log('[updateClientMap] tools:', tools);
|
console.log(
|
||||||
|
chalk.white('update client tools'),
|
||||||
|
chalk.blue(tools.tools.map(tool => tool.name).join(','))
|
||||||
|
);
|
||||||
return { res: true };
|
return { res: true };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[updateClientMap] error:', error);
|
console.error('[updateClientMap] error:', error);
|
||||||
@ -267,25 +270,6 @@ export async function connectService(
|
|||||||
webview?: PostMessageble
|
webview?: PostMessageble
|
||||||
): Promise<RestfulResponse> {
|
): Promise<RestfulResponse> {
|
||||||
try {
|
try {
|
||||||
// 使用cli-table3创建美观的表格
|
|
||||||
// const table = new Table({
|
|
||||||
// head: ['Property', 'Value'],
|
|
||||||
// colWidths: [20, 60],
|
|
||||||
// style: {
|
|
||||||
// head: ['green'],
|
|
||||||
// border: ['grey']
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
|
|
||||||
// table.push(
|
|
||||||
// ['Connection Type', option.connectionType],
|
|
||||||
// ['Command', option.command || 'N/A'],
|
|
||||||
// ['Arguments', option.args?.join(' ') || 'N/A'],
|
|
||||||
// ['Working Directory', option.cwd || 'N/A'],
|
|
||||||
// ['URL', option.url || 'N/A']
|
|
||||||
// );
|
|
||||||
|
|
||||||
// console.log(table.toString());
|
|
||||||
|
|
||||||
// 预处理字符串
|
// 预处理字符串
|
||||||
await preprocessCommand(option, webview);
|
await preprocessCommand(option, webview);
|
||||||
@ -301,6 +285,11 @@ export async function connectService(
|
|||||||
// }
|
// }
|
||||||
// const client = clientMap.get(uuid)!;
|
// const client = clientMap.get(uuid)!;
|
||||||
|
|
||||||
|
{
|
||||||
|
clientMap.get(uuid)?.disconnect();
|
||||||
|
clientMonitorMap.get(uuid)?.close();
|
||||||
|
}
|
||||||
|
|
||||||
const client = await connect(option);
|
const client = await connect(option);
|
||||||
clientMap.set(uuid, client);
|
clientMap.set(uuid, client);
|
||||||
clientMonitorMap.set(uuid, new McpServerConnectMonitor(uuid, option, updateClientMap, webview));
|
clientMonitorMap.set(uuid, new McpServerConnectMonitor(uuid, option, updateClientMap, webview));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user