From 3976670295af95488ea93b51acfe46b7dd02ab3f Mon Sep 17 00:00:00 2001 From: Kirigaya <1193466151@qq.com> Date: Tue, 22 Apr 2025 15:13:54 +0800 Subject: [PATCH] push save MVP to 95% --- .gitignore | 4 ++- .vscode-test.mjs | 5 --- CHANGELOG.md | 3 ++ package.json | 2 +- .../main-panel/resource/resouce-reader.vue | 33 +++++++++++++------ .../resource/resource-templates.vue | 5 ++- .../main-panel/resource/resources.ts | 7 ++-- .../main-panel/tool/tool-executor.vue | 18 ++-------- renderer/src/hook/mcp.ts | 30 +++++++++++++++++ service/tabs.锦恢的 MCP Server.json | 25 ++++++++++++-- 10 files changed, 92 insertions(+), 40 deletions(-) delete mode 100644 .vscode-test.mjs create mode 100644 renderer/src/hook/mcp.ts diff --git a/.gitignore b/.gitignore index 02c03a0..40ccff1 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,6 @@ node_modules .vscode-test/ *.vsix .env -resources \ No newline at end of file +resources +.DS_Store +.exe \ No newline at end of file diff --git a/.vscode-test.mjs b/.vscode-test.mjs deleted file mode 100644 index b62ba25..0000000 --- a/.vscode-test.mjs +++ /dev/null @@ -1,5 +0,0 @@ -import { defineConfig } from '@vscode/test-cli'; - -export default defineConfig({ - files: 'out/test/**/*.test.js', -}); diff --git a/CHANGELOG.md b/CHANGELOG.md index 667b329..f32ec6f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Change Log +## [main] 0.0.5 +- 支持对已经打开过的文件项目进行管理 + ## [main] 0.0.4 - 修复选择模型后点击确认跳转回 deepseek 的 bug - 修复 mcp 项目初始化点击工具全部都是空的 bug diff --git a/package.json b/package.json index b3fba7e..bf79d2e 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "openmcp", "displayName": "OpenMCP", "description": "An all in one MCP Client/TestTool", - "version": "0.0.4", + "version": "0.0.5", "publisher": "kirigaya", "author": { "name": "kirigaya", diff --git a/renderer/src/components/main-panel/resource/resouce-reader.vue b/renderer/src/components/main-panel/resource/resouce-reader.vue index e3518d4..973364a 100644 --- a/renderer/src/components/main-panel/resource/resouce-reader.vue +++ b/renderer/src/components/main-panel/resource/resouce-reader.vue @@ -3,19 +3,19 @@

{{ currentResource.template?.name }}

