@yh-ui/ai-sdk 0.1.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +309 -0
- package/dist/agent-enhanced.cjs +292 -0
- package/dist/agent-enhanced.d.ts +143 -0
- package/dist/agent-enhanced.mjs +267 -0
- package/dist/cache-adapter.cjs +99 -0
- package/dist/cache-adapter.d.ts +42 -0
- package/dist/cache-adapter.mjs +95 -0
- package/dist/future.cjs +882 -0
- package/dist/future.d.ts +519 -0
- package/dist/future.mjs +765 -0
- package/dist/index.cjs +913 -0
- package/dist/index.d.ts +55 -0
- package/dist/index.mjs +217 -0
- package/dist/langchain.cjs +363 -0
- package/dist/langchain.d.ts +232 -0
- package/dist/langchain.mjs +319 -0
- package/dist/loaders.cjs +110 -0
- package/dist/loaders.d.ts +58 -0
- package/dist/loaders.mjs +76 -0
- package/dist/mcp-server.cjs +265 -0
- package/dist/mcp-server.d.ts +186 -0
- package/dist/mcp-server.mjs +234 -0
- package/dist/mcp.cjs +370 -0
- package/dist/mcp.d.ts +206 -0
- package/dist/mcp.mjs +354 -0
- package/dist/observability.cjs +150 -0
- package/dist/observability.d.ts +112 -0
- package/dist/observability.mjs +117 -0
- package/dist/rag-production.cjs +95 -0
- package/dist/rag-production.d.ts +43 -0
- package/dist/rag-production.mjs +85 -0
- package/dist/rate-limit.cjs +73 -0
- package/dist/rate-limit.d.ts +55 -0
- package/dist/rate-limit.mjs +51 -0
- package/dist/vector-store.cjs +63 -0
- package/dist/vector-store.d.ts +74 -0
- package/dist/vector-store.mjs +55 -0
- package/dist/vue/index.cjs +1023 -0
- package/dist/vue/index.d.ts +627 -0
- package/dist/vue/index.mjs +913 -0
- package/package.json +87 -0
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import { ref, onUnmounted } from "vue";
|
|
2
|
+
export class MCPServer {
|
|
3
|
+
config;
|
|
4
|
+
tools = /* @__PURE__ */ new Map();
|
|
5
|
+
requestHandlers = /* @__PURE__ */ new Map();
|
|
6
|
+
isRunning = false;
|
|
7
|
+
constructor(options) {
|
|
8
|
+
this.config = options.config;
|
|
9
|
+
if (options.tools) {
|
|
10
|
+
for (const tool of options.tools) {
|
|
11
|
+
this.tools.set(tool.name, tool);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
this.registerRequestHandler("initialize", this.handleInitialize.bind(this));
|
|
15
|
+
this.registerRequestHandler("tools/list", this.handleToolsList.bind(this));
|
|
16
|
+
this.registerRequestHandler("tools/call", this.handleToolsCall.bind(this));
|
|
17
|
+
this.registerRequestHandler("ping", this.handlePing.bind(this));
|
|
18
|
+
options.onStart?.(this);
|
|
19
|
+
}
|
|
20
|
+
registerRequestHandler(method, handler) {
|
|
21
|
+
this.requestHandlers.set(method, handler);
|
|
22
|
+
}
|
|
23
|
+
generateId() {
|
|
24
|
+
return Math.random().toString(36).substring(2, 9);
|
|
25
|
+
}
|
|
26
|
+
// ── Request Handlers ─────────────────────────────────────────────────────
|
|
27
|
+
handleInitialize(params) {
|
|
28
|
+
const initParams = params;
|
|
29
|
+
return {
|
|
30
|
+
protocolVersion: initParams?.protocolVersion || "2024-11-05",
|
|
31
|
+
capabilities: {
|
|
32
|
+
tools: {}
|
|
33
|
+
},
|
|
34
|
+
serverInfo: {
|
|
35
|
+
name: this.config.name,
|
|
36
|
+
version: this.config.version
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
handleToolsList() {
|
|
41
|
+
const tools = Array.from(this.tools.values()).map((tool) => ({
|
|
42
|
+
name: tool.name,
|
|
43
|
+
description: tool.description,
|
|
44
|
+
inputSchema: tool.inputSchema
|
|
45
|
+
}));
|
|
46
|
+
return { tools };
|
|
47
|
+
}
|
|
48
|
+
async handleToolsCall(params) {
|
|
49
|
+
const callParams = params;
|
|
50
|
+
if (!callParams?.name) {
|
|
51
|
+
throw new Error("Missing tool name");
|
|
52
|
+
}
|
|
53
|
+
const tool = this.tools.get(callParams.name);
|
|
54
|
+
if (!tool) {
|
|
55
|
+
throw new Error(`Tool not found: ${callParams.name}`);
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
const result = await tool.execute(callParams.arguments || {});
|
|
59
|
+
return { content: result };
|
|
60
|
+
} catch (err) {
|
|
61
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
62
|
+
return {
|
|
63
|
+
content: [{ type: "text", text: errorMessage }],
|
|
64
|
+
isError: true
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
handlePing() {
|
|
69
|
+
return { pong: true };
|
|
70
|
+
}
|
|
71
|
+
// ── Public API ───────────────────────────────────────────────────────────
|
|
72
|
+
/** Add a tool to the server */
|
|
73
|
+
addTool(tool) {
|
|
74
|
+
this.tools.set(tool.name, tool);
|
|
75
|
+
}
|
|
76
|
+
/** Remove a tool from the server */
|
|
77
|
+
removeTool(name) {
|
|
78
|
+
return this.tools.delete(name);
|
|
79
|
+
}
|
|
80
|
+
/** Get all tools */
|
|
81
|
+
getTools() {
|
|
82
|
+
return Array.from(this.tools.values());
|
|
83
|
+
}
|
|
84
|
+
/** Check if server is running */
|
|
85
|
+
getRunning() {
|
|
86
|
+
return this.isRunning;
|
|
87
|
+
}
|
|
88
|
+
/** Set running state */
|
|
89
|
+
setRunning(running) {
|
|
90
|
+
this.isRunning = running;
|
|
91
|
+
}
|
|
92
|
+
/** Handle a JSON-RPC request */
|
|
93
|
+
async handleRequest(request) {
|
|
94
|
+
const { method, params, id } = request;
|
|
95
|
+
const handler = this.requestHandlers.get(method);
|
|
96
|
+
if (!handler) {
|
|
97
|
+
return {
|
|
98
|
+
jsonrpc: "2.0",
|
|
99
|
+
id,
|
|
100
|
+
error: {
|
|
101
|
+
code: -32601,
|
|
102
|
+
// Method not found
|
|
103
|
+
message: `Method not found: ${method}`
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
try {
|
|
108
|
+
const result = await handler(params);
|
|
109
|
+
return {
|
|
110
|
+
jsonrpc: "2.0",
|
|
111
|
+
id,
|
|
112
|
+
result
|
|
113
|
+
};
|
|
114
|
+
} catch (err) {
|
|
115
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
116
|
+
return {
|
|
117
|
+
jsonrpc: "2.0",
|
|
118
|
+
id,
|
|
119
|
+
error: {
|
|
120
|
+
code: -32e3,
|
|
121
|
+
message: errorMessage
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/** Handle a batch of JSON-RPC requests */
|
|
127
|
+
async handleBatch(requests) {
|
|
128
|
+
return Promise.all(requests.map((req) => this.handleRequest(req)));
|
|
129
|
+
}
|
|
130
|
+
/** Cleanup */
|
|
131
|
+
destroy() {
|
|
132
|
+
this.tools.clear();
|
|
133
|
+
this.requestHandlers.clear();
|
|
134
|
+
this.isRunning = false;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
export function useMCPServer(options) {
|
|
138
|
+
const config = {
|
|
139
|
+
name: options.name,
|
|
140
|
+
version: options.version,
|
|
141
|
+
capabilities: {
|
|
142
|
+
tools: true
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
const tools = ref(options.tools || []);
|
|
146
|
+
const isRunning = ref(false);
|
|
147
|
+
const server = new MCPServer({
|
|
148
|
+
config,
|
|
149
|
+
tools: options.tools,
|
|
150
|
+
onStart: () => {
|
|
151
|
+
isRunning.value = true;
|
|
152
|
+
},
|
|
153
|
+
onStop: () => {
|
|
154
|
+
isRunning.value = false;
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
const addTool = (tool) => {
|
|
158
|
+
server.addTool(tool);
|
|
159
|
+
tools.value = server.getTools();
|
|
160
|
+
options.onToolsChange?.(tools.value);
|
|
161
|
+
};
|
|
162
|
+
const removeTool = (name) => {
|
|
163
|
+
const result = server.removeTool(name);
|
|
164
|
+
tools.value = server.getTools();
|
|
165
|
+
options.onToolsChange?.(tools.value);
|
|
166
|
+
return result;
|
|
167
|
+
};
|
|
168
|
+
const handleRequest = async (request) => {
|
|
169
|
+
return server.handleRequest(request);
|
|
170
|
+
};
|
|
171
|
+
const start = () => {
|
|
172
|
+
server.setRunning(true);
|
|
173
|
+
isRunning.value = true;
|
|
174
|
+
};
|
|
175
|
+
const stop = () => {
|
|
176
|
+
server.setRunning(false);
|
|
177
|
+
isRunning.value = false;
|
|
178
|
+
server.destroy();
|
|
179
|
+
};
|
|
180
|
+
onUnmounted(() => {
|
|
181
|
+
stop();
|
|
182
|
+
});
|
|
183
|
+
return {
|
|
184
|
+
server,
|
|
185
|
+
config,
|
|
186
|
+
tools,
|
|
187
|
+
isRunning,
|
|
188
|
+
addTool,
|
|
189
|
+
removeTool,
|
|
190
|
+
handleRequest,
|
|
191
|
+
start,
|
|
192
|
+
stop
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
export function createMCPServerHTTPHandler(options) {
|
|
196
|
+
const { server, handleRequest } = useMCPServer(options);
|
|
197
|
+
return async function(request) {
|
|
198
|
+
if (request.method === "OPTIONS") {
|
|
199
|
+
return new Response(null, {
|
|
200
|
+
headers: {
|
|
201
|
+
"Access-Control-Allow-Origin": "*",
|
|
202
|
+
"Access-Control-Allow-Methods": "GET, POST",
|
|
203
|
+
"Access-Control-Allow-Headers": "Content-Type"
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
try {
|
|
208
|
+
const body = await request.json();
|
|
209
|
+
if (Array.isArray(body)) {
|
|
210
|
+
const responses = await server.handleBatch(body);
|
|
211
|
+
return new Response(JSON.stringify(responses), {
|
|
212
|
+
headers: { "Content-Type": "application/json" }
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
const response = await handleRequest(body);
|
|
216
|
+
return new Response(JSON.stringify(response), {
|
|
217
|
+
headers: { "Content-Type": "application/json" }
|
|
218
|
+
});
|
|
219
|
+
} catch (err) {
|
|
220
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
221
|
+
return new Response(
|
|
222
|
+
JSON.stringify({
|
|
223
|
+
jsonrpc: "2.0",
|
|
224
|
+
id: null,
|
|
225
|
+
error: {
|
|
226
|
+
code: -32603,
|
|
227
|
+
message: errorMessage
|
|
228
|
+
}
|
|
229
|
+
}),
|
|
230
|
+
{ status: 500, headers: { "Content-Type": "application/json" } }
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
}
|
package/dist/mcp.cjs
ADDED
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.useMCPClient = useMCPClient;
|
|
7
|
+
exports.useMCPTools = useMCPTools;
|
|
8
|
+
var _vue = require("vue");
|
|
9
|
+
let requestId = 0;
|
|
10
|
+
function createJSONRPCRequest(method, params) {
|
|
11
|
+
return {
|
|
12
|
+
jsonrpc: "2.0",
|
|
13
|
+
id: ++requestId,
|
|
14
|
+
method,
|
|
15
|
+
params
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
class MCPHTTPTransport {
|
|
19
|
+
serverUrl;
|
|
20
|
+
timeout;
|
|
21
|
+
constructor(serverUrl, timeout = 3e4) {
|
|
22
|
+
this.serverUrl = serverUrl;
|
|
23
|
+
this.timeout = timeout;
|
|
24
|
+
}
|
|
25
|
+
async sendRequest(method, params) {
|
|
26
|
+
const response = await fetch(this.serverUrl, {
|
|
27
|
+
method: "POST",
|
|
28
|
+
headers: {
|
|
29
|
+
"Content-Type": "application/json"
|
|
30
|
+
},
|
|
31
|
+
body: JSON.stringify(createJSONRPCRequest(method, params)),
|
|
32
|
+
signal: AbortSignal.timeout(this.timeout)
|
|
33
|
+
});
|
|
34
|
+
if (!response.ok) {
|
|
35
|
+
throw new Error(`MCP HTTP Error: ${response.status} ${response.statusText}`);
|
|
36
|
+
}
|
|
37
|
+
const data = await response.json();
|
|
38
|
+
if (data.error) {
|
|
39
|
+
throw new Error(`MCP Error: ${data.error.message}`);
|
|
40
|
+
}
|
|
41
|
+
return data.result;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
class MCPStdioTransport {
|
|
45
|
+
command;
|
|
46
|
+
args;
|
|
47
|
+
env;
|
|
48
|
+
process = null;
|
|
49
|
+
requestMap = /* @__PURE__ */new Map();
|
|
50
|
+
notificationHandlers = /* @__PURE__ */new Map();
|
|
51
|
+
messageBuffer = "";
|
|
52
|
+
initialized;
|
|
53
|
+
constructor(command, args = [], env = {}) {
|
|
54
|
+
this.command = command;
|
|
55
|
+
this.args = args;
|
|
56
|
+
this.env = env;
|
|
57
|
+
this.initialized = this.init();
|
|
58
|
+
}
|
|
59
|
+
init() {
|
|
60
|
+
return new Promise((resolve, reject) => {
|
|
61
|
+
try {
|
|
62
|
+
const {
|
|
63
|
+
spawn
|
|
64
|
+
} = require("child_process");
|
|
65
|
+
this.process = spawn(this.command, this.args, {
|
|
66
|
+
env: {
|
|
67
|
+
...process.env,
|
|
68
|
+
...this.env
|
|
69
|
+
},
|
|
70
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
71
|
+
});
|
|
72
|
+
this.process.on("error", err => {
|
|
73
|
+
reject(err);
|
|
74
|
+
});
|
|
75
|
+
this.process.on("close", () => {
|
|
76
|
+
this.process = null;
|
|
77
|
+
});
|
|
78
|
+
this.process.stdout?.on("data", data => {
|
|
79
|
+
this.handleData(data.toString());
|
|
80
|
+
});
|
|
81
|
+
this.process.stderr?.on("data", data => {
|
|
82
|
+
console.error("[MCP Stdio]", data.toString());
|
|
83
|
+
});
|
|
84
|
+
resolve();
|
|
85
|
+
} catch (err) {
|
|
86
|
+
reject(err);
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
handleData(data) {
|
|
91
|
+
this.messageBuffer += data;
|
|
92
|
+
let newlineIndex;
|
|
93
|
+
while ((newlineIndex = this.messageBuffer.indexOf("\n")) !== -1) {
|
|
94
|
+
const line = this.messageBuffer.slice(0, newlineIndex);
|
|
95
|
+
this.messageBuffer = this.messageBuffer.slice(newlineIndex + 1);
|
|
96
|
+
if (!line.trim()) continue;
|
|
97
|
+
try {
|
|
98
|
+
const message = JSON.parse(line);
|
|
99
|
+
this.handleMessage(message);
|
|
100
|
+
} catch {}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
handleMessage(message) {
|
|
104
|
+
if ("id" in message && message.id !== void 0) {
|
|
105
|
+
const pending = this.requestMap.get(message.id);
|
|
106
|
+
if (pending) {
|
|
107
|
+
this.requestMap.delete(message.id);
|
|
108
|
+
if ("error" in message && message.error) {
|
|
109
|
+
pending.reject(new Error(message.error.message));
|
|
110
|
+
} else {
|
|
111
|
+
pending.resolve(message.result);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
} else if ("method" in message) {
|
|
115
|
+
const handler = this.notificationHandlers.get(message.method);
|
|
116
|
+
if (handler) {
|
|
117
|
+
handler(message.params);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
async sendRequest(method, params) {
|
|
122
|
+
await this.initialized;
|
|
123
|
+
if (!this.process) {
|
|
124
|
+
throw new Error("MCP process not running");
|
|
125
|
+
}
|
|
126
|
+
const request = createJSONRPCRequest(method, params);
|
|
127
|
+
const requestId2 = request.id;
|
|
128
|
+
return new Promise((resolve, reject) => {
|
|
129
|
+
this.requestMap.set(requestId2, {
|
|
130
|
+
resolve,
|
|
131
|
+
reject
|
|
132
|
+
});
|
|
133
|
+
this.process.stdin?.write(JSON.stringify(request) + "\n");
|
|
134
|
+
setTimeout(() => {
|
|
135
|
+
if (this.requestMap.has(requestId2)) {
|
|
136
|
+
this.requestMap.delete(requestId2);
|
|
137
|
+
reject(new Error(`MCP request timeout: ${method}`));
|
|
138
|
+
}
|
|
139
|
+
}, 3e4);
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
onNotification(method, handler) {
|
|
143
|
+
this.notificationHandlers.set(method, handler);
|
|
144
|
+
}
|
|
145
|
+
async close() {
|
|
146
|
+
if (this.process) {
|
|
147
|
+
this.process.kill();
|
|
148
|
+
this.process = null;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
function useMCPClient(options) {
|
|
153
|
+
const {
|
|
154
|
+
config,
|
|
155
|
+
autoConnect = true,
|
|
156
|
+
clientName = "@yh-ui/ai-sdk",
|
|
157
|
+
clientVersion = "1.0.0",
|
|
158
|
+
onToolsUpdate,
|
|
159
|
+
onConnectionChange
|
|
160
|
+
} = options;
|
|
161
|
+
const state = (0, _vue.shallowRef)({
|
|
162
|
+
isConnected: false,
|
|
163
|
+
isConnecting: false,
|
|
164
|
+
error: null,
|
|
165
|
+
tools: []
|
|
166
|
+
});
|
|
167
|
+
const isCallingTool = (0, _vue.ref)(false);
|
|
168
|
+
const transport = (0, _vue.shallowRef)(null);
|
|
169
|
+
const connect = async () => {
|
|
170
|
+
if (state.value.isConnected || state.value.isConnecting) {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
state.value = {
|
|
174
|
+
...state.value,
|
|
175
|
+
isConnecting: true,
|
|
176
|
+
error: null
|
|
177
|
+
};
|
|
178
|
+
try {
|
|
179
|
+
let t;
|
|
180
|
+
if (config.serverUrl) {
|
|
181
|
+
t = new MCPHTTPTransport(config.serverUrl, config.timeout);
|
|
182
|
+
} else if (config.command) {
|
|
183
|
+
t = new MCPStdioTransport(config.command, config.args, config.env);
|
|
184
|
+
} else {
|
|
185
|
+
throw new Error("Invalid MCP config: must provide either serverUrl or command");
|
|
186
|
+
}
|
|
187
|
+
transport.value = t;
|
|
188
|
+
const _initResult = await t.sendRequest("initialize", {
|
|
189
|
+
protocolVersion: "2024-11-05",
|
|
190
|
+
capabilities: {},
|
|
191
|
+
clientInfo: {
|
|
192
|
+
name: clientName,
|
|
193
|
+
version: clientVersion
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
await t.sendRequest("initialized", {});
|
|
197
|
+
const toolsResult = await t.sendRequest("tools/list", {});
|
|
198
|
+
const tools = toolsResult.tools.map(tool => ({
|
|
199
|
+
name: tool.name,
|
|
200
|
+
description: tool.description || "",
|
|
201
|
+
inputSchema: tool.inputSchema
|
|
202
|
+
}));
|
|
203
|
+
state.value = {
|
|
204
|
+
isConnected: true,
|
|
205
|
+
isConnecting: false,
|
|
206
|
+
error: null,
|
|
207
|
+
tools
|
|
208
|
+
};
|
|
209
|
+
onToolsUpdate?.(tools);
|
|
210
|
+
onConnectionChange?.(true);
|
|
211
|
+
} catch (err) {
|
|
212
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
213
|
+
state.value = {
|
|
214
|
+
isConnected: false,
|
|
215
|
+
isConnecting: false,
|
|
216
|
+
error,
|
|
217
|
+
tools: []
|
|
218
|
+
};
|
|
219
|
+
onConnectionChange?.(false);
|
|
220
|
+
throw error;
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
const disconnect = async () => {
|
|
224
|
+
const t = transport.value;
|
|
225
|
+
if (t) {
|
|
226
|
+
if ("close" in t) {
|
|
227
|
+
await t.close();
|
|
228
|
+
}
|
|
229
|
+
transport.value = null;
|
|
230
|
+
}
|
|
231
|
+
state.value = {
|
|
232
|
+
isConnected: false,
|
|
233
|
+
isConnecting: false,
|
|
234
|
+
error: null,
|
|
235
|
+
tools: []
|
|
236
|
+
};
|
|
237
|
+
onConnectionChange?.(false);
|
|
238
|
+
};
|
|
239
|
+
const callTool = async (name, args = {}) => {
|
|
240
|
+
if (!state.value.isConnected) {
|
|
241
|
+
throw new Error("MCP client not connected");
|
|
242
|
+
}
|
|
243
|
+
const t = transport.value;
|
|
244
|
+
if (!t) {
|
|
245
|
+
throw new Error("MCP transport not initialized");
|
|
246
|
+
}
|
|
247
|
+
isCallingTool.value = true;
|
|
248
|
+
try {
|
|
249
|
+
const result = await t.sendRequest("tools/call", {
|
|
250
|
+
name,
|
|
251
|
+
arguments: args
|
|
252
|
+
});
|
|
253
|
+
const textContent = result.content.find(c => c.type === "text");
|
|
254
|
+
if (result.isError) {
|
|
255
|
+
throw new Error(textContent?.text || "Tool execution failed");
|
|
256
|
+
}
|
|
257
|
+
if (textContent?.text) {
|
|
258
|
+
try {
|
|
259
|
+
return JSON.parse(textContent.text);
|
|
260
|
+
} catch {
|
|
261
|
+
return textContent.text;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
return result;
|
|
265
|
+
} finally {
|
|
266
|
+
isCallingTool.value = false;
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
if (autoConnect) {
|
|
270
|
+
connect();
|
|
271
|
+
}
|
|
272
|
+
(0, _vue.onUnmounted)(() => {
|
|
273
|
+
disconnect();
|
|
274
|
+
});
|
|
275
|
+
return {
|
|
276
|
+
state,
|
|
277
|
+
connect,
|
|
278
|
+
disconnect,
|
|
279
|
+
callTool,
|
|
280
|
+
isCallingTool
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
function useMCPTools(options) {
|
|
284
|
+
const {
|
|
285
|
+
servers,
|
|
286
|
+
autoConnect = true,
|
|
287
|
+
onServerConnect
|
|
288
|
+
} = options;
|
|
289
|
+
const allTools = (0, _vue.ref)([]);
|
|
290
|
+
const serverStates = (0, _vue.ref)(servers.map((config, index) => ({
|
|
291
|
+
index,
|
|
292
|
+
config,
|
|
293
|
+
isConnected: false,
|
|
294
|
+
tools: [],
|
|
295
|
+
error: null
|
|
296
|
+
})));
|
|
297
|
+
const clients = [];
|
|
298
|
+
for (let i = 0; i < servers.length; i++) {
|
|
299
|
+
const serverState = serverStates.value[i];
|
|
300
|
+
const client = useMCPClient({
|
|
301
|
+
config: servers[i],
|
|
302
|
+
autoConnect: false,
|
|
303
|
+
onToolsUpdate: tools => {
|
|
304
|
+
serverState.tools = tools;
|
|
305
|
+
updateAllTools();
|
|
306
|
+
},
|
|
307
|
+
onConnectionChange: isConnected => {
|
|
308
|
+
serverState.isConnected = isConnected;
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
clients.push({
|
|
312
|
+
get state() {
|
|
313
|
+
return client.state.value;
|
|
314
|
+
},
|
|
315
|
+
connect: client.connect,
|
|
316
|
+
disconnect: client.disconnect
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
function updateAllTools() {
|
|
320
|
+
const tools = [];
|
|
321
|
+
for (const server of serverStates.value) {
|
|
322
|
+
if (server.isConnected) {
|
|
323
|
+
tools.push(...server.tools);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
allTools.value = tools;
|
|
327
|
+
}
|
|
328
|
+
const connectAll = async () => {
|
|
329
|
+
for (let i = 0; i < clients.length; i++) {
|
|
330
|
+
const client = clients[i];
|
|
331
|
+
try {
|
|
332
|
+
await client.connect();
|
|
333
|
+
const tools = serverStates.value[i].tools;
|
|
334
|
+
onServerConnect?.(i, tools);
|
|
335
|
+
} catch (err) {
|
|
336
|
+
serverStates.value[i].error = err instanceof Error ? err : new Error(String(err));
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
const disconnectAll = async () => {
|
|
341
|
+
for (const client of clients) {
|
|
342
|
+
await client.disconnect();
|
|
343
|
+
}
|
|
344
|
+
};
|
|
345
|
+
const callTool = async (name, args = {}) => {
|
|
346
|
+
for (const server of serverStates.value) {
|
|
347
|
+
const tool = server.tools.find(t => t.name === name);
|
|
348
|
+
if (tool) {
|
|
349
|
+
const clientIndex = serverStates.value.indexOf(server);
|
|
350
|
+
const _client = clients[clientIndex];
|
|
351
|
+
const mcpClient = useMCPClient({
|
|
352
|
+
config: server.config,
|
|
353
|
+
autoConnect: false
|
|
354
|
+
});
|
|
355
|
+
return mcpClient.callTool(name, args);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
throw new Error(`Tool not found: ${name}`);
|
|
359
|
+
};
|
|
360
|
+
if (autoConnect) {
|
|
361
|
+
connectAll();
|
|
362
|
+
}
|
|
363
|
+
return {
|
|
364
|
+
allTools,
|
|
365
|
+
serverStates,
|
|
366
|
+
connectAll,
|
|
367
|
+
disconnectAll,
|
|
368
|
+
callTool
|
|
369
|
+
};
|
|
370
|
+
}
|