Skip to main content
Glama

search_repos

Find GitHub repositories by keyword or topic to identify competitors, similar tools, or related projects with activity signals and star rankings.

Instructions

Search GitHub for repositories matching a keyword or topic. Returns top results by stars with activity signals. Use to find competitors, similar tools, or related projects.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
queryYesSearch query e.g. 'mcp server typescript' or 'cashflow prediction python'
max_lengthNo

Implementation Reference

  • src/server.ts:121-130 (registration)
    Registration of the 'search_repos' tool in server.ts.
    server.registerTool(
      "search_repos",
      {
        description:
          "Search GitHub for repositories matching a keyword or topic. Returns top results by stars with activity signals. Use to find competitors, similar tools, or related projects.",
        inputSchema: z.object({
          query: z.string().describe("Search query e.g. 'mcp server typescript' or 'cashflow prediction python'"),
          max_length: z.number().optional().default(6000),
        }),
        annotations: { readOnlyHint: true, openWorldHint: true },
  • The tool handler function in server.ts which calls repoSearchAdapter.
    async ({ query, max_length }) => {
      try {
        const result = await repoSearchAdapter({ url: query, maxLength: max_length });
        const ctx = stampFreshness(result, { url: query, maxLength: max_length }, "github_search");
        return { content: [{ type: "text", text: formatForLLM(ctx) }] };
      } catch (err) {
        return { content: [{ type: "text", text: formatSecurityError(err) }] };
      }
    }
  • The actual implementation of the repoSearch logic.
    export async function repoSearchAdapter(options: ExtractOptions): Promise<AdapterResult> {
      // Sanitize query input
      const query_input = sanitizeQuery(options.url);
      let query = query_input;
    
      // If it's a full URL, extract the query param
      try {
        const parsed = new URL(options.url);
        if (parsed.hostname === "github.com" && parsed.pathname.includes("/search")) {
          query = parsed.searchParams.get("q") ?? options.url;
        } else if (parsed.hostname === "github.com") {
          // It's a direct URL — not a search
          query = parsed.pathname.replace("/search", "").trim().replace(/^\//, "");
        }
      } catch {
        // plain string query, use as-is
      }
    
      const apiUrl = `https://api.github.com/search/repositories?q=${encodeURIComponent(query)}&sort=stars&order=desc&per_page=10`;
    
      const res = await fetch(apiUrl, {
        headers: {
          Accept: "application/vnd.github.v3+json",
          "User-Agent": "freshcontext-mcp/0.1.0",
        },
      });
    
      if (!res.ok) {
        throw new Error(`GitHub Search API error: ${res.status} ${await res.text()}`);
      }
    
      const data = await res.json() as {
        total_count: number;
        items: Array<{
          full_name: string;
          description: string | null;
          html_url: string;
          stargazers_count: number;
          forks_count: number;
          language: string | null;
          topics: string[];
          pushed_at: string;
          created_at: string;
          open_issues_count: number;
        }>;
      };
    
      const raw = [
        `Total matching repos: ${data.total_count.toLocaleString()}`,
        `Top ${data.items.length} by stars:\n`,
        ...data.items.map((r, i) =>
          [
            `[${i + 1}] ${r.full_name}`,
            `⭐ ${r.stargazers_count.toLocaleString()} stars | 🍴 ${r.forks_count} forks | Issues: ${r.open_issues_count}`,
            `Language: ${r.language ?? "unknown"}`,
            `Topics: ${r.topics?.join(", ") || "none"}`,
            `Description: ${r.description ?? "N/A"}`,
            `Last push: ${r.pushed_at}`,
            `Created: ${r.created_at}`,
            `URL: ${r.html_url}`,
          ].join("\n")
        ),
      ]
        .join("\n\n")
        .slice(0, options.maxLength ?? 6000);
    
      // Most recently pushed repo date as content_date
      const dates = data.items.map((r) => r.pushed_at).sort().reverse();
    
      return {
        raw,
        content_date: dates[0] ?? null,
        freshness_confidence: "high",
      };
    }

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/PrinceGabriel-lgtm/freshcontext-mcp'

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