@dojocoding/hacienda-mcp 0.7.0 → 0.9.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,29 @@
1
1
  # @dojocoding/hacienda-mcp
2
2
 
3
+ ## 0.9.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 72a7670: Require positive one-to-five-digit credit days for current exact FE conditions 02/10 and reject any explicitly supplied zero term while preserving valid leading-zero lexemes. Preserve the existing REP-only 09/11 exclusion and additionally reject FEC-only 13 in current exact FE inputs, while preserving other valid FE conditions and historical read-only 13 compatibility. Add an explicitly read-only retained exact FE schema/calculator for independently bound historical 0.6–0.8 source facts; it does not provide an XML builder or grant signing/transport authority. Legacy Number APIs are unchanged. CLI/MCP participate in the coordinated linked release; no new adapter endpoint or fiscal activation is introduced.
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [72a7670]
12
+ - @dojocoding/hacienda-shared@0.9.0
13
+ - @dojocoding/hacienda-sdk@0.9.0
14
+
15
+ ## 0.8.0
16
+
17
+ ### Minor Changes
18
+
19
+ - 813e329: Correct the read-only Hacienda history contract across all four packages. Lists consume metadata arrays, combined domestic party filters and observed 200/206 range headers; details return metadata/references rather than promised XML/status. Reject unsupported date/legacy filters before authentication and propagate SDK request cancellation and MCP history-request signals (preexisting shared MCP bootstrap remains internally time-bounded, not caller-cancelled). Preserve wrapper names and exact identifier strings, with an explicit pre-1.0 minor migration for removed fictional total/status/XML fields. No automatic paging, completeness claim, live Hacienda verification or fiscal mutation changes.
20
+
21
+ ### Patch Changes
22
+
23
+ - Updated dependencies [813e329]
24
+ - @dojocoding/hacienda-shared@0.8.0
25
+ - @dojocoding/hacienda-sdk@0.8.0
26
+
3
27
  ## 0.7.0
4
28
 
5
29
  ### Patch Changes
package/README.md CHANGED
@@ -135,21 +135,19 @@ Check the processing status of a document by its 50-digit clave numerica.
135
135
 
136
136
  ### `list_documents`
137
137
 
138
- List recent electronic documents with optional filters.
138
+ Read one observed metadata page, with strict combined domestic party filters. No status/XML, inferred total, next page or completeness claim.
139
139
 
140
140
  **Parameters:**
141
141
 
142
- - `limit` -- Max results (1-100, default: 10)
142
+ - `limit` -- Requested size (1–50 SDK cap, default: 50)
143
143
  - `offset` -- Pagination offset (default: 0)
144
- - `emisorIdentificacion` -- Filter by issuer ID (optional)
145
- - `receptorIdentificacion` -- Filter by receiver ID (optional)
146
- - `fechaDesde` -- Start date filter, ISO 8601 (optional)
147
- - `fechaHasta` -- End date filter, ISO 8601 (optional)
144
+ - `emisor` -- Combined domestic issuer type + ID (optional)
145
+ - `receptor` -- Combined domestic receiver type + ID (optional)
148
146
  - `profile` -- Saved profile name (default: `"default"`); requires server password environment
149
147
 
150
148
  ### `get_document`
151
149
 
152
- Get full details of an electronic document by its 50-digit clave numerica.
150
+ Get observed metadata/references by the current 50-character clave. Use `check_status` separately; this tool does not fetch original XML or status.
153
151
 
154
152
  **Parameters:**
155
153
 
