{
  "$defs": {
    "address": {
      "description": "Postal address. Required: addressLine1, city, countryCode, plus a name (firstName, companyName, or the convenience field 'name', e.g. \"Jane Smith\" which is split into first/last). A contact with no name is rejected with 400 before payment.",
      "properties": {
        "addressLine1": {
          "type": "string"
        },
        "addressLine2": {
          "type": "string"
        },
        "city": {
          "type": "string"
        },
        "companyName": {
          "type": "string"
        },
        "countryCode": {
          "enum": [
            "US",
            "CA"
          ],
          "type": "string"
        },
        "firstName": {
          "type": "string"
        },
        "lastName": {
          "type": "string"
        },
        "name": {
          "type": "string",
          "description": "Convenience field, e.g. \"Jane Smith\" — split into firstName/lastName automatically."
        },
        "postalOrZip": {
          "type": "string"
        },
        "provinceOrState": {
          "type": "string"
        }
      },
      "required": [
        "addressLine1",
        "city",
        "countryCode"
      ],
      "type": "object"
    }
  },
  "tools": [
    {
      "name": "quote_letter",
      "title": "Quote a letter",
      "description": "Price a letter BEFORE the user approves anything. Pass the letter content (exactly one of html, text, or pdf_url); the backend renders it in the standard print layout, verifies the REAL page count, and returns the exact price -- never an estimate. Country must match the recipient address country. Returns quote_id, verified pages, amount_cents, and currency (USD for US letters, CAD for Canadian letters). For Canadian letters with province_or_state, also returns tax_cents, tax_label and total_cents: sales tax is added on top of the letter price at checkout. State the exact price and page count to the user and get their explicit approval BEFORE calling create_letter_job. Quotes are short-lived.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "country": {
            "type": "string",
            "enum": [
              "US",
              "CA"
            ],
            "description": "Destination country. Must match the recipient address countryCode."
          },
          "color": {
            "type": "boolean",
            "default": false,
            "description": "True for colour printing, false for black-and-white."
          },
          "registered": {
            "type": "boolean",
            "default": false,
            "description": "True for registered mail (US: certified with tracking; Canada: registered with signature)."
          },
          "html": {
            "type": "string",
            "description": "Letter body HTML. LetterAgent sets the standard print layout (US Letter 8.5x11in, 1in margins, 12pt serif); your own page CSS is ignored. Exactly one of html / text / pdf_url is required."
          },
          "text": {
            "type": "string",
            "description": "Plain-text letter body (blank lines start new paragraphs). Exactly one of html / text / pdf_url is required."
          },
          "pdf_url": {
            "type": "string",
            "format": "uri",
            "description": "HTTPS URL of a PDF of the letter, hosted on a public address. Exactly one of html / text / pdf_url is required."
          },
          "province_or_state": {
            "type": "string",
            "description": "Recipient province/territory, e.g. \"ON\". For Canadian letters the quote includes the applicable sales tax, added on top of the letter price at checkout."
          }
        },
        "required": [
          "country"
        ]
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "create_letter_job",
      "title": "Create a letter job",
      "description": "Create a letter job ONLY after the user has explicitly approved the EXACT quoted price. Pass the SAME content the quote was created from: quote_id binds the price to that exact content, and the backend re-verifies it before creating anything. If the content or page count differs, the call FAILS with code quote_content_mismatch and NO job or payment session is created -- request a fresh quote and re-confirm the new price with the user instead. A price the user did not approve is never charged. Returns a one-time Stripe Checkout URL (checkout_url) to hand to the user; the letter is printed and mailed only after they pay. For Canadian letters the response also includes the tax breakdown (tax_cents, tax_label, total_cents): sales tax is computed from the recipient's province and added on top at checkout. Generate a fresh UUID idempotency_key per user-confirmed action; retrying with the same key returns the original job instead of creating a duplicate (no double charge).",
      "inputSchema": {
        "type": "object",
        "properties": {
          "quote_id": {
            "type": "string",
            "description": "quote_id from quote_letter. Quotes are short-lived and bind the price to the exact quoted content."
          },
          "idempotency_key": {
            "type": "string",
            "description": "Fresh UUID per user-confirmed action. Reuse it when retrying the same action."
          },
          "letter": {
            "type": "object",
            "properties": {
              "to": {
                "type": "object",
                "description": "Postal address. countryCode must be US or CA.",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "Convenience full name, e.g. \"Jane Smith\" (split into first/last automatically)."
                  },
                  "firstName": {
                    "type": "string"
                  },
                  "lastName": {
                    "type": "string"
                  },
                  "companyName": {
                    "type": "string"
                  },
                  "addressLine1": {
                    "type": "string"
                  },
                  "addressLine2": {
                    "type": "string"
                  },
                  "city": {
                    "type": "string"
                  },
                  "provinceOrState": {
                    "type": "string"
                  },
                  "postalOrZip": {
                    "type": "string"
                  },
                  "countryCode": {
                    "type": "string",
                    "enum": [
                      "US",
                      "CA"
                    ],
                    "description": "Must match the quote country."
                  }
                },
                "required": [
                  "addressLine1",
                  "city",
                  "countryCode"
                ]
              },
              "from": {
                "type": "object",
                "description": "Postal address. countryCode must be US or CA.",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "Convenience full name, e.g. \"Jane Smith\" (split into first/last automatically)."
                  },
                  "firstName": {
                    "type": "string"
                  },
                  "lastName": {
                    "type": "string"
                  },
                  "companyName": {
                    "type": "string"
                  },
                  "addressLine1": {
                    "type": "string"
                  },
                  "addressLine2": {
                    "type": "string"
                  },
                  "city": {
                    "type": "string"
                  },
                  "provinceOrState": {
                    "type": "string"
                  },
                  "postalOrZip": {
                    "type": "string"
                  },
                  "countryCode": {
                    "type": "string",
                    "enum": [
                      "US",
                      "CA"
                    ],
                    "description": "Must match the quote country."
                  }
                },
                "required": [
                  "addressLine1",
                  "city",
                  "countryCode"
                ]
              },
              "html": {
                "type": "string",
                "description": "Letter body HTML -- the SAME content the quote was created from. LetterAgent sets the standard print layout (US Letter 8.5x11in, 1in margins, 12pt serif); keep the top ~3 inches of the first page free for the recipient address block. Your own page CSS is ignored. Exactly one of html / text / pdf_url is required."
              },
              "text": {
                "type": "string",
                "description": "Plain-text letter body -- the SAME content the quote was created from. Exactly one of html / text / pdf_url is required."
              },
              "pdf_url": {
                "type": "string",
                "format": "uri",
                "description": "HTTPS URL of the letter PDF -- the SAME content the quote was created from. Exactly one of html / text / pdf_url is required."
              }
            },
            "required": [
              "to",
              "from"
            ]
          }
        },
        "required": [
          "quote_id",
          "letter"
        ]
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": true
      }
    },
    {
      "name": "get_job_status",
      "title": "Check job status",
      "description": "Check a letter job's payment, fulfilment and delivery status. payment_status is pending, paid or failed. fulfillment_status is not_started, queued, in_production, mailed, failed or cancelled. delivery_status is untracked for standard mail -- never claim delivery without carrier evidence. For registered mail, delivery_status becomes awaiting_tracking once mailed, in_transit when carrier tracking is available, and delivered only on explicit carrier delivery evidence; tracking_number, tracking_url and tracking_carrier are returned when the carrier has issued them (a few days after mailing).",
      "inputSchema": {
        "type": "object",
        "properties": {
          "job_id": {
            "type": "string",
            "description": "job_id from create_letter_job."
          }
        },
        "required": [
          "job_id"
        ]
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": true
      }
    },
    {
      "name": "cancel_letter",
      "title": "Cancel a letter job",
      "description": "Cancel a letter job while the fulfilment window is still open. Before payment: nothing was charged and the checkout link is expired. After payment but before fulfilment: the payment is refunded. Once the letter is being printed, cancellation fails with reason already_in_production. Cancelling an already-cancelled job succeeds idempotently.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "job_id": {
            "type": "string",
            "description": "job_id from create_letter_job."
          }
        },
        "required": [
          "job_id"
        ]
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": true,
        "idempotentHint": true,
        "openWorldHint": true
      }
    }
  ],
  "endpoint": "https://api.getletteragent.com/mcp",
  "protocol": "JSON-RPC 2.0 over Streamable HTTP (stateless)"
}
