Skip to main content
Glama
klodr

mercury-invoicing-mcp

mercury_add_recipient

Idempotent

Add a new payment recipient to send money via ACH, wire, or check. Returns a recipient ID used for sending payments.

Instructions

Add a new payment recipient (a counterparty you can later send money to via ACH/wire/check).

USE WHEN: onboarding a new vendor, contractor, or other payee before sending money. The returned id is what mercury_send_money and mercury_request_send_money expect as recipientId.

DO NOT USE: for AR customers (use mercury_create_customer — recipients receive money, customers pay invoices). Mercury enforces strict KYC/banking validation on bank fields — invalid routing numbers or account numbers are rejected at create time.

SIDE EFFECTS: writes a new recipient to Mercury. Persistent. Idempotent via idempotencyKey — the MCP auto-generates one if not provided, so repeated calls with the same generated key would not duplicate; pass an explicit idempotencyKey to make this stable across retries you control.

RETURNS: { id, name, status, defaultPaymentMethod, ... } — keep id for the send-money tools.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
nameYesRecipient legal name
emailsYesList of email addresses
paymentMethodYesPayment method to send to this recipient
defaultPaymentMethodNoDefault payment method
electronicRoutingInfoNoBank account info for ACH/wire
idempotencyKeyNoUnique key to prevent duplicates

