Skip to main content
Glama

search

Find Disney parks attractions, restaurants, and shows by ID or name using fuzzy matching for Walt Disney World or Disneyland.

Instructions

Search for Disney entities by ID or name. Uses fuzzy matching for name queries like 'Space Mountain' or 'Be Our Guest'. For conceptual queries like 'thrill rides' or 'romantic dinner', use discover instead.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
idNoEntity ID for exact lookup (e.g., '80010190')
nameNoEntity name to search for (e.g., 'Space Mountain', 'Haunted Mansion')
destinationNoLimit search to a destination: 'wdw' or 'dlr'
entityTypeNoFilter by entity type

Implementation Reference

  • The main handler function for the 'search' tool. Handles exact lookup by ID or fuzzy matching by name for Disney entities (attractions, dining, shows). Falls back to API fetches if not in local DB, performs fuzzy search, returns best match with alternatives and confidence scores.
    export const handler: ToolHandler = async (args) => {
      return withTimeout(
        "search",
        async () => {
          const id = args.id as string | undefined;
          const name = args.name as string | undefined;
          const destination = args.destination as DestinationId | undefined;
          const entityType = args.entityType as EntityType | undefined;
    
          // Require either id or name
          if (!id && !name) {
            return formatErrorResponse(
              new ValidationError("Either 'id' or 'name' is required", "id|name", null)
            );
          }
    
          try {
            // Direct ID lookup
            if (id) {
              const entity = await getEntityById(id);
    
              if (!entity) {
                // Try fetching from API if not in local DB
                const client = getDisneyFinderClient();
                const fetched = await client.getEntityById(id);
    
                if (!fetched) {
                  return {
                    content: [
                      {
                        type: "text" as const,
                        text: JSON.stringify(
                          {
                            id,
                            found: false,
                            message: "No entity found with this ID",
                          },
                          null,
                          2
                        ),
                      },
                    ],
                  };
                }
    
                return formatEntityResult(fetched);
              }
    
              return formatEntityResult(entity);
            }
    
            // Fuzzy name search
            if (name) {
              // First try fuzzy search in database
              let candidates = await searchEntitiesByName<DisneyEntity>(name, {
                destinationId: destination,
                entityType,
                limit: EXTENDED_SEARCH_LIMIT,
              });
    
              // If no results in DB, fetch from API first
              if (candidates.length === 0) {
                const client = getDisneyFinderClient();
                const destinations = destination ? [destination] : (["wdw", "dlr"] as DestinationId[]);
    
                for (const dest of destinations) {
                  if (!entityType || entityType === "ATTRACTION") {
                    await client.getAttractions(dest);
                  }
                  if (!entityType || entityType === "RESTAURANT") {
                    await client.getDining(dest);
                  }
                  if (!entityType || entityType === "SHOW") {
                    await client.getShows(dest);
                  }
                }
    
                // Try search again
                candidates = await searchEntitiesByName<DisneyEntity>(name, {
                  destinationId: destination,
                  entityType,
                  limit: EXTENDED_SEARCH_LIMIT,
                });
              }
    
              // If still no results, try loading from DB and fuzzy matching
              if (candidates.length === 0) {
                const destinations = destination ? [destination] : (["wdw", "dlr"] as DestinationId[]);
                candidates = [];
    
                for (const dest of destinations) {
                  if (!entityType || entityType === "ATTRACTION") {
                    candidates.push(...(await getAttractions(dest)));
                  }
                  if (!entityType || entityType === "RESTAURANT") {
                    candidates.push(...(await getDining(dest)));
                  }
                  if (!entityType || entityType === "SHOW") {
                    candidates.push(...(await getShows(dest)));
                  }
                }
              }
    
              // Perform fuzzy matching
              const matches = fuzzySearch(name, candidates, {
                threshold: DEFAULT_FUZZY_SEARCH_THRESHOLD,
                limit: DEFAULT_DISCOVER_LIMIT,
              });
    
              if (matches.length === 0) {
                return {
                  content: [
                    {
                      type: "text" as const,
                      text: JSON.stringify(
                        {
                          query: name,
                          found: false,
                          message: "No matching entities found. Try discover for conceptual searches.",
                        },
                        null,
                        2
                      ),
                    },
                  ],
                };
              }
    
              // Return best match with alternatives
              // WHY: Safe to assert - we checked matches.length > 0 above
              // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
              const bestMatch = matches[0]!;
              const alternatives = matches.slice(1);
    
              return {
                content: [
                  {
                    type: "text" as const,
                    text: JSON.stringify(
                      {
                        query: name,
                        found: true,
                        confidence: Math.round(bestMatch.score * 100) / 100,
                        bestMatch: formatEntity(bestMatch.entity),
                        alternatives: alternatives.map((m) => ({
                          name: m.entity.name,
                          id: m.entity.id,
                          type: m.entity.entityType,
                          score: Math.round(m.score * 100) / 100,
                        })),
                      },
                      null,
                      2
                    ),
                  },
                ],
              };
            }
    
            return formatErrorResponse(new Error("Unexpected state"));
          } catch (error) {
            return formatErrorResponse(error);
          }
        },
        TIMEOUTS.SEARCH
      );
    };
  • ToolDefinition for 'search' including name, description, and inputSchema defining parameters: id (optional string), name (optional string), destination (optional enum wdw/dlr), entityType (optional enum ATTRACTION/RESTAURANT/SHOW). Requires either id or name.
    export const definition: ToolDefinition = {
      name: "search",
      description:
        "Search for Disney entities by ID or name. " +
        "Uses fuzzy matching for name queries like 'Space Mountain' or 'Be Our Guest'. " +
        "For conceptual queries like 'thrill rides' or 'romantic dinner', use discover instead.",
      inputSchema: {
        type: "object" as const,
        properties: {
          id: {
            type: "string",
            description: "Entity ID for exact lookup (e.g., '80010190')",
          },
          name: {
            type: "string",
            description: "Entity name to search for (e.g., 'Space Mountain', 'Haunted Mansion')",
          },
          destination: {
            type: "string",
            description: "Limit search to a destination: 'wdw' or 'dlr'",
            enum: ["wdw", "dlr"],
          },
          entityType: {
            type: "string",
            description: "Filter by entity type",
            enum: ["ATTRACTION", "RESTAURANT", "SHOW"],
          },
        },
        required: [],
      },
    };
  • Registration of all tools in the tools array, including the 'search' tool entry with its definition and handler.
    const tools: ToolEntry[] = [
      { definition: destinations.definition, handler: destinations.handler },
      { definition: attractions.definition, handler: attractions.handler },
      { definition: dining.definition, handler: dining.handler },
      { definition: search.definition, handler: search.handler },
      { definition: discover.definition, handler: discover.handler },
      { definition: status.definition, handler: status.handler },
      { definition: sync.definition, handler: sync.handler },
    ];
  • registerTools function that populates a Map with all tools by name, including 'search', for MCP tool lookup.
    export function registerTools(toolMap: Map<string, ToolEntry>): void {
      for (const tool of tools) {
        toolMap.set(tool.definition.name, tool);
      }
    }
  • Helper function to format entity data for output, normalizing field names.
    function formatEntity(entity: DisneyEntity): Record<string, unknown> {
      // Return full entity data with normalized field names
      const { entityType, destinationId, parkName, ...rest } = entity;
      return {
        ...rest,
        type: entityType,
        destination: destinationId,
        park: parkName,
      };
    }
