Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
df34285
test: add mock data files for templates endpoint
JanKulhavy Apr 16, 2026
48602c5
feat: add Templates endpoint class and unit tests
JanKulhavy Apr 16, 2026
fe24fea
feat: wire Templates endpoint into Make client and exports
JanKulhavy Apr 16, 2026
c2861c5
style: align listPublic with codebase conventions
JanKulhavy Apr 16, 2026
62af959
feat: add MCP tool definitions for templates endpoint
JanKulhavy Apr 18, 2026
21ca17a
test: add integration tests for templates endpoint
JanKulhavy Apr 18, 2026
b237c0b
chore: format templates files and fix conditional expects
JanKulhavy Apr 18, 2026
4d9ce92
feat: add getPublic and getPublicBlueprint methods for templates
JanKulhavy Apr 18, 2026
4d853ca
refactor(templates): drop private templates, keep public only
JanKulhavy Apr 18, 2026
9a6c6a7
chore(scripts): add usedApps filter to templates smoke test
JanKulhavy Apr 18, 2026
b672277
remove: file
JanKulhavy Apr 18, 2026
b7161bb
feat(templates): update template names and enhance documentation for …
JanKulhavy Apr 18, 2026
ab9c170
feat(templates): rename templates to public-templates and update rela…
JanKulhavy Apr 18, 2026
b2d609b
Merge branch 'main' into feat/templates
JanKulhavy Apr 18, 2026
d333930
Update src/endpoints/public-templates.mcp.ts
JanKulhavy Apr 18, 2026
c710f30
Merge remote-tracking branch 'origin/main' into feat/templates
JanKulhavy Apr 24, 2026
d9e6142
Update test/public-templates.integration.test.ts
patriksimek Apr 25, 2026
87d394e
refactor: rename templates to publicTemplates for consistency
patriksimek Apr 25, 2026
82fe4fb
refactor: rename templates to publicTemplates for consistency
patriksimek Apr 25, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions scripts/test-templates.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#!/usr/bin/env node

import dotenv from 'dotenv';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
const __dirname = dirname(fileURLToPath(import.meta.url));
dotenv.config({ path: join(__dirname, '..', '.env') });

import { Make } from '../dist/index.js';

if (!process.env.MAKE_API_KEY) {
console.error('Please provide MAKE_API_KEY environment variable.');
process.exit(1);
}
if (!process.env.MAKE_ZONE) {
console.error('Please provide MAKE_ZONE environment variable.');
process.exit(1);
}

const searchTerm = process.argv[2] ?? 'webhook';
const usedApps = process.argv[3] ? process.argv[3].split(',').map(s => s.trim()).filter(Boolean) : undefined;

const make = new Make(process.env.MAKE_API_KEY, process.env.MAKE_ZONE);

const filterDesc = usedApps ? `"${searchTerm}" with apps [${usedApps.join(', ')}]` : `"${searchTerm}"`;
console.log(`\n=== Searching public templates for ${filterDesc} ===\n`);
const templates = await make.templates.list({ name: searchTerm, usedApps });

console.log(`Found ${templates.length} template(s):`);
templates.slice(0, 5).forEach(t => {
console.log(` [${t.id}] ${t.name} — apps: ${t.usedApps.join(', ')} — usage: ${t.usage}`);
});

if (templates.length === 0) {
console.log('No templates found. Try a different search term.');
process.exit(0);
}

const first = templates[0];
console.log(`\n=== Fetching blueprint for template [${first.id}] "${first.name}" (url: ${first.url}) ===\n`);
const blueprint = await make.templates.getBlueprint(first.url);

console.log('Language:', blueprint.language);
console.log('Scheduling:', JSON.stringify(blueprint.scheduling));
console.log('Controller name:', blueprint.controller?.name);
console.log('Blueprint flow (modules):');
const flow = blueprint.blueprint?.flow || [];
flow.forEach((step, i) => {
console.log(` ${i + 1}. ${step.module} (id ${step.id})`);
});
console.log(`\nFull blueprint size: ${JSON.stringify(blueprint).length} bytes`);
86 changes: 86 additions & 0 deletions src/endpoints/templates.mcp.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import type { Make } from '../make.js';

export const tools = [
{
name: 'templates_list',
title: 'List public templates',
description:
'Search and list public (approved) templates available for anyone. Supports name-based search for template discovery. Results are sorted by usage by default.',
category: 'templates',
scope: 'templates:read',
annotations: {
readOnlyHint: true,
},
inputSchema: {
type: 'object',
properties: {
name: { type: 'string', description: 'Search templates by name' },
usedApps: {
type: 'array',
items: { type: 'string' },
description: 'Filter templates by apps used',
},
includeEn: {
type: 'boolean',
description: 'Whether to include English-language templates in results',
},
},
},
examples: [{ name: 'webhook' }],
execute: async (make: Make, args: { name?: string; usedApps?: string[]; includeEn?: boolean }) => {
return await make.templates.list({ ...args, cols: ['*'] });
},
},
{
name: 'templates_get',
title: 'Get public template',
description:
'Get details of a public template by its URL slug (e.g. "12289-add-webhook-data-to-a-google-sheet"). Use this for templates discovered via templates_list.',
category: 'templates',
scope: 'templates:read',
identifier: 'templateUrl',
annotations: {
readOnlyHint: true,
},
inputSchema: {
type: 'object',
properties: {
templateUrl: {
type: 'string',
description: 'The URL slug of the template (e.g. "12289-add-webhook-data-to-a-google-sheet")',
},
},
required: ['templateUrl'],
},
examples: [{ templateUrl: '12289-add-webhook-data-to-a-google-sheet' }],
execute: async (make: Make, args: { templateUrl: string }) => {
return await make.templates.get(args.templateUrl, { cols: ['*'] });
},
},
{
name: 'templates_get-blueprint',
title: 'Get public template blueprint',
description:
'Get the full blueprint of a public template including scenario flow, controller configuration, scheduling, and metadata. Use this for templates discovered via templates_list.',
category: 'templates',
scope: 'templates:read',
identifier: 'templateUrl',
annotations: {
readOnlyHint: true,
},
inputSchema: {
type: 'object',
properties: {
templateUrl: {
type: 'string',
description: 'The URL slug of the template (e.g. "12289-add-webhook-data-to-a-google-sheet")',
},
},
required: ['templateUrl'],
},
examples: [{ templateUrl: '12289-add-webhook-data-to-a-google-sheet' }],
execute: async (make: Make, args: { templateUrl: string }) => {
return await make.templates.getBlueprint(args.templateUrl);
},
},
];
171 changes: 171 additions & 0 deletions src/endpoints/templates.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
import type { FetchFunction, Pagination, PickColumns } from '../types.js';

/**
* Represents a publicly available approved template in Make.
* Public templates can be discovered and used by all Make users.
*/
export type Template = {
/** Unique identifier of the public template */
id: number;
/** Name of the public template */
name: string;
/** Human-readable description of what the template does, or null if not set */
description: string | null;
/** URL slug identifying this public template */
url: string;
/** List of app identifiers used in the template */
usedApps: string[];
/** Number of times this template has been used */
usage: number;
};

/**
* Represents the blueprint (scenario definition) extracted from a template.
* Contains the full scenario configuration including flow, scheduling, and metadata.
*/
export type TemplateBlueprint = {
/** The scenario blueprint definition */
blueprint: Record<string, unknown>;
/** Controller configuration for the scenario */
controller: Record<string, unknown>;
/** Scheduling configuration for the scenario */
scheduling: Record<string, unknown>;
/** Language code for the template */
language: string;
/** Additional metadata for the template, or null if not set */
metadata: Record<string, unknown> | null;
};

/**
* Options for listing public approved templates.
* @template C Keys of the Template type to include in the response
*/
export type ListTemplatesOptions<C extends keyof Template = never> = {
/** Specific columns/fields to include in the response */
cols?: C[] | ['*'];
/** Pagination options */
pg?: Partial<Pagination<Template>>;
/** Search templates by name */
name?: string;
/** Filter templates by apps used */
usedApps?: string[];
/** Whether to include English-language templates in results */
includeEn?: boolean;
};

/**
* Options for getting a single public template.
* @template C Keys of the Template type to include in the response
*/
export type GetTemplateOptions<C extends keyof Template = never> = {
/** Specific columns/fields to include in the response */
cols?: C[] | ['*'];
};

/**
* Response format for listing public templates.
*/
type ListTemplatesResponse<C extends keyof Template = never> = {
/** List of public templates matching the query */
templatesPublic: PickColumns<Template, C>[];
/** Pagination information */
pg: Pagination<Template>;
};

/**
* Response format for getting a single public template.
*/
type GetTemplateResponse<C extends keyof Template = never> = {
/** The requested public template */
templatePublic: PickColumns<Template, C>;
};

/**
* Class providing methods for working with public Make templates.
* Public templates are approved scenario configurations that can be
* discovered and used by any Make user.
*/
export class Templates {
readonly #fetch: FetchFunction;

/**
* Create a new Templates instance.
* @param fetch Function for making API requests
*/
constructor(fetch: FetchFunction) {
this.#fetch = fetch;
}

/**
* List public (approved) templates available for anyone.
* Supports name-based search for template discovery.
* Results are sorted by usage in descending order by default.
* @param options Optional parameters for searching, filtering, and pagination
* @returns Promise with the list of public templates
*
* @example
* ```typescript
* // Search public templates by name
* const templates = await make.templates.list({ name: 'webhook' });
*
* // Filter by apps used
* const gmailTemplates = await make.templates.list({ usedApps: ['gmail'] });
* ```
*/
async list<C extends keyof Template = never>(
options: ListTemplatesOptions<C> = {},
): Promise<PickColumns<Template, C>[]> {
return (
await this.#fetch<ListTemplatesResponse<C>>('/templates/public', {
query: {
name: options.name,
usedApps: options.usedApps,
includeEn: options.includeEn,
cols: options.cols,
pg: options.pg,
},
Comment thread
JanKulhavy marked this conversation as resolved.
Outdated
})
).templatesPublic;
}

/**
* Get a single public template by its URL slug.
* Use this for templates discovered via {@link list}.
* @param templateUrl The URL slug of the template (e.g. "12289-add-webhook-data-to-a-google-sheet")
* @param options Optional parameters for field selection
* @returns Promise with the public template details
*
* @example
* ```typescript
* const template = await make.templates.get('12289-add-webhook-data-to-a-google-sheet');
* ```
*/
async get<C extends keyof Template = never>(
templateUrl: string,
options: GetTemplateOptions<C> = {},
): Promise<PickColumns<Template, C>> {
return (
await this.#fetch<GetTemplateResponse<C>>(`/templates/public/${templateUrl}`, {
query: {
cols: options.cols,
},
})
).templatePublic;
}

/**
* Get the blueprint (scenario definition) for a public template.
* The full response object is returned directly since the API returns a flat
* structure rather than wrapping the blueprint in a named property.
* @param templateUrl The URL slug of the template (e.g. "12289-add-webhook-data-to-a-google-sheet")
* @returns Promise with the full blueprint response
*
* @example
* ```typescript
* const blueprint = await make.templates.getBlueprint('12289-add-webhook-data-to-a-google-sheet');
* ```
*/
async getBlueprint(templateUrl: string): Promise<TemplateBlueprint> {
return await this.#fetch<TemplateBlueprint>(`/templates/public/${templateUrl}/blueprint`);
}
}
7 changes: 7 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,4 +166,11 @@ export type {
UpdateSDKWebhookBody,
} from './endpoints/sdk/webhooks.js';
export type { Team, Teams, CreateTeamBody, ListTeamsOptions, GetTeamOptions } from './endpoints/teams.js';
export type {
Template,
TemplateBlueprint,
Templates,
ListTemplatesOptions,
GetTemplateOptions,
} from './endpoints/templates.js';
export type { User, Users } from './endpoints/users.js';
9 changes: 9 additions & 0 deletions src/make.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { Devices } from './endpoints/devices.js';
import { Functions } from './endpoints/functions.js';
import { Organizations } from './endpoints/organizations.js';
import { Enums } from './endpoints/enums.js';
import { Templates } from './endpoints/templates.js';
import { SDKApps } from './endpoints/sdk/apps.js';
import { SDKModules } from './endpoints/sdk/modules.js';
import { SDKConnections } from './endpoints/sdk/connections.js';
Expand Down Expand Up @@ -163,6 +164,13 @@ export class Make {
*/
public readonly enums: Enums;

/**
* Access to template-related endpoints
* Templates allow users to create reusable scenario configurations
* that can be shared, published, and discovered by other users
*/
public readonly templates: Templates;

/**
* Access to SDK-related endpoints
*/
Expand Down Expand Up @@ -248,6 +256,7 @@ export class Make {
this.organizations = new Organizations(this.fetch.bind(this));
this.enums = new Enums(this.fetch.bind(this));
this.credentialRequests = new CredentialRequests(this.fetch.bind(this));
this.templates = new Templates(this.fetch.bind(this));
this.sdk = {
apps: new SDKApps(this.fetch.bind(this)),
modules: new SDKModules(this.fetch.bind(this)),
Expand Down
2 changes: 2 additions & 0 deletions src/mcp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { tools as FoldersTools } from './endpoints/folders.mcp.js';
import { tools as IncompleteExecutionsTools } from './endpoints/incomplete-executions.mcp.js';
import { tools as DataStructuresTools } from './endpoints/data-structures.mcp.js';
import { tools as EnumsTools } from './endpoints/enums.mcp.js';
import { tools as TemplatesTools } from './endpoints/templates.mcp.js';

/**
* JSON Schema definition for input parameters.
Expand Down Expand Up @@ -149,4 +150,5 @@ export const MakeMCPTools = [
...OrganizationsTools,
...UsersTools,
...EnumsTools,
...TemplatesTools,
] as MakeMCPTool[];
Loading