marketo_clone_email
Clone an existing Marketo email to create a draft copy in a target folder, with a new name and optional description. Ideal for reusing email templates or creating variations.
Instructions
Clone an existing Marketo email asset. Creates a draft copy with the specified name in the target folder.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | ID of the email to clone | |
| name | Yes | Name for the cloned email | |
| folderId | Yes | Destination folder ID | |
| folderType | No | Type of destination folder | Folder |
| description | No | Description for the cloned email |
Implementation Reference
- src/tools/emails.ts:40-66 (handler)The marketo_clone_email tool handler function defined via server.tool(). It takes id, name, folderId, folderType, and optional description, then POSTs to /rest/asset/v1/email/{id}/clone.json with x-www-form-urlencoded body containing name, folder (JSON), and optional description.
// ── marketo_clone_email ──────────────────────────────────────────────────── server.tool( "marketo_clone_email", "Clone an existing Marketo email asset. Creates a draft copy with the specified name in the target folder.", { id: z.number().describe("ID of the email to clone"), name: z.string().describe("Name for the cloned email"), 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 email"), }, 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/email/${args.id}/clone.json`, "POST", body, "application/x-www-form-urlencoded" )); } catch (e) { return err(e); } } ); - src/tools/emails.ts:5-94 (registration)The registerEmailTools function is exported and called from src/index.ts, which is where all tools including marketo_clone_email are registered on the MCP server.
export function registerEmailTools(server: McpServer) { // ── marketo_get_emails ───────────────────────────────────────────────────── server.tool( "marketo_get_emails", "List email assets in Marketo. Supports pagination via maxReturn/offset and filtering by status (approved/draft). Returns email metadata including subject line, from address, and folder.", { maxReturn: z.number().optional().describe("Max emails to return (1-200, default 20)"), offset: z.number().optional().describe("Pagination offset"), status: z.enum(["approved", "draft"]).optional().describe("Filter by approval status"), }, async (args) => { try { const params: Record<string, unknown> = {}; if (args.maxReturn) params.maxReturn = args.maxReturn; if (args.offset) params.offset = args.offset; if (args.status) params.status = args.status; return ok(await makeRequest("/rest/asset/v1/emails.json", "GET", params)); } catch (e) { return err(e); } } ); // ── marketo_get_email_by_id ──────────────────────────────────────────────── server.tool( "marketo_get_email_by_id", "Get a single Marketo email asset by ID. Returns full email metadata including HTML content, subject line, from/reply-to, and module structure.", { id: z.number().describe("Email asset ID"), }, async (args) => { try { return ok(await makeRequest(`/rest/asset/v1/email/${args.id}.json`)); } catch (e) { return err(e); } } ); // ── marketo_clone_email ──────────────────────────────────────────────────── server.tool( "marketo_clone_email", "Clone an existing Marketo email asset. Creates a draft copy with the specified name in the target folder.", { id: z.number().describe("ID of the email to clone"), name: z.string().describe("Name for the cloned email"), 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 email"), }, 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/email/${args.id}/clone.json`, "POST", body, "application/x-www-form-urlencoded" )); } catch (e) { return err(e); } } ); // ── marketo_send_sample ──────────────────────────────────────────────────── server.tool( "marketo_send_sample", "Send a sample/test email to an email address. Optionally render personalization tokens using a specific lead's data. Useful for QA before approving.", { id: z.number().describe("Email asset ID"), emailAddress: z.string().describe("Recipient email address for the sample"), textOnly: z.boolean().optional().describe("Send text-only version"), leadId: z.number().optional().describe("Lead ID whose data to use for token rendering"), }, async (args) => { try { const body: Record<string, unknown> = { emailAddress: args.emailAddress, }; if (args.textOnly !== undefined) body.textOnly = args.textOnly; if (args.leadId) body.leadId = args.leadId; return ok(await makeRequest( `/rest/asset/v1/email/${args.id}/sendSample.json`, "POST", body, "application/x-www-form-urlencoded" )); } catch (e) { return err(e); } } ); } - src/index.ts:20-29 (registration)The registration call-site where registerEmailTools(server) is invoked, which registers marketo_clone_email on the MCP server.
// Register all tool groups registerFormTools(server); registerLeadTools(server); registerProgramTools(server); registerEmailTools(server); registerSmartListTools(server); registerListTools(server); registerChannelTools(server); registerLandingPageTools(server); registerBulkExportTools(server); - src/tools/emails.ts:44-50 (schema)Zod schema definitions for the marketo_clone_email tool inputs: id (number), name (string), folderId (number), folderType (enum Folder/Program with default Folder), and optional description (string).
{ id: z.number().describe("ID of the email to clone"), name: z.string().describe("Name for the cloned email"), 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 email"), }, - src/client.ts:21-49 (helper)The makeRequest helper function used by the marketo_clone_email handler to make authenticated HTTP requests to the Marketo API. Also provides ok/err wrappers used for return values.
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; }