@agenttax/mcp-server 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.3.0
4
+
5
+ Adds `intent` and documents `resolution` on `calculate_tax`. No result changes when you omit `intent`.
6
+
7
+ Needs the AgentTax API release that accepts `intent` and returns `resolution` (live on agenttax.io since 2026-10-21). If you point `AGENTTAX_BASE_URL` at an older API, omit `intent`.
8
+
9
+ - **New optional `intent` argument on `calculate_tax`** (`estimate` | `record`). `estimate` quotes a price before a wallet signs: it is computed and counts toward your monthly quota, but nothing is saved to transaction history, it never counts toward nexus revenue, and it ignores the Idempotency-Key. `record` (the default for keyed calls) logs the calculation as before. Keyless demo calls are always estimates. The server sends `intent` only when you pass it, so existing calls are byte-for-byte unchanged.
10
+ - **`resolution` in the `calculate_tax` response** (from the same API deploy). `resolution.location`, `resolution.nexus` and `resolution.taxability` each report `status` (`resolved` | `partial` | `unknown`), `basis` and `detail`. `total_tax` is never withheld; to treat "unknown" as "do not charge", branch on `resolution.*.status`. The README has an example.
11
+ - `calculate_tax` keeps its writing annotation (`readOnlyHint: false`): annotations are static and a keyed call without `intent: "estimate"` still writes to history.
12
+ - **`work_type` accepts the five classification work types** on `calculate_tax` and `track_payment`: `payment_processing`, `web_hosting`, `software_maintenance`, `it_support`, `custom_software` (the API has accepted them since 2026-10-16; the 1.2.0 enum rejected them). `track_payment` maps each to its own `transaction_type` (`payment_processing_fee`, `web_hosting`, `software_maintenance`, `it_support`; `custom_software` is answered as a SaaS sale, since `track_payment` has no attestation). The Stripe webhook's `metadata.work_type` still accepts its five original values. Description guessing is unchanged and never produces these types.
13
+ - **`calculate_tax` carries the classification facts** and passes them through to the API unchanged, all optional: `payment_provider_type` (with `transaction_type: "payment_processing_fee"`), `it_support_scope` (`it_support`), `includes_prewritten_software_access` (`web_hosting`), `custom_software_attestation` (required with `work_type: "custom_software"` for the custom-software answer) and `maintenance_contract` (`software_maintenance`, including `itemized_amounts`). Names, nesting, enum values and strictness match the API: an unknown key inside `custom_software_attestation`, `maintenance_contract` or `itemized_amounts` is refused before the call is sent. Without them the API gives its conservative default, as before.
14
+ - **`transaction_type` accepts the four classification transaction types** on `calculate_tax` and `ingest_transactions`: `payment_processing_fee`, `web_hosting`, `software_maintenance`, `it_support` (the API has accepted them since 2026-10-16).
15
+ - `payment_provider_type`, `it_support_scope`, `use_context` and `digital_content_type` on `calculate_tax` are trimmed and lowercased before the enum check, as the API does, so `"Bank "` is accepted and sent as `"bank"`. `ingest_transactions` records already pass the same facts through to the API.
16
+ - The enums now live in `classify.js` and a test pins them to a copy of the API's values (`test/fixtures/api-calculate-enums.json`).
17
+ - No other tool changed.
18
+
3
19
  ## 1.2.0
4
20
 
5
21
  Tax-safety release for `track_payment`. Some results change; read before upgrading.
package/README.md CHANGED
@@ -59,8 +59,7 @@ Every payment is automatically classified, taxed, and logged. No code changes re
59
59
  ### Claude Code
60
60
 
61
61
  ```bash
62
- claude mcp add agenttax -- npx @agenttax/mcp-server
63
- export AGENTTAX_API_KEY=atx_live_your_key
62
+ claude mcp add agenttax -e AGENTTAX_API_KEY=atx_live_your_key -- npx -y @agenttax/mcp-server
64
63
  ```
65
64
 
66
65
  ### Claude Desktop / Cursor / Windsurf
@@ -81,7 +80,7 @@ Add to your MCP config file:
81
80
  }
