完成 Resources 的支持
This commit is contained in:
parent
4947a0d2c2
commit
d4e6775a47
@ -69,6 +69,8 @@ class MessageBridge {
|
|||||||
|
|
||||||
this.postMessage = (message) => {
|
this.postMessage = (message) => {
|
||||||
if (this.ws?.readyState === WebSocket.OPEN) {
|
if (this.ws?.readyState === WebSocket.OPEN) {
|
||||||
|
console.log(message);
|
||||||
|
|
||||||
this.ws.send(JSON.stringify(message));
|
this.ws.send(JSON.stringify(message));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -118,10 +120,6 @@ const messageBridge = new MessageBridge();
|
|||||||
export function useMessageBridge() {
|
export function useMessageBridge() {
|
||||||
const bridge = messageBridge;
|
const bridge = messageBridge;
|
||||||
|
|
||||||
onUnmounted(() => {
|
|
||||||
bridge.destroy();
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
postMessage: bridge.postMessage.bind(bridge),
|
postMessage: bridge.postMessage.bind(bridge),
|
||||||
addCommandListener: bridge.addCommandListener.bind(bridge),
|
addCommandListener: bridge.addCommandListener.bind(bridge),
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import { reactive } from 'vue';
|
import { reactive } from 'vue';
|
||||||
|
|
||||||
|
import Resource from './resource/index.vue';
|
||||||
import Chat from './chat/index.vue';
|
import Chat from './chat/index.vue';
|
||||||
import Resource from './chat/index.vue';
|
|
||||||
import Prompt from './prompt/index.vue';
|
import Prompt from './prompt/index.vue';
|
||||||
import Tool from './tool/index.vue';
|
import Tool from './tool/index.vue';
|
||||||
|
|
||||||
|
@ -1,16 +1,23 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="resource-module">
|
<div class="resource-module">
|
||||||
<h2>资源模块</h2>
|
<div class="left">
|
||||||
|
<h2>
|
||||||
|
<span class="iconfont icon-file"></span>
|
||||||
|
资源模块
|
||||||
|
</h2>
|
||||||
|
<h3><code>resources/templates/list</code></h3>
|
||||||
|
|
||||||
|
<ResourceTemplates></ResourceTemplates>
|
||||||
|
</div>
|
||||||
|
<div class="right">
|
||||||
|
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import ResourceTemplates from './resource-templates.vue';
|
||||||
|
|
||||||
defineComponent({ name: 'resource' });
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
@ -18,4 +25,14 @@ defineComponent({ name: 'resource' });
|
|||||||
padding: 20px;
|
padding: 20px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.resource-module .left {
|
||||||
|
width: 45%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-module .right {
|
||||||
|
width: 45%;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
</style>
|
</style>
|
@ -0,0 +1,94 @@
|
|||||||
|
<template>
|
||||||
|
<div class="resource-template-container-scrollbar">
|
||||||
|
<el-scrollbar height="500px">
|
||||||
|
<div class="resource-template-container">
|
||||||
|
<div
|
||||||
|
class="item"
|
||||||
|
v-for="template of resourcesManager.templates"
|
||||||
|
:key="template.name"
|
||||||
|
>
|
||||||
|
<span>{{ template.name }}</span>
|
||||||
|
<span>{{ template.description || '' }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-scrollbar>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useMessageBridge } from '@/api/message-bridge';
|
||||||
|
import { CasualRestAPI, ResourceTemplatesListResponse } from '@/hook/type';
|
||||||
|
import { onMounted, onUnmounted } from 'vue';
|
||||||
|
import { resourcesManager } from './resources';
|
||||||
|
|
||||||
|
const bridge = useMessageBridge();
|
||||||
|
let cancelListener: undefined | (() => void) = undefined;
|
||||||
|
|
||||||
|
function reloadResources() {
|
||||||
|
bridge.postMessage({
|
||||||
|
command: 'resources/templates/list'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
cancelListener = bridge.addCommandListener('resources/templates/list', (data: CasualRestAPI<ResourceTemplatesListResponse>) => {
|
||||||
|
resourcesManager.templates = data.msg.resourceTemplates;
|
||||||
|
});
|
||||||
|
reloadResources();
|
||||||
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
if (cancelListener) {
|
||||||
|
cancelListener();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.resource-template-container-scrollbar {
|
||||||
|
background-color: var(--background);
|
||||||
|
border-radius: .5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-template-container {
|
||||||
|
height: fit-content;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-template-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);
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-template-container > .item:hover {
|
||||||
|
background-color: var(--main-light-color);
|
||||||
|
transition: var(--animation-3s);
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-template-container > .item > span:first-child {
|
||||||
|
max-width: 200px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-template-container > .item > span:last-child {
|
||||||
|
opacity: 0.6;
|
||||||
|
font-size: 12.5px;
|
||||||
|
max-width: 200px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
11
app/src/components/main-panel/resource/resources.ts
Normal file
11
app/src/components/main-panel/resource/resources.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { ResourceTemplate, ResourceTemplatesListResponse } from '@/hook/type';
|
||||||
|
import { reactive } from 'vue';
|
||||||
|
|
||||||
|
|
||||||
|
export const resourcesManager = reactive<{
|
||||||
|
current: ResourceTemplate | undefined
|
||||||
|
templates: ResourceTemplate[]
|
||||||
|
}>({
|
||||||
|
current: undefined,
|
||||||
|
templates: []
|
||||||
|
});
|
@ -30,8 +30,6 @@ function isActive(name: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function gotoOption(ident: string) {
|
function gotoOption(ident: string) {
|
||||||
console.log(router);
|
|
||||||
|
|
||||||
router.push('/' + ident);
|
router.push('/' + ident);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
110
app/src/hook/type.ts
Normal file
110
app/src/hook/type.ts
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
// ==================== 基础类型定义 ====================
|
||||||
|
export interface SchemaProperty {
|
||||||
|
title: string;
|
||||||
|
type: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface InputSchema {
|
||||||
|
type: string;
|
||||||
|
properties: Record<string, SchemaProperty>;
|
||||||
|
required?: string[];
|
||||||
|
title?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Argument {
|
||||||
|
name: string;
|
||||||
|
required: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Content {
|
||||||
|
uri: string;
|
||||||
|
mimeType: string;
|
||||||
|
text: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MessageContent {
|
||||||
|
type: string;
|
||||||
|
text: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CasualRestAPI<T> {
|
||||||
|
code: number
|
||||||
|
msg: T
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 响应接口定义 ====================
|
||||||
|
export interface ToolsListResponse {
|
||||||
|
tools: Array<{
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
inputSchema: InputSchema;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PromptsListResponse {
|
||||||
|
prompts: Array<{
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
arguments: Argument[];
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ResourceTemplate {
|
||||||
|
uriTemplate: string;
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ResourceTemplatesListResponse {
|
||||||
|
resourceTemplates: ResourceTemplate[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ResourcesListResponse {
|
||||||
|
resources: any[]; // 根据示例返回空数组,可进一步定义具体类型
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ResourcesReadResponse {
|
||||||
|
contents: Content[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PromptsGetResponse {
|
||||||
|
messages: Array<{
|
||||||
|
role: string;
|
||||||
|
content: MessageContent;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 请求接口定义 ====================
|
||||||
|
export interface BaseRequest {
|
||||||
|
method: string;
|
||||||
|
params: Record<string, any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ResourcesReadRequest extends BaseRequest {
|
||||||
|
method: 'resources/read';
|
||||||
|
params: {
|
||||||
|
uri: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PromptsGetRequest extends BaseRequest {
|
||||||
|
method: 'prompts/get';
|
||||||
|
params: {
|
||||||
|
name: string;
|
||||||
|
arguments: Record<string, any>;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 合并类型定义 ====================
|
||||||
|
export type APIResponse =
|
||||||
|
| ToolsListResponse
|
||||||
|
| PromptsListResponse
|
||||||
|
| ResourceTemplatesListResponse
|
||||||
|
| ResourcesListResponse
|
||||||
|
| ResourcesReadResponse
|
||||||
|
| PromptsGetResponse;
|
||||||
|
|
||||||
|
export type APIRequest =
|
||||||
|
| BaseRequest
|
||||||
|
| ResourcesReadRequest
|
||||||
|
| PromptsGetRequest;
|
@ -36,7 +36,7 @@ const { t } = useI18n();
|
|||||||
user-select: text;
|
user-select: text;
|
||||||
cursor: text;
|
cursor: text;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
line-height: 1.3;
|
line-height: 1.5;
|
||||||
background-color: var(--sidebar);
|
background-color: var(--sidebar);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
@ -1,7 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
<div style="height: 100%;">
|
<div style="height: 100%;">
|
||||||
<Welcome v-if="!tabs.activeTab.component"></Welcome>
|
<Welcome v-show="!tabs.activeTab.component"></Welcome>
|
||||||
<component v-else :is="tabs.activeTab.component" />
|
|
||||||
|
<!-- 如果存在激活标签页,则根据标签页进行渲染 -->
|
||||||
|
<div v-show="tabs.activeTab.component">
|
||||||
|
<component
|
||||||
|
v-for="(tab, index) of tabs.content"
|
||||||
|
v-show="tab === tabs.activeTab"
|
||||||
|
:key="index"
|
||||||
|
:is="tab.component"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -11,7 +20,7 @@ import { defineComponent } from 'vue';
|
|||||||
import Welcome from './welcome.vue';
|
import Welcome from './welcome.vue';
|
||||||
import { tabs } from '@/components/main-panel/panel';
|
import { tabs } from '@/components/main-panel/panel';
|
||||||
|
|
||||||
defineComponent({ name: 'TEMPLATE_NAME' });
|
defineComponent({ name: 'debug' });
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
@ -25,3 +25,90 @@ def get_greeting(name: str) -> str:
|
|||||||
)
|
)
|
||||||
def translate(message: str) -> str:
|
def translate(message: str) -> str:
|
||||||
return f'请将下面的话语翻译成中文:\n\n{message}'
|
return f'请将下面的话语翻译成中文:\n\n{message}'
|
||||||
|
|
||||||
|
@mcp.tool(
|
||||||
|
name='multiply',
|
||||||
|
description='对两个数字进行实数域的乘法运算'
|
||||||
|
)
|
||||||
|
def multiply(a: float, b: float) -> float:
|
||||||
|
"""返回 a 和 b 的乘积"""
|
||||||
|
return a * b
|
||||||
|
|
||||||
|
@mcp.tool(
|
||||||
|
name='is_even',
|
||||||
|
description='判断一个整数是否为偶数'
|
||||||
|
)
|
||||||
|
def is_even(number: int) -> bool:
|
||||||
|
"""返回 True 如果数字是偶数,否则 False"""
|
||||||
|
return number % 2 == 0
|
||||||
|
|
||||||
|
@mcp.tool(
|
||||||
|
name='capitalize',
|
||||||
|
description='将字符串首字母大写'
|
||||||
|
)
|
||||||
|
def capitalize(text: str) -> str:
|
||||||
|
"""返回首字母大写的字符串"""
|
||||||
|
return text.capitalize()
|
||||||
|
|
||||||
|
@mcp.resource(
|
||||||
|
uri="weather://{city}",
|
||||||
|
name='weather',
|
||||||
|
description='获取指定城市的天气信息'
|
||||||
|
)
|
||||||
|
def get_weather(city: str) -> str:
|
||||||
|
"""模拟天气查询协议,返回格式化字符串"""
|
||||||
|
return f"Weather in {city}: Sunny, 25°C"
|
||||||
|
|
||||||
|
@mcp.resource(
|
||||||
|
uri="user://{user_id}",
|
||||||
|
name='user_profile',
|
||||||
|
description='获取用户基本信息'
|
||||||
|
)
|
||||||
|
def get_user_profile(user_id: str) -> dict:
|
||||||
|
"""模拟用户协议,返回字典数据"""
|
||||||
|
return {
|
||||||
|
"id": user_id,
|
||||||
|
"name": "张三",
|
||||||
|
"role": "developer"
|
||||||
|
}
|
||||||
|
|
||||||
|
@mcp.resource(
|
||||||
|
uri="book://{isbn}",
|
||||||
|
name='book_info',
|
||||||
|
description='通过ISBN查询书籍信息'
|
||||||
|
)
|
||||||
|
def get_book_info(isbn: str) -> dict:
|
||||||
|
"""模拟书籍协议,返回结构化数据"""
|
||||||
|
return {
|
||||||
|
"isbn": isbn,
|
||||||
|
"title": "Python编程:从入门到实践",
|
||||||
|
"author": "Eric Matthes"
|
||||||
|
}
|
||||||
|
|
||||||
|
@mcp.prompt(
|
||||||
|
name='summarize',
|
||||||
|
description='生成文本摘要的提示词模板'
|
||||||
|
)
|
||||||
|
def summarize(text: str) -> str:
|
||||||
|
"""返回摘要生成提示词"""
|
||||||
|
return f"请用一句话总结以下内容:\n\n{text}"
|
||||||
|
|
||||||
|
@mcp.prompt(
|
||||||
|
name='code_explanation',
|
||||||
|
description='解释代码功能的提示词模板'
|
||||||
|
)
|
||||||
|
def explain_code(code: str) -> str:
|
||||||
|
"""返回代码解释提示词"""
|
||||||
|
return f"请解释以下代码的功能:\n```python\n{code}\n```"
|
||||||
|
|
||||||
|
@mcp.prompt(
|
||||||
|
name='email_generator',
|
||||||
|
description='生成正式邮件的提示词模板'
|
||||||
|
)
|
||||||
|
def generate_email(context: str) -> str:
|
||||||
|
"""返回邮件生成提示词"""
|
||||||
|
return (
|
||||||
|
"根据以下需求撰写一封正式邮件:\n"
|
||||||
|
f"需求描述:{context}\n"
|
||||||
|
"要求:使用礼貌用语,长度不超过200字"
|
||||||
|
)
|
@ -91,6 +91,11 @@ export class MCPClient {
|
|||||||
return await this.client.listResources();
|
return await this.client.listResources();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 列出所有模板资源
|
||||||
|
public async listResourceTemplates() {
|
||||||
|
return await this.client.listResourceTemplates();
|
||||||
|
}
|
||||||
|
|
||||||
// 读取资源
|
// 读取资源
|
||||||
public async readResource(uri: string) {
|
public async readResource(uri: string) {
|
||||||
return await this.client.readResource({
|
return await this.client.readResource({
|
||||||
|
@ -115,6 +115,40 @@ export async function listResources(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 列出所有resources
|
||||||
|
*/
|
||||||
|
export async function listResourceTemplates(
|
||||||
|
client: MCPClient | undefined,
|
||||||
|
webview: VSCodeWebViewLike
|
||||||
|
) {
|
||||||
|
if (!client) {
|
||||||
|
const connectResult = {
|
||||||
|
code: 501,
|
||||||
|
msg: 'mcp client 尚未连接'
|
||||||
|
};
|
||||||
|
webview.postMessage({ command: 'resources/templates/list', data: connectResult });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const resources = await client.listResourceTemplates();
|
||||||
|
const result = {
|
||||||
|
code: 200,
|
||||||
|
msg: resources
|
||||||
|
};
|
||||||
|
webview.postMessage({ command: 'resources/templates/list', data: result });
|
||||||
|
} catch (error) {
|
||||||
|
const result = {
|
||||||
|
code: 500,
|
||||||
|
msg: (error as any).toString()
|
||||||
|
};
|
||||||
|
webview.postMessage({ command: 'resources/templates/list', data: result });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 读取特定resource
|
* @description 读取特定resource
|
||||||
*/
|
*/
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
|
|
||||||
import { VSCodeWebViewLike } from '../adapter';
|
import { VSCodeWebViewLike } from '../adapter';
|
||||||
import { connect, MCPClient, type MCPOptions } from './connect';
|
import { connect, MCPClient, type MCPOptions } from './connect';
|
||||||
import { callTool, getPrompt, listPrompts, listResources, readResource } from './handler';
|
import { callTool, getPrompt, listPrompts, listResources, listResourceTemplates, readResource } from './handler';
|
||||||
|
import { ping } from './util';
|
||||||
|
|
||||||
|
|
||||||
// TODO: 支持更多的 client
|
// TODO: 支持更多的 client
|
||||||
@ -48,6 +49,10 @@ export function messageController(command: string, data: any, webview: VSCodeWeb
|
|||||||
listResources(client, webview);
|
listResources(client, webview);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'resources/templates/list':
|
||||||
|
listResourceTemplates(client, webview);
|
||||||
|
break;
|
||||||
|
|
||||||
case 'resources/read':
|
case 'resources/read':
|
||||||
readResource(client, data, webview);
|
readResource(client, data, webview);
|
||||||
break;
|
break;
|
||||||
@ -56,6 +61,10 @@ export function messageController(command: string, data: any, webview: VSCodeWeb
|
|||||||
callTool(client, data, webview);
|
callTool(client, data, webview);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'ping':
|
||||||
|
ping(client, webview);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
103
test/src/controller/protocol.type.ts
Normal file
103
test/src/controller/protocol.type.ts
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
// ==================== 基础类型定义 ====================
|
||||||
|
export interface SchemaProperty {
|
||||||
|
title: string;
|
||||||
|
type: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface InputSchema {
|
||||||
|
type: string;
|
||||||
|
properties: Record<string, SchemaProperty>;
|
||||||
|
required?: string[];
|
||||||
|
title?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Argument {
|
||||||
|
name: string;
|
||||||
|
required: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Content {
|
||||||
|
uri: string;
|
||||||
|
mimeType: string;
|
||||||
|
text: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MessageContent {
|
||||||
|
type: string;
|
||||||
|
text: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 响应接口定义 ====================
|
||||||
|
export interface ToolsListResponse {
|
||||||
|
tools: Array<{
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
inputSchema: InputSchema;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PromptsListResponse {
|
||||||
|
prompts: Array<{
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
arguments: Argument[];
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ResourceTemplatesListResponse {
|
||||||
|
resourceTemplates: Array<{
|
||||||
|
uriTemplate: string;
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ResourcesListResponse {
|
||||||
|
resources: any[]; // 根据示例返回空数组,可进一步定义具体类型
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ResourcesReadResponse {
|
||||||
|
contents: Content[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PromptsGetResponse {
|
||||||
|
messages: Array<{
|
||||||
|
role: string;
|
||||||
|
content: MessageContent;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 请求接口定义 ====================
|
||||||
|
export interface BaseRequest {
|
||||||
|
method: string;
|
||||||
|
params: Record<string, any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ResourcesReadRequest extends BaseRequest {
|
||||||
|
method: 'resources/read';
|
||||||
|
params: {
|
||||||
|
uri: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PromptsGetRequest extends BaseRequest {
|
||||||
|
method: 'prompts/get';
|
||||||
|
params: {
|
||||||
|
name: string;
|
||||||
|
arguments: Record<string, any>;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 合并类型定义 ====================
|
||||||
|
export type APIResponse =
|
||||||
|
| ToolsListResponse
|
||||||
|
| PromptsListResponse
|
||||||
|
| ResourceTemplatesListResponse
|
||||||
|
| ResourcesListResponse
|
||||||
|
| ResourcesReadResponse
|
||||||
|
| PromptsGetResponse;
|
||||||
|
|
||||||
|
export type APIRequest =
|
||||||
|
| BaseRequest
|
||||||
|
| ResourcesReadRequest
|
||||||
|
| PromptsGetRequest;
|
20
test/src/controller/util.ts
Normal file
20
test/src/controller/util.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { VSCodeWebViewLike } from "../adapter";
|
||||||
|
import { MCPClient } from "./connect";
|
||||||
|
|
||||||
|
export function ping(client: MCPClient | undefined, webview: VSCodeWebViewLike) {
|
||||||
|
if (!client) {
|
||||||
|
const connectResult = {
|
||||||
|
code: 501,
|
||||||
|
msg: 'mcp client 尚未连接'
|
||||||
|
};
|
||||||
|
webview.postMessage({ command: 'ping', data: connectResult });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
webview.postMessage({
|
||||||
|
command: 'ping', data: {
|
||||||
|
code: 200,
|
||||||
|
msg: {}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user