How to Filter n8n-MCP Templates by Complexity, Target Audience, and Setup Time Using Metadata

n8n-MCP stores workflow templates with structured metadata in SQLite, enabling precise filtering by complexity level, target audience, and setup time using the TemplateService.searchTemplatesByMetadata method and SQLite's json_extract function.

The czlonkowski/n8n-mcp repository provides a metadata-driven template catalog that allows developers and AI assistants to discover n8n workflows matching specific technical requirements. By leveraging automatically generated JSON metadata and a type-safe filtering layer, you can quickly identify templates suited to your skill level and time constraints without downloading entire workflow payloads.

Understanding the Metadata Architecture

Every workflow template in n8n-MCP includes a metadata JSON document generated by the MetadataGenerator class. This document describes categories, implementation complexity, typical use-cases, estimated setup time, required external services, and the intended target audience.

Metadata Generation and Schema

The metadata generation logic resides in src/templates/metadata-generator.ts. The MetadataGenerator class uses a Zod schema (TemplateMetadataSchema) to validate and structure the metadata, ensuring consistency across the catalog. When a template is fetched from n8n.io, the generateSingle method (or the batch API) produces a TemplateMetadata object that conforms to this schema.

Database Storage Strategy

Metadata persists in the SQLite templates table within the metadata_json column. The TemplateRepository class in src/templates/template-repository.ts handles persistence through saveTemplate, which stores the JSON string alongside compressed workflow data. This separation allows the system to query metadata efficiently without decompressing full workflow payloads until necessary.

How Metadata Filtering Works

Filtering occurs entirely inside the TemplateService layer, which delegates database operations to TemplateRepository. The implementation uses SQLite's native JSON functions combined with parameterized queries to ensure both precision and security.

Building Filter Conditions with buildMetadataFilterConditions

The TemplateRepository.buildMetadataFilterConditions method (lines 654-702 in src/templates/template-repository.ts) creates a safe, parameterized list of SQL conditions based on supplied filters. Because metadata lives in a JSON column, the method uses SQLite's json_extract function for precise field extraction. All values inject via prepared-statement parameters, eliminating SQL-injection risk while supporting filters for complexity, target audience, minimum/maximum setup minutes, and categories.

The Two-Phase Query Strategy

The searchTemplatesByMetadata implementation employs a two-phase query for optimal performance:

  1. ID Selection Phase – Executes the metadata-filter SQL to retrieve only matching template IDs without fetching large workflow payloads
  2. Data Retrieval Phase – Retrieves full rows in the exact order found, decompressing stored workflows only when required

This approach minimizes memory usage and query latency, particularly when filtering large template catalogs.

Practical Implementation Examples

Filtering by Complexity, Audience, and Setup Time

To find templates matching specific criteria, initialize the DatabaseAdapter and TemplateService, then call searchTemplatesByMetadata with your filter object:

import { DatabaseAdapter } from '../database/database-adapter';
import { TemplateService } from '../templates/template-service';

const db = new DatabaseAdapter();
const service = new TemplateService(db);

async function findSimpleDevTemplates() {
  const results = await service.searchTemplatesByMetadata(
    {
      complexity: 'simple',
      targetAudience: 'developers',
      maxSetupMinutes: 30,
    },
    20,   // limit
    0     // offset
  );

  console.log('Found', results.items.length, 'templates');
  results.items.forEach(t => {
    console.log(`- ${t.name} (≈${t.metadata?.estimated_setup_minutes} min)`);
  });
}

findSimpleDevTemplates();

This example queries for simple workflows targeting developers with setup times under 30 minutes. The method signature and filter logic reside in src/templates/template-service.ts (lines 220-250), while the underlying SQL construction appears in src/templates/template-repository.ts.

Retrieving Available Target Audiences

To populate UI selectors or discover available filter values, use the convenience methods exposed by TemplateService:

import { DatabaseAdapter } from '../database/database-adapter';
import { TemplateService } from '../templates/template-service';