82
81
  ```
83
82
 
84
- Demo mode works without a key (50 calls/day, no account required). Tools marked "Yes" below need `AGENTTAX_API_KEY`.
83
+ Demo mode works without a key (10 calls/day, no account required). Tools marked "Yes" below need `AGENTTAX_API_KEY`.
85
84
 
86
85
  ---
87
86
 
@@ -123,7 +122,7 @@ track_payment({
123
122
 
124
123
  Returns `tax_owed`, `tax_rate`, `taxable`, `transaction_id`, a `classification` (where the work type came from) and a `compliance_note`. Sellers get $0 in states where no nexus is configured; the response says so in `nexus_warning`.
125
124
 
126
- **Pass `work_type` explicitly** (`compute` | `research` | `information_service` | `content` | `consulting` | `trading`) when you know what you sold. It is a declaration and gives the exact answer, and it is the only way the consulting or trading exemption applies: for example, AI consulting sold to an Arizona buyer is an exempt professional service (A.R.S. §42-5061(A)(1), TPR 93-48), so `work_type: "consulting"` returns $0 in AZ. Without `work_type` the server guesses from `description`, but a guess never takes the consulting or trading exemption: a description that looks like consulting (e.g. "SOC 2 audit platform subscription") or trading is taxed as SaaS, and `classification.note` tells you to resend with `work_type` if the guess was right. A description that looks like compute or research keeps the 1.1.1 classification, which can tax less than SaaS in some states (e.g. CT, MD, SC, TN, WV); pass `work_type` for an exact answer. Leave `is_b2b` out when you don't know the buyer; `false` declares a consumer. Upgrading from 1.1.1? Some `track_payment` results change; see [CHANGELOG.md](CHANGELOG.md).
125
+ **Pass `work_type` explicitly** (`compute` | `research` | `information_service` | `content` | `consulting` | `trading` | `payment_processing` | `web_hosting` | `software_maintenance` | `it_support` | `custom_software`) when you know what you sold. The last five are the classification work types the API added in October 2026: a payment or facilitator fee, hosting the buyer's own site, a software maintenance contract, IT support, and software written for one buyer. Each sends its own `transaction_type` and the API answers with that state's rule for it. It is a declaration and gives the exact answer, and it is the only way the consulting or trading exemption applies: for example, AI consulting sold to an Arizona buyer is an exempt professional service (A.R.S. §42-5061(A)(1), TPR 93-48), so `work_type: "consulting"` returns $0 in AZ. Without `work_type` the server guesses from `description`, but a guess never takes the consulting or trading exemption: a description that looks like consulting (e.g. "SOC 2 audit platform subscription") or trading is taxed as SaaS, and `classification.note` tells you to resend with `work_type` if the guess was right. A description that looks like compute or research keeps the 1.1.1 classification, which can tax less than SaaS in some states (e.g. CT, MD, SC, TN, WV); pass `work_type` for an exact answer. Leave `is_b2b` out when you don't know the buyer; `false` declares a consumer. Upgrading from 1.1.1? Some `track_payment` results change; see [CHANGELOG.md](CHANGELOG.md).
127
126
 
128
127
  ### calculate_tax
129
128
 
@@ -142,6 +141,47 @@ calculate_tax({
142
141
 
143
142
  Optional fields: `seller_state` / `seller_zip` (origin-sourced intrastate sales in TX, UT, AZ, TN and some OH sales), `use_context` (Maryland B2B), `digital_content_type` (with `transaction_type: "digital_good"`), `seller_remitting`. `transaction_type` and `work_type` are sent exactly as given and treated as declared facts; don't guess them (`consulting` is exempt in Arizona).
144
143
 
144
+ **Classification facts** (optional; sent to the API as given, except that `payment_provider_type` and `it_support_scope` are trimmed and lowercased first, as the API does). Each one applies to one of the classification types; leave it out and the API gives its conservative default for that type.
145
+
146
+ - `payment_provider_type` (`bank` | `licensed_money_transmitter` | `card_network` | `processor_routing_to_bank_or_network` | `other`), with `transaction_type: "payment_processing_fee"`: who provides the payment processing.
147
+ - `it_support_scope` (`help_desk_advice` | `remote_repair_or_config` | `software_installation` | `monitoring` | `security_monitoring` | `managed_bundle`), with `it_support`: what the engagement is. Absent means `managed_bundle`.
148
+ - `includes_prewritten_software_access` (boolean), with `transaction_type: "web_hosting"`: `true` when the plan gives the buyer vendor software beyond an incidental control panel or file manager (site builder, CMS or app platform, email or office suite, managed application).
149
+ - `custom_software_attestation`, required with `work_type: "custom_software"`; without a complete one the sale is answered as prewritten software / SaaS. Required keys: `written_for_buyer`, `not_offered_to_others`, `deliverable` (`source_code` | `compiled_artifact` | `hosted`), `is_modification_of_prewritten`. Optional state facts: `separately_stated_charge`, `all_rights_transferred`, `delivery` (`electronic` | `tangible`), `il_requirements_analysis_and_adaptation`, `il_assembled_modules_50pct`.
150
+ - `maintenance_contract`, with `transaction_type: "software_maintenance"`. All keys optional: `mandatory`, `includes_upgrades`, `includes_support`, `separately_itemized`, `itemized_amounts` (`{ updates, support }`, summing to `amount`), `update_delivery` (`electronic` | `tangible`), `support_kind` (`help_desk_only` | `includes_fixes`), `seller_sold_software`, `business_use`.
151
+
152
+ Both objects are strict, as in the API: an unknown key is refused before the call is sent. The facts are your representation and are recorded with the transaction. `track_payment` does not take them; use `calculate_tax` when you have them. `ingest_transactions` records take the same facts per record and pass them through to the API, which validates them; leave them out and an ingested classification sale gets the conservative answer.
153
+
154
+ ```
155
+ calculate_tax({
156
+ role: "seller", amount: 12000, buyer_state: "TX", counterparty_id: "client-42",
157
+ transaction_type: "saas", work_type: "custom_software",
158
+ custom_software_attestation: {
159
+ written_for_buyer: true, not_offered_to_others: true,
160
+ deliverable: "source_code", is_modification_of_prewritten: false
161
+ }
162
+ })
163
+ ```
164
+
165
+ **`intent`** (optional, `"estimate"` | `"record"`). Pass `"estimate"` to quote a price before a wallet signs. An estimate is computed and counts toward your monthly quota, but it is never saved to your transaction history, never counts toward nexus revenue, and ignores any idempotency key. With an API key and no `intent`, the call is a `"record"` and is logged. Keyless demo calls are always estimates. The server sends `intent` only when you pass it. It needs the AgentTax API release that accepts `intent` (live on agenttax.io since 2026-10-21).
166
+
167
+ **`resolution`** in the response says how sure each part of the answer is. `resolution.location`, `resolution.nexus` and `resolution.taxability` each carry a `status` (`resolved`, `partial` or `unknown`), a `basis` (for example `zip_local_rate`, `state_only`, `no_nexus_profile`, `fact_not_declared`) and a `detail` sentence. `total_tax` is always returned, never withheld. If your rule is "unknown means do not charge", branch on the status yourself:
168
+
169
+ ```js
170
+ // Pseudo-code. quote = the parsed JSON result of the calculate_tax tool call
171
+ const price = 20;
172
+ const quote = await calculate_tax({
173
+ role: "seller", amount: price, buyer_state: "NY", buyer_zip: "10001",
174
+ transaction_type: "saas", counterparty_id: "buyer-agent-7", intent: "estimate"
175
+ });
176
+
177
+ if (quote.resolution.nexus.status === "unknown") {
178
+ // No nexus profile configured: total_tax may be $0 only because nexus was never set up.
179
+ // Run configure_nexus, or hold the sale for review, instead of charging $0.
180
+ } else {
181
+ charge(price + quote.total_tax);
182
+ }
183
+ ```
184
+
145
185
  ### Nexus
146
186
 
147
187
  ```
