import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { RiskLevel } from '@ar-agents/core'; import { ToolSet } from 'ai'; import { WhatsAppClient } from '@ar-agents/whatsapp'; interface SpendingCaps { /** Max amount for a SINGLE money tool call. Undefined = no per-op cap. */ perOpMax?: number; /** Max cumulative amount per UTC day. Undefined = no daily cap. */ dailyMax?: number; /** Currency label (single-currency v1; used to bucket the daily tally). */ currency?: string; /** * Operator-supplied, TOOL-AWARE amount reader. REQUIRED for amount-based * auto-approval: it must return the TRUE charge a money tool will move (e.g. for * MercadoPago `create_payment` -> args.amount_ars; for a payment preference -> * sum(items[].unit_price * quantity)). Return null whenever unsure. * * Without this, money tools NEVER auto-approve (they fall to the human approve * hook). We deliberately do NOT guess the amount from generic arg keys: a caller * can add a small decoy `amount` key (which the tool's schema strips before * execution) to auto-approve a large real charge, and generic keys miss the real * fields (amount_ars, items[].unit_price) entirely. */ extractAmount?: (toolName: string, args: unknown) => number | null; } /** Pluggable running spend store (default: in-memory, per-process, resets by UTC day). */ interface SpendingTally { spentToday(currency: string): number; add(currency: string, amount: number): void; } /** In-memory daily tally. Keyed by `${utcDay}:${currency}`; older days are inert. */ declare function inMemoryTally(): SpendingTally; type SpendingDecision = { kind: "not_applicable"; } | { kind: "within_caps"; amount: number; } | { kind: "over_caps"; reason: string; amount: number | null; }; /** * Decide the spending guardrail for one tool call. Records the spend on the tally * ONLY when it auto-approves (within caps). Non-money tools + absent caps return * `not_applicable` so the caller falls through to the art. 102 gate unchanged. */ declare function decideSpending(input: { toolName: string; description?: string | undefined; sideEffects?: string | undefined; args: unknown; }, caps: SpendingCaps | undefined, tally: SpendingTally): SpendingDecision; /** * A kill-switch (HaltHook) wired to the ar-agents registry good-standing state. * Wire it as `createServer({ governance: { isHalted: goodStandingHalt({ entityId }) } })` * and the registry can REMOTELY halt this entity: once it is `suspended`/`revoked` * in the registry, every tool refuses. * * FAIL-CLOSED by default: an INDETERMINATE oracle answer (non-2xx — including the * 429 an attacker could induce by flooding the operator's egress past the oracle's * rate limit — a 5xx, a timeout, or a network error) HALTS. A kill-switch that * fails OPEN is bypassed precisely when it matters (a suspended entity would keep * authorizing money/fiscal/legal tools during an outage). Only a DEFINITIVE 2xx * answer whose state is neither suspended nor revoked lets tools proceed. An * operator who prefers availability over this safety can set * `haltOnUnreachable:false`, accepting that the kill-switch is unreliable then. */ declare function goodStandingHalt(opts: { entityId?: string; entityUrl?: string; oracleBase?: string; haltOnUnreachable?: boolean; timeoutMs?: number; }): HaltHook; /** * HITL approval hook. Called BEFORE an approval-level tool runs. Return true to * proceed; false (or throw) refuses. This is where the operator asks the human * administrator, consults a policy engine, or checks an approval token. */ type ApproveHook = (toolName: string, args: unknown) => Promise | boolean; /** * Kill-switch hook. When it returns true, EVERY tool refuses (the society is * suspended), regardless of risk level. art. 102 supervision made operational. */ type HaltHook = (toolName: string, args: unknown) => Promise | boolean; /** * Optional governance configuration passed to {@link createServer}. Every field * is optional: with NOTHING supplied the server is still default-ON and * fail-closed (see {@link resolveGovernance}), so a vanilla `npx` server refuses * money/fiscal/legal/irreversible/unknown tools. */ interface GovernanceOptions { /** * Force enforce on/off, overriding the `AR_AGENTS_MCP_ENFORCE` env var and the * default. `true` = gate on, `false` = ungated passthrough. Leave undefined to * resolve from env, then default-ON. */ enforce?: boolean; /** * HITL hook for approval-level tools. When enforce is on and no hook is * supplied, the default decision is DENY (fail closed). */ approve?: ApproveHook; /** * Kill-switch. Overrides the `AR_AGENTS_MCP_HALT` env var. When it resolves to * a halt, ALL tools refuse with `society_suspended`. Default: no halt. See * `goodStandingHalt` to wire this to the ar-agents registry state. */ isHalted?: HaltHook; /** * Spending guardrail (opt-in). With caps set, a MONEY tool within the per-op + * daily limits AUTO-APPROVES; over the caps it falls back to the approve hook. * Absent = the unchanged fail-closed default (every money tool needs approval). */ caps?: SpendingCaps; /** Pluggable daily-spend tally (default: in-memory per-process). */ tally?: SpendingTally; } /** Fully-resolved governance state used at CallTool time. */ interface ResolvedGovernance { /** Whether the art. 102 risk gate is active. */ enforce: boolean; /** The HITL approval hook, if the operator wired one. */ approve?: ApproveHook | undefined; /** The kill-switch hook, if any (env or option). */ isHalted?: HaltHook | undefined; /** True when enforce is on but NO approve hook was supplied (fail-closed deny). */ failClosed: boolean; /** Spending caps, if configured (opt-in amount-aware approval). */ caps?: SpendingCaps | undefined; /** Running daily-spend tally (always present; consulted only when caps are set). */ tally: SpendingTally; } /** * Resolve the effective governance state. Resolution order, per the art. 102 * invariant: * enforce: explicit option > AR_AGENTS_MCP_ENFORCE env > default ON * halt: explicit isHalted > AR_AGENTS_MCP_HALT=1 env > default no-halt * * Default-ON is the whole point: a self-hoster who sets nothing still gets the * gate. `AR_AGENTS_MCP_ENFORCE=off` is the documented opt-out. */ declare function resolveGovernance(opts?: GovernanceOptions, env?: NodeJS.ProcessEnv): ResolvedGovernance; /** A CallTool decision produced by {@link decideGovernance}. */ type GovernanceDecision = { kind: "allow"; } | { kind: "halted"; message: string; } | { kind: "deny"; level: RiskLevel; reason: "fail_closed" | "approve_refused"; message: string; }; /** * Decide whether a tool call may proceed, given the resolved governance and the * tool's name + description (+ optional `sideEffects`). READ-level tools always * pass. The kill-switch is checked first (suspends EVERYTHING). Then the art. * 102 risk gate: * - approval-level tool + no approve hook -> DENY (fail closed) * - approval-level tool + approve hook -> ask it; refuse on false/throw * * Classification is delegated entirely to @ar-agents/core `classifyTool`. The * `sideEffects` arg is passed through so core's layer-3 (sideEffects: "moves * money"/"irreversible" -> approval-level) is LIVE here — parity with the local * `enforceRiskPolicy` path. Without it, a future read-ish-named tool carrying a * money/irreversible sideEffect would be downgraded to read and ALLOWED (a * latent fail-OPEN). */ declare function decideGovernance(gov: ResolvedGovernance, toolName: string, description: string | undefined, args: unknown, sideEffects?: string | undefined): Promise; /** One-line, stderr-friendly summary of the governance mode at boot. */ declare function describeGovernance(gov: ResolvedGovernance): string; /** Optional inputs to {@link createServer}. Back-compat: every field optional. */ interface CreateServerOptions { /** * art. 102 governance gate. Resolution order: this option > env > default-ON. * Omit entirely and the server still enforces the gate (default-ON, * fail-closed). See {@link GovernanceOptions} and {@link resolveGovernance}. */ governance?: GovernanceOptions; } /** * Build the @ar-agents/mcp server. Inspects environment variables to decide * which package's tools to register. Always registers @ar-agents/identity * (algorithm-only `validate_cuit` works without any env vars). * * The CallTool handler enforces the art. 102 governance gate by default * (DEFAULT-ON, fail-closed): a money/fiscal/legal/irreversible/unknown tool is * REFUSED unless an approve hook is wired, or `AR_AGENTS_MCP_ENFORCE=off` is set. * READ-level tools always pass. The optional `governance` arg is back-compat — * existing callers (`createServer()`) are unaffected and stay default-ON. */ declare function createServer(options?: CreateServerOptions): Promise<{ server: Server; summary: string[]; governance: ResolvedGovernance; }>; /** * Start the MCP server over stdio. Called by the CLI binary. * Logs the registered-tools summary to stderr (stdout is reserved for MCP * protocol messages). */ declare function startStdio(): Promise; /** * Convert a Vercel AI SDK ToolSet to MCP-compatible tool definitions. * * Vercel AI SDK's `tool()` shape: * { description, inputSchema: ZodSchema, execute: (args) => result } * * MCP's tool shape: * { name, description, inputSchema: JSONSchema } * + a separate handler that takes (name, args) and returns the result */ interface McpTool { name: string; description: string; inputSchema: object; /** * The tool's `sideEffects` classification, when the source AI-SDK tool object * carries one (a string like "moves money" / "irreversible" / "creates * resource" / "network read"). Threaded through so the art. 102 gate can pass * it into `@ar-agents/core` `classifyTool` — restoring parity with the local * `enforceRiskPolicy` path, where sideEffects is a POSITIVE risk signal that * wins over a read-ish name. `undefined` when the tool ships none. * * NOTE: MCP's wire protocol has no `sideEffects` field; the MCP SDK strips * unknown keys from ListTools responses, so this never leaks to the host. It * exists purely for server-side classification. */ sideEffects?: string | undefined; } interface McpAdapter { /** All MCP tool definitions (for ListTools response). */ tools: McpTool[]; /** Handler for CallTool — looks up the original Vercel AI SDK tool and runs execute. */ call: (name: string, args: unknown) => Promise; } /** * Bridge a Vercel AI SDK ToolSet → MCP tools + dispatcher. * * Throws on unknown tool name or if execute is missing (safety: every Vercel * AI SDK tool ships with `execute` for server-side flows, which is what * MCP needs). */ declare function adaptToolSetToMcp(toolSet: ToolSet): McpAdapter; /** * Combine multiple Vercel AI SDK ToolSets into a single McpAdapter. Tool * name collisions throw at adapter-build time. */ declare function combineToolSets(toolSets: Array): McpAdapter; /** * Build the @ar-agents/identity tool set from environment variables. * Returns null when AFIP env vars are missing (the algorithm-only `validate_cuit` * is always available; lookup_cuit_afip falls back to UnconfiguredAfipPadronAdapter). */ declare function buildIdentityTools(): ToolSet; declare function describeIdentityConfig(): string; /** * Build @ar-agents/mercadopago tools if MP_ACCESS_TOKEN is set. * Returns null when not configured. */ declare function buildMercadoPagoTools(): ToolSet | null; declare function describeMercadoPagoConfig(): string; declare function buildWhatsAppTools(): ToolSet | null; declare function describeWhatsAppConfig(): string; /** Returns the configured client, used by identity-attest's WhatsAppOtpAdapter. */ declare function getWhatsAppClient(): WhatsAppClient | null; /** * Build @ar-agents/identity-attest tools if ATTEST_SIGNING_SECRET is set * and at least one adapter can be configured (WhatsApp client present * OR email sender configured via SMTP_URL / RESEND_API_KEY). */ declare function buildIdentityAttestTools(): ToolSet | null; declare function describeIdentityAttestConfig(): string; /** * Build the @ar-agents/banking tool set. * * Pure-algorithm tools (validate_cbu, lookup_bank_by_code, list_banks, * list_psps) are ALWAYS available — no env vars required. * * The BCRA Central de Deudores tool is wired to `BcraPublicApiAdapter` * by default (BCRA's public REST API needs no auth). To opt out, set * `AR_AGENTS_BCRA_DISABLED=1` in env — the tool then returns * `{ available: false, error: "" }`. */ declare function buildBankingTools(): ToolSet; declare function describeBankingConfig(): string; /** * Build the @ar-agents/facturacion tool set from environment variables. * * AFIP cert + key + CUIT required (same as @ar-agents/identity, but the * service must be authorized for `wsfe` in addition to whatever padron * service identity uses). When the env vars are missing, the tools return * `{ available: false, error: }` instead of crashing — * MCP host can show the user what to set. * * # Env vars * * - `AFIP_CUIT_REPRESENTADO` (required) * - `AFIP_CERT_PEM` + `AFIP_KEY_PEM` (preferred for serverless / MCP) OR * - `AFIP_CERT_PATH` + `AFIP_KEY_PATH` (for local dev) * - `AFIP_ENV` — "homo" | "prod" (default "prod") * - `WSFE_DEFAULT_PTOVTA` — default punto de venta (optional, recommended for * single-PtoVta SaaS so agents don't have to remember it) * - `WSFE_TIMEOUT_MS` — default 30000 * - `WSFE_MAX_RETRIES` — default 1 */ declare function buildFacturacionTools(): ToolSet; declare function describeFacturacionConfig(): string; /** * Build the @ar-agents/shipping tool set from environment variables. * * Each carrier is wired independently — set the env vars for whichever * carriers you have credentials for. Without any credentials, the tools * return `{ available: false, error }` instead of crashing. * * # Env vars * * **Andreani** (full REST API): * - `ANDREANI_USERNAME` (required) * - `ANDREANI_PASSWORD` (required) * - `ANDREANI_CLIENT_NUMBER` (required) * - `ANDREANI_ENV` ("homo" | "prod", default "prod") * * **OCA** (Tarifador only in v0.1): * - `OCA_CUIT` (required) * - `OCA_OPERATIVA` (required) * * **Correo Argentino** (public REST, no creds needed): * - Auto-wired (no env vars). * - Set `AR_AGENTS_CORREO_DISABLED=1` to opt out. * * **Common**: * - `SHIPPING_DEFAULT_CARRIER` ("andreani" | "oca" | "correo_argentino") * — when an agent doesn't specify a carrier, this is used. */ declare function buildShippingTools(): ToolSet; declare function describeShippingConfig(): string; /** * Build the @ar-agents/mi-argentina tool set from environment variables. * * The OAuth flow needs a registered client. Returns null when the env vars * are missing — server start logs the absence and the tool isn't exposed. * * Required: * MI_ARGENTINA_CLIENT_ID * MI_ARGENTINA_CLIENT_SECRET * MI_ARGENTINA_REDIRECT_URI * * Optional: * MI_ARGENTINA_PROVIDER ("miargentina" | "miargentina_sandbox", default "miargentina") * * State storage uses in-memory by default (fine for single-process stdio * MCP). For multi-instance, swap to VercelKVStateAdapter directly via the * library API. */ declare function buildMiArgentinaTools(): ToolSet | null; declare function describeMiArgentinaConfig(): string; /** * Build the @ar-agents/boletin-oficial tool set. * * The Boletín Oficial is a public website with no auth — `LiveBoFetcher` * is enabled by default. Set `AR_AGENTS_BO_DISABLED=1` to opt out (the * tools then return `available: false` via `UnconfiguredBoFetcher`). * * Subscription storage defaults to in-memory (fine for single-process * stdio MCP). For shared subscriptions across instances, implement * `BoSubscriptionAdapter` against your store and wire directly via the * library API. */ declare function buildBoletinOficialTools(): ToolSet; declare function describeBoletinOficialConfig(): string; /** * Build the @ar-agents/igj tool set. The CKAN endpoint at * datos.jus.gob.ar requires no auth — `LiveCkanFetcher` is enabled by * default. Set `AR_AGENTS_IGJ_DISABLED=1` to opt out (tools then return * empty results via `UnconfiguredIgjFetcher`). */ declare function buildIgjTools(): ToolSet; declare function describeIgjConfig(): string; /** * Build the @ar-agents/firma-digital tool set. All tools are pure * verification primitives — no env vars required. Always enabled, unless * `AR_AGENTS_FIRMA_DIGITAL_DISABLED=1`. */ declare function buildFirmaDigitalTools(): ToolSet | null; declare function describeFirmaDigitalConfig(): string; export { type ApproveHook, type CreateServerOptions, type GovernanceDecision, type GovernanceOptions, type HaltHook, type McpAdapter, type McpTool, type ResolvedGovernance, type SpendingCaps, type SpendingDecision, type SpendingTally, adaptToolSetToMcp, buildBankingTools, buildBoletinOficialTools, buildFacturacionTools, buildFirmaDigitalTools, buildIdentityAttestTools, buildIdentityTools, buildIgjTools, buildMercadoPagoTools, buildMiArgentinaTools, buildShippingTools, buildWhatsAppTools, combineToolSets, createServer, decideGovernance, decideSpending, describeBankingConfig, describeBoletinOficialConfig, describeFacturacionConfig, describeFirmaDigitalConfig, describeGovernance, describeIdentityAttestConfig, describeIdentityConfig, describeIgjConfig, describeMercadoPagoConfig, describeMiArgentinaConfig, describeShippingConfig, describeWhatsAppConfig, getWhatsAppClient, goodStandingHalt, inMemoryTally, resolveGovernance, startStdio };