Skip to main content
Glama
metrxbots

Metrx MCP Server

by metrxbots

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
NameRequiredDescriptionDefault
agent_idYesThe agent UUID to attribute
event_idNoOptional: specific event/task ID to attribute
outcome_typeYesType of outcome
outcome_sourceYesSource of the outcome data
value_centsNoOutcome value in cents
descriptionNoOptional description of the outcome

Implementation Reference

  • 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') }],
        };
      }
    );
  • 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') }],
      };
    }
  • 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);
    };
  • 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;
    }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/metrxbots/metrx-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server