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

> Filter n8n-MCP templates by complexity target audience and setup time using metadata and SQLite Search templates precisely with TemplateService searchTemplatesByMetadata and json_extract

- Repository: [Romuald Członkowski/n8n-mcp](https://github.com/czlonkowski/n8n-mcp)
- Tags: how-to-guide
- Published: 2026-03-24

---

**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`](https://github.com/czlonkowski/n8n-mcp/blob/main/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`](https://github.com/czlonkowski/n8n-mcp/blob/main/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`](https://github.com/czlonkowski/n8n-mcp/blob/main/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:

```typescript
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`](https://github.com/czlonkowski/n8n-mcp/blob/main/src/templates/template-service.ts) (lines 220-250), while the underlying SQL construction appears in [`src/templates/template-repository.ts`](https://github.com/czlonkowski/n8n-mcp/blob/main/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`:

```typescript
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`](https://github.com/czlonkowski/n8n-mcp/blob/main/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:

```typescript
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`](https://github.com/czlonkowski/n8n-mcp/blob/main/src/templates/template-service.ts) and connect to the MCP server's tool definitions in [`src/mcp/tools.ts`](https://github.com/czlonkowski/n8n-mcp/blob/main/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`](https://github.com/czlonkowski/n8n-mcp/blob/main/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`](https://github.com/czlonkowski/n8n-mcp/blob/main/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.