Implementation Reference

  • The handler function for mercury_add_recipient. Takes name, emails, paymentMethod, optional electronicRoutingInfo, and idempotencyKey; POSTs to /recipients on Mercury API.
      async ({ idempotencyKey, ...body }) => {
        const idem = idempotencyKey ?? randomUUID();
        const data = await client.post("/recipients", { ...body, idempotencyKey: idem });
        return textResult(data);
      },
      { title: "Add Recipient", destructiveHint: false, idempotentHint: true, openWorldHint: true },
    );
  • Zod input schema for mercury_add_recipient: validates name, emails, paymentMethod, defaultPaymentMethod, electronicRoutingInfo (bank details), and idempotencyKey.
    {
      name: z.string().describe("Recipient legal name"),
      emails: z.array(z.email()).describe("List of email addresses"),
      paymentMethod: z
        .enum(["domesticAch", "internationalWire", "domesticWire", "check"])
        .describe("Payment method to send to this recipient"),
      defaultPaymentMethod: z
        .enum(["domesticAch", "internationalWire", "domesticWire", "check"])
        .optional()
        .describe("Default payment method"),
      electronicRoutingInfo: z
        .object({
          accountNumber: z.string(),
          routingNumber: z.string(),
          electronicAccountType: z.enum([
            "businessChecking",
            "businessSavings",
            "personalChecking",
            "personalSavings",
          ]),
          address: z
            .object({
              address1: z.string(),
              address2: z.string().optional(),
              city: z.string(),
              region: z.string(),
              postalCode: z.string(),
              country: z.string(),
            })
            .optional(),
        })
        .optional()
        .describe("Bank account info for ACH/wire"),
      idempotencyKey: z.string().optional().describe("Unique key to prevent duplicates"),
  • Registration: calls defineTool with name 'mercury_add_recipient', description, schema, handler, and annotations.
    defineTool(
      server,
      "mercury_add_recipient",
      [
        "Add a new payment recipient (a counterparty you can later send money to via ACH/wire/check).",
        "",
        "USE WHEN: onboarding a new vendor, contractor, or other payee before sending money. The returned `id` is what `mercury_send_money` and `mercury_request_send_money` expect as `recipientId`.",
        "",
        "DO NOT USE: for AR customers (use `mercury_create_customer` — recipients receive money, customers pay invoices). Mercury enforces strict KYC/banking validation on bank fields — invalid routing numbers or account numbers are rejected at create time.",
        "",
        "SIDE EFFECTS: writes a new recipient to Mercury. Persistent. **Idempotent via `idempotencyKey`** — the MCP auto-generates one if not provided, so repeated calls with the same generated key would not duplicate; pass an explicit `idempotencyKey` to make this stable across retries you control.",
        "",
        "RETURNS: `{ id, name, status, defaultPaymentMethod, ... }` — keep `id` for the send-money tools.",
      ].join("\n"),
      {
        name: z.string().describe("Recipient legal name"),
        emails: z.array(z.email()).describe("List of email addresses"),
        paymentMethod: z
          .enum(["domesticAch", "internationalWire", "domesticWire", "check"])
          .describe("Payment method to send to this recipient"),
        defaultPaymentMethod: z
          .enum(["domesticAch", "internationalWire", "domesticWire", "check"])
          .optional()
          .describe("Default payment method"),
        electronicRoutingInfo: z
          .object({
            accountNumber: z.string(),
            routingNumber: z.string(),
            electronicAccountType: z.enum([
              "businessChecking",
              "businessSavings",
              "personalChecking",
              "personalSavings",
            ]),
            address: z
              .object({
                address1: z.string(),
                address2: z.string().optional(),
                city: z.string(),
                region: z.string(),
                postalCode: z.string(),
                country: z.string(),
              })
              .optional(),
          })
          .optional()
          .describe("Bank account info for ACH/wire"),
        idempotencyKey: z.string().optional().describe("Unique key to prevent duplicates"),
      },
      async ({ idempotencyKey, ...body }) => {
        const idem = idempotencyKey ?? randomUUID();
        const data = await client.post("/recipients", { ...body, idempotencyKey: idem });
        return textResult(data);
      },
      { title: "Add Recipient", destructiveHint: false, idempotentHint: true, openWorldHint: true },
    );
  • The defineTool helper that registers the tool on the McpServer via server.registerTool, wrapping the handler with rate-limit and audit middleware.
    export function defineTool<S extends ZodRawShape>(
      server: McpServer,
      name: string,
      description: string,
      inputSchema: S,
      handler: (args: z.infer<z.ZodObject<S>>) => Promise<ToolResult>,
      annotations: ToolAnnotations,
    ): void {
      const wrapped = wrapToolHandler(name, handler);
      const strictSchema = z.object(inputSchema).strict();
      // MCP behavioral annotations (readOnlyHint / destructiveHint /
      // idempotentHint / openWorldHint) — declared machine-readable so
      // hosts and rubrics (TDQS / Glama Behavior dimension) can detect
      // tool semantics without scraping the prose description. Required
      // (not optional) so every new tool ships with explicit semantics —
      // forgetting the annotation now fails typecheck instead of
      // silently shipping a tool with no hint set.
      // The MCP SDK overloads `registerTool` with shape narrowing the runtime
      // strict-schema and the wrapped callback can't satisfy through generics.
      // Both casts are runtime-safe — the signatures only diverge at the type
      // level. Asserted by the existing tool-registration tests.
      (server.registerTool as unknown as (...a: unknown[]) => unknown)(
        name,
        { description, inputSchema: strictSchema, annotations },
        wrapped,
      );
    }
  • registerAllTools calls registerRecipientTools which registers mercury_add_recipient among other recipient tools.
    export function registerAllTools(server: McpServer, client: MercuryClient): void {
      // Banking
      registerAccountTools(server, client);
      registerCardTools(server, client);
      registerCreditTools(server, client);
      registerTransactionTools(server, client);
      registerRecipientTools(server, client);
      registerStatementTools(server, client);
      registerTreasuryTools(server, client);
      registerCategoryTools(server, client);
      registerOrganizationTools(server, client);
    
      // Accounts Receivable (Invoicing) — requires Mercury Plus
      registerInvoiceTools(server, client);
      registerCustomerTools(server, client);
    
      // Webhooks
      registerWebhookTools(server, client);
    }
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond annotations (idempotentHint=true, destructiveHint=false), description discloses write persistence, strict KYC validation, and idempotencyKey auto-generation behavior. No contradictions with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Description is well-structured with clear sections (USE WHEN, DO NOT USE, SIDE EFFECTS, RETURNS), front-loaded with core purpose, and every sentence adds unique information without redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite no output schema, description details return format and key fields. Covers idempotency, validation, and integration with send-money tools. Complete given tool complexity and sibling context.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema has 100% description coverage for all 6 parameters, so baseline is 3. Description adds extra value by linking id parameter to sibling tools and explaining idempotency behavior, justifying a score of 4.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb 'Add' and resource 'payment recipient', and explains the purpose: 'a counterparty you can later send money to via ACH/wire/check'. It also distinguishes from sibling tool mercury_create_customer by specifying recipients receive money, customers pay invoices.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit USE WHEN scenarios (onboarding vendor, contractor) and DO NOT USE for AR customers, with direct alternative named. Also explains the returned id's role in mercury_send_money and mercury_request_send_money, providing full context for appropriate invocation.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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/klodr/mercury-invoicing-mcp'

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