metrx_attribute_task
Link agent tasks to business outcomes for ROI tracking. Maps agent actions to measurable results like revenue, cost savings, efficiency, or quality improvements.
Instructions
Link an agent task/event to a business outcome for ROI tracking. This creates a mapping between agent actions and measurable business results. Do NOT use for reading attribution data — use get_attribution_report or get_task_roi.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| agent_id | Yes | The agent UUID to attribute | |
| event_id | No | Optional: specific event/task ID to attribute | |
| outcome_type | Yes | Type of outcome | |
| outcome_source | Yes | Source of the outcome data | |
| value_cents | No | Outcome value in cents | |
| description | No | Optional description of the outcome |
Implementation Reference
- src/tools/attribution.ts:44-109 (registration)Full registration of the 'attribute_task' tool (which becomes 'metrx_attribute_task' after namespace prefix is applied). Includes tool name, description, input schema validation (agent_id, event_id, outcome_type, outcome_source, value_cents, description), annotations, and the handler function.
// ── attribute_task ── server.registerTool( 'attribute_task', { title: 'Attribute Task to Outcome', description: 'Link an agent task/event to a business outcome for ROI tracking. ' + 'This creates a mapping between agent actions and measurable business results. ' + 'Do NOT use for reading attribution data — use get_attribution_report or get_task_roi.', inputSchema: { agent_id: z.string().uuid().describe('The agent UUID to attribute'), event_id: z.string().optional().describe('Optional: specific event/task ID to attribute'), outcome_type: z .enum(['revenue', 'cost_saving', 'efficiency', 'quality']) .describe('Type of outcome'), outcome_source: z .enum(['stripe', 'calendly', 'hubspot', 'zendesk', 'webhook', 'manual']) .describe('Source of the outcome data'), value_cents: z.number().int().optional().describe('Outcome value in cents'), description: z.string().optional().describe('Optional description of the outcome'), }, annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false, }, }, async ({ agent_id, event_id, outcome_type, outcome_source, value_cents, description }) => { const body: Record<string, unknown> = { agent_id, outcome_type, outcome_source, }; if (event_id) body.event_id = event_id; if (value_cents !== undefined) body.value_cents = value_cents; if (description) body.description = description; const result = await client.post<AttributionResponse>('/outcomes', body); if (result.error) { return { content: [{ type: 'text', text: `Error attributing task: ${result.error}` }], isError: true, }; } const outcome = result.data!; const lines: string[] = ['## Task Attributed Successfully', '']; lines.push(`- **Outcome Type**: ${outcome.outcome_type}`); lines.push(`- **Source**: ${outcome.outcome_source}`); if (outcome.value_cents) { const formatted = (outcome.value_cents / 100).toFixed(2); lines.push(`- **Value**: $${formatted}`); } if (outcome.description) { lines.push(`- **Description**: ${outcome.description}`); } lines.push(`- **Created**: ${new Date(outcome.created_at).toLocaleString()}`); return { content: [{ type: 'text', text: lines.join('\n') }], }; } ); - src/tools/attribution.ts:72-108 (handler)The handler function that executes the tool logic. Accepts attribution parameters, builds the request body, calls the API client to POST to /outcomes endpoint, and formats a success/error response with formatted output including outcome type, source, value, and creation timestamp.
async ({ agent_id, event_id, outcome_type, outcome_source, value_cents, description }) => { const body: Record<string, unknown> = { agent_id, outcome_type, outcome_source, }; if (event_id) body.event_id = event_id; if (value_cents !== undefined) body.value_cents = value_cents; if (description) body.description = description; const result = await client.post<AttributionResponse>('/outcomes', body); if (result.error) { return { content: [{ type: 'text', text: `Error attributing task: ${result.error}` }], isError: true, }; } const outcome = result.data!; const lines: string[] = ['## Task Attributed Successfully', '']; lines.push(`- **Outcome Type**: ${outcome.outcome_type}`); lines.push(`- **Source**: ${outcome.outcome_source}`); if (outcome.value_cents) { const formatted = (outcome.value_cents / 100).toFixed(2); lines.push(`- **Value**: $${formatted}`); } if (outcome.description) { lines.push(`- **Description**: ${outcome.description}`); } lines.push(`- **Created**: ${new Date(outcome.created_at).toLocaleString()}`); return { content: [{ type: 'text', text: lines.join('\n') }], }; } - src/tools/attribution.ts:53-64 (schema)Input schema validation using zod. Defines required fields: agent_id (UUID), outcome_type (enum: revenue, cost_saving, efficiency, quality), outcome_source (enum: stripe, calendly, hubspot, zendesk, webhook, manual); optional fields: event_id, value_cents (integer), description.
inputSchema: { agent_id: z.string().uuid().describe('The agent UUID to attribute'), event_id: z.string().optional().describe('Optional: specific event/task ID to attribute'), outcome_type: z .enum(['revenue', 'cost_saving', 'efficiency', 'quality']) .describe('Type of outcome'), outcome_source: z .enum(['stripe', 'calendly', 'hubspot', 'zendesk', 'webhook', 'manual']) .describe('Source of the outcome data'), value_cents: z.number().int().optional().describe('Outcome value in cents'), description: z.string().optional().describe('Optional description of the outcome'), }, - src/index.ts:74-103 (registration)Namespace prefix wrapper that automatically adds 'metrx_' prefix to all registered tools. When 'attribute_task' is registered, it becomes 'metrx_attribute_task'. Also applies rate limiting middleware to all tool calls.
// ── Rate limiting middleware + metrx_ namespace prefix ── // All tools are registered exclusively as metrx_{name}. // The metrx_ prefix namespaces our tools to avoid collisions when // multiple MCP servers are used together. const METRX_PREFIX = 'metrx_'; const originalRegisterTool = server.registerTool.bind(server); (server as any).registerTool = function ( name: string, config: any, handler: (...handlerArgs: any[]) => Promise<any> ) { const wrappedHandler = async (...handlerArgs: any[]) => { if (!rateLimiter.isAllowed(name)) { return { content: [ { type: 'text' as const, text: `Rate limit exceeded for tool '${name}'. Maximum 60 requests per minute allowed.`, }, ], isError: true, }; } return handler(...handlerArgs); }; // Register with metrx_ prefix (only — no deprecated aliases) const prefixedName = name.startsWith(METRX_PREFIX) ? name : `${METRX_PREFIX}${name}`; originalRegisterTool(prefixedName, config, wrappedHandler); }; - src/tools/attribution.ts:12-21 (schema)Type definition for AttributionResponse interface that defines the structure of the API response: id, agent_id, event_id (optional), outcome_type, outcome_source, value_cents (optional), description (optional), and created_at timestamp.
interface AttributionResponse { id: string; agent_id: string; event_id?: string; outcome_type: string; outcome_source: string; value_cents?: number; description?: string; created_at: string; }