marketo_create_or_update_lead
Bulk create or update Marketo leads (upsert) using an array of records. Deduplicates by specified lookup field, defaulting to email. Supports up to 300 leads per call.
Instructions
Bulk create or update leads (upsert). Accepts an array of lead records with standard and custom fields. Deduplicates by lookupField (default: email). Max 300 leads per call.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| input | Yes | ||
| lookupField | No | ||
| partitionName | No |
Implementation Reference
- src/index.ts:286-313 (registration)Registration of the 'marketo_create_or_update_lead' tool on the MCP server via server.tool(). Defines the tool name, description, schema, and handler.
server.tool( 'marketo_create_or_update_lead', 'Bulk create or update leads (upsert). Accepts an array of lead records with standard and custom fields. Deduplicates by lookupField (default: email). Max 300 leads per call.', { input: z.array( z.object({ email: z.string().email(), firstName: z.string().optional(), lastName: z.string().optional(), company: z.string().optional(), title: z.string().optional(), phone: z.string().optional(), address: z.string().optional(), city: z.string().optional(), state: z.string().optional(), zipCode: z.string().optional(), country: z.string().optional(), website: z.string().optional(), customFields: z.record(z.string(), z.any()).optional(), }) ), lookupField: z.enum(['email', 'id', 'cookie']).optional(), partitionName: z.string().optional(), }, tool(async ({ input, lookupField = 'email', partitionName }) => makeApiRequest('/rest/v1/leads.json', 'POST', { input, lookupField, partitionName }) ) ); - src/index.ts:310-312 (handler)The actual handler function for the tool. Makes a POST request to Marketo's /rest/v1/leads.json endpoint with the input leads, lookupField, and partitionName parameters via makeApiRequest.
tool(async ({ input, lookupField = 'email', partitionName }) => makeApiRequest('/rest/v1/leads.json', 'POST', { input, lookupField, partitionName }) ) - src/index.ts:289-309 (schema)Zod schema definitions for the tool's input parameters: input (array of lead objects with standard fields and optional customFields), lookupField (enum: email/id/cookie), and partitionName (optional string).
{ input: z.array( z.object({ email: z.string().email(), firstName: z.string().optional(), lastName: z.string().optional(), company: z.string().optional(), title: z.string().optional(), phone: z.string().optional(), address: z.string().optional(), city: z.string().optional(), state: z.string().optional(), zipCode: z.string().optional(), country: z.string().optional(), website: z.string().optional(), customFields: z.record(z.string(), z.any()).optional(), }) ), lookupField: z.enum(['email', 'id', 'cookie']).optional(), partitionName: z.string().optional(), }, - src/index.ts:23-53 (helper)The makeApiRequest helper function that executes the actual HTTP request. It obtains a Bearer token via TokenManager, then makes the axios call to the Marketo API endpoint.
async function makeApiRequest( endpoint: string, method: string, data?: any, contentType: string = 'application/json' ) { const token = await tokenManager.getToken(); const headers: Record<string, string> = { Authorization: `Bearer ${token}`, }; if (contentType) { headers['Content-Type'] = contentType; } try { const response = await axios({ url: `${MARKETO_BASE_URL}${endpoint}`, method, data: contentType === 'application/x-www-form-urlencoded' ? new URLSearchParams(data).toString() : data, headers, }); return response.data; } catch (error: any) { console.error('API request failed:', error.response?.data || error.message); throw error; } } - src/index.ts:55-74 (helper)The 'tool' wrapper helper that wraps the handler to return a formatted response object with content array for the MCP protocol, including error handling.
function tool<T>(handler: (args: T) => Promise<unknown>) { return async (args: T) => { try { const response = await handler(args); return { content: [{ type: 'text' as const, text: JSON.stringify(response, null, 2) }], }; } catch (error: any) { return { content: [ { type: 'text' as const, text: `Error: ${error.response?.data?.message || error.message}`, }, ], isError: true, }; } }; }