smart_search
Search across all text fields in your Contentful content types with one query. Uses cached metadata for fast results.
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
| 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
- The smartSearch handler function that performs the actual smart search logic. It validates cache availability, fetches content types from cache, optionally filters by content type, then for each content type builds a GraphQL query searching across all String text fields using _contains with OR conditions. Results are collected and returned as JSON with query term, per-content-type matches, and stats.
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, } } }, - SmartSearchArgs interface defining the input arguments for the smart search handler: query (string), contentTypes (optional array of strings to filter), limit (optional number per content type), spaceId and environmentId (optional overrides).
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/types/tools.ts:109-133 (schema)SMART_SEARCH tool registration definition in the tools schema. Defines the tool name 'smart_search', description, and inputSchema with properties: query (required string), contentTypes (optional array of strings), limit (optional number, default 5), plus optional spaceId/environmentId 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"], }), }, - src/index.ts:43-44 (registration)Registration of SMART_SEARCH from the static tools definition into the MCP server's tool list via getAllTools(), conditionally including it if the definition exists.
if (allStaticTools.SMART_SEARCH) staticTools.SMART_SEARCH = allStaticTools.SMART_SEARCH - src/index.ts:126-128 (registration)Handler mapping in getHandler() that maps the string 'smart_search' to graphqlHandlers.smartSearch, which is called when the MCP server receives a CallToolRequest for smart_search.
smart_search: graphqlHandlers.smartSearch, build_search_query: graphqlHandlers.buildSearchQuery, }