Skip to main content
Glama
opentofu

OpenTofu MCP Server

Official
by opentofu

search-opentofu-registry

Search the OpenTofu Registry to find providers, modules, resources, and data sources for infrastructure configuration. Enter simple terms like 'aws' or 'kubernetes' to locate components.

Instructions

Search the OpenTofu Registry to find providers, modules, resources, and data sources. Use simple terms without prefixes like 'terraform-provider-' or 'terraform-module-'.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
queryYesSearch query for finding OpenTofu components (e.g., 'aws', 'kubernetes', 'database', 's3')
typeNoType of registry items to search forall

Implementation Reference

  • The inline async handler function for the 'search-opentofu-registry' tool. It invokes the RegistryClient.search method, handles empty results and errors, and formats the output using textResult and renderSearchResults.
    async (params) => {
      try {
        const results = await client.search(params.query, params.type);
        if (results.length === 0) {
          return textResult(`No results found for "${params.query}" in the OpenTofu Registry.`);
        }
        return textResult(`Found ${results.length} results for "${params.query}" in the OpenTofu Registry:\n\n${results.map((r) => renderSearchResults(r)).join("\n\n")}`);
      } catch (error: unknown) {
        const errorMessage = error instanceof Error ? error.message : "Unknown error";
        return textResult(`Error searching the OpenTofu Registry: ${errorMessage}`);
      }
    },
  • Zod schema defining the input parameters for the search tool: query (string, min 2 chars) and type (enum with default 'all').
    const searchSchema = {
      query: z.string().min(2).describe("Search query for finding OpenTofu components (e.g., 'aws', 'kubernetes', 'database', 's3')"),
      type: z.enum(["provider", "module", "resource", "data-source", "all"]).default("all").describe("Type of registry items to search for"),
    };
  • MCP server.tool registration call that registers the 'search-opentofu-registry' tool with its name, description, schema, and handler function.
      "search-opentofu-registry",
      "Search the OpenTofu Registry to find providers, modules, resources, and data sources. Use simple terms without prefixes like 'terraform-provider-' or 'terraform-module-'.",
      searchSchema,
      async (params) => {
        try {
          const results = await client.search(params.query, params.type);
          if (results.length === 0) {
            return textResult(`No results found for "${params.query}" in the OpenTofu Registry.`);
          }
          return textResult(`Found ${results.length} results for "${params.query}" in the OpenTofu Registry:\n\n${results.map((r) => renderSearchResults(r)).join("\n\n")}`);
        } catch (error: unknown) {
          const errorMessage = error instanceof Error ? error.message : "Unknown error";
          return textResult(`Error searching the OpenTofu Registry: ${errorMessage}`);
        }
      },
    );
  • Core search logic in RegistryClient class: performs API fetch to /registry/docs/search with query 'q', optionally filters by type.
    async search(query: string, type?: string): Promise<apiDefinition["SearchResultItem"][]> {
      const params: Record<string, string> = { q: query };
      const response = await this.fetchFromApi<apiDefinition["SearchResultItem"][]>("/registry/docs/search", params);
    
      let results = response;
      if (type && type !== "all") {
        results = response.filter((item) => item.type.toLowerCase() === type.toLowerCase());
      }
      return results;
    }
  • Utility function to render a formatted string for each search result item, including type-specific details and instructions for further tools.
    export function renderSearchResults(r: apiDefinition["SearchResultItem"]): string {
      let result = `- ${r.title} ${r.description.trim()} (${r.type})`;
      result += ` (latest version: ${r.version})`;
      switch (r.type) {
        case "provider":
          result += `\n  Provider: ${r.link_variables.namespace}/${r.link_variables.name}`;
          result += `\n  Provider Details: Use 'get-provider-details' with namespace="${r.link_variables.namespace}" and name="${r.link_variables.name}"`;
          break;
        case "module":
          result += `\n  Module: ${r.link_variables.namespace}/${r.link_variables.name} (${r.link_variables.target})`;
          result += `\n  Module Details: Use 'get-module-details' with namespace="${r.link_variables.namespace}", name="${r.link_variables.name}", target="${r.link_variables.target}"`;
          break;
        case "provider/resource": {
          const versionParam = r.version ? `, version="${r.version}"` : "";
          result += `\n  Resource: ${r.link_variables.namespace}/${r.link_variables.name} (${r.link_variables.id})`;
          result += `\n  Full identifier: ${r.link_variables.name}_${r.link_variables.id}`;
          result += `\n  Resource Docs: Use 'get-resource-docs' with namespace="${r.link_variables.namespace}", name="${r.link_variables.name}", resource="${r.link_variables.id}"${versionParam}`;
          result += `\n  Provider Details: Use 'get-provider-details' with namespace="${r.link_variables.namespace}" and name="${r.link_variables.name}"`;
          break;
        }
        case "provider/data-source": {
          const versionParam = r.version ? `, version="${r.version}"` : "";
          result += `\n  Data Source: ${r.link_variables.namespace}/${r.link_variables.name} (${r.link_variables.id})`;
          result += `\n  Full identifier: ${r.link_variables.name}_${r.link_variables.id}`;
          result += `\n  Data Source Docs: Use 'get-datasource-docs' with namespace="${r.link_variables.namespace}", name="${r.link_variables.name}", dataSource="${r.link_variables.id}"${versionParam}`;
          result += `\n  Provider Details: Use 'get-provider-details' with namespace="${r.link_variables.namespace}" and name="${r.link_variables.name}"`;
          break;
        }
        default:
          result += `\n  Unknown type: ${r.type}`;
      }
      return result;
    }
Behavior3/5

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

With no annotations provided, the description carries full burden for behavioral disclosure. It describes the search functionality and query formatting constraints, but doesn't mention other behavioral aspects like rate limits, authentication needs, pagination, error handling, or what the search results look like. The description adds some value but leaves significant gaps in behavioral context.

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 perfectly concise with two sentences that each earn their place. The first sentence states the core purpose, and the second provides essential usage guidance about query formatting. There's zero wasted text and the information is front-loaded appropriately.

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 moderate complexity (search functionality with 2 parameters) and no output schema, the description is adequate but incomplete. It covers the basic purpose and query formatting, but lacks information about result format, pagination, error conditions, or how results relate to the sibling tools for getting details. The absence of annotations increases the need for more comprehensive description.

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 100%, so the schema already fully documents both parameters. The description adds minimal value beyond the schema - it mentions searching for 'providers, modules, resources, and data sources' which aligns with the 'type' parameter enum values, but doesn't provide additional semantic context about parameter usage or interactions.

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 specific action ('Search the OpenTofu Registry') and the resources involved ('providers, modules, resources, and data sources'). It distinguishes from sibling tools like get-provider-details or get-module-details by focusing on broad search rather than detailed retrieval of specific items.

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 on when to use this tool ('Search the OpenTofu Registry') and includes practical guidance about query formatting ('Use simple terms without prefixes'). However, it doesn't explicitly state when NOT to use it or name specific alternatives among the sibling tools, though the distinction is implied by the different purposes.

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/opentofu/opentofu-mcp-server'

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