const db = new DatabaseAdapter();
const service = new TemplateService(db);

async function listAudiences() {
  const audiences = await service.getAvailableTargetAudiences();
  console.log('Target audiences in the catalog:', audiences);
}

listAudiences();

The getAvailableTargetAudiences method delegates to TemplateRepository.getAvailableTargetAudiences (lines 822-831 in src/templates/template-repository.ts), which queries distinct values from the metadata JSON column.

Combining Categories with Pagination

For catalog browsing with pagination, pass limit and offset parameters alongside category and complexity filters:

import { DatabaseAdapter } from '../database/database-adapter';
import { TemplateService } from '../templates/template-service';

const db = new DatabaseAdapter();
const service = new TemplateService(db);

async function fetchAutomationTemplates(page = 0) {
  const limit = 10;
  const offset = page * limit;

  const response = await service.searchTemplatesByMetadata(
    {
      category: 'automation',
      complexity: 'medium',
    },
    limit,
    offset
  );

  console.log(`Page ${page + 1}:`);
  response.items.forEach(t => console.log(`• ${t.name}`));
}

fetchAutomationTemplates(0);

Pagination parameters pass directly through to TemplateRepository.searchTemplatesByMetadata (lines 707-783), maintaining the two-phase query strategy for consistent performance across result pages.

Available Filter Methods in TemplateService

The service layer exposes several convenience methods that wrap the core filtering functionality:

  • getTemplatesByComplexity(complexity, limit, offset) – Retrieves templates matching a specific complexity level (e.g., "simple", "medium", "advanced")
  • getAvailableCategories() – Returns all distinct category values present in the metadata catalog
  • getAvailableTargetAudiences() – Returns all distinct target audience identifiers for filtering UI generation
  • searchTemplatesByMetadata(filter, limit, offset) – The primary filtering interface accepting complex filter objects with multiple criteria

These methods reside in src/templates/template-service.ts and connect to the MCP server's tool definitions in src/mcp/tools.ts, enabling AI assistants and HTTP clients to request filtered templates without retrieving the entire dataset.

Summary

  • Metadata Generation: The MetadataGenerator class in src/templates/metadata-generator.ts creates validated JSON metadata using Zod schemas when templates are fetched from n8n.io
  • Secure Storage: Metadata persists in the SQLite templates table metadata_json column, separate from compressed workflow payloads
  • Safe Filtering: TemplateRepository.buildMetadataFilterConditions uses parameterized SQL with json_extract to prevent injection while filtering by complexity, audience, and setup time
  • Performance Optimization: The two-phase query strategy selects matching IDs first, then retrieves full records only when necessary
  • Developer API: TemplateService provides high-level methods like searchTemplatesByMetadata and getAvailableTargetAudiences for easy integration

Frequently Asked Questions

How is template metadata generated in n8n-mcp?

The MetadataGenerator class processes each template using AI analysis to produce structured metadata. Located in src/templates/metadata-generator.ts, it validates output against TemplateMetadataSchema using Zod, ensuring fields like complexity, target_audience, and estimated_setup_minutes conform to expected types before storage.

What database functions enable metadata filtering?

The system uses SQLite's native json_extract function within the TemplateRepository.buildMetadataFilterConditions method to query specific JSON fields. All filter values pass through prepared statement parameters, ensuring type-safe, injection-proof queries against the metadata_json column in the templates table.

How does the two-phase query improve performance?

searchTemplatesByMetadata first executes a lightweight query returning only template IDs that match the metadata filters. In the second phase, it retrieves full rows—including decompressed workflow data—only for those specific IDs. This prevents loading and decompressing large workflow payloads for templates that do not match the filter criteria.

Can I combine multiple filter criteria in a single query?

Yes. The searchTemplatesByMetadata method accepts a filter object containing complexity, targetAudience, category, minSetupMinutes, and maxSetupMinutes simultaneously. The repository builds a compound SQL WHERE clause combining these criteria with AND logic, returning only templates matching all specified conditions.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →