marketo_clone_program
Clone any Marketo program to a new folder, copying all local assets (emails, landing pages, smart campaigns). Specify the source program ID, new name, destination folder, and optional description.
Instructions
Clone an existing Marketo program. Creates a copy with all local assets (emails, LPs, smart campaigns) under the specified name and folder.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | ID of the program to clone | |
| name | Yes | Name for the cloned program | |
| folderId | Yes | Destination folder ID | |
| folderType | No | Type of destination folder | Folder |
| description | No | Description for the cloned program |
Implementation Reference
- src/tools/programs.ts:57-72 (handler)The async handler function that executes the clone logic: builds a POST body with name, folder (JSON stringified), and optional description, then calls the Marketo Asset API endpoint /rest/asset/v1/program/{id}/clone.json via makeRequest.
async (args) => { try { const body: Record<string, unknown> = { name: args.name, folder: JSON.stringify({ id: args.folderId, type: args.folderType }), }; if (args.description) body.description = args.description; return ok(await makeRequest( `/rest/asset/v1/program/${args.id}/clone.json`, "POST", body, "application/x-www-form-urlencoded" )); } catch (e) { return err(e); } } ); - src/tools/programs.ts:50-56 (schema)Input schema using Zod: id (number, required), name (string, required), folderId (number, required), folderType (enum 'Folder'|'Program', default 'Folder'), description (optional string).
{ id: z.number().describe("ID of the program to clone"), name: z.string().describe("Name for the cloned program"), folderId: z.number().describe("Destination folder ID"), folderType: z.enum(["Folder", "Program"]).default("Folder").describe("Type of destination folder"), description: z.string().optional().describe("Description for the cloned program"), }, - src/tools/programs.ts:47-72 (registration)Registration via server.tool('marketo_clone_program', ...) inside the registerProgramTools function, which is called from src/index.ts.
server.tool( "marketo_clone_program", "Clone an existing Marketo program. Creates a copy with all local assets (emails, LPs, smart campaigns) under the specified name and folder.", { id: z.number().describe("ID of the program to clone"), name: z.string().describe("Name for the cloned program"), folderId: z.number().describe("Destination folder ID"), folderType: z.enum(["Folder", "Program"]).default("Folder").describe("Type of destination folder"), description: z.string().optional().describe("Description for the cloned program"), }, async (args) => { try { const body: Record<string, unknown> = { name: args.name, folder: JSON.stringify({ id: args.folderId, type: args.folderType }), }; if (args.description) body.description = args.description; return ok(await makeRequest( `/rest/asset/v1/program/${args.id}/clone.json`, "POST", body, "application/x-www-form-urlencoded" )); } catch (e) { return err(e); } } ); - src/client.ts:21-49 (helper)The makeRequest helper handles the actual HTTP call to the Marketo API with authentication, error handling, and content-type support (used with 'application/x-www-form-urlencoded' for clone).
export async function makeRequest<T = unknown>( endpoint: string, method: Method = "GET", data?: unknown, contentType?: string, ): Promise<T> { const token = await getAccessToken(); const config: AxiosRequestConfig = { url: `${MARKETO_BASE_URL}${endpoint}`, method, headers: { Authorization: `Bearer ${token}`, ...(contentType ? { "Content-Type": contentType } : {}), }, ...(data && method !== "GET" ? { data } : {}), ...(data && method === "GET" ? { params: data } : {}), }; const res = await axios(config); const body = res.data; // Marketo REST API returns errors inside the response body if (body?.errors?.length) { const e = body.errors[0]; throw new MarketoError(`${e.code}: ${e.message}`, res.status); } return body as T; } - src/client.ts:53-57 (helper)The ok/err response helpers used by the handler to format the MCP tool response.
export function ok(data: unknown) { return { content: [{ type: "text" as const, text: JSON.stringify(data, null, 2) }], }; }