Skip to main content
Glama
by OpaqueGlass
vectorSearch.ts4.57 kB
import { z } from "zod"; import { createErrorResponse, createJsonResponse, createSuccessResponse } from "../utils/mcpResponse"; import { McpToolsProvider } from "./baseToolProvider"; import { debugPush, errorPush, logPush } from "@/logger"; import { useConsumer, useProvider } from "@/utils/indexerHelper"; import { lang } from "@/utils/lang"; export class DocVectorSearchProvider extends McpToolsProvider<any> { async getTools(): Promise<McpTool<any>[]> { const indexProvider = useProvider(); const healthResult = await indexProvider.health(); if (healthResult == null) { logPush("Connection with RAG backend ERROR: (RAG Tool will not be load to MCP server)", healthResult); return []; } const EXPORT_API = async (question)=>{ const provider = useProvider(); return await provider.query(question) }; if (window["OpaqueGlassAPI"]) { window["OpaqueGlassAPI"]["ragQuery"] = EXPORT_API; } else { window["OpaqueGlassAPI"] = { "ragQuery": EXPORT_API } } window["OpaqueGlassAPI"][""] return [{ name: "siyuan_generate_answer_with_doc", description: 'This tool provides a Retrieval-Augmented Generation (RAG) based Q&A capability. It generates context-aware answers using only the notes that the user has explicitly indexed from their siyuan-notes. Please note: the tool does not access or use all documents—only those that have been indexed by the user. ', schema: { question: z.string().describe("Describe question about note here"), }, handler: answerWithRAG, title: lang("tool_title_generate_answer_with_doc"), annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, } }]; } } async function answerWithRAG(params, extra) { const { question } = params; debugPush("API被调用:RAG"); const provider = useProvider(); let progressInterval; let timeoutId; let finished = false; const progressToken = extra?._meta?.progressToken; let currentProgress = 0; const maxDuration = 120 * 1000; // 120秒 const updateInterval = 3000; // 3秒 const progressIncrement = updateInterval / maxDuration; if (progressToken) { progressInterval = setInterval(() => { currentProgress += progressIncrement; if (currentProgress < 0.95) { extra.sendNotification && extra.sendNotification({ method: "notifications/progress", params: { progress: currentProgress, progressToken } }); } }, updateInterval); timeoutId = setTimeout(() => { if (!finished) { finished = true; clearInterval(progressInterval); extra.sendNotification && extra.sendNotification({ method: "notifications/progress", params: { progress: 1, progressToken } }); } }, maxDuration); } try { const resultPromise = provider.query(question); const result = await Promise.race([ resultPromise, new Promise((_, reject) => setTimeout(() => reject(new Error("RAG query timeout (120s)")), maxDuration)) ]); finished = true; if (progressInterval) clearInterval(progressInterval); if (timeoutId) clearTimeout(timeoutId); if (progressToken) { extra.sendNotification && extra.sendNotification({ method: "notifications/progress", params: { progress: 1, progressToken } }); } logPush("RAG result", result); return createJsonResponse(result); } catch (err) { finished = true; if (progressInterval) clearInterval(progressInterval); if (timeoutId) clearTimeout(timeoutId); if (progressToken) { extra.sendNotification && extra.sendNotification({ method: "notifications/progress", params: { progress: 1, progressToken } }); } errorPush("RAG API error", err); return createErrorResponse("The tool call failed. " + (err?.message || "There was a problem with the connection to the RAG service. Please remind the user to troubleshoot the problem.")); } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/OpaqueGlass/syplugin-anMCPServer'

If you have feedback or need assistance with the MCP directory API, please join our Discord server