smart_search
Search across multiple content types using cached metadata to find content without manually chaining GraphQL calls.
Instructions
Perform intelligent search across multiple content types using cached metadata. This tool automatically searches all text fields in your content types for the given query term. Much faster and easier than manually chaining multiple GraphQL calls.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | The search term to look for across content types | |
| contentTypes | No | Optional: Limit search to specific content types (default: search all) | |
| limit | No | Maximum number of results per content type (default: 5) | |
| spaceId | No | Optional override for the space ID (defaults to SPACE_ID environment variable) | |
| environmentId | No | Optional override for the environment ID (defaults to ENVIRONMENT_ID environment variable or 'master') |
Implementation Reference
- Main handler function for the 'smart_search' tool. It searches across multiple content types using cached schemas, building dynamic GraphQL queries for text fields containing the search term.smartSearch: async (args: SmartSearchArgs): Promise<ToolResponse> => { try { if (!isCacheAvailable()) { return { content: [ { type: "text", text: "Smart search requires cached metadata. Please wait for the cache to load or use individual GraphQL queries.", }, ], isError: true, } } const spaceId = args.spaceId || process.env.SPACE_ID const environmentId = args.environmentId || process.env.ENVIRONMENT_ID || "master" const accessToken = process.env.CONTENTFUL_DELIVERY_ACCESS_TOKEN const limit = args.limit || 5 if (!spaceId || !accessToken) { return { content: [ { type: "text", text: "Space ID and CDA token are required for smart search", }, ], isError: true, } } const contentTypes = getCachedContentTypes() if (!contentTypes) { return { content: [{ type: "text", text: "No content types available in cache" }], isError: true, } } // Filter content types if specified const targetContentTypes = args.contentTypes ? contentTypes.filter((ct) => args.contentTypes!.includes(ct.name)) : contentTypes const searchPromises = targetContentTypes.map(async (contentType) => { try { const schema = getCachedContentTypeSchema(contentType.name) if (!schema) return null // Find searchable text fields const textFields = schema.fields.filter((field: any) => isSearchableTextField(field.type)) if (textFields.length === 0) return null // Build search query with OR conditions across text fields const searchConditions = textFields .map((field: any) => `{ ${field.name}_contains: $searchTerm }`) .join(", ") const query = ` query SearchIn${contentType.name}($searchTerm: String!) { ${contentType.queryName}(where: { OR: [${searchConditions}] }, limit: ${limit}) { items { sys { id } ${textFields.map((field: any) => field.name).join("\n ")} } } } ` const result = await graphqlHandlers.executeQuery({ query, variables: { searchTerm: args.query }, spaceId, environmentId, }) if (!result.isError) { const data = JSON.parse(result.content[0].text) const items = data.data?.[contentType.queryName]?.items || [] if (items.length > 0) { return { contentType: contentType.name, items: items.map((item: any) => ({ id: item.sys.id, ...Object.fromEntries( textFields.map((field: any) => [field.name, item[field.name]]), ), })), } } } return null } catch (error) { console.error(`Search error for ${contentType.name}:`, error) return null } }) const results = await Promise.all(searchPromises) const validResults = results.filter(Boolean) return { content: [ { type: "text", text: JSON.stringify( { query: args.query, results: validResults, totalContentTypesSearched: targetContentTypes.length, contentTypesWithResults: validResults.length, }, null, 2, ), }, ], } } catch (error) { return { content: [ { type: "text", text: `Error in smart search: ${error instanceof Error ? error.message : String(error)}`, }, ], isError: true, } } },
- src/types/tools.ts:109-133 (schema)Tool schema definition for 'smart_search', including input schema with query, optional contentTypes, limit, and environment overrides.SMART_SEARCH: { name: "smart_search", description: "Perform intelligent search across multiple content types using cached metadata. This tool automatically searches all text fields in your content types for the given query term. Much faster and easier than manually chaining multiple GraphQL calls.", inputSchema: getOptionalEnvProperties({ type: "object", properties: { query: { type: "string", description: "The search term to look for across content types", }, contentTypes: { type: "array", items: { type: "string" }, description: "Optional: Limit search to specific content types (default: search all)", }, limit: { type: "number", description: "Maximum number of results per content type (default: 5)", default: 5, }, }, required: ["query"], }), },
- TypeScript interface defining the input arguments for the smartSearch handler.export interface SmartSearchArgs { query: string contentTypes?: string[] // Optional filter to specific content types limit?: number // Limit per content type (default: 5) spaceId?: string // Optional override for environment variable environmentId?: string // Optional override for environment variable }
- src/index.ts:126-126 (registration)Registration of the 'smart_search' tool name to the graphqlHandlers.smartSearch function in the handler map.smart_search: graphqlHandlers.smartSearch,
- src/index.ts:43-44 (registration)Conditional inclusion of the SMART_SEARCH tool in the staticTools object used for MCP capabilities.if (allStaticTools.SMART_SEARCH) staticTools.SMART_SEARCH = allStaticTools.SMART_SEARCH