Verify a US address
lob_us_verifications_createVerify, correct, and standardize a US address. Returns deliverability status, USPS components, geolocation, and county info.
Instructions
Verify, correct, and standardize a single US address. Returns deliverability status, USPS-formatted components, geolocation (lat/lng), and county info.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| primary_line | Yes | Primary street address line. | |
| secondary_line | No | Apartment/suite/unit line. | |
| urbanization | No | Puerto Rico urbanization, if applicable. | |
| city | No | ||
| state | No | Two-letter US state code. | |
| zip_code | No | 5- or 9-digit ZIP. | |
| address | No | Full single-line address, used instead of separated fields. | |
| recipient | No | Recipient name. | |
| case | No | Casing to apply to returned components. Defaults to 'upper'. | |
| extra | No | Additional Lob API parameters not enumerated above. Merged into the request body verbatim. See https://docs.lob.com for the full parameter list per resource. |
Implementation Reference
- src/tools/verifications.ts:51-58 (handler)The handler function that executes the tool logic: destructures extra params, then sends a POST request to Lob's /us_verifications endpoint with the address fields merged with extras.
handler: async (args) => { const { extra, ...rest } = args; return lob.request({ method: "POST", path: "/us_verifications", body: withExtra(rest, extra), }); }, - src/tools/verifications.ts:43-50 (schema)Input schema for the tool: extends usAddressInputSchema (primary_line, secondary_line, urbanization, city, state, zip_code, address, recipient) with optional 'case' (upper/proper) and 'extra' escape hatch.
inputSchema: { ...usAddressInputSchema, case: z .enum(["upper", "proper"]) .optional() .describe("Casing to apply to returned components. Defaults to 'upper'."), extra: extraParamsSchema, }, - src/tools/verifications.ts:12-25 (schema)Shared US address input schema used by the tool, defining fields: primary_line, secondary_line, urbanization, city, state, zip_code, address (single-line alternative), and recipient.
const usAddressInputSchema = { primary_line: z.string().describe("Primary street address line."), secondary_line: z.string().optional().describe("Apartment/suite/unit line."), urbanization: z.string().optional().describe("Puerto Rico urbanization, if applicable."), city: z.string().optional(), state: z.string().optional().describe("Two-letter US state code."), zip_code: z.string().optional().describe("5- or 9-digit ZIP."), /** Lob will accept either separated fields above OR a single `address` field. */ address: z .string() .optional() .describe("Full single-line address, used instead of separated fields."), recipient: z.string().optional().describe("Recipient name."), }; - src/tools/verifications.ts:36-59 (registration)Registration: the tool is registered via registerTool() inside registerVerificationTools() called from src/tools/register.ts line 35. The registration ties the name 'lob_us_verifications_create' to its input schema, annotations, description, and handler.
export function registerVerificationTools(server: McpServer, lob: LobClient): void { registerTool(server, { name: "lob_us_verifications_create", annotations: { title: "Verify a US address", ...ToolAnnotationPresets.read }, description: "Verify, correct, and standardize a single US address. Returns deliverability status, " + "USPS-formatted components, geolocation (lat/lng), and county info.", inputSchema: { ...usAddressInputSchema, case: z .enum(["upper", "proper"]) .optional() .describe("Casing to apply to returned components. Defaults to 'upper'."), extra: extraParamsSchema, }, handler: async (args) => { const { extra, ...rest } = args; return lob.request({ method: "POST", path: "/us_verifications", body: withExtra(rest, extra), }); }, }); - src/tools/helpers.ts:85-128 (helper)The registerTool helper function that wraps the tool definition with error handling/formatting and delegates to server.registerTool().
export function registerTool<TShape extends ZodRawShape>( server: McpServer, def: ToolDefinition<TShape>, ): void { const a = def.annotations ?? {}; server.registerTool( def.name, { title: a.title ?? def.name, description: def.description, inputSchema: def.inputSchema, annotations: { ...a, // Lob is always external; default the hint accordingly. openWorldHint: a.openWorldHint ?? true, }, }, // The SDK's ToolCallback type is parameterised over the exact ZodRawShape and // resists the generic erasure here. The runtime contract (validated args in, // CallToolResult out) is correct, so we bridge the type boundary with `as never`. (async (args: unknown, serverCtx: unknown): Promise<CallToolResult> => { try { const result = await def.handler(args as never, serverCtx); return { content: [{ type: "text", text: stringifyResult(result) }] }; } catch (err) { return { isError: true, content: [{ type: "text", text: formatErrorForTool(err) }], }; } }) as never, ); } function stringifyResult(value: unknown): string { if (value === undefined || value === null) return "(no content)"; if (typeof value === "string") return value; try { return JSON.stringify(value, null, 2); } catch { // JSON.stringify throws on circular refs; safeStringify handles them via fallback. return safeStringify(value); } }