- + - - - + @@ -38,6 +38,7 @@ import { tabs } from '../panel'; import { parseResourceTemplate, resourcesManager, ResourceStorage } from './resources'; import { CasualRestAPI, ResourcesReadResponse } from '@/hook/type'; import { useMessageBridge } from '@/api/message-bridge'; +import { getDefaultValue, normaliseJavascriptType } from '@/hook/mcp'; defineComponent({ name: 'resource-reader' }); @@ -53,9 +54,12 @@ const props = defineProps({ const tab = tabs.content[props.tabId]; const tabStorage = tab.storage as ResourceStorage; +if (!tabStorage.formData) { + tabStorage.formData = {}; +} + // 表单相关状态 const formRef = ref(); -const formData = ref>({}); const loading = ref(false); const responseData = ref(); @@ -94,12 +98,21 @@ const formRules = computed(() => { }); + + // 初始化表单数据 const initFormData = () => { - formData.value = {} - currentResource.value?.params.forEach(param => { - formData.value[param.name] = param.type === 'number' ? 0 : - param.type === 'boolean' ? false : '' + if (!currentResource.value?.params) return; + + const newSchemaDataForm: Record = {}; + + currentResource.value.params.forEach(param => { + newSchemaDataForm[param.name] = getDefaultValue(param); + const originType = normaliseJavascriptType(typeof tabStorage.formData[param.name]); + + if (tabStorage.formData[param.name]!== undefined && originType === param.type) { + newSchemaDataForm[param.name] = tabStorage.formData[param.name]; + } }) } @@ -112,7 +125,7 @@ const resetForm = () => { // 提交表单 function handleSubmit() { const fillFn = currentResource.value.fill; - const uri = fillFn(formData.value); + const uri = fillFn(tabStorage.formData); const bridge = useMessageBridge(); diff --git a/renderer/src/components/main-panel/resource/resource-templates.vue b/renderer/src/components/main-panel/resource/resource-templates.vue index 0ce8dee..757bb8d 100644 --- a/renderer/src/components/main-panel/resource/resource-templates.vue +++ b/renderer/src/components/main-panel/resource/resource-templates.vue @@ -64,7 +64,6 @@ function reloadResources(option: { first: boolean }) { function handleClick(template: ResourceTemplate) { tabStorage.currentResourceName = template.name; - // TODO: 恢复这部分响应? tabStorage.lastResourceReadResponse = undefined; } @@ -74,9 +73,9 @@ onMounted(() => { commandCancel = bridge.addCommandListener('resources/templates/list', (data: CasualRestAPI) => { resourcesManager.templates = data.msg.resourceTemplates || []; - if (resourcesManager.templates.length > 0) { + const targetResource = resourcesManager.templates.find(template => template.name === tabStorage.currentResourceName); + if (targetResource === undefined) { tabStorage.currentResourceName = resourcesManager.templates[0].name; - // TODO: 恢复这部分响应? tabStorage.lastResourceReadResponse = undefined; } }, { once: false }); diff --git a/renderer/src/components/main-panel/resource/resources.ts b/renderer/src/components/main-panel/resource/resources.ts index 419ac62..2d6c81d 100644 --- a/renderer/src/components/main-panel/resource/resources.ts +++ b/renderer/src/components/main-panel/resource/resources.ts @@ -13,6 +13,7 @@ export const resourcesManager = reactive<{ export interface ResourceStorage { currentResourceName: string; lastResourceReadResponse?: ResourcesReadResponse; + formData: Record; } /** @@ -22,7 +23,7 @@ export interface ResourceStorage { */ export function parseResourceTemplate(template: string): { params: string[], - fill: (params: Record) => string + fill: (params: Record) => string } { // 1. 提取所有参数名 const paramRegex = /\{([^}]+)\}/g; @@ -36,7 +37,7 @@ export function parseResourceTemplate(template: string): { const paramList = Array.from(params); // 2. 创建填充函数 - const fill = (values: Record): string => { + const fill = (values: Record): string => { let result = template; // 验证所有必填参数 @@ -48,7 +49,7 @@ export function parseResourceTemplate(template: string): { // 替换所有参数 for (const param of paramList) { - result = result.replace(new RegExp(`\\{${param}\\}`, 'g'), values[param]); + result = result.replace(new RegExp(`\\{${param}\\}`, 'g'), values[param].toString()); } return result; diff --git a/renderer/src/components/main-panel/tool/tool-executor.vue b/renderer/src/components/main-panel/tool/tool-executor.vue index d456b7d..d49dd95 100644 --- a/renderer/src/components/main-panel/tool/tool-executor.vue +++ b/renderer/src/components/main-panel/tool/tool-executor.vue @@ -54,6 +54,7 @@ import type { FormInstance, FormRules } from 'element-plus'; import { tabs } from '../panel'; import { callTool, toolsManager, ToolStorage } from './tools'; import { pinkLog } from '@/views/setting/util'; +import { getDefaultValue, normaliseJavascriptType } from '@/hook/mcp'; defineComponent({ name: 'tool-executor' }); @@ -99,15 +100,6 @@ const formRules = computed(() => { return rules; }); -const getDefaultValue = (property: any) => { - if (property.type === 'number' || property.type === 'integer') { - return 0; - } else if (property.type === 'boolean') { - return false; - } else { - return ''; - } -}; const initFormData = () => { // 初始化,根据输入的 inputSchema 校验 @@ -120,11 +112,8 @@ const initFormData = () => { Object.entries(currentTool.value.inputSchema.properties).forEach(([name, property]) => { newSchemaDataForm[name] = getDefaultValue(property); - let originType: string = typeof tabStorage.formData[name]; - if (originType === 'number') { - originType = 'integer'; - } - + const originType = normaliseJavascriptType(typeof tabStorage.formData[name]); + if (tabStorage.formData[name] !== undefined && originType === property.type) { newSchemaDataForm[name] = tabStorage.formData[name]; } @@ -135,7 +124,6 @@ const initFormData = () => { const resetForm = () => { formRef.value?.resetFields(); - tabStorage.lastToolCallResponse = undefined; }; async function handleExecute() { diff --git a/renderer/src/hook/mcp.ts b/renderer/src/hook/mcp.ts new file mode 100644 index 0000000..9e19f78 --- /dev/null +++ b/renderer/src/hook/mcp.ts @@ -0,0 +1,30 @@ +import { SchemaProperty } from "./type"; + +interface TypeAble { + type: string; +} + +export function getDefaultValue(property: TypeAble) { + if (property.type === 'number' || property.type === 'integer') { + return 0; + } else if (property.type === 'boolean') { + return false; + } else { + return ''; + } +} + +export function normaliseJavascriptType(type: string) { + switch (type) { + case 'integer': + return 'number'; + case 'number': + return 'integer'; + case 'boolean': + return 'boolean'; + case 'string': + return 'string'; + default: + return 'string'; + } +} \ No newline at end of file diff --git a/service/tabs.锦恢的 MCP Server.json b/service/tabs.锦恢的 MCP Server.json index 5875047..a966a72 100644 --- a/service/tabs.锦恢的 MCP Server.json +++ b/service/tabs.锦恢的 MCP Server.json @@ -1,5 +1,5 @@ { - "currentIndex": 1, + "currentIndex": 2, "tabs": [ { "name": "交互测试", @@ -133,12 +133,33 @@ "content": [ { "type": "text", - "text": "CityWeather(city_name_en='hangzhou', city_name_cn='杭州', city_code='101210101', temp='20.7', wd='', ws='', sd='93%', aqi='13', weather='阴')" + "text": "CityWeather(city_name_en='hangzhou', city_name_cn='杭州', city_code='101210101', temp='20.3', wd='', ws='', sd='89%', aqi='38', weather='阴')" } ], "isError": false } } + }, + { + "name": "资源", + "icon": "icon-file", + "type": "blank", + "componentIndex": 0, + "storage": { + "currentResourceName": "greeting", + "formData": { + "name": "kirigaya" + }, + "lastResourceReadResponse": { + "contents": [ + { + "uri": "greeting://kirigaya", + "mimeType": "text/plain", + "text": "Hello, kirigaya!" + } + ] + } + } } ] } \ No newline at end of file