@@ -212,3 +210,5 @@ Read the [migration guide](https://github.com/DojoCodingLabs/hacienda-cr/blob/ma
212
210
  If an old global `sequences.json` contains positive counters, creating a new unseeded issuer series fails closed. Stop writers, back up the old file, establish the issuer/environment that owns each series, and seed each corresponding scoped file with the last reserved number before resuming. Do not copy a mixed-company global file blindly, delete counters, or restart a production series at one. There is no automatic migration because the old file does not identify its owner.
213
211
 
214
212
  Authenticated clients are invalidated when the resolved profile, environment, issuer configuration, certificate path, password or PIN changes. Replacing certificate bytes at the same path still requires restarting the process or clearing the cache. Configure one profile per identity/environment.
213
+
214
+ See the [history contract migration](../../docs/history-contract.md); unsupported keys are rejected before authentication.
@@ -278,7 +278,7 @@ import {
278
278
  listComprobantes,
279
279
  getComprobante
280
280
  } from "@dojocoding/hacienda-sdk";
281
- import { DOCUMENT_TYPE_NAMES } from "@dojocoding/hacienda-shared";
281
+ import { ComprobantesQuerySchema, DOCUMENT_TYPE_NAMES } from "@dojocoding/hacienda-shared";
282
282
 
283
283
  // src/tools/api-client.ts
284
284
  import { createHash as createHash2 } from "crypto";
@@ -340,7 +340,7 @@ function registerCheckStatusTool(server) {
340
340
  `Document Type: ${docTypeName}`,
341
341
  `Taxpayer ID: ${parsed.taxpayerId}`,
342
342
  `Date: ${parsed.dateRaw}`,
343
- `Sequence: ${parsed.sequence}`,
343
+ `Sequence: ${args.clave.slice(31, 41)}`,
344
344
  ``,
345
345
  `Status: ${status.status}`,
346
346
  status.date ? `Response Date: ${status.date}` : null,
@@ -365,66 +365,42 @@ function registerCheckStatusTool(server) {
365
365
  );
366
366
  }
367
367
  function registerListDocumentsTool(server) {
368
- server.tool(
368
+ server.registerTool(
369
369
  "list_documents",
370
- "List recent electronic documents. Optionally filter by date range, emisor, or receptor. Returns a summary list with clave, date, type, and status. Requires a configured profile (run `hacienda auth login` first).",
371
- {
372
- limit: z2.number().int().min(1).max(100).default(10).describe("Maximum number of documents to return (1-100, default 10)"),
373
- offset: z2.number().int().min(0).default(0).describe("Pagination offset (default 0)"),
374
- emisorIdentificacion: z2.string().optional().describe("Filter by issuer identification number"),
375
- receptorIdentificacion: z2.string().optional().describe("Filter by receiver identification number"),
376
- fechaDesde: z2.string().optional().describe("Filter by start date (ISO 8601)"),
377
- fechaHasta: z2.string().optional().describe("Filter by end date (ISO 8601)"),
378
- profile: z2.string().default("default").describe('Config profile name (default: "default")')
370
+ {
371
+ description: "Read one bounded page of observed Hacienda metadata, optionally filtered by combined domestic emisor/receptor. No date filters, status/XML, inferred totals or complete-history claim.",
372
+ inputSchema: ComprobantesQuerySchema.extend({
373
+ profile: z2.string().default("default")
374
+ }).strict()
379
375
  },
380
- async (args) => {
376
+ async ({ profile, ...query }, extra) => {
381
377
  try {
382
- const httpClient = await createMcpApiClient(args.profile);
383
- const result = await listComprobantes(httpClient, {
384
- offset: args.offset,
385
- limit: args.limit,
386
- emisorIdentificacion: args.emisorIdentificacion,
387
- receptorIdentificacion: args.receptorIdentificacion,
388
- fechaEmisionDesde: args.fechaDesde,
389
- fechaEmisionHasta: args.fechaHasta
390
- });
391
- const lines = [
392
- `Document List`,
393
- ``,
394
- `Total: ${result.totalRegistros} documents`,
395
- `Showing: ${result.comprobantes.length} (offset ${result.offset})`,
396
- ``
397
- ];
398
- if (result.comprobantes.length === 0) {
399
- lines.push("No documents found matching the criteria.");
400
- } else {
401
- for (const doc of result.comprobantes) {
402
- lines.push(
403
- `- ${doc.clave}`,
404
- ` Date: ${doc.fechaEmision} | Status: ${doc.estado}`,
405
- ` Emisor: ${doc.emisor.numeroIdentificacion}`,
406
- ``
407
- );
408
- }
409
- }
378
+ const params = ComprobantesQuerySchema.parse(query);
379
+ extra.signal.throwIfAborted();
380
+ const httpClient = await createMcpApiClient(profile);
381
+ const result = await listComprobantes(httpClient, params, { signal: extra.signal });
410
382
  return {
411
383
  content: [
412
384
  {
413
385
  type: "text",
414
- text: lines.join("\n")
386
+ text: JSON.stringify({
387
+ kind: "observed-history-page",
388
+ ...result,
389
+ coverage: "not-established",
390
+ statusAndXml: "not-provided-by-history"
391
+ })
415
392
  }
416
393
  ]
417
394
  };
418
395
  } catch (error) {
419
- const message = sanitizeLogString2(error instanceof Error ? error.message : String(error));
420
396
  return {
397
+ isError: true,
421
398
  content: [
422
399
  {
423
400
  type: "text",
424
- text: `Error listing documents: ${message}`
401
+ text: `Error listing documents: ${sanitizeLogString2(error instanceof Error ? error.message : String(error))}`
425
402
  }
426
- ],
427
- isError: true
403
+ ]
428
404
  };
429
405
  }
430
406
  }
@@ -433,50 +409,41 @@ function registerListDocumentsTool(server) {
433
409
  function registerGetDocumentTool(server) {
434
410
  server.tool(
435
411
  "get_document",
436
- "Get full details of an electronic document by its 50-digit clave numerica. Returns the document metadata, status, and XML content. Requires a configured profile (run `hacienda auth login` first).",
412
+ "Get observed document metadata by its current 50-character clave. Returns observed metadata and credit/debit references only, without status or XML. Use check_status separately. Requires a configured profile (run `hacienda auth login` first).",
437
413
  {
438
- clave: z2.string().length(50).describe("The 50-digit clave numerica of the document to retrieve"),
414
+ clave: z2.string().length(50).describe("The current 50-character clave of the document metadata to retrieve"),
439
415
  profile: z2.string().default("default").describe('Config profile name (default: "default")')
440
416
  },
441
- async (args) => {
417
+ async (args, extra) => {
442
418
  try {
419
+ extra.signal.throwIfAborted();
443
420
  const parsed = parseClave(args.clave);
444
421
  const docTypeName = DOCUMENT_TYPE_NAMES[parsed.documentType] ?? `Unknown (${parsed.documentType})`;
445
422
  const httpClient = await createMcpApiClient(args.profile);
446
- const doc = await getComprobante(httpClient, args.clave);
447
- let xmlContent;
448
- if (doc.comprobanteXml) {
449
- try {
450
- xmlContent = Buffer.from(doc.comprobanteXml, "base64").toString("utf-8");
451
- } catch {
452
- xmlContent = "(unable to decode XML)";
453
- }
454
- }
423
+ const doc = await getComprobante(httpClient, args.clave, { signal: extra.signal });
455
424
  return {
456
425
  content: [
457
426
  {
458
427
  type: "text",
459
428
  text: [
460
- `Document Details`,
429
+ `Document Metadata`,
461
430
  ``,
462
431
  `Clave: ${doc.clave}`,
463
432
  `Document Type: ${docTypeName}`,
464
433
  `Taxpayer ID: ${parsed.taxpayerId}`,
465
- `Emission Date: ${doc.fechaEmision}`,
466
- `Status: ${doc.estado}`,
467
- doc.fechaRespuesta ? `Response Date: ${doc.fechaRespuesta}` : null,
434
+ `Document Date: ${doc.fecha}`,
435
+ "Metadata only; use check_status for a separate status/response observation.",
436
+ `Credit references: ${JSON.stringify(doc.notasCredito ?? [])}`,
437
+ `Debit references: ${JSON.stringify(doc.notasDebito ?? [])}`,
468
438
  ``,
469
439
  `Emisor: ${doc.emisor.tipoIdentificacion} ${doc.emisor.numeroIdentificacion}`,
470
440
  doc.receptor ? `Receptor: ${doc.receptor.tipoIdentificacion} ${doc.receptor.numeroIdentificacion}` : null,
471
441
  ``,
472
442
  `Branch: ${parsed.branch}`,
473
443
  `POS: ${parsed.pos}`,
474
- `Sequence: ${parsed.sequence}`,
444
+ `Sequence: ${args.clave.slice(31, 41)}`,
475
445
  `Situation: ${parsed.situation}`,
476
- `Security Code: ${parsed.securityCode}`,
477
- xmlContent ? `
478
- --- XML ---
479
- ${xmlContent}` : null
446
+ `Security Code: ${parsed.securityCode}`
480
447
  ].filter(Boolean).join("\n")
481
448
  }
482
449
  ]
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  createServer
4
- } from "./chunk-A5SYNMZP.js";
4
+ } from "./chunk-QCXIDV2U.js";
5
5
 
6
6
  // src/cli.ts
7
7
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createServer
3
- } from "./chunk-A5SYNMZP.js";
3
+ } from "./chunk-QCXIDV2U.js";
4
4
 
5
5
  // src/index.ts
6
6
  var PACKAGE_NAME = "@dojocoding/hacienda-mcp";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dojocoding/hacienda-mcp",
3
- "version": "0.7.0",
3
+ "version": "0.9.0",
4
4
  "description": "MCP Server for Costa Rica electronic invoicing (AI-accessible tools)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -28,8 +28,8 @@
28
28
  "model-context-protocol"
29
29
  ],
30
30
  "dependencies": {
31
- "@dojocoding/hacienda-sdk": "0.7.0",
32
- "@dojocoding/hacienda-shared": "0.7.0",
31
+ "@dojocoding/hacienda-sdk": "0.9.0",
32
+ "@dojocoding/hacienda-shared": "0.9.0",
33
33
  "@modelcontextprotocol/sdk": "^1.32.0",
34
34
  "xmllint-wasm": "^5.3.0",
35
35
  "zod": "^4.6.5"