Skip to main content
Glama

vigile_search

Search the Vigile registry by keyword to find MCP servers and agent skills. Returns trust scores for evaluating integration safety.

Instructions

Search the Vigile registry for MCP servers and agent skills by keyword. Returns matching entries with trust scores. Use this when you need to find servers by description or capability.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
queryYesSearch query (e.g., 'filesystem', 'database', 'code execution')
limitNoMax results to return (default: 10, max: 50)

Implementation Reference

  • src/index.ts:98-111 (registration)
    Registration of the 'vigile_search' tool on the MCP server via server.tool(), with Zod schema for 'query' and optional 'limit' parameters, and handler that calls searchRegistry().
    // ── Tool: vigile_search ──
    
    server.tool(
      "vigile_search",
      "Search the Vigile registry for MCP servers and agent skills by keyword. Returns matching entries with trust scores. Use this when you need to find servers by description or capability.",
      {
        query: z.string().min(1).max(200).describe("Search query (e.g., 'filesystem', 'database', 'code execution')"),
        limit: z.number().int().min(1).max(50).optional().describe("Max results to return (default: 10, max: 50)"),
      },
      async ({ query, limit }) => {
        const result = await searchRegistry(API_BASE, API_KEY, query, limit);
        return { content: [{ type: "text" as const, text: result }] };
      }
    );
  • The searchRegistry() function: executes the tool logic by querying the Vigile API (both /api/v1/search/ and /api/v1/search/skills endpoints in parallel) and formats results into a Markdown table with trust scores, emojis, and links.
    export async function searchRegistry(
      baseUrl: string,
      apiKey: string,
      query: string,
      limit?: number
    ): Promise<string> {
      const effectiveLimit = Math.min(limit || 10, 50);
      const qs = `q=${encodeURIComponent(query)}&limit=${effectiveLimit}`;
    
      // Search both servers and skills in parallel
      const [serverRes, skillRes] = await Promise.all([
        fetchVigile(baseUrl, apiKey, `/api/v1/search/?${qs}`),
        fetchVigile(baseUrl, apiKey, `/api/v1/search/skills?${qs}`),
      ]);
    
      const servers = serverRes.ok && Array.isArray(serverRes.data) ? serverRes.data : [];
      const skills = skillRes.ok && Array.isArray(skillRes.data) ? skillRes.data : [];
    
      if (servers.length === 0 && skills.length === 0) {
        return [
          `## Search: "${query}"`,
          "",
          "No results found in the Vigile registry.",
          "",
          "Try a different search term, or submit a server/skill for scanning at https://vigile.dev",
        ].join("\n");
      }
    
      const lines = [`## Search: "${query}"`, ""];
    
      // Server results
      if (servers.length > 0) {
        lines.push(`### MCP Servers (${servers.length} results)`, "");
        lines.push("| Server | Score | Level | Source |");
        lines.push("|--------|-------|-------|--------|");
        for (const s of servers) {
          const emoji = trustLevelEmoji(s.trust_level);
          lines.push(
            `| [${s.name}](https://vigile.dev/server/${encodeURIComponent(s.name)}) | ${formatScore(s.trust_score)} | ${emoji} ${s.trust_level} | ${s.source} |`
          );
        }
      }
    
      // Skill results
      if (skills.length > 0) {
        if (servers.length > 0) lines.push("");
        lines.push(`### Agent Skills (${skills.length} results)`, "");
        lines.push("| Skill | Score | Level | Platform |");
        lines.push("|-------|-------|-------|----------|");
        for (const s of skills) {
          const emoji = trustLevelEmoji(s.trust_level);
          lines.push(
            `| [${s.name}](https://vigile.dev/skill/${encodeURIComponent(s.name)}) | ${formatScore(s.trust_score)} | ${emoji} ${s.trust_level} | ${s.platform} |`
          );
        }
      }
    
      return lines.join("\n");
    }
  • Zod schema definitions for the vigile_search tool: 'query' (string, 1-200 chars, required) and 'limit' (integer 1-50, optional, default 10).
    {
      query: z.string().min(1).max(200).describe("Search query (e.g., 'filesystem', 'database', 'code execution')"),
      limit: z.number().int().min(1).max(50).optional().describe("Max results to return (default: 10, max: 50)"),
    },
  • fetchVigile() helper function performing the actual HTTP GET requests to the Vigile API with auth headers and error sanitization.
    export async function fetchVigile(
      baseUrl: string,
      apiKey: string,
      path: string,
      options?: { method?: string; body?: string }
    ): Promise<{ ok: boolean; status: number; data: any }> {
      const headers: Record<string, string> = {
        "Content-Type": "application/json",
        "User-Agent": "vigile-mcp/0.1.7",
      };
    
      if (apiKey) {
        headers["Authorization"] = `Bearer ${apiKey}`;
      }
    
      try {
        const res = await fetch(`${baseUrl}${path}`, {
          method: options?.method || "GET",
          headers,
          body: options?.body,
        });
    
        const data = await res.json().catch(() => null);
        return { ok: res.ok, status: res.status, data };
      } catch (error: any) {
        // Sanitize error message — don't leak internal details like
        // hostnames, ports, file paths, or stack traces
        const rawMsg = error?.message || "Unknown error";
        const safeMsg = rawMsg.includes("ECONNREFUSED") || rawMsg.includes("ENOTFOUND")
          ? "API server unreachable"
          : rawMsg.includes("ETIMEDOUT") || rawMsg.includes("timeout")
          ? "Request timed out"
          : rawMsg.includes("ECONNRESET")
          ? "Connection reset"
          : "Connection failed";
        return {
          ok: false,
          status: 0,
          data: { detail: safeMsg },
        };
      }
    }
  • Helper functions trustLevelEmoji() and formatScore() used by searchRegistry() to format trust levels as emojis and scores as N/100 strings.
    export function trustLevelEmoji(level: string): string {
      switch (level) {
        case "trusted":
          return "🟢";
        case "caution":
          return "🟡";
        case "risky":
          return "🟠";
        case "dangerous":
          return "🔴";
        default:
          return "⚪";
      }
    }
    
    export function formatScore(score: number): string {
      return `${Math.round(score)}/100`;
    }
Behavior3/5

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

With no annotations provided, the description carries the full burden. It mentions returning 'matching entries with trust scores' but does not disclose pagination, rate limits, or behavior for empty results. Adequate but could add more.

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 two sentences with front-loaded purpose and immediate usage guidance. Every word serves a purpose with no unnecessary detail.

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

Completeness4/5

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

Given only two parameters and no output schema, the description covers the main purpose and usage. However, it lacks details on result structure (e.g., how trust scores are presented), leaving some incompleteness for a search tool.

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?

The input schema has 100% coverage with descriptions for both 'query' and 'limit'. The tool description adds no new semantic information beyond what the schema already provides. Baselines at 3 are appropriate.

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

Purpose5/5

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

The description clearly states the tool searches the Vigile registry for MCP servers and agent skills by keyword, which is specific and differentiates it from sibling tools that check, recall, or verify.

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 explicitly says 'Use this when you need to find servers by description or capability,' providing clear context. It doesn't mention when not to use it or alternatives, but the guidance is sufficient.

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/Vigile-ai/vigile-mcp'

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