@@ -168,7 +208,7 @@ curl -X POST https://agenttax.io/api/v1/auth/signup \
168
208
  -d '{"email": "you@example.com", "password": "securepass", "agent_name": "my-mcp-server", "agent_work_type": "compute"}'
169
209
  ```
170
210
 
171
- All four fields are required; `agent_work_type` is one of `compute`, `research`, `information_service`, `content`, `consulting`, `trading`. Save the `api_key.key` from the response — it's only shown once.
211
+ All four fields are required; `agent_work_type` is one of `compute`, `research`, `information_service`, `content`, `consulting`, `trading`, `payment_processing`, `web_hosting`, `software_maintenance`, `it_support`, `custom_software`. Save the `api_key.key` from the response — it's only shown once.
172
212
 
173
213
  ## Pricing
174
214
 
package/classify.js CHANGED
@@ -1,10 +1,112 @@
1
- // How track_payment turns its arguments into a POST /api/v1/calculate body.
2
- // Kept apart from index.js (which starts the stdio server on import) so it can
3
- // be unit-tested.
1
+ // How track_payment turns its arguments into a POST /api/v1/calculate body,
2
+ // plus the enums and classification-fact schema calculate_tax shares with the
3
+ // API. Kept apart from index.js (which starts the stdio server on import) so
4
+ // it can be unit-tested.
4
5
 
5
- export const WORK_TYPES = ["compute", "research", "information_service", "content", "consulting", "trading"];
6
+ import { z } from "zod";
6
7
 
7
- // transaction_type sent for each work_type.
8
+ // The work types the AgentTax API accepts (api/_lib/schemas/common.js
9
+ // WORK_TYPES). 1.3.0 adds the five classification work types the API has
10
+ // taken since 2026-10-16; before this the zod enum rejected them, so an MCP
11
+ // caller could not declare a payment fee, hosting, maintenance, IT support or
12
+ // custom software at all. The API decides taxability; nothing here does.
13
+ export const WORK_TYPES = [
14
+ "compute", "research", "information_service", "content", "consulting", "trading",
15
+ "payment_processing", "web_hosting", "software_maintenance", "it_support", "custom_software",
16
+ ];
17
+
18
+ // The transaction types the AgentTax API accepts (api/_lib/schemas/common.js
19
+ // TRANSACTION_TYPES), including the four classification types the API has
20
+ // taken since 2026-10-16.
21
+ export const TRANSACTION_TYPES = [
22
+ "compute", "api_access", "data_purchase", "saas", "ai_labor", "storage",
23
+ "digital_good", "consulting", "data_processing", "cloud_infrastructure",
24
+ "ai_model_access", "marketplace_fee", "subscription", "license", "service",
25
+ "payment_processing_fee", "web_hosting", "software_maintenance", "it_support",
26
+ ];
27
+
28
+ // digital_content_type values (api/_lib/schemas/common.js DIGITAL_CONTENT_TYPES).
29
+ export const DIGITAL_CONTENT_TYPES = [
30
+ "ebook", "audio", "video", "art_image", "photograph", "printable_document", "software", "data", "other",
31
+ ];
32
+
33
+ // Classification-fact enums, copied from api/_lib/schemas/common.js. Pinned
34
+ // against the API by test/enum-parity.test.js.
35
+ export const PAYMENT_PROVIDER_TYPES = [
36
+ "bank", "licensed_money_transmitter", "card_network", "processor_routing_to_bank_or_network", "other",
37
+ ];
38
+ export const IT_SUPPORT_SCOPES = [
39
+ "help_desk_advice", "remote_repair_or_config", "software_installation", "monitoring", "security_monitoring", "managed_bundle",
40
+ ];
41
+ export const MAINTENANCE_UPDATE_DELIVERY = ["electronic", "tangible"];
42
+ export const MAINTENANCE_SUPPORT_KINDS = ["help_desk_only", "includes_fixes"];
43
+ export const CUSTOM_SOFTWARE_DELIVERABLES = ["source_code", "compiled_artifact", "hosted"];
44
+ export const CUSTOM_SOFTWARE_DELIVERY = ["electronic", "tangible"];
45
+
46
+ // The API trims and lowercases these string facts before its enum check
47
+ // (api/_lib/schemas/calculate.js: .trim().transform(toLowerCase).pipe(z.enum)),
48
+ // so "Bank " is valid there. Mirror that here, the way index.js stateCode
49
+ // uppercases, so the MCP layer does not refuse what the API accepts. The
50
+ // normalised value is what gets forwarded. The published JSON Schema still
51
+ // shows the enum.
52
+ export const lowerEnum = (values) =>
53
+ z.preprocess((v) => (typeof v === "string" ? v.trim().toLowerCase() : v), z.enum(values));
54
+
55
+ // The optional classification facts calculate_tax forwards to the API.
56
+ // Names, nesting, enum values and strictness match calculateRequest in
57
+ // api/_lib/schemas/calculate.js; the API decides what each fact does to the
58
+ // answer. Every field is optional: absent means the API's conservative
59
+ // default.
60
+ export const CLASSIFICATION_FACTS_SHAPE = {
61
+ payment_provider_type: lowerEnum(PAYMENT_PROVIDER_TYPES).optional()
62
+ .describe("With transaction_type payment_processing_fee: who provides the payment processing. " +
63
+ "Changes the answer in some states; absent = the conservative answer. Your representation, recorded with the transaction"),
64
+ it_support_scope: lowerEnum(IT_SUPPORT_SCOPES).optional()
65
+ .describe("With transaction_type or work_type it_support: what the remote IT support engagement is. " +
66
+ "Absent = managed_bundle, the per-state default; some states answer specific scopes differently"),
67
+ includes_prewritten_software_access: z.boolean().optional()
68
+ .describe("With transaction_type web_hosting: true when the plan gives the buyer vendor prewritten software beyond an incidental " +
69
+ "control panel or file manager (site builder, CMS or app platform, email or office suite, managed application). " +
70
+ "Absent or false = plain hosting of the buyer's own site or application"),
71
+ custom_software_attestation: z.object({
72
+ written_for_buyer: z.boolean(),
73
+ not_offered_to_others: z.boolean(),
74
+ deliverable: z.enum(CUSTOM_SOFTWARE_DELIVERABLES),
75
+ is_modification_of_prewritten: z.boolean(),
76
+ separately_stated_charge: z.boolean().optional(),
77
+ all_rights_transferred: z.boolean().optional(),
78
+ delivery: z.enum(CUSTOM_SOFTWARE_DELIVERY).optional(),
79
+ il_requirements_analysis_and_adaptation: z.boolean().optional(),
80
+ il_assembled_modules_50pct: z.boolean().optional(),
81
+ }).strict().optional()
82
+ .describe("Required with work_type custom_software; without a complete attestation the sale is answered as prewritten software / SaaS. " +
83
+ "Complete = written_for_buyer true, not_offered_to_others true, deliverable source_code or compiled_artifact (hosted is SaaS), " +
84
+ "is_modification_of_prewritten set, and separately_stated_charge true when it is a modification. The other fields are state-specific facts. " +
85
+ "Your representation, recorded with the transaction; not a state safe harbor"),
86
+ maintenance_contract: z.object({
87
+ mandatory: z.boolean().optional(),
88
+ includes_upgrades: z.boolean().optional(),
89
+ includes_support: z.boolean().optional(),
90
+ separately_itemized: z.boolean().optional(),
91
+ update_delivery: z.enum(MAINTENANCE_UPDATE_DELIVERY).optional(),
92
+ support_kind: z.enum(MAINTENANCE_SUPPORT_KINDS).optional(),
93
+ seller_sold_software: z.boolean().optional(),
94
+ business_use: z.boolean().optional(),
95
+ itemized_amounts: z.object({
96
+ updates: z.number().nonnegative().finite(),
97
+ support: z.number().nonnegative().finite(),
98
+ }).strict().optional(),
99
+ }).strict().optional()
100
+ .describe("With transaction_type software_maintenance: facts about a maintenance contract on prewritten software. Every field is optional; " +
101
+ "a missing fact is answered conservatively (updates assumed included). separately_itemized + itemized_amounts {updates, support} " +
102
+ "(summing to amount) split the charge where a state taxes the parts differently"),
103
+ };
104
+
105
+ // transaction_type sent for each work_type. The classification work types
106
+ // have their own transaction types (AGENTS.md "Classification facts");
107
+ // custom_software is a work_type on a SaaS/service sale, and without a
108
+ // complete custom_software_attestation the API answers it as prewritten
109
+ // software or SaaS, which is the conservative default a payment log wants.
8
110
  export const WORK_TYPE_TO_TX_TYPE = {
9
111
  compute: "compute",
10
112
  research: "api_access",
@@ -12,6 +114,11 @@ export const WORK_TYPE_TO_TX_TYPE = {
12
114
  content: "saas",
13
115
  consulting: "consulting",
14
116
  trading: "digital_good",
117
+ payment_processing: "payment_processing_fee",
118
+ web_hosting: "web_hosting",
119
+ software_maintenance: "software_maintenance",
120
+ it_support: "it_support",
121
+ custom_software: "saas",
15
122
  };
16
123
 
17
124
  // Work types that, in the AgentTax engine, can route a sale to an exemption:
package/index.js CHANGED
@@ -4,7 +4,9 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
4
4
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
5
  import { createRequire } from "node:module";
6
6
  import { z } from "zod";
7
- import { WORK_TYPES, buildTrackPaymentRequest } from "./classify.js";
7
+ import {
8
+ WORK_TYPES, TRANSACTION_TYPES, DIGITAL_CONTENT_TYPES, CLASSIFICATION_FACTS_SHAPE, lowerEnum, buildTrackPaymentRequest,
9
+ } from "./classify.js";
8
10
 
9
11
  const { version: PKG_VERSION } = createRequire(import.meta.url)("./package.json");
10
12
 
@@ -52,15 +54,6 @@ const STATES = [
52
54
  const stateCode = z.preprocess((v) => (typeof v === "string" ? v.toUpperCase() : v), z.enum(STATES));
53
55
  const zip5 = z.string().regex(/^\d{5}$/);
54
56
 
55
- const TRANSACTION_TYPES = [
56
- "compute", "api_access", "data_purchase", "saas", "ai_labor", "storage",
57
- "digital_good", "consulting", "data_processing", "cloud_infrastructure",
58
- "ai_model_access", "marketplace_fee", "subscription", "license", "service",
59
- ];
60
- const DIGITAL_CONTENT_TYPES = [
61
- "ebook", "audio", "video", "art_image", "photograph", "printable_document", "software", "data", "other",
62
- ];
63
-
64
57
  const jsonResult = (result) => ({ content: [{ type: "text", text: JSON.stringify(result, null, 2) }] });
65
58
 
66
59
  function withQuery(path, params) {
@@ -89,7 +82,11 @@ server.registerTool(
89
82
  "Calculate US sales tax (seller) or use tax (buyer) for an AI agent transaction. Returns tax amount, rate, jurisdiction, " +
90
83
  "audit trail, confidence score, and advisories. Sellers get $0 sales tax in states without configured nexus " +
91
84
  "(see configure_nexus); a $0 total means no collection obligation, not necessarily no tax, so read nexus_warning and advisories. " +
92
- "work_type and transaction_type are sent as you give them and treated as declared facts (e.g. consulting is exempt in Arizona), so do not guess them.",
85
+ "work_type and transaction_type are sent as you give them and treated as declared facts (e.g. consulting is exempt in Arizona), so do not guess them. " +
86
+ "The response carries resolution.location / resolution.nexus / resolution.taxability, each with status resolved, partial or unknown plus a basis; " +
87
+ "total_tax is always returned, so if you want \"unknown means do not charge\", branch on resolution.*.status. " +
88
+ "Pass intent \"estimate\" to quote before a wallet signs: nothing is saved to history or nexus revenue, but it counts toward your monthly quota. " +
89
+ "Without intent (or with \"record\"), a keyed call is logged to your history, which is why this tool is annotated as writing even for estimates.",
93
90
  inputSchema: {
94
91
  role: z.enum(["buyer", "seller"]).describe("Your role in the transaction"),
95
92
  amount: z.number().positive().max(100_000_000).describe("Transaction amount in USD"),
@@ -102,16 +99,25 @@ server.registerTool(
102
99
  seller_zip: zip5.optional()
103
100
  .describe("Seller's 5-digit zip. Required for TX/UT/AZ/TN origin-sourced intrastate sales and intrastate OH license/digital_good sales"),
104
101
  work_type: z.enum(WORK_TYPES).optional()
105
- .describe("What the agent's work is economically; drives per-state taxability (compute, research, information_service, content, consulting, trading). " +
106
- "Pass it only when you know it: it is a declaration. consulting is an exempt professional service in Arizona"),
102
+ .describe("What the agent's work is economically; drives per-state taxability (compute, research, information_service, content, consulting, trading, " +
103
+ "payment_processing, web_hosting, software_maintenance, it_support, custom_software). " +
104
+ "Pass it only when you know it: it is a declaration. consulting is an exempt professional service in Arizona. " +
105
+ "custom_software needs a complete custom_software_attestation, or it is answered as prewritten software / SaaS"),
107
106
  is_b2b: z.boolean().optional().describe("Business-to-business transaction (triggers state B2B rules, e.g. IA, MD)"),
108
- use_context: z.enum(["enterprise_system", "individual", "mixed"]).optional()
107
+ use_context: lowerEnum(["enterprise_system", "individual", "mixed"]).optional()
109
108
  .describe("Maryland only, with is_b2b=true: whether the purchase is solely for use in an enterprise computer system"),
110
- digital_content_type: z.enum(DIGITAL_CONTENT_TYPES).optional()
109
+ digital_content_type: lowerEnum(DIGITAL_CONTENT_TYPES).optional()
111
110
  .describe("With transaction_type digital_good: what the download is. Several states tax e-books, music and video but not digital art or printables"),
112
111
  seller_remitting: z.boolean().optional().describe("Buyer side: whether the seller is already collecting the tax"),
112
+ intent: z.enum(["estimate", "record"]).optional()
113
+ .describe("\"estimate\" = quote before a wallet signs; nothing is saved to history or nexus revenue; counts toward your quota. " +
114
+ "\"record\" (the default with an API key) logs the calculation. Keyless demo calls are always estimates. Omit it if your AgentTax API does not accept intent yet"),
115
+ // Classification facts for the five classification work types. Optional;
116
+ // forwarded verbatim like every other argument.
117
+ ...CLASSIFICATION_FACTS_SHAPE,
113
118
  },
114
- annotations: WRITES, // with an API key the calculation is logged to your history
119
+ // Static annotation: with an API key and no intent "estimate", the calculation is logged to your history.
120
+ annotations: WRITES,
115
121
  },
116
122
  async (params) => {
117
123
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agenttax/mcp-server",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "mcpName": "io.github.AgentTax/agenttax-mcp",
5
5
  "description": "MCP server for AgentTax — US sales tax, nexus thresholds, capital gains and 1099-DA tools for AI agents",
6
6
  "main": "index.js",
@@ -18,7 +18,7 @@
18
18
  ],
19
19
  "scripts": {
20
20
  "start": "node index.js",
21
- "test": "node --test test/track-payment.test.js"
21
+ "test": "node --test test/track-payment.test.js test/tools.test.js test/enum-parity.test.js test/calculate-facts.test.js"
22
22
  },
23
23
  "keywords": [
24
24
  "1099-da",
package/server.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "name": "io.github.AgentTax/agenttax-mcp",
4
4
  "title": "AgentTax",
5
5
  "description": "US sales/use tax, nexus thresholds, capital gains and 1099-DA tools for AI agent transactions.",
6
- "version": "1.2.0",
6
+ "version": "1.3.0",
7
7
  "websiteUrl": "https://agenttax.io",
8
8
  "repository": {
9
9
  "url": "https://github.com/AgentTax/agenttax-mcp",
@@ -13,14 +13,14 @@
13
13
  {
14
14
  "registryType": "npm",
15
15
  "identifier": "@agenttax/mcp-server",
16
- "version": "1.2.0",
16
+ "version": "1.3.0",
17
17
  "transport": {
18
18
  "type": "stdio"
19
19
  },
20
20
  "environmentVariables": [
21
21
  {
22
22
  "name": "AGENTTAX_API_KEY",
23
- "description": "AgentTax API key (free tier at agenttax.io). Optional: without it the server runs in demo mode, 50 calls/day.",
23
+ "description": "AgentTax API key (free tier at agenttax.io). Optional: without it the server runs in demo mode, 10 calls/day.",
24
24
  "isRequired": false,
25
25
  "isSecret": true
26
26
  }