Skip to main content
Glama

DeepSearch 通用检索

deepsearch

Execute web searches using the DeepSearch model to retrieve structured results, balancing search quality against processing time for comprehensive information retrieval.

Instructions

使用 DeepSearch 模型执行广域检索并返回结构化结果,拥有比AI Agent内置搜索更好的搜索效果但更耗时,需要平衡需求

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
queryYes
top_kNo
localeNo
filtersNo

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
itemsYes
usageYes
metadataYes

Implementation Reference

  • main.ts:78-99 (handler)
    The handler function for the 'deepsearch' MCP tool. It receives args, logs, invokes DeepSearchAgent.search(), validates the result with searchResultSchema.parse(), logs the item count, and returns formatted content and structured result.
    async (args) => {
      const toolLogger = logger.child({ tool: "deepsearch" });
      toolLogger.info("收到工具调用", args);
      const result = await deepsearchAgent.search(args.query, {
        top_k: args.top_k,
        locale: args.locale,
        filters: args.filters,
      });
    
      const structured = searchResultSchema.parse(result);
      toolLogger.info("完成工具调用", { itemCount: structured.items.length });
    
      return {
        content: [
          {
            type: "text" as const,
            text: JSON.stringify(structured, null, 2),
          },
        ],
        structuredContent: structured,
      };
    },
  • main.ts:10-44 (schema)
    Zod schema definitions for 'deepsearch' tool input (deepSearchInputShape), output (searchResultShape via searchItemShape), and compiled schemas. Note: deepSearchWebInputShape is for the related web tool.
    const searchItemShape = {
      title: z.string(),
      snippet: z.string(),
      url: z.string(),
      score: z.number().nullable(),
    };
    
    const searchResultShape = {
      items: z.array(z.object(searchItemShape)),
      metadata: z.record(z.any()),
      usage: z.object({
        input_tokens: z.number(),
        output_tokens: z.number(),
      }),
    };
    
    const deepSearchInputShape = {
      query: z.string().min(1, "query 不能为空"),
      top_k: z.number().int().min(1).max(10).optional(),
      locale: z.string().optional(),
      filters: z.record(z.any()).default({}),
    };
    
    const deepSearchWebInputShape = {
      ...deepSearchInputShape,
      filters: z
        .record(z.any())
        .refine((filters) => typeof filters.site === "string" || typeof filters.time_range === "string", {
          message: "filters 需要包含 site 或 time_range 字段",
        }),
    };
    
    const deepSearchInputSchema = z.object(deepSearchInputShape);
    const deepSearchWebInputSchema = z.object(deepSearchWebInputShape);
    const searchResultSchema = z.object(searchResultShape);
  • main.ts:70-100 (registration)
    Registration of the 'deepsearch' tool on the McpServer instance, specifying title, description, input/output schemas, and the handler function.
    server.registerTool(
      "deepsearch",
      {
        title: "DeepSearch 通用检索",
        description: "使用 DeepSearch 模型执行广域检索并返回结构化结果,拥有比AI Agent内置搜索更好的搜索效果但更耗时,需要平衡需求",
        inputSchema: deepSearchInputShape,
        outputSchema: searchResultShape,
      },
      async (args) => {
        const toolLogger = logger.child({ tool: "deepsearch" });
        toolLogger.info("收到工具调用", args);
        const result = await deepsearchAgent.search(args.query, {
          top_k: args.top_k,
          locale: args.locale,
          filters: args.filters,
        });
    
        const structured = searchResultSchema.parse(result);
        toolLogger.info("完成工具调用", { itemCount: structured.items.length });
    
        return {
          content: [
            {
              type: "text" as const,
              text: JSON.stringify(structured, null, 2),
            },
          ],
          structuredContent: structured,
        };
      },
    );
  • Helper class DeepSearchAgent that initializes a DeepSearchMCPClient with toolName 'deepsearch' and provides search method delegated to the client. Used by the MCP handler.
    export class DeepSearchAgent {
      private readonly client: DeepSearchMCPClient;
      private readonly transport?: DeepSearchTransport;
      private readonly logger: Logger;
    
      constructor(options: AgentOptions = {}) {
        const agentLogger = logger.child({ agent: "deepsearch" });
        agentLogger.debug("初始化 DeepSearchAgent", { providedClient: Boolean(options.client) });
    
        if (options.client) {
          this.client = options.client;
          this.transport = options.transport;
        } else {
          const transport = options.transport ?? DeepSearchTransport.fromEnv();
          this.client = new DeepSearchMCPClient(transport, { toolName: "deepsearch" });
          this.transport = transport;
        }
        this.logger = agentLogger;
      }
    
      search(query: string, options: SearchOptions = {}): Promise<SearchResult> {
        this.logger.info("执行检索", { query, options });
        return this.client.search(query, options);
      }
    
      close(): void {
        this.logger.debug("关闭代理");
        this.transport?.close();
      }
    }
  • Core helper DeepSearchTransport.fromEnv() that implements invokeTool by making HTTP requests to external DeepSearch API (Gemini with googleSearch tool), building specific prompts for 'deepsearch', parsing JSON responses into SearchResult format.
    export class DeepSearchTransport {
      private readonly config: DeepSearchConfig;
      private readonly endpoint: URL;
      private readonly logger = logger.child({ module: "DeepSearchTransport" });
    
      constructor(options: DeepSearchTransportOptions | DeepSearchConfig) {
        this.config = options instanceof DeepSearchConfig ? options : new DeepSearchConfig(options);
        this.endpoint = new URL("/v1beta/models/gemini-2.5-flash:generateContent", this.config.baseUrl);
        this.endpoint.searchParams.set("key", this.config.apiKey);
      }
    
      static fromEnv(): DeepSearchTransport {
        return new DeepSearchTransport(DeepSearchConfig.fromEnv());
      }
    
      async invokeTool(toolName: string, payload: InvokePayload): Promise<DeepSearchResponsePayload> {
        const body = this.buildRequest(toolName, payload);
        this.logger.info("调用 DeepSearch API", {
          toolName,
          endpoint: this.endpoint.toString(),
          timeoutMs: this.config.timeoutMs,
        });
    
        const controller = new AbortController();
        const timeout = setTimeout(() => controller.abort(), this.config.timeoutMs);
    
        try {
          const response = await fetch(this.endpoint, {
            method: "POST",
            headers: {
              "Content-Type": "application/json",
              "Accept": "application/json",
            },
            body: JSON.stringify(body),
            signal: controller.signal,
          });
    
          if (!response.ok) {
            const message = `DeepSearch API 返回错误状态: ${response.status}`;
            this.logger.warn(message, { responseHeaders: Object.fromEntries(response.headers.entries()) });
            throw new DeepSearchAPIError(message);
          }
    
          const data = (await response.json()) as Record<string, unknown>;
          this.logger.debug("收到 DeepSearch API 响应", data);
          return this.parseResponse(data);
        } catch (error) {
          if (error instanceof DeepSearchAPIError) {
            this.logger.error("DeepSearch API 调用失败", error);
            throw error;
          }
    
          if ((error as Error).name === "AbortError") {
            const timeoutError = new DeepSearchAPIError("DeepSearch API 请求超时", { cause: error as Error });
            this.logger.error("DeepSearch API 请求超时", timeoutError);
            throw timeoutError;
          }
    
          const wrapped = new DeepSearchAPIError(`DeepSearch API 请求失败: ${(error as Error).message}`, {
            cause: error as Error,
          });
          this.logger.error("DeepSearch API 调用过程中发生异常", wrapped);
          throw wrapped;
        } finally {
          clearTimeout(timeout);
        }
      }
    
      private buildRequest(toolName: string, payload: InvokePayload): Record<string, unknown> {
        const prompt = this.buildUserPrompt(toolName, payload);
        return {
          contents: [
            {
              role: "user",
              parts: [{ text: prompt }],
            },
          ],
          tools: [{ googleSearch: {} }],
        };
      }
    
      private parseResponse(data: Record<string, unknown>): DeepSearchResponsePayload {
        const candidates = data?.candidates;
        if (!Array.isArray(candidates) || candidates.length === 0) {
          this.logger.error("DeepSearch API 响应缺少候选项", data);
          throw new DeepSearchAPIError("DeepSearch API 响应缺少有效的消息内容");
        }
    
        const content = extractTextFromCandidate(candidates[0] as Record<string, unknown>);
        if (!content) {
          this.logger.error("DeepSearch API 响应无法提取文本", candidates[0]);
          throw new DeepSearchAPIError("DeepSearch API 响应内容不是合法的 JSON");
        }
    
        let parsed: Record<string, unknown>;
        try {
          parsed = JSON.parse(sanitizeJsonContent(content));
        } catch (error) {
          this.logger.error("DeepSearch API 响应 JSON 解析失败", { content, error });
          throw new DeepSearchAPIError("DeepSearch API 响应内容不是合法的 JSON", { cause: error as Error });
        }
    
        const itemsRaw = Array.isArray(parsed.items) ? (parsed.items as DeepSearchItem[]) : [];
        const metadata = (parsed.metadata as Record<string, unknown>) ?? {};
        let usage = parsed.usage as DeepSearchUsage | undefined;
    
        if (!usage) {
          const usageMetadata = (data.usageMetadata ?? {}) as Record<string, unknown>;
          usage = {
            input_tokens: Number(usageMetadata.promptTokenCount ?? 0),
            output_tokens: Number(usageMetadata.candidatesTokenCount ?? usageMetadata.cachedContentTokenCount ?? 0),
          };
        }
    
        return {
          items: itemsRaw.map((item) => ({
            title: item.title,
            snippet: item.snippet ?? "",
            url: item.url,
            score: item.score ?? null,
          })),
          metadata,
          usage,
        };
      }
    
      private buildUserPrompt(toolName: string, payload: InvokePayload): string {
        const topK = payload.top_k ?? 5;
        const locale = payload.locale ?? "zh-CN";
        const filters = payload.filters ?? {};
        const filterInstruction =
          toolName === "deepsearch-web"
            ? "必须使用 filters 中的 site/time_range 限制,确保返回结果满足条件。"
            : "可结合 filters 中提供的约束优化检索。";
    
        return [
          "任务: 调用 googleSearch 工具检索并汇总最新的权威信息。",
          `查询: ${payload.query}`,
          `语言: ${locale}`,
          `返回条数: ${topK}`,
          `附加筛选: ${JSON.stringify(filters)}`,
          filterInstruction,
          "输出格式要求: 必须返回合法 JSON,不能包含 Markdown、注释、额外文本或代码块标记。",
          "最终只输出以下结构: {\"items\":[{\"title\":string,\"snippet\":string,\"url\":string,\"score\":number|null}],\"metadata\":{\"source\":string,\"locale\":string,\"top_k\":number,\"filters\":object},\"usage\":{\"input_tokens\":number,\"output_tokens\":number}}。",
          "items 按相关度降序,snippet 使用中文简洁总结,score 为可信度(0-1),无法给出则为 null。",
          "metadata.source 固定为 'google-search',并补充 locale/top_k/filters 信息。",
          "⚠️ 严禁输出任何额外字符(包括 ```、解释文字、列表、粗体等)。",
        ].join("\n");
      }
    
      close(): void {
        // 当前实现使用无状态 HTTP 请求,无需保留连接
      }
    }
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden of behavioral disclosure. It mentions that the tool is '更耗时' (more time-consuming), which is useful behavioral context. However, it lacks details on other critical aspects such as rate limits, authentication requirements, error handling, or what 'structured results' entail (though an output schema exists). For a tool with no annotations, this is insufficient.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise and front-loaded: it starts with the core purpose, followed by key behavioral traits (better effectiveness, more time-consuming). Every sentence earns its place by adding value, with no redundant or vague language. The structure is efficient for quick understanding.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (4 parameters, nested objects, output schema exists), the description is moderately complete. It covers purpose and trade-offs but lacks parameter explanations and detailed behavioral context. The presence of an output schema means the description doesn't need to explain return values, but other gaps remain. It's adequate but with clear omissions.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the schema provides no parameter descriptions. The tool description does not mention any parameters explicitly, failing to compensate for the lack of schema documentation. However, with 4 parameters (query, top_k, locale, filters), the baseline is 3 since the description adds no semantic value beyond what the bare schema provides.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: '使用 DeepSearch 模型执行广域检索并返回结构化结果' (use DeepSearch model to perform wide-area retrieval and return structured results). It specifies the verb (执行广域检索), resource (DeepSearch 模型), and outcome (返回结构化结果). However, it doesn't explicitly differentiate from the sibling tool 'deepsearch-web', which would be needed for a score of 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context for when to use this tool: '拥有比AI Agent内置搜索更好的搜索效果但更耗时,需要平衡需求' (has better search effectiveness than AI Agent's built-in search but is more time-consuming, requiring balancing needs). This gives guidance on trade-offs (effectiveness vs. time) but doesn't explicitly mention when NOT to use it or name specific alternatives beyond the implied built-in search, so it falls short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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/yuemingruoan/DeepSearch-MCP'

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