modality-mcp-kit 1.6.0 → 1.6.1

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.
@@ -226,6 +226,63 @@ function clearStoredOAuthTokens(serverUrl) {
226
226
  return false;
227
227
  }
228
228
  }
229
+ // ============================================
230
+ // TOOL PREFETCH HELPERS
231
+ // ============================================
232
+ function parseToolsFromBody(body) {
233
+ try {
234
+ const parsed = JSON.parse(body);
235
+ if (parsed?.result?.tools)
236
+ return parsed.result.tools;
237
+ }
238
+ catch {
239
+ // Try SSE format
240
+ const lines = body.split("\n");
241
+ for (const line of lines) {
242
+ if (line.startsWith("data: ")) {
243
+ try {
244
+ const parsed = JSON.parse(line.substring(6));
245
+ if (parsed?.result?.tools)
246
+ return parsed.result.tools;
247
+ }
248
+ catch { }
249
+ }
250
+ }
251
+ }
252
+ return null;
253
+ }
254
+ async function prefetchAndCacheTools(mcpName, serverUrl, cache, storedToken) {
255
+ const cacheKey = "tools/list";
256
+ const cached = cache.get(cacheKey);
257
+ if (cached) {
258
+ const dataLine = cached.match(/^data: (.+)$/m)?.[1] ?? cached;
259
+ return { tools: parseToolsFromBody(dataLine), fromCache: true };
260
+ }
261
+ try {
262
+ const headers = {
263
+ "Content-Type": "application/json",
264
+ Accept: "application/json, text/event-stream",
265
+ };
266
+ if (storedToken) {
267
+ headers.authorization = `Bearer ${storedToken}`;
268
+ }
269
+ const response = await fetch(serverUrl, {
270
+ method: "POST",
271
+ headers,
272
+ body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "tools/list", params: {} }),
273
+ });
274
+ const body = await response.text();
275
+ const ttl = METHOD_TTL_MS["tools/list"];
276
+ const cacheValue = body.includes("event:") ? body : `event: message\ndata: ${body}\n\n`;
277
+ cache.set(cacheKey, cacheValue, ttl);
278
+ console.log(`[MCP-PROXY] Prefetched and cached tools/list for ${mcpName}`);
279
+ return { tools: parseToolsFromBody(body), fromCache: false };
280
+ }
281
+ catch (e) {
282
+ console.error(`[MCP-PROXY] Failed to prefetch tools for ${mcpName}:`, e);
283
+ return { tools: null, fromCache: false };
284
+ }
285
+ }
229
286
  /**
230
287
  * Hono handler for MCP proxy
231
288
  * @param c - Hono context with mcpName param
@@ -271,6 +328,22 @@ export const mcpProxyHandler = (MCP_SERVERS, oauthAllowAccess) => async (c) => {
271
328
  : "No cached OAuth state found",
272
329
  });
273
330
  }
331
+ // Handle /_tools sub-route — prefetch and return cached tool list
332
+ if (c.req.path.endsWith("/_tools")) {
333
+ const serverConfig = MCP_SERVERS[mcpName];
334
+ if (!serverConfig) {
335
+ return c.json({ error: "MCP server not found", availableServers: Object.keys(MCP_SERVERS) }, 404);
336
+ }
337
+ const cache = getServerCache(mcpName);
338
+ const storedToken = getStoredOAuthToken(serverConfig.url);
339
+ const { tools, fromCache } = await prefetchAndCacheTools(mcpName, serverConfig.url, cache, storedToken);
340
+ return c.json({
341
+ mcpName,
342
+ fromCache,
343
+ count: tools?.length ?? 0,
344
+ tools: tools ?? [],
345
+ });
346
+ }
274
347
  // Handle /_cache sub-routes (matched via app.use prefix routing)
275
348
  const cachePathMatch = c.req.path.match(/\/_cache(?:\/(.+))?$/);
276
349
  if (cachePathMatch) {
@@ -385,6 +458,7 @@ export const mcpProxyHandler = (MCP_SERVERS, oauthAllowAccess) => async (c) => {
385
458
  endpoints: {
386
459
  sse: `${basePath} (GET, Accept: text/event-stream)`,
387
460
  rpc: `${basePath} (POST)`,
461
+ tools: `${basePath}/_tools`,
388
462
  allow: `${basePath}/_allow`,
389
463
  clearAuth: `${basePath}/_clear-auth`,
390
464
  cache: `${basePath}/_cache`,
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.6.0",
2
+ "version": "1.6.1",
3
3
  "name": "modality-mcp-kit",
4
4
  "repository": {
5
5
  "type": "git",