Behavior3/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. It discloses behavioral traits like 'fuzzy matching for name queries' and scope limitations (ID/name vs. conceptual), but lacks details on permissions, rate limits, response format, or error handling. For a search tool with no annotations, this is adequate but has gaps.

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 front-loaded with the core purpose, followed by specific usage details and a clear alternative. Both sentences earn their place by providing essential guidance without redundancy, making it efficient and well-structured.

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 no annotations and no output schema, the description is moderately complete for a search tool. It covers purpose and usage guidelines well but lacks behavioral details like response format or error handling. For a 4-parameter tool with 100% schema coverage, it's adequate but could be more comprehensive.

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 fully documents all 4 parameters. The description adds minimal value beyond the schema by implying fuzzy matching applies to 'name' queries, but doesn't provide additional syntax or format details. Baseline 3 is appropriate when the schema does the heavy lifting.

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's purpose: 'Search for Disney entities by ID or name' with specific verbs ('search', 'uses fuzzy matching') and resources ('Disney entities'). It explicitly distinguishes from sibling 'discover' for conceptual queries, making the scope precise.

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

Usage Guidelines5/5

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

The description provides explicit guidance on when to use this tool ('by ID or name', 'fuzzy matching for name queries') and when not to ('For conceptual queries... use discover instead'), naming the alternative tool. This clearly differentiates it from siblings like 'discover' and implies usage contexts.

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/cameronsjo/mouse-mcp'

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