update
This commit is contained in:
parent
f9ecdf233b
commit
2c643107ee
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,3 +3,4 @@ dist
|
||||
node_modules
|
||||
.vscode-test/
|
||||
*.vsix
|
||||
.env
|
@ -1,27 +1,57 @@
|
||||
<template>
|
||||
<div class="tools-module">
|
||||
<h2>工具模块</h2>
|
||||
<!-- 工具模块内容将在这里实现 -->
|
||||
<div class="tool-module">
|
||||
<div class="left">
|
||||
<h2>
|
||||
<span class="iconfont icon-tool"></span>
|
||||
工具模块
|
||||
</h2>
|
||||
<h3><code>tools/list</code></h3>
|
||||
|
||||
<ToolList
|
||||
:tab-id="props.tabId"
|
||||
></ToolList>
|
||||
|
||||
</div>
|
||||
<div class="right">
|
||||
<ToolExecutor
|
||||
:tab-id="props.tabId"
|
||||
></ToolExecutor>
|
||||
|
||||
<ToolLogger
|
||||
:tab-id="props.tabId"
|
||||
></ToolLogger>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { defineComponent, defineProps } from 'vue';
|
||||
|
||||
defineComponent({ name: 'tool' });
|
||||
import { defineProps } from 'vue';
|
||||
import ToolList from './tool-list.vue';
|
||||
import ToolExecutor from './tool-executor.vue';
|
||||
import ToolLogger from './tool-logger.vue';
|
||||
|
||||
const props = defineProps({
|
||||
storage: {
|
||||
type: Object,
|
||||
tabId: {
|
||||
type: Number,
|
||||
required: true
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tools-module {
|
||||
.tool-module {
|
||||
padding: 20px;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
.tool-module .left {
|
||||
width: 45%;
|
||||
max-width: 410px;
|
||||
}
|
||||
|
||||
.tool-module .right {
|
||||
width: 45%;
|
||||
}
|
||||
</style>
|
147
app/src/components/main-panel/tool/tool-executor.vue
Normal file
147
app/src/components/main-panel/tool/tool-executor.vue
Normal file
@ -0,0 +1,147 @@
|
||||
<template>
|
||||
<div>
|
||||
<h3>{{ currentTool?.name }}</h3>
|
||||
</div>
|
||||
<div class="tool-executor-container">
|
||||
<el-form :model="formData" :rules="formRules" ref="formRef" label-position="top">
|
||||
<template v-if="currentTool?.inputSchema?.properties">
|
||||
<el-scrollbar height="150px">
|
||||
<el-form-item
|
||||
v-for="[name, property] in Object.entries(currentTool.inputSchema.properties)"
|
||||
:key="name"
|
||||
:label="property.title || name"
|
||||
:prop="name"
|
||||
:required="currentTool.inputSchema.required?.includes(name)"
|
||||
>
|
||||
<el-input
|
||||
v-if="property.type === 'string'"
|
||||
v-model="formData[name]"
|
||||
:placeholder="t('enter') + ' ' + (property.title || name)"
|
||||
/>
|
||||
|
||||
<el-input-number
|
||||
v-else-if="property.type === 'number' || property.type === 'integer'"
|
||||
v-model="formData[name]"
|
||||
controls-position="right"
|
||||
:placeholder="t('enter') + ' ' + (property.title || name)"
|
||||
/>
|
||||
|
||||
<el-switch
|
||||
v-else-if="property.type === 'boolean'"
|
||||
v-model="formData[name]"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-scrollbar>
|
||||
</template>
|
||||
|
||||
<el-form-item>
|
||||
<el-button type="primary" :loading="loading" @click="handleExecute">
|
||||
{{ t('execute-tool') }}
|
||||
</el-button>
|
||||
<el-button @click="resetForm">
|
||||
{{ t('reset') }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { defineComponent, defineProps, watch, ref, computed } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import type { FormInstance, FormRules } from 'element-plus';
|
||||
import { tabs } from '../panel';
|
||||
import { toolsManager, ToolStorage } from './tools';
|
||||
import { CasualRestAPI, ToolCallResponse } from '@/hook/type';
|
||||
import { useMessageBridge } from '@/api/message-bridge';
|
||||
|
||||
defineComponent({ name: 'tool-executor' });
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const props = defineProps({
|
||||
tabId: {
|
||||
type: Number,
|
||||
required: true
|
||||
}
|
||||
});
|
||||
|
||||
const tab = tabs.content[props.tabId];
|
||||
const tabStorage = tab.storage as ToolStorage;
|
||||
|
||||
const formRef = ref<FormInstance>();
|
||||
const formData = ref<Record<string, any>>({});
|
||||
const loading = ref(false);
|
||||
|
||||
const currentTool = computed(() => {
|
||||
return toolsManager.tools.find(tool => tool.name === tabStorage.currentToolName);
|
||||
});
|
||||
|
||||
const formRules = computed<FormRules>(() => {
|
||||
const rules: FormRules = {};
|
||||
if (!currentTool.value?.inputSchema?.properties) return rules;
|
||||
|
||||
Object.entries(currentTool.value.inputSchema.properties).forEach(([name, property]) => {
|
||||
if (currentTool.value?.inputSchema?.required?.includes(name)) {
|
||||
rules[name] = [
|
||||
{
|
||||
required: true,
|
||||
message: `${property.title || name} 是必填字段`,
|
||||
trigger: 'blur'
|
||||
}
|
||||
];
|
||||
}
|
||||
});
|
||||
|
||||
return rules;
|
||||
});
|
||||
|
||||
const initFormData = () => {
|
||||
formData.value = {};
|
||||
if (!currentTool.value?.inputSchema?.properties) return;
|
||||
|
||||
Object.entries(currentTool.value.inputSchema.properties).forEach(([name, property]) => {
|
||||
formData.value[name] = (property.type === 'number' || property.type === 'integer') ? 0 :
|
||||
property.type === 'boolean' ? false : '';
|
||||
});
|
||||
};
|
||||
|
||||
const resetForm = () => {
|
||||
formRef.value?.resetFields();
|
||||
tabStorage.lastToolCallResponse = undefined;
|
||||
};
|
||||
|
||||
function handleExecute() {
|
||||
if (!currentTool.value) return;
|
||||
|
||||
const bridge = useMessageBridge();
|
||||
|
||||
bridge.addCommandListener('tools/call', (data: CasualRestAPI<ToolCallResponse>) => {
|
||||
console.log(data.msg);
|
||||
|
||||
tabStorage.lastToolCallResponse = data.msg;
|
||||
}, { once: true });
|
||||
|
||||
bridge.postMessage({
|
||||
command: 'tools/call',
|
||||
data: {
|
||||
toolName: tabStorage.currentToolName,
|
||||
toolArgs: formData.value
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
watch(() => tabStorage.currentToolName, () => {
|
||||
initFormData();
|
||||
resetForm();
|
||||
}, { immediate: true });
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.tool-executor-container {
|
||||
background-color: var(--background);
|
||||
padding: 10px 12px;
|
||||
border-radius: .5em;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
</style>
|
154
app/src/components/main-panel/tool/tool-list.vue
Normal file
154
app/src/components/main-panel/tool/tool-list.vue
Normal file
@ -0,0 +1,154 @@
|
||||
<template>
|
||||
<div class="tool-list-container-scrollbar">
|
||||
<el-scrollbar height="500px">
|
||||
<div class="tool-list-container">
|
||||
<div
|
||||
class="item"
|
||||
:class="{ 'active': tabStorage.currentToolName === tool.name }"
|
||||
v-for="tool of toolsManager.tools"
|
||||
:key="tool.name"
|
||||
@click="handleClick(tool)"
|
||||
>
|
||||
<span>{{ tool.name }}</span>
|
||||
<span>{{ tool.description || '' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
<div class="tool-list-function-container">
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="reloadTools({ first: false })"
|
||||
>
|
||||
{{ t('refresh') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useMessageBridge } from '@/api/message-bridge';
|
||||
import { CasualRestAPI, ToolsListResponse } from '@/hook/type';
|
||||
import { onMounted, onUnmounted, defineProps } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { toolsManager, ToolStorage } from './tools';
|
||||
import { tabs } from '../panel';
|
||||
import { ElMessage } from 'element-plus';
|
||||
|
||||
const bridge = useMessageBridge();
|
||||
const { t } = useI18n();
|
||||
|
||||
const props = defineProps({
|
||||
tabId: {
|
||||
type: Number,
|
||||
required: true
|
||||
}
|
||||
});
|
||||
|
||||
const tab = tabs.content[props.tabId];
|
||||
const tabStorage = tab.storage as ToolStorage;
|
||||
|
||||
function reloadTools(option: { first: boolean }) {
|
||||
bridge.postMessage({
|
||||
command: 'tools/list'
|
||||
});
|
||||
|
||||
if (!option.first) {
|
||||
ElMessage({
|
||||
message: t('finish-refresh'),
|
||||
type: 'success',
|
||||
duration: 3000,
|
||||
showClose: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function handleClick(tool: { name: string }) {
|
||||
tabStorage.currentToolName = tool.name;
|
||||
tabStorage.lastToolCallResponse = undefined;
|
||||
}
|
||||
|
||||
let commandCancel: (() => void);
|
||||
|
||||
onMounted(() => {
|
||||
commandCancel = bridge.addCommandListener('tools/list', (data: CasualRestAPI<ToolsListResponse>) => {
|
||||
toolsManager.tools = data.msg.tools || [];
|
||||
|
||||
if (toolsManager.tools.length > 0) {
|
||||
tabStorage.currentToolName = toolsManager.tools[0].name;
|
||||
tabStorage.lastToolCallResponse = undefined;
|
||||
}
|
||||
}, { once: false });
|
||||
|
||||
reloadTools({ first: true });
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
if (commandCancel){
|
||||
commandCancel();
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.tool-list-container-scrollbar {
|
||||
background-color: var(--background);
|
||||
margin-bottom: 10px;
|
||||
border-radius: .5em;
|
||||
}
|
||||
|
||||
.tool-list-container {
|
||||
height: fit-content;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.tool-list-function-container {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.tool-list-function-container button {
|
||||
width: 175px;
|
||||
}
|
||||
|
||||
.tool-list-container > .item {
|
||||
margin: 3px;
|
||||
padding: 5px 10px;
|
||||
border-radius: .3em;
|
||||
user-select: none;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
transition: var(--animation-3s);
|
||||
}
|
||||
|
||||
.tool-list-container > .item:hover {
|
||||
background-color: var(--main-light-color);
|
||||
transition: var(--animation-3s);
|
||||
}
|
||||
|
||||
.tool-list-container > .item.active {
|
||||
background-color: var(--main-light-color);
|
||||
transition: var(--animation-3s);
|
||||
}
|
||||
|
||||
.tool-list-container > .item > span:first-child {
|
||||
max-width: 200px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.tool-list-container > .item > span:last-child {
|
||||
opacity: 0.6;
|
||||
font-size: 12.5px;
|
||||
max-width: 200px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
</style>
|
109
app/src/components/main-panel/tool/tool-logger.vue
Normal file
109
app/src/components/main-panel/tool/tool-logger.vue
Normal file
@ -0,0 +1,109 @@
|
||||
<template>
|
||||
<div class="tool-logger">
|
||||
<span>
|
||||
<span>{{ t('response') }}</span>
|
||||
<span style="width: 200px;">
|
||||
<el-switch
|
||||
v-model="showRawJson"
|
||||
inline-prompt
|
||||
active-text="JSON"
|
||||
inactive-text="Text"
|
||||
style="margin-left: 10px; width: 200px;"
|
||||
:inactive-action-style="'backgroundColor: var(--sidebar)'"
|
||||
/>
|
||||
</span>
|
||||
</span>
|
||||
<el-scrollbar height="350px">
|
||||
<div
|
||||
class="output-content"
|
||||
contenteditable="false"
|
||||
>
|
||||
<template v-if="!showRawJson">
|
||||
<template v-if="tabStorage.lastToolCallResponse?.isError">
|
||||
<span style="color: var(--el-color-error)">
|
||||
{{ tabStorage.lastToolCallResponse.content.map(c => c.text).join('\n') }}
|
||||
</span>
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ tabStorage.lastToolCallResponse?.content.map(c => c.text).join('\n') }}
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ formattedJson }}
|
||||
</template>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { defineComponent, defineProps, computed, ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { tabs } from '../panel';
|
||||
import { ToolStorage } from './tools';
|
||||
|
||||
defineComponent({ name: 'tool-logger' });
|
||||
const { t } = useI18n();
|
||||
|
||||
const props = defineProps({
|
||||
tabId: {
|
||||
type: Number,
|
||||
required: true
|
||||
}
|
||||
});
|
||||
|
||||
const tab = tabs.content[props.tabId];
|
||||
const tabStorage = tab.storage as ToolStorage;
|
||||
|
||||
const showRawJson = ref(false);
|
||||
|
||||
const formattedJson = computed(() => {
|
||||
try {
|
||||
return JSON.stringify(tabStorage.lastToolCallResponse, null, 2);
|
||||
} catch {
|
||||
return 'Invalid JSON';
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.tool-logger {
|
||||
border-radius: .5em;
|
||||
background-color: var(--background);
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.tool-logger .el-switch__core {
|
||||
border: 1px solid var(--main-color) !important;
|
||||
width: 60px !important;
|
||||
}
|
||||
|
||||
.tool-logger .el-switch .el-switch__action {
|
||||
background-color: var(--main-color);
|
||||
}
|
||||
|
||||
.tool-logger .el-switch.is-checked .el-switch__action {
|
||||
background-color: var(--sidebar);
|
||||
}
|
||||
|
||||
.tool-logger > span:first-child {
|
||||
margin-bottom: 5px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.tool-logger .output-content {
|
||||
border-radius: .5em;
|
||||
padding: 15px;
|
||||
min-height: 300px;
|
||||
height: fit-content;
|
||||
font-family: var(--code-font-family);
|
||||
white-space: pre-wrap;
|
||||
word-break: break-all;
|
||||
user-select: text;
|
||||
cursor: text;
|
||||
font-size: 15px;
|
||||
line-height: 1.5;
|
||||
background-color: var(--sidebar);
|
||||
}
|
||||
</style>
|
13
app/src/components/main-panel/tool/tools.ts
Normal file
13
app/src/components/main-panel/tool/tools.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { ToolsListResponse, ToolCallResponse } from '@/hook/type';
|
||||
import { reactive } from 'vue';
|
||||
|
||||
export const toolsManager = reactive<{
|
||||
tools: ToolsListResponse['tools']
|
||||
}>({
|
||||
tools: []
|
||||
});
|
||||
|
||||
export interface ToolStorage {
|
||||
currentToolName: string;
|
||||
lastToolCallResponse?: ToolCallResponse;
|
||||
}
|
@ -76,6 +76,16 @@ export interface PromptsGetResponse {
|
||||
}>;
|
||||
}
|
||||
|
||||
export interface ToolCallContent {
|
||||
type: string;
|
||||
text: string;
|
||||
}
|
||||
|
||||
export interface ToolCallResponse {
|
||||
content: ToolCallContent[];
|
||||
isError: boolean;
|
||||
}
|
||||
|
||||
// ==================== 请求接口定义 ====================
|
||||
export interface BaseRequest {
|
||||
method: string;
|
||||
@ -97,6 +107,17 @@ export interface PromptsGetRequest extends BaseRequest {
|
||||
};
|
||||
}
|
||||
|
||||
export interface ToolCallRequest extends BaseRequest {
|
||||
method: 'tools/call';
|
||||
params: {
|
||||
name: string;
|
||||
arguments: Record<string, any>;
|
||||
_meta?: {
|
||||
progressToken?: number;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
// ==================== 合并类型定义 ====================
|
||||
export type APIResponse =
|
||||
| ToolsListResponse
|
||||
@ -104,9 +125,11 @@ export type APIResponse =
|
||||
| ResourceTemplatesListResponse
|
||||
| ResourcesListResponse
|
||||
| ResourcesReadResponse
|
||||
| PromptsGetResponse;
|
||||
| PromptsGetResponse
|
||||
| ToolCallResponse;
|
||||
|
||||
export type APIRequest =
|
||||
| BaseRequest
|
||||
| ResourcesReadRequest
|
||||
| PromptsGetRequest;
|
||||
| PromptsGetRequest
|
||||
| ToolCallRequest;
|
@ -112,5 +112,6 @@
|
||||
"refresh": "تحديث",
|
||||
"finish-refresh": "تم التحديث",
|
||||
"response": "الاستجابة",
|
||||
"read-prompt": "استخراج الكلمات الرئيسية"
|
||||
"read-prompt": "استخراج الكلمات الرئيسية",
|
||||
"execute-tool": "تشغيل الأداة"
|
||||
}
|
@ -112,5 +112,6 @@
|
||||
"refresh": "Aktualisieren",
|
||||
"finish-refresh": "Aktualisierung abgeschlossen",
|
||||
"response": "Antwort",
|
||||
"read-prompt": "Stichwörter extrahieren"
|
||||
"read-prompt": "Stichwörter extrahieren",
|
||||
"execute-tool": "Werkzeug ausführen"
|
||||
}
|
@ -112,5 +112,6 @@
|
||||
"refresh": "Refresh",
|
||||
"finish-refresh": "Refresh completed",
|
||||
"response": "Response",
|
||||
"read-prompt": "Extract keywords"
|
||||
"read-prompt": "Extract keywords",
|
||||
"execute-tool": "Run tool"
|
||||
}
|
@ -112,5 +112,6 @@
|
||||
"refresh": "Rafraîchir",
|
||||
"finish-refresh": "Actualisation terminée",
|
||||
"response": "Réponse",
|
||||
"read-prompt": "Extraire des mots-clés"
|
||||
"read-prompt": "Extraire des mots-clés",
|
||||
"execute-tool": "Exécuter l'outil"
|
||||
}
|
@ -112,5 +112,6 @@
|
||||
"refresh": "更新",
|
||||
"finish-refresh": "更新が完了しました",
|
||||
"response": "応答",
|
||||
"read-prompt": "キーワードを抽出"
|
||||
"read-prompt": "キーワードを抽出",
|
||||
"execute-tool": "ツールを実行"
|
||||
}
|
@ -112,5 +112,6 @@
|
||||
"refresh": "새로 고침",
|
||||
"finish-refresh": "새로 고침 완료",
|
||||
"response": "응답",
|
||||
"read-prompt": "키워드 추출"
|
||||
"read-prompt": "키워드 추출",
|
||||
"execute-tool": "도구 실행"
|
||||
}
|
@ -112,5 +112,6 @@
|
||||
"refresh": "Обновить",
|
||||
"finish-refresh": "Обновление завершено",
|
||||
"response": "Ответ",
|
||||
"read-prompt": "Извлечь ключевые слова"
|
||||
"read-prompt": "Извлечь ключевые слова",
|
||||
"execute-tool": "Запустить инструмент"
|
||||
}
|
@ -112,5 +112,6 @@
|
||||
"refresh": "刷新",
|
||||
"finish-refresh": "刷新完成",
|
||||
"response": "响应",
|
||||
"read-prompt": "提取提词"
|
||||
"read-prompt": "提取提词",
|
||||
"execute-tool": "运行工具"
|
||||
}
|
@ -112,5 +112,6 @@
|
||||
"refresh": "重新整理",
|
||||
"finish-refresh": "刷新完成",
|
||||
"response": "響應",
|
||||
"read-prompt": "提取關鍵詞"
|
||||
"read-prompt": "提取關鍵詞",
|
||||
"execute-tool": "執行工具"
|
||||
}
|
1
test/.gitignore
vendored
1
test/.gitignore
vendored
@ -21,3 +21,4 @@ pnpm-debug.log*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
config.json
|
@ -105,6 +105,11 @@ export class MCPClient {
|
||||
});
|
||||
}
|
||||
|
||||
// 列出所有工具
|
||||
public async listTools() {
|
||||
return await this.client.listTools();
|
||||
}
|
||||
|
||||
// 调用工具
|
||||
public async callTool(options: { name: string; arguments: Record<string, any> }) {
|
||||
return await this.client.callTool(options);
|
||||
|
@ -182,6 +182,41 @@ export async function readResource(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取工具列表
|
||||
*/
|
||||
export async function listTools(
|
||||
client: MCPClient | undefined,
|
||||
webview: VSCodeWebViewLike
|
||||
) {
|
||||
if (!client) {
|
||||
const connectResult = {
|
||||
code: 501,
|
||||
msg: 'mcp client 尚未连接'
|
||||
};
|
||||
webview.postMessage({ command: 'tools/list', data: connectResult });
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const tools = await client.listTools();
|
||||
|
||||
const result = {
|
||||
code: 200,
|
||||
msg: tools
|
||||
};
|
||||
|
||||
webview.postMessage({ command: 'tools/list', data: result });
|
||||
} catch (error) {
|
||||
const result = {
|
||||
code: 500,
|
||||
msg: (error as any).toString()
|
||||
};
|
||||
webview.postMessage({ command: 'tools/list', data: result });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @description 调用工具
|
||||
*/
|
||||
@ -204,6 +239,7 @@ export async function callTool(
|
||||
name: option.toolName,
|
||||
arguments: option.toolArgs
|
||||
});
|
||||
|
||||
const result = {
|
||||
code: 200,
|
||||
msg: toolResult
|
||||
|
@ -1,7 +1,7 @@
|
||||
|
||||
import { VSCodeWebViewLike } from '../adapter';
|
||||
import { connect, MCPClient, type MCPOptions } from './connect';
|
||||
import { callTool, getPrompt, listPrompts, listResources, listResourceTemplates, readResource } from './handler';
|
||||
import { callTool, getPrompt, listPrompts, listResources, listResourceTemplates, listTools, readResource } from './handler';
|
||||
import { ping } from './util';
|
||||
|
||||
|
||||
@ -57,6 +57,10 @@ export function messageController(command: string, data: any, webview: VSCodeWeb
|
||||
readResource(client, data, webview);
|
||||
break;
|
||||
|
||||
case 'tools/list':
|
||||
listTools(client, webview);
|
||||
break;
|
||||
|
||||
case 'tools/call':
|
||||
callTool(client, data, webview);
|
||||
break;
|
||||
|
@ -67,6 +67,16 @@ export interface PromptsGetResponse {
|
||||
}>;
|
||||
}
|
||||
|
||||
export interface ToolListItem {
|
||||
name: string;
|
||||
description: string;
|
||||
inputSchema: InputSchema;
|
||||
}
|
||||
|
||||
export interface ToolsListResponse {
|
||||
tools: ToolListItem[];
|
||||
}
|
||||
|
||||
// ==================== 请求接口定义 ====================
|
||||
export interface BaseRequest {
|
||||
method: string;
|
||||
|
12
test/src/util.ts
Normal file
12
test/src/util.ts
Normal file
@ -0,0 +1,12 @@
|
||||
function getConfigurationPath() {
|
||||
// 如果是 vscode 插件下,则修改为 ~/.openmcp/config.json
|
||||
return 'config.json';
|
||||
}
|
||||
|
||||
export function loadConfig() {
|
||||
|
||||
}
|
||||
|
||||
export function saveConfig() {
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user