@mcpjam/inspector 0.8.2 → 0.9.0
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/README.md +24 -6
- package/bin/start.js +78 -66
- package/dist/client/assets/index-C4nE74q5.css +1 -0
- package/dist/client/assets/index-CcfG-2LO.js +357 -0
- package/dist/client/assets/index-CcfG-2LO.js.map +1 -0
- package/dist/client/catalyst.png +0 -0
- package/dist/client/index.html +14 -0
- package/dist/main/main.cjs +1330 -0
- package/dist/preload/preload.js +26 -0
- package/dist/renderer/assets/index-CYiU4_x2.css +1 -0
- package/dist/renderer/assets/index-woGCpEdp.js +356 -0
- package/dist/renderer/catalyst.png +0 -0
- package/dist/renderer/demo_1.png +0 -0
- package/dist/renderer/demo_2.png +0 -0
- package/dist/renderer/demo_3.png +0 -0
- package/dist/renderer/file.svg +1 -0
- package/dist/renderer/globe.svg +1 -0
- package/dist/renderer/index.html +14 -0
- package/dist/renderer/mcp.svg +1 -0
- package/dist/renderer/mcp_jam.svg +12 -0
- package/dist/renderer/mcp_jam_dark.png +0 -0
- package/dist/renderer/mcp_jam_light.png +0 -0
- package/dist/renderer/next.svg +1 -0
- package/dist/renderer/vercel.svg +1 -0
- package/dist/renderer/window.svg +1 -0
- package/dist/server/index.js +1101 -0
- package/dist/server/index.js.map +1 -0
- package/package.json +32 -17
- package/.next/BUILD_ID +0 -1
- package/.next/app-build-manifest.json +0 -89
- package/.next/app-path-routes-manifest.json +0 -13
- package/.next/build-manifest.json +0 -33
- package/.next/cache/.previewinfo +0 -1
- package/.next/cache/.rscinfo +0 -1
- package/.next/cache/.tsbuildinfo +0 -1
- package/.next/cache/eslint/.cache_1pr0xfn +0 -1
- package/.next/cache/webpack/client-production/0.pack +0 -0
- package/.next/cache/webpack/client-production/index.pack +0 -0
- package/.next/cache/webpack/edge-server-production/0.pack +0 -0
- package/.next/cache/webpack/edge-server-production/index.pack +0 -0
- package/.next/cache/webpack/server-production/0.pack +0 -0
- package/.next/cache/webpack/server-production/index.pack +0 -0
- package/.next/diagnostics/build-diagnostics.json +0 -6
- package/.next/diagnostics/framework.json +0 -1
- package/.next/export-marker.json +0 -6
- package/.next/images-manifest.json +0 -57
- package/.next/next-minimal-server.js.nft.json +0 -1
- package/.next/next-server.js.nft.json +0 -1
- package/.next/package.json +0 -1
- package/.next/prerender-manifest.json +0 -41
- package/.next/react-loadable-manifest.json +0 -1
- package/.next/required-server-files.json +0 -318
- package/.next/routes-manifest.json +0 -65
- package/.next/server/app/_not-found/page.js +0 -2
- package/.next/server/app/_not-found/page.js.nft.json +0 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +0 -1
- package/.next/server/app/api/mcp/chat/route.js +0 -45
- package/.next/server/app/api/mcp/chat/route.js.nft.json +0 -1
- package/.next/server/app/api/mcp/chat/route_client-reference-manifest.js +0 -1
- package/.next/server/app/api/mcp/connect/route.js +0 -1
- package/.next/server/app/api/mcp/connect/route.js.nft.json +0 -1
- package/.next/server/app/api/mcp/connect/route_client-reference-manifest.js +0 -1
- package/.next/server/app/api/mcp/prompts/get/route.js +0 -1
- package/.next/server/app/api/mcp/prompts/get/route.js.nft.json +0 -1
- package/.next/server/app/api/mcp/prompts/get/route_client-reference-manifest.js +0 -1
- package/.next/server/app/api/mcp/prompts/list/route.js +0 -1
- package/.next/server/app/api/mcp/prompts/list/route.js.nft.json +0 -1
- package/.next/server/app/api/mcp/prompts/list/route_client-reference-manifest.js +0 -1
- package/.next/server/app/api/mcp/resources/list/route.js +0 -1
- package/.next/server/app/api/mcp/resources/list/route.js.nft.json +0 -1
- package/.next/server/app/api/mcp/resources/list/route_client-reference-manifest.js +0 -1
- package/.next/server/app/api/mcp/resources/read/route.js +0 -1
- package/.next/server/app/api/mcp/resources/read/route.js.nft.json +0 -1
- package/.next/server/app/api/mcp/resources/read/route_client-reference-manifest.js +0 -1
- package/.next/server/app/api/mcp/tools/route.js +0 -21
- package/.next/server/app/api/mcp/tools/route.js.nft.json +0 -1
- package/.next/server/app/api/mcp/tools/route_client-reference-manifest.js +0 -1
- package/.next/server/app/favicon.ico/route.js +0 -1
- package/.next/server/app/favicon.ico/route.js.nft.json +0 -1
- package/.next/server/app/favicon.ico.body +0 -0
- package/.next/server/app/favicon.ico.meta +0 -1
- package/.next/server/app/oauth/callback/page.js +0 -2
- package/.next/server/app/oauth/callback/page.js.nft.json +0 -1
- package/.next/server/app/oauth/callback/page_client-reference-manifest.js +0 -1
- package/.next/server/app/page.js +0 -16
- package/.next/server/app/page.js.nft.json +0 -1
- package/.next/server/app/page_client-reference-manifest.js +0 -1
- package/.next/server/app-paths-manifest.json +0 -13
- package/.next/server/chunks/175.js +0 -8
- package/.next/server/chunks/260.js +0 -82
- package/.next/server/chunks/546.js +0 -1
- package/.next/server/chunks/548.js +0 -6
- package/.next/server/chunks/55.js +0 -1
- package/.next/server/chunks/985.js +0 -22
- package/.next/server/functions-config-manifest.json +0 -4
- package/.next/server/interception-route-rewrite-manifest.js +0 -1
- package/.next/server/middleware-build-manifest.js +0 -1
- package/.next/server/middleware-manifest.json +0 -6
- package/.next/server/middleware-react-loadable-manifest.js +0 -1
- package/.next/server/next-font-manifest.js +0 -1
- package/.next/server/next-font-manifest.json +0 -1
- package/.next/server/pages/500.html +0 -1
- package/.next/server/pages/_app.js +0 -1
- package/.next/server/pages/_app.js.nft.json +0 -1
- package/.next/server/pages/_document.js +0 -1
- package/.next/server/pages/_document.js.nft.json +0 -1
- package/.next/server/pages/_error.js +0 -19
- package/.next/server/pages/_error.js.nft.json +0 -1
- package/.next/server/pages-manifest.json +0 -5
- package/.next/server/server-reference-manifest.js +0 -1
- package/.next/server/server-reference-manifest.json +0 -1
- package/.next/server/webpack-runtime.js +0 -1
- package/.next/static/SigynMKeJ0KJs0Nc9i0E-/_buildManifest.js +0 -1
- package/.next/static/SigynMKeJ0KJs0Nc9i0E-/_ssgManifest.js +0 -1
- package/.next/static/chunks/214-cc4c35d88f2695ed.js +0 -1
- package/.next/static/chunks/4bd1b696-cf72ae8a39fa05aa.js +0 -1
- package/.next/static/chunks/574-9365237f47ed3a68.js +0 -1
- package/.next/static/chunks/866-04c19dda4c52f2bf.js +0 -1
- package/.next/static/chunks/964-eda38e26c0391a47.js +0 -1
- package/.next/static/chunks/app/_not-found/page-8601c49989b0be94.js +0 -1
- package/.next/static/chunks/app/api/mcp/chat/route-0341498a8bf5f2da.js +0 -1
- package/.next/static/chunks/app/api/mcp/connect/route-0341498a8bf5f2da.js +0 -1
- package/.next/static/chunks/app/api/mcp/prompts/get/route-0341498a8bf5f2da.js +0 -1
- package/.next/static/chunks/app/api/mcp/prompts/list/route-0341498a8bf5f2da.js +0 -1
- package/.next/static/chunks/app/api/mcp/resources/list/route-0341498a8bf5f2da.js +0 -1
- package/.next/static/chunks/app/api/mcp/resources/read/route-0341498a8bf5f2da.js +0 -1
- package/.next/static/chunks/app/api/mcp/tools/route-0341498a8bf5f2da.js +0 -1
- package/.next/static/chunks/app/layout-9e8115d4bf656fa0.js +0 -1
- package/.next/static/chunks/app/oauth/callback/page-cf6cb1ac31175f40.js +0 -1
- package/.next/static/chunks/app/page-b0e3ed6257734413.js +0 -1
- package/.next/static/chunks/framework-7c95b8e5103c9e90.js +0 -1
- package/.next/static/chunks/main-app-4e9e28316818cdde.js +0 -1
- package/.next/static/chunks/main-bbdafee21a7bd1d6.js +0 -1
- package/.next/static/chunks/pages/_app-0a0020ddd67f79cf.js +0 -1
- package/.next/static/chunks/pages/_error-03529f2c21436739.js +0 -1
- package/.next/static/chunks/polyfills-42372ed130431b0a.js +0 -1
- package/.next/static/chunks/webpack-cdfccaf38062dd25.js +0 -1
- package/.next/static/css/1e852d83e9c1d0c6.css +0 -1
- package/.next/static/css/f30152c0704fba31.css +0 -1
- package/.next/static/css/fe751fdbe975e9ca.css +0 -1
- package/.next/static/media/569ce4b8f30dc480-s.p.woff2 +0 -0
- package/.next/static/media/747892c23ea88013-s.woff2 +0 -0
- package/.next/static/media/8d697b304b401681-s.woff2 +0 -0
- package/.next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
- package/.next/static/media/9610d9e46709d722-s.woff2 +0 -0
- package/.next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
- package/.next/trace +0 -35
- package/.next/types/app/api/mcp/chat/route.ts +0 -347
- package/.next/types/app/api/mcp/connect/route.ts +0 -347
- package/.next/types/app/api/mcp/prompts/get/route.ts +0 -347
- package/.next/types/app/api/mcp/prompts/list/route.ts +0 -347
- package/.next/types/app/api/mcp/resources/list/route.ts +0 -347
- package/.next/types/app/api/mcp/resources/read/route.ts +0 -347
- package/.next/types/app/api/mcp/tools/route.ts +0 -347
- package/.next/types/app/layout.ts +0 -84
- package/.next/types/app/oauth/callback/page.ts +0 -84
- package/.next/types/app/page.ts +0 -84
- package/.next/types/cache-life.d.ts +0 -141
- package/.next/types/package.json +0 -1
- package/next.config.ts +0 -7
- /package/{public → dist/client}/claude_logo.png +0 -0
- /package/{public → dist/client}/demo_1.png +0 -0
- /package/{public → dist/client}/demo_2.png +0 -0
- /package/{public → dist/client}/demo_3.png +0 -0
- /package/{public → dist/client}/file.svg +0 -0
- /package/{public → dist/client}/globe.svg +0 -0
- /package/{public → dist/client}/mcp.svg +0 -0
- /package/{public → dist/client}/mcp_jam.svg +0 -0
- /package/{public → dist/client}/mcp_jam_dark.png +0 -0
- /package/{public → dist/client}/mcp_jam_light.png +0 -0
- /package/{public → dist/client}/next.svg +0 -0
- /package/{public → dist/client}/ollama_dark.png +0 -0
- /package/{public → dist/client}/ollama_logo.svg +0 -0
- /package/{public → dist/client}/openai_logo.png +0 -0
- /package/{public → dist/client}/vercel.svg +0 -0
- /package/{public → dist/client}/window.svg +0 -0
- /package/{.next/static/media/claude_logo.d33b25b0.png → dist/renderer/claude_logo.png} +0 -0
- /package/{.next/static/media/ollama_dark.9af45ac0.png → dist/renderer/ollama_dark.png} +0 -0
- /package/{.next/static/media/ollama_logo.9f08a95b.svg → dist/renderer/ollama_logo.svg} +0 -0
- /package/{.next/static/media/openai_logo.3f83154a.png → dist/renderer/openai_logo.png} +0 -0
|
@@ -0,0 +1,1101 @@
|
|
|
1
|
+
// index.ts
|
|
2
|
+
import { serve } from "@hono/node-server";
|
|
3
|
+
import { Hono as Hono8 } from "hono";
|
|
4
|
+
import { cors } from "hono/cors";
|
|
5
|
+
import { logger } from "hono/logger";
|
|
6
|
+
import { serveStatic } from "@hono/node-server/serve-static";
|
|
7
|
+
import { readFileSync } from "fs";
|
|
8
|
+
import { join } from "path";
|
|
9
|
+
|
|
10
|
+
// routes/mcp/index.ts
|
|
11
|
+
import { Hono as Hono7 } from "hono";
|
|
12
|
+
|
|
13
|
+
// routes/mcp/connect.ts
|
|
14
|
+
import { Hono } from "hono";
|
|
15
|
+
|
|
16
|
+
// utils/mcp-utils.ts
|
|
17
|
+
import { MCPClient } from "@mastra/mcp";
|
|
18
|
+
function validateServerConfig(serverConfig) {
|
|
19
|
+
if (!serverConfig) {
|
|
20
|
+
return {
|
|
21
|
+
success: false,
|
|
22
|
+
error: {
|
|
23
|
+
message: "Server configuration is required",
|
|
24
|
+
status: 400
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
const config = { ...serverConfig };
|
|
29
|
+
if (config.url) {
|
|
30
|
+
try {
|
|
31
|
+
if (typeof config.url === "string") {
|
|
32
|
+
config.url = new URL(config.url);
|
|
33
|
+
} else if (typeof config.url === "object" && !config.url.href) {
|
|
34
|
+
return {
|
|
35
|
+
success: false,
|
|
36
|
+
error: {
|
|
37
|
+
message: "Invalid URL configuration",
|
|
38
|
+
status: 400
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
if (config.oauth?.access_token) {
|
|
43
|
+
const authHeaders = {
|
|
44
|
+
Authorization: `Bearer ${config.oauth.access_token}`,
|
|
45
|
+
...config.requestInit?.headers || {}
|
|
46
|
+
};
|
|
47
|
+
config.requestInit = {
|
|
48
|
+
...config.requestInit,
|
|
49
|
+
headers: authHeaders
|
|
50
|
+
};
|
|
51
|
+
config.eventSourceInit = {
|
|
52
|
+
fetch(input, init) {
|
|
53
|
+
const headers = new Headers(init?.headers || {});
|
|
54
|
+
headers.set(
|
|
55
|
+
"Authorization",
|
|
56
|
+
`Bearer ${config.oauth.access_token}`
|
|
57
|
+
);
|
|
58
|
+
if (config.requestInit?.headers) {
|
|
59
|
+
const requestHeaders = new Headers(config.requestInit.headers);
|
|
60
|
+
requestHeaders.forEach((value, key) => {
|
|
61
|
+
if (key.toLowerCase() !== "authorization") {
|
|
62
|
+
headers.set(key, value);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
return fetch(input, {
|
|
67
|
+
...init,
|
|
68
|
+
headers
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
} else if (config.requestInit?.headers) {
|
|
73
|
+
config.eventSourceInit = {
|
|
74
|
+
fetch(input, init) {
|
|
75
|
+
const headers = new Headers(init?.headers || {});
|
|
76
|
+
const requestHeaders = new Headers(config.requestInit.headers);
|
|
77
|
+
requestHeaders.forEach((value, key) => {
|
|
78
|
+
headers.set(key, value);
|
|
79
|
+
});
|
|
80
|
+
return fetch(input, {
|
|
81
|
+
...init,
|
|
82
|
+
headers
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
} catch (error) {
|
|
88
|
+
return {
|
|
89
|
+
success: false,
|
|
90
|
+
error: {
|
|
91
|
+
message: `Invalid URL format: ${error}`,
|
|
92
|
+
status: 400
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
success: true,
|
|
99
|
+
config
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
function createMCPClient(config, id) {
|
|
103
|
+
return new MCPClient({
|
|
104
|
+
id,
|
|
105
|
+
servers: {
|
|
106
|
+
server: config
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
var validateMultipleServerConfigs = (serverConfigs) => {
|
|
111
|
+
if (!serverConfigs || Object.keys(serverConfigs).length === 0) {
|
|
112
|
+
return {
|
|
113
|
+
success: false,
|
|
114
|
+
error: {
|
|
115
|
+
message: "At least one server configuration is required",
|
|
116
|
+
status: 400
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
const validConfigs = {};
|
|
121
|
+
const errors = {};
|
|
122
|
+
let hasErrors = false;
|
|
123
|
+
for (const [serverName, serverConfig] of Object.entries(serverConfigs)) {
|
|
124
|
+
const validationResult = validateServerConfig(serverConfig);
|
|
125
|
+
if (validationResult.success && validationResult.config) {
|
|
126
|
+
validConfigs[serverName] = validationResult.config;
|
|
127
|
+
} else {
|
|
128
|
+
hasErrors = true;
|
|
129
|
+
let errorMessage = "Configuration validation failed";
|
|
130
|
+
if (validationResult.error) {
|
|
131
|
+
errorMessage = validationResult.error.message;
|
|
132
|
+
}
|
|
133
|
+
errors[serverName] = errorMessage;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (!hasErrors) {
|
|
137
|
+
return {
|
|
138
|
+
success: true,
|
|
139
|
+
validConfigs
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
if (Object.keys(validConfigs).length > 0) {
|
|
143
|
+
return {
|
|
144
|
+
success: false,
|
|
145
|
+
validConfigs,
|
|
146
|
+
errors
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
return {
|
|
150
|
+
success: false,
|
|
151
|
+
errors,
|
|
152
|
+
error: {
|
|
153
|
+
message: "All server configurations failed validation",
|
|
154
|
+
status: 400
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
};
|
|
158
|
+
function createMCPClientWithMultipleConnections(serverConfigs) {
|
|
159
|
+
const normalizedConfigs = {};
|
|
160
|
+
for (const [serverName, config] of Object.entries(serverConfigs)) {
|
|
161
|
+
const normalizedName = normalizeServerConfigName(serverName);
|
|
162
|
+
normalizedConfigs[normalizedName] = config;
|
|
163
|
+
}
|
|
164
|
+
return new MCPClient({
|
|
165
|
+
id: `chat-${Date.now()}`,
|
|
166
|
+
servers: normalizedConfigs
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
function normalizeServerConfigName(serverName) {
|
|
170
|
+
return serverName.toLowerCase().replace(/[\s\-]+/g, "_").replace(/[^a-z0-9_]/g, "");
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// routes/mcp/connect.ts
|
|
174
|
+
var connect = new Hono();
|
|
175
|
+
connect.post("/", async (c) => {
|
|
176
|
+
try {
|
|
177
|
+
const { serverConfig } = await c.req.json();
|
|
178
|
+
const validation = validateServerConfig(serverConfig);
|
|
179
|
+
if (!validation.success) {
|
|
180
|
+
const error = validation.error;
|
|
181
|
+
return c.json(
|
|
182
|
+
{
|
|
183
|
+
success: false,
|
|
184
|
+
error: error.message
|
|
185
|
+
},
|
|
186
|
+
error.status
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
let client;
|
|
190
|
+
try {
|
|
191
|
+
client = createMCPClient(validation.config, `test-${Date.now()}`);
|
|
192
|
+
} catch (error) {
|
|
193
|
+
return c.json(
|
|
194
|
+
{
|
|
195
|
+
success: false,
|
|
196
|
+
error: `Failed to create a MCP client. Please double check your server configuration: ${JSON.stringify(serverConfig)}`,
|
|
197
|
+
details: error instanceof Error ? error.message : "Unknown error"
|
|
198
|
+
},
|
|
199
|
+
500
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
try {
|
|
203
|
+
await client.getTools();
|
|
204
|
+
await client.disconnect();
|
|
205
|
+
return c.json({
|
|
206
|
+
success: true
|
|
207
|
+
});
|
|
208
|
+
} catch (error) {
|
|
209
|
+
return c.json(
|
|
210
|
+
{
|
|
211
|
+
success: false,
|
|
212
|
+
error: `MCP configuration is invalid. Please double check your server configuration: ${JSON.stringify(serverConfig)}`,
|
|
213
|
+
details: error instanceof Error ? error.message : "Unknown error"
|
|
214
|
+
},
|
|
215
|
+
500
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
} catch (error) {
|
|
219
|
+
return c.json(
|
|
220
|
+
{
|
|
221
|
+
success: false,
|
|
222
|
+
error: "Failed to parse request body",
|
|
223
|
+
details: error instanceof Error ? error.message : "Unknown error"
|
|
224
|
+
},
|
|
225
|
+
400
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
var connect_default = connect;
|
|
230
|
+
|
|
231
|
+
// routes/mcp/tools.ts
|
|
232
|
+
import { Hono as Hono2 } from "hono";
|
|
233
|
+
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
234
|
+
var tools = new Hono2();
|
|
235
|
+
var pendingElicitations = /* @__PURE__ */ new Map();
|
|
236
|
+
tools.post("/", async (c) => {
|
|
237
|
+
let client = null;
|
|
238
|
+
let encoder = null;
|
|
239
|
+
let streamController = null;
|
|
240
|
+
let action;
|
|
241
|
+
let toolName;
|
|
242
|
+
try {
|
|
243
|
+
const requestData = await c.req.json();
|
|
244
|
+
action = requestData.action;
|
|
245
|
+
toolName = requestData.toolName;
|
|
246
|
+
const { serverConfig, parameters, requestId, response } = requestData;
|
|
247
|
+
if (!action || !["list", "execute", "respond"].includes(action)) {
|
|
248
|
+
return c.json(
|
|
249
|
+
{
|
|
250
|
+
success: false,
|
|
251
|
+
error: "Action must be 'list', 'execute', or 'respond'"
|
|
252
|
+
},
|
|
253
|
+
400
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
if (action === "respond") {
|
|
257
|
+
if (!requestId) {
|
|
258
|
+
return c.json(
|
|
259
|
+
{
|
|
260
|
+
success: false,
|
|
261
|
+
error: "requestId is required for respond action"
|
|
262
|
+
},
|
|
263
|
+
400
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
const pending = pendingElicitations.get(requestId);
|
|
267
|
+
if (!pending) {
|
|
268
|
+
return c.json(
|
|
269
|
+
{
|
|
270
|
+
success: false,
|
|
271
|
+
error: "No pending elicitation found for this requestId"
|
|
272
|
+
},
|
|
273
|
+
404
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
pending.resolve(response);
|
|
277
|
+
pendingElicitations.delete(requestId);
|
|
278
|
+
return c.json({ success: true });
|
|
279
|
+
}
|
|
280
|
+
const validation = validateServerConfig(serverConfig);
|
|
281
|
+
if (!validation.success) {
|
|
282
|
+
return c.json(
|
|
283
|
+
{ success: false, error: validation.error.message },
|
|
284
|
+
validation.error.status
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
encoder = new TextEncoder();
|
|
288
|
+
const readableStream = new ReadableStream({
|
|
289
|
+
async start(controller) {
|
|
290
|
+
streamController = controller;
|
|
291
|
+
try {
|
|
292
|
+
const clientId = `tools-${action}-${Date.now()}`;
|
|
293
|
+
client = createMCPClient(validation.config, clientId);
|
|
294
|
+
if (action === "list") {
|
|
295
|
+
controller.enqueue(
|
|
296
|
+
encoder.encode(
|
|
297
|
+
`data: ${JSON.stringify({
|
|
298
|
+
type: "tools_loading",
|
|
299
|
+
message: "Fetching tools from server..."
|
|
300
|
+
})}
|
|
301
|
+
|
|
302
|
+
`
|
|
303
|
+
)
|
|
304
|
+
);
|
|
305
|
+
const tools2 = await client.getTools();
|
|
306
|
+
const toolsWithJsonSchema = Object.fromEntries(
|
|
307
|
+
Object.entries(tools2).map(([toolName2, tool]) => {
|
|
308
|
+
return [
|
|
309
|
+
toolName2,
|
|
310
|
+
{
|
|
311
|
+
...tool,
|
|
312
|
+
inputSchema: zodToJsonSchema(
|
|
313
|
+
tool.inputSchema
|
|
314
|
+
)
|
|
315
|
+
}
|
|
316
|
+
];
|
|
317
|
+
})
|
|
318
|
+
);
|
|
319
|
+
controller.enqueue(
|
|
320
|
+
encoder.encode(
|
|
321
|
+
`data: ${JSON.stringify({
|
|
322
|
+
type: "tools_list",
|
|
323
|
+
tools: toolsWithJsonSchema
|
|
324
|
+
})}
|
|
325
|
+
|
|
326
|
+
`
|
|
327
|
+
)
|
|
328
|
+
);
|
|
329
|
+
} else if (action === "execute") {
|
|
330
|
+
if (!toolName) {
|
|
331
|
+
controller.enqueue(
|
|
332
|
+
encoder.encode(
|
|
333
|
+
`data: ${JSON.stringify({
|
|
334
|
+
type: "tool_error",
|
|
335
|
+
error: "Tool name is required for execution"
|
|
336
|
+
})}
|
|
337
|
+
|
|
338
|
+
`
|
|
339
|
+
)
|
|
340
|
+
);
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
controller.enqueue(
|
|
344
|
+
encoder.encode(
|
|
345
|
+
`data: ${JSON.stringify({
|
|
346
|
+
type: "tool_executing",
|
|
347
|
+
toolName,
|
|
348
|
+
parameters: parameters || {},
|
|
349
|
+
message: "Executing tool..."
|
|
350
|
+
})}
|
|
351
|
+
|
|
352
|
+
`
|
|
353
|
+
)
|
|
354
|
+
);
|
|
355
|
+
const tools2 = await client.getTools();
|
|
356
|
+
const tool = tools2[toolName];
|
|
357
|
+
if (!tool) {
|
|
358
|
+
controller.enqueue(
|
|
359
|
+
encoder.encode(
|
|
360
|
+
`data: ${JSON.stringify({
|
|
361
|
+
type: "tool_error",
|
|
362
|
+
error: `Tool '${toolName}' not found`
|
|
363
|
+
})}
|
|
364
|
+
|
|
365
|
+
`
|
|
366
|
+
)
|
|
367
|
+
);
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
const toolArgs = parameters && typeof parameters === "object" ? parameters : {};
|
|
371
|
+
const elicitationHandler = async (elicitationRequest) => {
|
|
372
|
+
const requestId2 = `elicit_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
373
|
+
if (streamController && encoder) {
|
|
374
|
+
streamController.enqueue(
|
|
375
|
+
encoder.encode(
|
|
376
|
+
`data: ${JSON.stringify({
|
|
377
|
+
type: "elicitation_request",
|
|
378
|
+
requestId: requestId2,
|
|
379
|
+
message: elicitationRequest.message,
|
|
380
|
+
schema: elicitationRequest.requestedSchema,
|
|
381
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
382
|
+
})}
|
|
383
|
+
|
|
384
|
+
`
|
|
385
|
+
)
|
|
386
|
+
);
|
|
387
|
+
}
|
|
388
|
+
return new Promise((resolve, reject) => {
|
|
389
|
+
pendingElicitations.set(requestId2, { resolve, reject });
|
|
390
|
+
setTimeout(() => {
|
|
391
|
+
if (pendingElicitations.has(requestId2)) {
|
|
392
|
+
pendingElicitations.delete(requestId2);
|
|
393
|
+
reject(new Error("Elicitation timeout"));
|
|
394
|
+
}
|
|
395
|
+
}, 3e5);
|
|
396
|
+
});
|
|
397
|
+
};
|
|
398
|
+
if (client.elicitation && client.elicitation.onRequest) {
|
|
399
|
+
const serverName = "server";
|
|
400
|
+
client.elicitation.onRequest(serverName, elicitationHandler);
|
|
401
|
+
}
|
|
402
|
+
const result = await tool.execute({
|
|
403
|
+
context: toolArgs
|
|
404
|
+
});
|
|
405
|
+
controller.enqueue(
|
|
406
|
+
encoder.encode(
|
|
407
|
+
`data: ${JSON.stringify({
|
|
408
|
+
type: "tool_result",
|
|
409
|
+
toolName,
|
|
410
|
+
result
|
|
411
|
+
})}
|
|
412
|
+
|
|
413
|
+
`
|
|
414
|
+
)
|
|
415
|
+
);
|
|
416
|
+
controller.enqueue(
|
|
417
|
+
encoder.encode(
|
|
418
|
+
`data: ${JSON.stringify({
|
|
419
|
+
type: "elicitation_complete",
|
|
420
|
+
toolName
|
|
421
|
+
})}
|
|
422
|
+
|
|
423
|
+
`
|
|
424
|
+
)
|
|
425
|
+
);
|
|
426
|
+
}
|
|
427
|
+
controller.enqueue(encoder.encode(`data: [DONE]
|
|
428
|
+
|
|
429
|
+
`));
|
|
430
|
+
} catch (error) {
|
|
431
|
+
const errorMsg = error instanceof Error ? error.message : "Unknown error";
|
|
432
|
+
controller.enqueue(
|
|
433
|
+
encoder.encode(
|
|
434
|
+
`data: ${JSON.stringify({
|
|
435
|
+
type: "tool_error",
|
|
436
|
+
error: errorMsg
|
|
437
|
+
})}
|
|
438
|
+
|
|
439
|
+
`
|
|
440
|
+
)
|
|
441
|
+
);
|
|
442
|
+
} finally {
|
|
443
|
+
if (client) {
|
|
444
|
+
await client.disconnect();
|
|
445
|
+
}
|
|
446
|
+
controller.close();
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
});
|
|
450
|
+
return new Response(readableStream, {
|
|
451
|
+
headers: {
|
|
452
|
+
"Content-Type": "text/event-stream",
|
|
453
|
+
"Cache-Control": "no-cache",
|
|
454
|
+
Connection: "keep-alive"
|
|
455
|
+
}
|
|
456
|
+
});
|
|
457
|
+
} catch (error) {
|
|
458
|
+
const errorMsg = error instanceof Error ? error.message : "Unknown error";
|
|
459
|
+
if (client) {
|
|
460
|
+
try {
|
|
461
|
+
await client.disconnect();
|
|
462
|
+
} catch (cleanupError) {
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
return c.json(
|
|
466
|
+
{
|
|
467
|
+
success: false,
|
|
468
|
+
error: errorMsg
|
|
469
|
+
},
|
|
470
|
+
500
|
|
471
|
+
);
|
|
472
|
+
}
|
|
473
|
+
});
|
|
474
|
+
var tools_default = tools;
|
|
475
|
+
|
|
476
|
+
// routes/mcp/resources.ts
|
|
477
|
+
import { Hono as Hono3 } from "hono";
|
|
478
|
+
var resources = new Hono3();
|
|
479
|
+
resources.post("/list", async (c) => {
|
|
480
|
+
try {
|
|
481
|
+
const { serverConfig } = await c.req.json();
|
|
482
|
+
const validation = validateServerConfig(serverConfig);
|
|
483
|
+
if (!validation.success) {
|
|
484
|
+
return c.json(
|
|
485
|
+
{ success: false, error: validation.error.message },
|
|
486
|
+
validation.error.status
|
|
487
|
+
);
|
|
488
|
+
}
|
|
489
|
+
const client = createMCPClient(
|
|
490
|
+
validation.config,
|
|
491
|
+
`resources-list-${Date.now()}`
|
|
492
|
+
);
|
|
493
|
+
try {
|
|
494
|
+
const resources2 = await client.resources.list();
|
|
495
|
+
await client.disconnect();
|
|
496
|
+
return c.json({ resources: resources2 });
|
|
497
|
+
} catch (error) {
|
|
498
|
+
await client.disconnect();
|
|
499
|
+
throw error;
|
|
500
|
+
}
|
|
501
|
+
} catch (error) {
|
|
502
|
+
console.error("Error fetching resources:", error);
|
|
503
|
+
return c.json(
|
|
504
|
+
{
|
|
505
|
+
success: false,
|
|
506
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
507
|
+
},
|
|
508
|
+
500
|
|
509
|
+
);
|
|
510
|
+
}
|
|
511
|
+
});
|
|
512
|
+
resources.post("/read", async (c) => {
|
|
513
|
+
try {
|
|
514
|
+
const { serverConfig, uri } = await c.req.json();
|
|
515
|
+
const validation = validateServerConfig(serverConfig);
|
|
516
|
+
if (!validation.success) {
|
|
517
|
+
return c.json(
|
|
518
|
+
{ success: false, error: validation.error.message },
|
|
519
|
+
validation.error.status
|
|
520
|
+
);
|
|
521
|
+
}
|
|
522
|
+
if (!uri) {
|
|
523
|
+
return c.json(
|
|
524
|
+
{
|
|
525
|
+
success: false,
|
|
526
|
+
error: "Resource URI is required"
|
|
527
|
+
},
|
|
528
|
+
400
|
|
529
|
+
);
|
|
530
|
+
}
|
|
531
|
+
const client = createMCPClient(
|
|
532
|
+
validation.config,
|
|
533
|
+
`resources-read-${Date.now()}`
|
|
534
|
+
);
|
|
535
|
+
try {
|
|
536
|
+
const content = await client.resources.read("server", uri);
|
|
537
|
+
await client.disconnect();
|
|
538
|
+
return c.json({ content });
|
|
539
|
+
} catch (error) {
|
|
540
|
+
await client.disconnect();
|
|
541
|
+
throw error;
|
|
542
|
+
}
|
|
543
|
+
} catch (error) {
|
|
544
|
+
console.error("Error reading resource:", error);
|
|
545
|
+
return c.json(
|
|
546
|
+
{
|
|
547
|
+
success: false,
|
|
548
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
549
|
+
},
|
|
550
|
+
500
|
|
551
|
+
);
|
|
552
|
+
}
|
|
553
|
+
});
|
|
554
|
+
var resources_default = resources;
|
|
555
|
+
|
|
556
|
+
// routes/mcp/prompts.ts
|
|
557
|
+
import { Hono as Hono4 } from "hono";
|
|
558
|
+
var prompts = new Hono4();
|
|
559
|
+
prompts.post("/list", async (c) => {
|
|
560
|
+
try {
|
|
561
|
+
const { serverConfig } = await c.req.json();
|
|
562
|
+
const validation = validateServerConfig(serverConfig);
|
|
563
|
+
if (!validation.success) {
|
|
564
|
+
return c.json(
|
|
565
|
+
{ success: false, error: validation.error.message },
|
|
566
|
+
validation.error.status
|
|
567
|
+
);
|
|
568
|
+
}
|
|
569
|
+
const client = createMCPClient(
|
|
570
|
+
validation.config,
|
|
571
|
+
`prompts-list-${Date.now()}`
|
|
572
|
+
);
|
|
573
|
+
try {
|
|
574
|
+
const prompts2 = await client.prompts.list();
|
|
575
|
+
await client.disconnect();
|
|
576
|
+
return c.json({ prompts: prompts2 });
|
|
577
|
+
} catch (error) {
|
|
578
|
+
await client.disconnect();
|
|
579
|
+
throw error;
|
|
580
|
+
}
|
|
581
|
+
} catch (error) {
|
|
582
|
+
console.error("Error fetching prompts:", error);
|
|
583
|
+
return c.json(
|
|
584
|
+
{
|
|
585
|
+
success: false,
|
|
586
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
587
|
+
},
|
|
588
|
+
500
|
|
589
|
+
);
|
|
590
|
+
}
|
|
591
|
+
});
|
|
592
|
+
prompts.post("/get", async (c) => {
|
|
593
|
+
try {
|
|
594
|
+
const { serverConfig, name, args } = await c.req.json();
|
|
595
|
+
const validation = validateServerConfig(serverConfig);
|
|
596
|
+
if (!validation.success) {
|
|
597
|
+
return c.json(
|
|
598
|
+
{ success: false, error: validation.error.message },
|
|
599
|
+
validation.error.status
|
|
600
|
+
);
|
|
601
|
+
}
|
|
602
|
+
if (!name) {
|
|
603
|
+
return c.json(
|
|
604
|
+
{
|
|
605
|
+
success: false,
|
|
606
|
+
error: "Prompt name is required"
|
|
607
|
+
},
|
|
608
|
+
400
|
|
609
|
+
);
|
|
610
|
+
}
|
|
611
|
+
const client = createMCPClient(
|
|
612
|
+
validation.config,
|
|
613
|
+
`prompts-get-${Date.now()}`
|
|
614
|
+
);
|
|
615
|
+
try {
|
|
616
|
+
const content = await client.prompts.get({
|
|
617
|
+
serverName: "server",
|
|
618
|
+
name,
|
|
619
|
+
args: args || {}
|
|
620
|
+
});
|
|
621
|
+
await client.disconnect();
|
|
622
|
+
return c.json({ content });
|
|
623
|
+
} catch (error) {
|
|
624
|
+
await client.disconnect();
|
|
625
|
+
throw error;
|
|
626
|
+
}
|
|
627
|
+
} catch (error) {
|
|
628
|
+
console.error("Error getting prompt:", error);
|
|
629
|
+
return c.json(
|
|
630
|
+
{
|
|
631
|
+
success: false,
|
|
632
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
633
|
+
},
|
|
634
|
+
500
|
|
635
|
+
);
|
|
636
|
+
}
|
|
637
|
+
});
|
|
638
|
+
var prompts_default = prompts;
|
|
639
|
+
|
|
640
|
+
// routes/mcp/chat.ts
|
|
641
|
+
import { Hono as Hono5 } from "hono";
|
|
642
|
+
import { Agent } from "@mastra/core/agent";
|
|
643
|
+
import { createAnthropic } from "@ai-sdk/anthropic";
|
|
644
|
+
import { createOpenAI } from "@ai-sdk/openai";
|
|
645
|
+
import { createOllama } from "ollama-ai-provider";
|
|
646
|
+
import { MCPClient as MCPClient2 } from "@mastra/mcp";
|
|
647
|
+
var chat = new Hono5();
|
|
648
|
+
var pendingElicitations2 = /* @__PURE__ */ new Map();
|
|
649
|
+
chat.post("/", async (c) => {
|
|
650
|
+
let client = null;
|
|
651
|
+
try {
|
|
652
|
+
const requestData = await c.req.json();
|
|
653
|
+
const {
|
|
654
|
+
serverConfigs,
|
|
655
|
+
model,
|
|
656
|
+
apiKey,
|
|
657
|
+
systemPrompt,
|
|
658
|
+
messages,
|
|
659
|
+
ollamaBaseUrl,
|
|
660
|
+
action,
|
|
661
|
+
requestId,
|
|
662
|
+
response
|
|
663
|
+
} = requestData;
|
|
664
|
+
if (action === "elicitation_response") {
|
|
665
|
+
if (!requestId) {
|
|
666
|
+
return c.json(
|
|
667
|
+
{
|
|
668
|
+
success: false,
|
|
669
|
+
error: "requestId is required for elicitation_response action"
|
|
670
|
+
},
|
|
671
|
+
400
|
|
672
|
+
);
|
|
673
|
+
}
|
|
674
|
+
const pending = pendingElicitations2.get(requestId);
|
|
675
|
+
if (!pending) {
|
|
676
|
+
return c.json(
|
|
677
|
+
{
|
|
678
|
+
success: false,
|
|
679
|
+
error: "No pending elicitation found for this requestId"
|
|
680
|
+
},
|
|
681
|
+
404
|
|
682
|
+
);
|
|
683
|
+
}
|
|
684
|
+
pending.resolve(response);
|
|
685
|
+
pendingElicitations2.delete(requestId);
|
|
686
|
+
return c.json({ success: true });
|
|
687
|
+
}
|
|
688
|
+
if (!model || !model.id || !apiKey || !messages) {
|
|
689
|
+
return c.json(
|
|
690
|
+
{
|
|
691
|
+
success: false,
|
|
692
|
+
error: "model (with id), apiKey, and messages are required"
|
|
693
|
+
},
|
|
694
|
+
400
|
|
695
|
+
);
|
|
696
|
+
}
|
|
697
|
+
if (serverConfigs && Object.keys(serverConfigs).length > 0) {
|
|
698
|
+
const validation = validateMultipleServerConfigs(serverConfigs);
|
|
699
|
+
if (!validation.success) {
|
|
700
|
+
return c.json(
|
|
701
|
+
{
|
|
702
|
+
success: false,
|
|
703
|
+
error: validation.error.message,
|
|
704
|
+
details: validation.errors
|
|
705
|
+
},
|
|
706
|
+
validation.error.status
|
|
707
|
+
);
|
|
708
|
+
}
|
|
709
|
+
client = createMCPClientWithMultipleConnections(validation.validConfigs);
|
|
710
|
+
} else {
|
|
711
|
+
client = new MCPClient2({
|
|
712
|
+
id: `chat-${Date.now()}`,
|
|
713
|
+
servers: {}
|
|
714
|
+
});
|
|
715
|
+
}
|
|
716
|
+
const tools2 = await client.getTools();
|
|
717
|
+
const llmModel = getLlmModel(model, apiKey, ollamaBaseUrl);
|
|
718
|
+
let toolCallId = 0;
|
|
719
|
+
let streamController = null;
|
|
720
|
+
let encoder = null;
|
|
721
|
+
const elicitationHandler = async (elicitationRequest) => {
|
|
722
|
+
const requestId2 = `elicit_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
|
|
723
|
+
if (streamController && encoder) {
|
|
724
|
+
streamController.enqueue(
|
|
725
|
+
encoder.encode(
|
|
726
|
+
`data: ${JSON.stringify({
|
|
727
|
+
type: "elicitation_request",
|
|
728
|
+
requestId: requestId2,
|
|
729
|
+
message: elicitationRequest.message,
|
|
730
|
+
schema: elicitationRequest.requestedSchema,
|
|
731
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
732
|
+
})}
|
|
733
|
+
|
|
734
|
+
`
|
|
735
|
+
)
|
|
736
|
+
);
|
|
737
|
+
}
|
|
738
|
+
return new Promise((resolve, reject) => {
|
|
739
|
+
pendingElicitations2.set(requestId2, { resolve, reject });
|
|
740
|
+
setTimeout(() => {
|
|
741
|
+
if (pendingElicitations2.has(requestId2)) {
|
|
742
|
+
pendingElicitations2.delete(requestId2);
|
|
743
|
+
reject(new Error("Elicitation timeout"));
|
|
744
|
+
}
|
|
745
|
+
}, 3e5);
|
|
746
|
+
});
|
|
747
|
+
};
|
|
748
|
+
if (client.elicitation && client.elicitation.onRequest && serverConfigs) {
|
|
749
|
+
for (const serverName of Object.keys(serverConfigs)) {
|
|
750
|
+
const normalizedName = serverName.toLowerCase().replace(/[\s\-]+/g, "_").replace(/[^a-z0-9_]/g, "");
|
|
751
|
+
client.elicitation.onRequest(normalizedName, elicitationHandler);
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
const originalTools = tools2 && Object.keys(tools2).length > 0 ? tools2 : {};
|
|
755
|
+
const wrappedTools = {};
|
|
756
|
+
for (const [name, tool] of Object.entries(originalTools)) {
|
|
757
|
+
wrappedTools[name] = {
|
|
758
|
+
...tool,
|
|
759
|
+
execute: async (params) => {
|
|
760
|
+
const currentToolCallId = ++toolCallId;
|
|
761
|
+
if (streamController && encoder) {
|
|
762
|
+
streamController.enqueue(
|
|
763
|
+
encoder.encode(
|
|
764
|
+
`data: ${JSON.stringify({
|
|
765
|
+
type: "tool_call",
|
|
766
|
+
toolCall: {
|
|
767
|
+
id: currentToolCallId,
|
|
768
|
+
name,
|
|
769
|
+
parameters: params,
|
|
770
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
771
|
+
status: "executing"
|
|
772
|
+
}
|
|
773
|
+
})}
|
|
774
|
+
|
|
775
|
+
`
|
|
776
|
+
)
|
|
777
|
+
);
|
|
778
|
+
}
|
|
779
|
+
try {
|
|
780
|
+
const result = await tool.execute(params);
|
|
781
|
+
if (streamController && encoder) {
|
|
782
|
+
streamController.enqueue(
|
|
783
|
+
encoder.encode(
|
|
784
|
+
`data: ${JSON.stringify({
|
|
785
|
+
type: "tool_result",
|
|
786
|
+
toolResult: {
|
|
787
|
+
id: currentToolCallId,
|
|
788
|
+
toolCallId: currentToolCallId,
|
|
789
|
+
result,
|
|
790
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
791
|
+
}
|
|
792
|
+
})}
|
|
793
|
+
|
|
794
|
+
`
|
|
795
|
+
)
|
|
796
|
+
);
|
|
797
|
+
}
|
|
798
|
+
return result;
|
|
799
|
+
} catch (error) {
|
|
800
|
+
if (streamController && encoder) {
|
|
801
|
+
streamController.enqueue(
|
|
802
|
+
encoder.encode(
|
|
803
|
+
`data: ${JSON.stringify({
|
|
804
|
+
type: "tool_result",
|
|
805
|
+
toolResult: {
|
|
806
|
+
id: currentToolCallId,
|
|
807
|
+
toolCallId: currentToolCallId,
|
|
808
|
+
error: error instanceof Error ? error.message : String(error),
|
|
809
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
810
|
+
}
|
|
811
|
+
})}
|
|
812
|
+
|
|
813
|
+
`
|
|
814
|
+
)
|
|
815
|
+
);
|
|
816
|
+
}
|
|
817
|
+
throw error;
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
};
|
|
821
|
+
}
|
|
822
|
+
const agent = new Agent({
|
|
823
|
+
name: "MCP Chat Agent",
|
|
824
|
+
instructions: systemPrompt || "You are a helpful assistant with access to MCP tools.",
|
|
825
|
+
model: llmModel,
|
|
826
|
+
tools: Object.keys(wrappedTools).length > 0 ? wrappedTools : void 0
|
|
827
|
+
});
|
|
828
|
+
const formattedMessages = messages.map((msg) => ({
|
|
829
|
+
role: msg.role,
|
|
830
|
+
content: msg.content
|
|
831
|
+
}));
|
|
832
|
+
const stream = await agent.stream(formattedMessages, {
|
|
833
|
+
maxSteps: 10
|
|
834
|
+
// Allow up to 10 steps for tool usage
|
|
835
|
+
});
|
|
836
|
+
encoder = new TextEncoder();
|
|
837
|
+
const readableStream = new ReadableStream({
|
|
838
|
+
async start(controller) {
|
|
839
|
+
streamController = controller;
|
|
840
|
+
try {
|
|
841
|
+
let hasContent = false;
|
|
842
|
+
for await (const chunk of stream.textStream) {
|
|
843
|
+
if (chunk && chunk.trim()) {
|
|
844
|
+
hasContent = true;
|
|
845
|
+
controller.enqueue(
|
|
846
|
+
encoder.encode(
|
|
847
|
+
`data: ${JSON.stringify({ type: "text", content: chunk })}
|
|
848
|
+
|
|
849
|
+
`
|
|
850
|
+
)
|
|
851
|
+
);
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
if (!hasContent) {
|
|
855
|
+
controller.enqueue(
|
|
856
|
+
encoder.encode(
|
|
857
|
+
`data: ${JSON.stringify({ type: "text", content: "I apologize, but I couldn't generate a response. Please try again." })}
|
|
858
|
+
|
|
859
|
+
`
|
|
860
|
+
)
|
|
861
|
+
);
|
|
862
|
+
}
|
|
863
|
+
controller.enqueue(
|
|
864
|
+
encoder.encode(
|
|
865
|
+
`data: ${JSON.stringify({
|
|
866
|
+
type: "elicitation_complete"
|
|
867
|
+
})}
|
|
868
|
+
|
|
869
|
+
`
|
|
870
|
+
)
|
|
871
|
+
);
|
|
872
|
+
controller.enqueue(encoder.encode(`data: [DONE]
|
|
873
|
+
|
|
874
|
+
`));
|
|
875
|
+
} catch (error) {
|
|
876
|
+
console.error("Streaming error:", error);
|
|
877
|
+
controller.enqueue(
|
|
878
|
+
encoder.encode(
|
|
879
|
+
`data: ${JSON.stringify({
|
|
880
|
+
type: "error",
|
|
881
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
882
|
+
})}
|
|
883
|
+
|
|
884
|
+
`
|
|
885
|
+
)
|
|
886
|
+
);
|
|
887
|
+
} finally {
|
|
888
|
+
if (client) {
|
|
889
|
+
try {
|
|
890
|
+
await client.disconnect();
|
|
891
|
+
} catch (cleanupError) {
|
|
892
|
+
console.warn(
|
|
893
|
+
"Error cleaning up MCP client after streaming:",
|
|
894
|
+
cleanupError
|
|
895
|
+
);
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
controller.close();
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
});
|
|
902
|
+
return new Response(readableStream, {
|
|
903
|
+
headers: {
|
|
904
|
+
"Content-Type": "text/event-stream",
|
|
905
|
+
"Cache-Control": "no-cache",
|
|
906
|
+
Connection: "keep-alive"
|
|
907
|
+
}
|
|
908
|
+
});
|
|
909
|
+
} catch (error) {
|
|
910
|
+
console.error("Error in chat API:", error);
|
|
911
|
+
if (client) {
|
|
912
|
+
try {
|
|
913
|
+
await client.disconnect();
|
|
914
|
+
} catch (cleanupError) {
|
|
915
|
+
console.warn("Error cleaning up MCP client after error:", cleanupError);
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
return c.json(
|
|
919
|
+
{
|
|
920
|
+
success: false,
|
|
921
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
922
|
+
},
|
|
923
|
+
500
|
|
924
|
+
);
|
|
925
|
+
}
|
|
926
|
+
});
|
|
927
|
+
var getLlmModel = (modelDefinition, apiKey, ollamaBaseUrl) => {
|
|
928
|
+
if (!modelDefinition || !modelDefinition.id || !modelDefinition.provider) {
|
|
929
|
+
throw new Error(
|
|
930
|
+
`Invalid model definition: ${JSON.stringify(modelDefinition)}`
|
|
931
|
+
);
|
|
932
|
+
}
|
|
933
|
+
switch (modelDefinition.provider) {
|
|
934
|
+
case "anthropic":
|
|
935
|
+
return createAnthropic({ apiKey })(modelDefinition.id);
|
|
936
|
+
case "openai":
|
|
937
|
+
return createOpenAI({ apiKey })(modelDefinition.id);
|
|
938
|
+
case "ollama":
|
|
939
|
+
const baseUrl = ollamaBaseUrl || "http://localhost:11434";
|
|
940
|
+
return createOllama({
|
|
941
|
+
baseURL: `${baseUrl}/api`
|
|
942
|
+
// Configurable Ollama API endpoint
|
|
943
|
+
})(modelDefinition.id, {
|
|
944
|
+
simulateStreaming: true
|
|
945
|
+
// Enable streaming for Ollama models
|
|
946
|
+
});
|
|
947
|
+
default:
|
|
948
|
+
throw new Error(
|
|
949
|
+
`Unsupported provider: ${modelDefinition.provider} for model: ${modelDefinition.id}`
|
|
950
|
+
);
|
|
951
|
+
}
|
|
952
|
+
};
|
|
953
|
+
var chat_default = chat;
|
|
954
|
+
|
|
955
|
+
// routes/mcp/oauth.ts
|
|
956
|
+
import { Hono as Hono6 } from "hono";
|
|
957
|
+
var oauth = new Hono6();
|
|
958
|
+
oauth.get("/metadata", async (c) => {
|
|
959
|
+
try {
|
|
960
|
+
const url = c.req.query("url");
|
|
961
|
+
if (!url) {
|
|
962
|
+
return c.json({ error: "Missing url parameter" }, 400);
|
|
963
|
+
}
|
|
964
|
+
let metadataUrl;
|
|
965
|
+
try {
|
|
966
|
+
metadataUrl = new URL(url);
|
|
967
|
+
if (metadataUrl.protocol !== "https:") {
|
|
968
|
+
return c.json({ error: "Only HTTPS URLs are allowed" }, 400);
|
|
969
|
+
}
|
|
970
|
+
} catch (error) {
|
|
971
|
+
return c.json({ error: "Invalid URL format" }, 400);
|
|
972
|
+
}
|
|
973
|
+
const response = await fetch(metadataUrl.toString(), {
|
|
974
|
+
method: "GET",
|
|
975
|
+
headers: {
|
|
976
|
+
Accept: "application/json",
|
|
977
|
+
"User-Agent": "MCP-Inspector/1.0"
|
|
978
|
+
}
|
|
979
|
+
});
|
|
980
|
+
if (!response.ok) {
|
|
981
|
+
return c.json(
|
|
982
|
+
{
|
|
983
|
+
error: `Failed to fetch OAuth metadata: ${response.status} ${response.statusText}`
|
|
984
|
+
},
|
|
985
|
+
response.status
|
|
986
|
+
);
|
|
987
|
+
}
|
|
988
|
+
const metadata = await response.json();
|
|
989
|
+
return c.json(metadata);
|
|
990
|
+
} catch (error) {
|
|
991
|
+
console.error("OAuth metadata proxy error:", error);
|
|
992
|
+
return c.json(
|
|
993
|
+
{
|
|
994
|
+
error: error instanceof Error ? error.message : "Unknown error occurred"
|
|
995
|
+
},
|
|
996
|
+
500
|
|
997
|
+
);
|
|
998
|
+
}
|
|
999
|
+
});
|
|
1000
|
+
var oauth_default = oauth;
|
|
1001
|
+
|
|
1002
|
+
// routes/mcp/index.ts
|
|
1003
|
+
var mcp = new Hono7();
|
|
1004
|
+
mcp.get("/health", (c) => {
|
|
1005
|
+
return c.json({
|
|
1006
|
+
service: "MCP API",
|
|
1007
|
+
status: "ready",
|
|
1008
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1009
|
+
});
|
|
1010
|
+
});
|
|
1011
|
+
mcp.route("/chat", chat_default);
|
|
1012
|
+
mcp.route("/connect", connect_default);
|
|
1013
|
+
mcp.route("/tools", tools_default);
|
|
1014
|
+
mcp.route("/resources", resources_default);
|
|
1015
|
+
mcp.route("/prompts", prompts_default);
|
|
1016
|
+
mcp.route("/oauth", oauth_default);
|
|
1017
|
+
var mcp_default = mcp;
|
|
1018
|
+
|
|
1019
|
+
// index.ts
|
|
1020
|
+
function logBox(content, title) {
|
|
1021
|
+
const lines = content.split("\n");
|
|
1022
|
+
const maxLength = Math.max(...lines.map((line) => line.length));
|
|
1023
|
+
const width = maxLength + 4;
|
|
1024
|
+
console.log("\u250C" + "\u2500".repeat(width) + "\u2510");
|
|
1025
|
+
if (title) {
|
|
1026
|
+
const titlePadding = Math.floor((width - title.length - 2) / 2);
|
|
1027
|
+
console.log(
|
|
1028
|
+
"\u2502" + " ".repeat(titlePadding) + title + " ".repeat(width - title.length - titlePadding) + "\u2502"
|
|
1029
|
+
);
|
|
1030
|
+
console.log("\u251C" + "\u2500".repeat(width) + "\u2524");
|
|
1031
|
+
}
|
|
1032
|
+
lines.forEach((line) => {
|
|
1033
|
+
const padding = width - line.length - 2;
|
|
1034
|
+
console.log("\u2502 " + line + " ".repeat(padding) + " \u2502");
|
|
1035
|
+
});
|
|
1036
|
+
console.log("\u2514" + "\u2500".repeat(width) + "\u2518");
|
|
1037
|
+
}
|
|
1038
|
+
var app = new Hono8();
|
|
1039
|
+
app.use("*", logger());
|
|
1040
|
+
var serverPort = process.env.PORT || "3001";
|
|
1041
|
+
var corsOrigins = [
|
|
1042
|
+
`http://localhost:${serverPort}`,
|
|
1043
|
+
"http://localhost:3000",
|
|
1044
|
+
// Keep for development
|
|
1045
|
+
"http://localhost:3001"
|
|
1046
|
+
// Keep for development
|
|
1047
|
+
];
|
|
1048
|
+
app.use(
|
|
1049
|
+
"*",
|
|
1050
|
+
cors({
|
|
1051
|
+
origin: corsOrigins,
|
|
1052
|
+
credentials: true
|
|
1053
|
+
})
|
|
1054
|
+
);
|
|
1055
|
+
app.route("/api/mcp", mcp_default);
|
|
1056
|
+
app.get("/health", (c) => {
|
|
1057
|
+
return c.json({ status: "ok", timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
1058
|
+
});
|
|
1059
|
+
if (process.env.NODE_ENV === "production") {
|
|
1060
|
+
app.use("/*", serveStatic({ root: "./dist/client" }));
|
|
1061
|
+
app.get("*", async (c) => {
|
|
1062
|
+
const path = c.req.path;
|
|
1063
|
+
if (path.startsWith("/api/")) {
|
|
1064
|
+
return c.notFound();
|
|
1065
|
+
}
|
|
1066
|
+
const indexPath = join(process.cwd(), "dist", "client", "index.html");
|
|
1067
|
+
const htmlContent = readFileSync(indexPath, "utf-8");
|
|
1068
|
+
return c.html(htmlContent);
|
|
1069
|
+
});
|
|
1070
|
+
} else {
|
|
1071
|
+
app.get("/", (c) => {
|
|
1072
|
+
return c.json({
|
|
1073
|
+
message: "MCP Inspector API Server",
|
|
1074
|
+
environment: "development",
|
|
1075
|
+
frontend: `http://localhost:${serverPort}`
|
|
1076
|
+
});
|
|
1077
|
+
});
|
|
1078
|
+
}
|
|
1079
|
+
var port = parseInt(process.env.PORT || "3001");
|
|
1080
|
+
logBox(`http://localhost:${port}`, "\u{1F680} Inspector Launched");
|
|
1081
|
+
var server = serve({
|
|
1082
|
+
fetch: app.fetch,
|
|
1083
|
+
port,
|
|
1084
|
+
hostname: "0.0.0.0"
|
|
1085
|
+
// Bind to all interfaces for Docker
|
|
1086
|
+
});
|
|
1087
|
+
process.on("SIGINT", () => {
|
|
1088
|
+
console.log("\n\u{1F6D1} Shutting down gracefully...");
|
|
1089
|
+
server.close();
|
|
1090
|
+
process.exit(0);
|
|
1091
|
+
});
|
|
1092
|
+
process.on("SIGTERM", () => {
|
|
1093
|
+
console.log("\n\u{1F6D1} Shutting down gracefully...");
|
|
1094
|
+
server.close();
|
|
1095
|
+
process.exit(0);
|
|
1096
|
+
});
|
|
1097
|
+
var index_default = app;
|
|
1098
|
+
export {
|
|
1099
|
+
index_default as default
|
|
1100
|
+
};
|
|
1101
|
+
//# sourceMappingURL=index.js.map
|