Skip to main content
Glama

discourse_search

Search content on Discourse forums to find topics, posts, and discussions using specific queries and filters.

Instructions

Search site content.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
queryYesSearch query
with_privateNo
max_resultsNo

Implementation Reference

  • The handler function that executes the discourse_search tool. It queries the Discourse search API with the provided query (optionally prefixed), extracts topics, formats a numbered list of results with URLs, appends a JSON summary, and handles errors.
    async (args, _extra: any) => {
      const { query, with_private = false, max_results = 10 } = args;
      const { base, client } = ctx.siteState.ensureSelectedSite();
      const q = new URLSearchParams();
      q.set("expanded", "true");
      const fullQuery = ctx.defaultSearchPrefix ? `${ctx.defaultSearchPrefix} ${query}` : query;
      q.set("q", fullQuery);
      try {
        const data = (await client.get(`/search.json?${q.toString()}`)) as any;
        const topics: any[] = data?.topics || [];
        const posts: any[] = data?.posts || [];
    
        const items = (topics.map((t) => ({
          type: "topic" as const,
          id: t.id,
          title: t.title,
          slug: t.slug,
        })) as Array<{ type: "topic"; id: number; title: string; slug: string }>).slice(0, max_results);
    
        const lines: string[] = [];
        lines.push(`Top results for "${query}":`);
        let idx = 1;
        for (const it of items) {
          const url = `${base}/t/${it.slug}/${it.id}`;
          lines.push(`${idx}. ${it.title} – ${url}`);
          idx++;
        }
    
        const jsonFooter = {
          results: items.map((it) => ({ id: it.id, url: `${base}/t/${it.slug}/${it.id}`, title: it.title })),
        };
        const text = lines.join("\n") + "\n\n```json\n" + JSON.stringify(jsonFooter) + "\n```\n";
        return { content: [{ type: "text", text }] };
      } catch (e: any) {
        return { content: [{ type: "text", text: `Search failed: ${e?.message || String(e)}` }], isError: true };
      }
    }
  • Zod schema defining the input parameters for the discourse_search tool: query (required string), with_private (optional boolean), max_results (optional int 1-50).
    const schema = z.object({
      query: z.string().min(1).describe("Search query"),
      with_private: z.boolean().optional(),
      max_results: z.number().int().min(1).max(50).optional(),
    });
  • Registration of the discourse_search tool using server.registerTool, including name, metadata (title, description, inputSchema), and the handler function.
    server.registerTool(
      "discourse_search",
      {
        title: "Discourse Search",
        description: "Search site content.",
        inputSchema: schema.shape,
      },
      async (args, _extra: any) => {
        const { query, with_private = false, max_results = 10 } = args;
        const { base, client } = ctx.siteState.ensureSelectedSite();
        const q = new URLSearchParams();
        q.set("expanded", "true");
        const fullQuery = ctx.defaultSearchPrefix ? `${ctx.defaultSearchPrefix} ${query}` : query;
        q.set("q", fullQuery);
        try {
          const data = (await client.get(`/search.json?${q.toString()}`)) as any;
          const topics: any[] = data?.topics || [];
          const posts: any[] = data?.posts || [];
    
          const items = (topics.map((t) => ({
            type: "topic" as const,
            id: t.id,
            title: t.title,
            slug: t.slug,
          })) as Array<{ type: "topic"; id: number; title: string; slug: string }>).slice(0, max_results);
    
          const lines: string[] = [];
          lines.push(`Top results for "${query}":`);
          let idx = 1;
          for (const it of items) {
            const url = `${base}/t/${it.slug}/${it.id}`;
            lines.push(`${idx}. ${it.title} – ${url}`);
            idx++;
          }
    
          const jsonFooter = {
            results: items.map((it) => ({ id: it.id, url: `${base}/t/${it.slug}/${it.id}`, title: it.title })),
          };
          const text = lines.join("\n") + "\n\n```json\n" + JSON.stringify(jsonFooter) + "\n```\n";
          return { content: [{ type: "text", text }] };
        } catch (e: any) {
          return { content: [{ type: "text", text: `Search failed: ${e?.message || String(e)}` }], isError: true };
        }
      }
    );
  • Invocation of registerSearch function within the registerAllTools, which internally registers the discourse_search tool.
    registerSearch(server, ctx, { allowWrites: false });

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/SamSaffron/discourse-mcp'

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