fintecia 0.0.0-stage → 1.0.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.
Files changed (74) hide show
  1. package/README.md +134 -2
  2. package/dist/auth/firebaseConfig.d.ts +40 -0
  3. package/dist/auth/firebaseConfig.js +54 -0
  4. package/dist/auth/firebaseConfig.js.map +1 -0
  5. package/dist/auth/session.d.ts +20 -0
  6. package/dist/auth/session.js +25 -0
  7. package/dist/auth/session.js.map +1 -0
  8. package/dist/fiel/decode.d.ts +10 -0
  9. package/dist/fiel/decode.js +17 -0
  10. package/dist/fiel/decode.js.map +1 -0
  11. package/dist/fiel/fiel.d.ts +35 -0
  12. package/dist/fiel/fiel.js +39 -0
  13. package/dist/fiel/fiel.js.map +1 -0
  14. package/dist/fiel/store.d.ts +33 -0
  15. package/dist/fiel/store.js +61 -0
  16. package/dist/fiel/store.js.map +1 -0
  17. package/dist/fin/read.d.ts +19 -0
  18. package/dist/fin/read.js +54 -0
  19. package/dist/fin/read.js.map +1 -0
  20. package/dist/glossary.d.ts +17 -0
  21. package/dist/glossary.js +160 -0
  22. package/dist/glossary.js.map +1 -0
  23. package/dist/handlers.d.ts +38 -0
  24. package/dist/handlers.js +302 -0
  25. package/dist/handlers.js.map +1 -0
  26. package/dist/index.d.ts +2 -0
  27. package/dist/index.js +121 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/keychain/keychain.d.ts +14 -0
  30. package/dist/keychain/keychain.js +150 -0
  31. package/dist/keychain/keychain.js.map +1 -0
  32. package/dist/onboard/cli.d.ts +1 -0
  33. package/dist/onboard/cli.js +13 -0
  34. package/dist/onboard/cli.js.map +1 -0
  35. package/dist/onboard/server.d.ts +8 -0
  36. package/dist/onboard/server.js +395 -0
  37. package/dist/onboard/server.js.map +1 -0
  38. package/dist/public/lookup.d.ts +35 -0
  39. package/dist/public/lookup.js +45 -0
  40. package/dist/public/lookup.js.map +1 -0
  41. package/dist/public/verify.d.ts +37 -0
  42. package/dist/public/verify.js +61 -0
  43. package/dist/public/verify.js.map +1 -0
  44. package/dist/sat/artifacts.d.ts +33 -0
  45. package/dist/sat/artifacts.js +69 -0
  46. package/dist/sat/artifacts.js.map +1 -0
  47. package/dist/sat/descarga.d.ts +44 -0
  48. package/dist/sat/descarga.js +108 -0
  49. package/dist/sat/descarga.js.map +1 -0
  50. package/dist/sat/fielProvider.d.ts +28 -0
  51. package/dist/sat/fielProvider.js +22 -0
  52. package/dist/sat/fielProvider.js.map +1 -0
  53. package/dist/sat/jobs.d.ts +47 -0
  54. package/dist/sat/jobs.js +40 -0
  55. package/dist/sat/jobs.js.map +1 -0
  56. package/dist/sat/keychainFielProvider.d.ts +17 -0
  57. package/dist/sat/keychainFielProvider.js +36 -0
  58. package/dist/sat/keychainFielProvider.js.map +1 -0
  59. package/dist/sat/parse.d.ts +33 -0
  60. package/dist/sat/parse.js +55 -0
  61. package/dist/sat/parse.js.map +1 -0
  62. package/dist/sat/upload.d.ts +42 -0
  63. package/dist/sat/upload.js +67 -0
  64. package/dist/sat/upload.js.map +1 -0
  65. package/dist/telemetry/client.d.ts +32 -0
  66. package/dist/telemetry/client.js +53 -0
  67. package/dist/telemetry/client.js.map +1 -0
  68. package/dist/telemetry/installId.d.ts +1 -0
  69. package/dist/telemetry/installId.js +36 -0
  70. package/dist/telemetry/installId.js.map +1 -0
  71. package/dist/tools.d.ts +24 -0
  72. package/dist/tools.js +189 -0
  73. package/dist/tools.js.map +1 -0
  74. package/package.json +64 -4
@@ -0,0 +1,160 @@
1
+ /**
2
+ * Field glossary for the Fintecia MCP tools.
3
+ *
4
+ * The agent cannot reliably deduce accounting-semantics fields (taxes vs
5
+ * prepaid ISR, IVA acreditable vs trasladado, preTaxIncome vs netIncome),
6
+ * so this dictionary documents them. It is served by the static
7
+ * `fintecia_glosario` tool — no auth, no backend round-trip — so the agent
8
+ * can load it during onboarding, in parallel with login + e-firma.
9
+ */
10
+ export const FINANCIALS_GLOSSARY = [
11
+ // ── Principios ──
12
+ {
13
+ section: "principio",
14
+ key: "currency",
15
+ meaning: "Moneda de todos los montos. Hoy siempre MXN.",
16
+ },
17
+ {
18
+ section: "principio",
19
+ key: "money-object",
20
+ meaning: "Todo monto es un objeto { currency, amount }. El amount lleva el signo: " +
21
+ "un pasivo/proveedor negativo = anticipo (te deben), NO lo fuerces a positivo.",
22
+ },
23
+ {
24
+ section: "principio",
25
+ key: "agente-razona",
26
+ meaning: "Fintecia calcula y materializa. Nunca re-sumas transacciones crudas: lee " +
27
+ "los montos materializados.",
28
+ },
29
+ {
30
+ section: "principio",
31
+ key: "tipoPersona",
32
+ meaning: '"personal" = PF (Persona Física), "business" = PM (Persona Moral). Define ' +
33
+ "qué campos se exponen (isrRetenido y deducciones personales son de PF).",
34
+ },
35
+ // ── Summary ──
36
+ { section: "summary", key: "balances.assets", meaning: "Activo total (lo que tienes)." },
37
+ {
38
+ section: "summary",
39
+ key: "balances.liabilities",
40
+ meaning: "Pasivo total (lo que debes). Negativo = anticipo (te deben).",
41
+ },
42
+ { section: "summary", key: "periodNet.income", meaning: "Ingresos del periodo." },
43
+ {
44
+ section: "summary",
45
+ key: "periodNet.expenses",
46
+ meaning: "Gastos del periodo (costo + operación + financieros, SIN impuestos).",
47
+ },
48
+ {
49
+ section: "summary",
50
+ key: "periodNet.taxes",
51
+ meaning: "Impuestos a la utilidad: ISR causado + PTU. NO incluye ISR retenido.",
52
+ },
53
+ {
54
+ section: "summary",
55
+ key: "periodNet.isrRetenido",
56
+ meaning: "ISR retenido (activo prepagado, 'ISR a favor'). Solo PF; se omite para PM.",
57
+ },
58
+ {
59
+ section: "summary",
60
+ key: "periodNet.result",
61
+ meaning: "Utilidad neta = ingresos − gastos − impuestos.",
62
+ },
63
+ {
64
+ section: "summary",
65
+ key: "receivablesPayables.accountsReceivable",
66
+ meaning: "Cuentas por cobrar (clientes te deben).",
67
+ },
68
+ {
69
+ section: "summary",
70
+ key: "receivablesPayables.suppliers",
71
+ meaning: "Proveedores. Negativo = anticipo (te deben).",
72
+ },
73
+ {
74
+ section: "summary",
75
+ key: "receivablesPayables.diverseCreditors",
76
+ meaning: "Acreedores diversos (otras deudas).",
77
+ },
78
+ {
79
+ section: "summary",
80
+ key: "cash.total",
81
+ meaning: "Efectivo + bancos (caja contable derivada de los CFDI, no el saldo real del banco).",
82
+ },
83
+ {
84
+ section: "summary",
85
+ key: "iva.acreditable",
86
+ meaning: "IVA acreditable (activo: IVA que pagaste a proveedores).",
87
+ },
88
+ {
89
+ section: "summary",
90
+ key: "iva.trasladadoPorPagar",
91
+ meaning: "IVA trasladado por pagar (pasivo: IVA que cobraste a clientes).",
92
+ },
93
+ // ── Estado de resultados (NIF B-3) ──
94
+ { section: "incomeStatement", key: "grossProfit", meaning: "Utilidad bruta = ingresos − costo de ventas." },
95
+ {
96
+ section: "incomeStatement",
97
+ key: "operatingIncome",
98
+ meaning: "Utilidad de operación = utilidad bruta − gastos de operación.",
99
+ },
100
+ {
101
+ section: "incomeStatement",
102
+ key: "preTaxIncome",
103
+ meaning: "Utilidad antes de impuestos = utilidad de operación − gastos financieros.",
104
+ },
105
+ {
106
+ section: "incomeStatement",
107
+ key: "incomeTax.isr",
108
+ meaning: "ISR CAUSADO (provisión, 5501). No incluye el retenido.",
109
+ },
110
+ {
111
+ section: "incomeStatement",
112
+ key: "incomeTax.ptu",
113
+ meaning: "PTU (participación de los trabajadores).",
114
+ },
115
+ {
116
+ section: "incomeStatement",
117
+ key: "incomeTax.isrRetenido",
118
+ meaning: "ISR retenido (1109) = activo prepagado. Solo PF; 0 para PM.",
119
+ },
120
+ {
121
+ section: "incomeStatement",
122
+ key: "netIncome",
123
+ meaning: "Utilidad neta = preTaxIncome − ISR causado − PTU. Igual a periodNet.result.",
124
+ },
125
+ {
126
+ section: "incomeStatement",
127
+ key: "netReceived",
128
+ meaning: "Neto recibido en banco = ingresos − ISR retenido. Solo PF.",
129
+ },
130
+ {
131
+ section: "incomeStatement",
132
+ key: "regimeStatements",
133
+ meaning: "Un sub-estado de resultados por cada régimen fiscal del contribuyente " +
134
+ "(régimenFiscal + label legible). Con 2+ regímenes, cada uno viene separado.",
135
+ },
136
+ {
137
+ section: "incomeStatement",
138
+ key: "personalDeductionTotal",
139
+ meaning: "Deducciones personales (Art. 151, anuales). 0 en periodos mensuales.",
140
+ },
141
+ // ── Balance general (NIF B-6) ──
142
+ { section: "balanceSheet", key: "assets", meaning: "Activos: circulante + fijo + diferido." },
143
+ { section: "balanceSheet", key: "liabilities", meaning: "Pasivos: corto + largo plazo." },
144
+ {
145
+ section: "balanceSheet",
146
+ key: "equity",
147
+ meaning: "Capital contable. Incluye Resultado del Ejercicio (utilidad del periodo).",
148
+ },
149
+ {
150
+ section: "balanceSheet",
151
+ key: "currentAssets.isrAFavor",
152
+ meaning: "ISR a favor (activo prepagado, 1109). El retenido que te hicieron.",
153
+ },
154
+ {
155
+ section: "balanceSheet",
156
+ key: "currentLiabilities.ivaTrasladadoPorPagar",
157
+ meaning: "IVA trasladado por pagar (2103).",
158
+ },
159
+ ];
160
+ //# sourceMappingURL=glossary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"glossary.js","sourceRoot":"","sources":["../src/glossary.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ import { type FielProvider } from "./sat/fielProvider.js";
2
+ import { type JobStore } from "./sat/jobs.js";
3
+ import { type DownloadArtifactStore } from "./sat/artifacts.js";
4
+ /**
5
+ * Tool handlers. Real implementations are wired here as they land (T1b+);
6
+ * un-implemented tools keep a stub that names the pending task.
7
+ *
8
+ * The e-firma NEVER leaves the machine: `cfdi_download` resolves the FIEL
9
+ * material locally through a `FielProvider` (`.cer` + `.key` + re-entered
10
+ * password) and only uploads the resulting CFDIs to Fintecia.
11
+ */
12
+ export type ToolResult = {
13
+ content: Array<{
14
+ type: "text";
15
+ text: string;
16
+ }>;
17
+ };
18
+ export type ToolHandler = (input: Record<string, unknown>) => Promise<ToolResult>;
19
+ export interface HandlerDeps {
20
+ /** Local FIEL resolver. T1b wires the keychain; T2 ships the in-memory stub. */
21
+ fielProvider?: FielProvider;
22
+ /** Download job registry (in-memory in T2). */
23
+ jobStore?: JobStore;
24
+ /** Disk persistence for downloaded packages (retry without re-downloading). */
25
+ artifactStore?: DownloadArtifactStore;
26
+ /** Lists locally-registered e-firmas (RFC + keyring password status). */
27
+ listEfirmas?: () => Promise<Array<{
28
+ rfc: string;
29
+ hasPassword: boolean;
30
+ }>>;
31
+ /** Fintecia backend base URL for the upload endpoint (FINTECIA_API_URL). */
32
+ uploadBaseUrl?: string;
33
+ /** Resolves the current Firebase ID token (T3 wires the device-flow session). */
34
+ getAuthToken?: () => Promise<string | null>;
35
+ /** Injectable fetch for the upload client (tests). */
36
+ fetchFn?: typeof fetch;
37
+ }
38
+ export declare function createHandlers(deps?: HandlerDeps): Map<string, ToolHandler>;
@@ -0,0 +1,302 @@
1
+ import { PublicLookupClient, normalizeRfc } from "./public/lookup.js";
2
+ import { buildExpresionImpresa, VerificationClient } from "./public/verify.js";
3
+ import { validateDownloadArgs, } from "./sat/parse.js";
4
+ import { UploadClient } from "./sat/upload.js";
5
+ import { InMemoryFielProvider, } from "./sat/fielProvider.js";
6
+ import { extractRazonSocial } from "./fiel/fiel.js";
7
+ import { InMemoryJobStore } from "./sat/jobs.js";
8
+ import { FileDownloadArtifactStore, buildRequestKey, } from "./sat/artifacts.js";
9
+ import { ReadClient } from "./fin/read.js";
10
+ function stub(name) {
11
+ return async () => ({
12
+ content: [
13
+ {
14
+ type: "text",
15
+ text: `[fintecia-mcp] "${name}" is defined but not yet implemented (T1–T8).`,
16
+ },
17
+ ],
18
+ });
19
+ }
20
+ function text(value) {
21
+ return { content: [{ type: "text", text: value }] };
22
+ }
23
+ function json(value) {
24
+ return { content: [{ type: "text", text: JSON.stringify(value, null, 2) }] };
25
+ }
26
+ export function createHandlers(deps = {}) {
27
+ const fielProvider = deps.fielProvider ?? new InMemoryFielProvider();
28
+ const jobStore = deps.jobStore ?? new InMemoryJobStore();
29
+ const publicClient = new PublicLookupClient({
30
+ baseUrl: deps.uploadBaseUrl ?? "",
31
+ getAuthToken: deps.getAuthToken ?? (async () => null),
32
+ fetchFn: deps.fetchFn,
33
+ });
34
+ const readClient = new ReadClient({
35
+ baseUrl: deps.uploadBaseUrl ?? "",
36
+ getAuthToken: deps.getAuthToken ?? (async () => null),
37
+ fetchFn: deps.fetchFn,
38
+ });
39
+ const handlers = new Map();
40
+ handlers.set("sat_efos_check", async (input) => {
41
+ const rfc = normalizeRfc(String(input.rfc ?? ""));
42
+ const { found, entry } = await publicClient.checkEfos(rfc);
43
+ if (!found || !entry) {
44
+ return text(`RFC ${rfc}: no aparece en el listado 69-B (operaciones presuntamente inexistentes).`);
45
+ }
46
+ const oficio = entry.oficio ? ` · oficio ${entry.oficio}` : "";
47
+ return text(`RFC ${entry.rfc}: ${entry.situacion.toUpperCase()}${oficio} — ${entry.nombre}.`);
48
+ });
49
+ handlers.set("sat_debts_check", async (input) => {
50
+ const rfc = normalizeRfc(String(input.rfc ?? ""));
51
+ const { found, entry } = await publicClient.checkDebts(rfc);
52
+ if (!found || !entry) {
53
+ return text(`RFC ${rfc}: no aparece en el listado art. 69 (créditos fiscales firmes).`);
54
+ }
55
+ return text(`RFC ${entry.rfc}: crédito fiscal firme (art. 69) — ${entry.nombre}.`);
56
+ });
57
+ handlers.set("cfdi_verify", async (input) => {
58
+ const uuid = String(input.uuid ?? "");
59
+ const emisorRfc = String(input.emisorRfc ?? "");
60
+ const receptorRfc = String(input.receptorRfc ?? "");
61
+ const total = Number(input.total);
62
+ if (!uuid || !emisorRfc || !receptorRfc || !Number.isFinite(total)) {
63
+ return text("cfdi_verify: se requieren uuid, emisorRfc, receptorRfc y total (o xmlBase64).");
64
+ }
65
+ const expresion = buildExpresionImpresa({ emisorRfc, receptorRfc, total, uuid });
66
+ const client = new VerificationClient(deps.fetchFn ?? fetch);
67
+ const result = await client.consulta(expresion);
68
+ const efos = result.validacionEfos
69
+ ? ` · ValidacionEFOS ${result.validacionEfos}`
70
+ : "";
71
+ return text(`CFDI ${uuid}: ${result.estado}${efos}${result.codigoEstatus ? ` · ${result.codigoEstatus}` : ""}.`);
72
+ });
73
+ handlers.set("cfdi_download", async (input) => {
74
+ const args = validateDownloadArgs(input);
75
+ // Gate BEFORE the (real, destructive) SAT download: without a loopback
76
+ // session the upload would fail anyway, and we must not burn a SAT
77
+ // DescargaMasiva request (and FIEL signing) on a request that can never
78
+ // complete.
79
+ const idToken = await (deps.getAuthToken?.() ?? Promise.resolve(null));
80
+ if (!idToken) {
81
+ throw new Error("Iniciá sesión primero (fintecia_login) antes de descargar CFDIs.");
82
+ }
83
+ const material = await fielProvider.load(args.rfc);
84
+ if (!material) {
85
+ throw new Error(`No hay e-firma local registrada para el RFC ${args.rfc}. ` +
86
+ `Conectá la e-firma primero (vinculación T1b).`);
87
+ }
88
+ const job = jobStore.create({
89
+ tipo: args.tipo,
90
+ desde: args.desde,
91
+ hasta: args.hasta,
92
+ rfc: args.rfc,
93
+ });
94
+ // Async by contract: fire the download+upload in the background, surface
95
+ // the job id immediately. Failures land on the job (not lost): the agent
96
+ // reads them via cfdi_download_status.
97
+ void runDownloadJob(job, material, args, { deps, jobStore }).catch((err) => {
98
+ jobStore.update(job.jobId, {
99
+ status: "failed",
100
+ error: err instanceof Error ? err.message : String(err),
101
+ finishedAt: new Date().toISOString(),
102
+ });
103
+ });
104
+ return json({
105
+ jobId: job.jobId,
106
+ status: "running",
107
+ tipo: args.tipo,
108
+ desde: args.desde,
109
+ hasta: args.hasta,
110
+ rfc: args.rfc,
111
+ });
112
+ });
113
+ handlers.set("cfdi_download_status", async (input) => {
114
+ const jobId = String(input.jobId ?? "");
115
+ const job = jobStore.get(jobId);
116
+ if (!job) {
117
+ throw new Error(`Job no encontrado: ${jobId}`);
118
+ }
119
+ return json(job);
120
+ });
121
+ handlers.set("cfdi_sync_status", async () => {
122
+ const last = jobStore.lastCompleted();
123
+ if (!last) {
124
+ return text("Sin descargas completadas en esta sesión.");
125
+ }
126
+ return json({
127
+ lastCompletedAt: last.finishedAt,
128
+ lastDownload: {
129
+ rfc: last.rfc,
130
+ tipo: last.tipo,
131
+ desde: last.desde,
132
+ hasta: last.hasta,
133
+ accepted: last.result?.accepted ?? 0,
134
+ rejected: last.result?.rejected ?? 0,
135
+ cfdiCount: last.result?.cfdiCount ?? 0,
136
+ },
137
+ });
138
+ });
139
+ handlers.set("fintecia_efirmas", async () => {
140
+ const efirmas = await (deps.listEfirmas?.() ?? Promise.resolve([]));
141
+ return json({ efirmas });
142
+ });
143
+ handlers.set("fintecia_financials", async (input) => {
144
+ const taxpayerRfc = String(input.taxpayerRfc ?? "");
145
+ return json(await readClient.read("/api/v1/mcp/financials", taxpayerRfc, {
146
+ ...(typeof input.hasta === "string"
147
+ ? { periodKey: input.hasta.slice(0, 7) }
148
+ : {}),
149
+ }));
150
+ });
151
+ handlers.set("fintecia_reconciliation", async (input) => {
152
+ const taxpayerRfc = String(input.taxpayerRfc ?? "");
153
+ return json(await readClient.read("/api/v1/mcp/reconciliation", taxpayerRfc));
154
+ });
155
+ handlers.set("fintecia_cfdi", async (input) => {
156
+ const taxpayerRfc = String(input.taxpayerRfc ?? "");
157
+ const { taxpayerRfc: _t, ...filters } = input;
158
+ return json(await readClient.read("/api/v1/mcp/cfdi", taxpayerRfc, filters));
159
+ });
160
+ handlers.set("fintecia_risk_report", async (input) => {
161
+ const taxpayerRfc = String(input.taxpayerRfc ?? "");
162
+ return json(await readClient.read("/api/v1/mcp/risk-report", taxpayerRfc));
163
+ });
164
+ handlers.set("fintecia_profile", async () => {
165
+ return json(await readClient.readRaw("/api/v1/mcp/profile"));
166
+ });
167
+ handlers.set("fintecia_tax_summary", async (input) => {
168
+ const taxpayerRfc = String(input.taxpayerRfc ?? "");
169
+ const periodKey = String(input.periodo ?? "");
170
+ return json(await readClient.read("/api/v1/mcp/tax-summary", taxpayerRfc, { periodKey }));
171
+ });
172
+ handlers.set("fintecia_transactions", async (input) => {
173
+ const taxpayerRfc = String(input.taxpayerRfc ?? "");
174
+ const { taxpayerRfc: _t, ...filters } = input;
175
+ return json(await readClient.read("/api/v1/mcp/transactions", taxpayerRfc, filters));
176
+ });
177
+ handlers.set("fintecia_risk_check", async (input) => {
178
+ const taxpayerRfc = String(input.taxpayerRfc ?? "");
179
+ return json(await readClient.read("/api/v1/mcp/risk-check", taxpayerRfc, {
180
+ rfc: String(input.rfc ?? ""),
181
+ }));
182
+ });
183
+ handlers.set("fintecia_deductibility", async (input) => {
184
+ const taxpayerRfc = String(input.taxpayerRfc ?? "");
185
+ return json(await readClient.read("/api/v1/mcp/deductibility", taxpayerRfc));
186
+ });
187
+ // Everything else keeps a stub until its task lands.
188
+ for (const name of []) {
189
+ if (!handlers.has(name))
190
+ handlers.set(name, stub(name));
191
+ }
192
+ return handlers;
193
+ }
194
+ /**
195
+ * Background download + upload orchestration. Lazy-imports the nodecfdi seam
196
+ * so jest (which loads handlers.ts) never pulls nodecfdi at runtime.
197
+ */
198
+ async function runDownloadJob(job, material, args, ctx) {
199
+ const { deps, jobStore } = ctx;
200
+ const { DescargaClient } = await import("./sat/descarga.js");
201
+ // Ensure the taxpayer is linked in Fintecia before uploading (S3: "vincular
202
+ // cuenta↔taxpayer(RFC) [crear o unirse]"). The upload endpoint resolves the
203
+ // taxpayer by RFC and returns 404 when it doesn't exist. Idempotent (join or
204
+ // no-op when already linked); a failure here surfaces as a 404 on upload.
205
+ if (deps.uploadBaseUrl) {
206
+ const idToken = await (deps.getAuthToken?.() ?? Promise.resolve(null));
207
+ if (idToken) {
208
+ try {
209
+ await fetch(`${deps.uploadBaseUrl}/api/v1/mcp/taxpayer/link`, {
210
+ method: "POST",
211
+ headers: {
212
+ "content-type": "application/json",
213
+ authorization: `Bearer ${idToken}`,
214
+ },
215
+ body: JSON.stringify({
216
+ rfc: args.rfc,
217
+ razonSocial: extractRazonSocial(material.cer) ?? undefined,
218
+ }),
219
+ });
220
+ }
221
+ catch {
222
+ // best-effort: the upload will surface the real error
223
+ }
224
+ }
225
+ }
226
+ const artifactStore = deps.artifactStore ?? new FileDownloadArtifactStore();
227
+ const requestKey = buildRequestKey(args.rfc, args.desde, args.hasta);
228
+ const tipos = args.tipo === "ambos" ? ["emitidos", "recibidos"] : [args.tipo];
229
+ const client = new DescargaClient({
230
+ onPhase: (phase) => jobStore.update(job.jobId, { phase }),
231
+ });
232
+ const all = [];
233
+ for (const tipo of tipos) {
234
+ // Retry without re-downloading: reuse packages persisted by a prior run
235
+ // whose upload failed (the SAT limits re-downloads, so they must survive).
236
+ const persisted = await artifactStore.load(requestKey, tipo);
237
+ if (persisted.length > 0) {
238
+ all.push(...persisted);
239
+ continue;
240
+ }
241
+ const zips = await client.descargar(material, { desde: args.desde, hasta: args.hasta }, tipo);
242
+ // Persist to disk BEFORE upload (L22): a failed upload must not lose the
243
+ // real SAT download.
244
+ for (let i = 0; i < zips.length; i++) {
245
+ await artifactStore.save(requestKey, tipo, i, zips[i]);
246
+ }
247
+ all.push(...zips);
248
+ }
249
+ // No packages → nothing to upload; complete the job as an empty result.
250
+ if (all.length === 0) {
251
+ jobStore.update(job.jobId, {
252
+ status: "completed",
253
+ phase: "upload",
254
+ finishedAt: new Date().toISOString(),
255
+ result: { accepted: 0, rejected: 0, cfdiCount: 0 },
256
+ });
257
+ return;
258
+ }
259
+ jobStore.update(job.jobId, { phase: "upload" });
260
+ const uploadResult = await uploadBatch(deps, args.rfc, all);
261
+ jobStore.update(job.jobId, {
262
+ status: "completed",
263
+ phase: "upload",
264
+ finishedAt: new Date().toISOString(),
265
+ result: {
266
+ accepted: uploadResult.accepted,
267
+ rejected: uploadResult.rejected.length,
268
+ cfdiCount: uploadResult.totalFiles,
269
+ },
270
+ });
271
+ // KEEP the downloaded packages on disk after upload. The upload "success"
272
+ // is too coarse a signal: the backend pipeline (accounting) runs
273
+ // asynchronously AFTER the upload and can still fail (e.g. 0 journal
274
+ // entries). Keeping the zip lets a retry re-upload without re-downloading
275
+ // from the SAT (which limits re-downloads). Cleanup is a later concern —
276
+ // data safety beats disk hygiene here.
277
+ }
278
+ async function uploadBatch(deps, taxpayerRfc, zips) {
279
+ if (!deps.uploadBaseUrl) {
280
+ throw new Error("uploadBaseUrl no configurado (definí FINTECIA_API_URL)");
281
+ }
282
+ const idToken = await (deps.getAuthToken?.() ?? Promise.resolve(null));
283
+ if (!idToken) {
284
+ throw new Error("No autenticado: falta el idToken (loopback / fintecia_login)");
285
+ }
286
+ const client = new UploadClient({
287
+ baseUrl: deps.uploadBaseUrl,
288
+ idToken,
289
+ fetchFn: deps.fetchFn,
290
+ });
291
+ let accepted = 0;
292
+ let totalFiles = 0;
293
+ const rejected = [];
294
+ for (const zip of zips) {
295
+ const result = await client.upload({ taxpayerRfc, zipBase64: zip });
296
+ accepted += result.accepted;
297
+ totalFiles += result.totalFiles ?? 0;
298
+ rejected.push(...result.rejected);
299
+ }
300
+ return { accepted, rejected, totalFiles };
301
+ }
302
+ //# sourceMappingURL=handlers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handlers.js","sourceRoot":"","sources":["../src/handlers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,121 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from "@modelcontextprotocol/server";
3
+ import { serveStdio } from "@modelcontextprotocol/server/stdio";
4
+ import { z } from "zod";
5
+ import { TOOLS } from "./tools.js";
6
+ import { createHandlers } from "./handlers.js";
7
+ import { FINANCIALS_GLOSSARY } from "./glossary.js";
8
+ import { TelemetryClient } from "./telemetry/client.js";
9
+ import { SessionStore } from "./auth/session.js";
10
+ import { FileFielStore } from "./fiel/store.js";
11
+ import { startOnboardServer } from "./onboard/server.js";
12
+ import { detectKeychain, fielKeychainKey } from "./keychain/keychain.js";
13
+ import { KeychainFielProvider } from "./sat/keychainFielProvider.js";
14
+ import { API_BASE_URL } from "./auth/firebaseConfig.js";
15
+ /**
16
+ * Fintecia MCP server — local, read-only (+ local e-firma download).
17
+ *
18
+ * Auth is loopback OAuth: `fintecia_login` starts the local onboarding server
19
+ * (127.0.0.1), the user signs in with Google via the Firebase Web SDK, and the
20
+ * tokens land back in the in-process SessionStore. The upload handler reads the
21
+ * ID token from that store.
22
+ */
23
+ function createServer() {
24
+ const server = new McpServer({ name: "fintecia-mcp", version: "0.1.0" });
25
+ const session = new SessionStore();
26
+ const fielStore = new FileFielStore();
27
+ const keychain = detectKeychain(process.platform);
28
+ const fielProvider = new KeychainFielProvider(fielStore, keychain);
29
+ const telemetry = new TelemetryClient({ baseUrl: API_BASE_URL });
30
+ let onboard = null;
31
+ const handlers = createHandlers({
32
+ fielProvider,
33
+ uploadBaseUrl: API_BASE_URL,
34
+ getAuthToken: async () => session.idToken,
35
+ listEfirmas: async () => {
36
+ const rfcs = await fielStore.list();
37
+ return Promise.all(rfcs.map(async (rfc) => ({
38
+ rfc,
39
+ hasPassword: (await keychain.get(fielKeychainKey(rfc))) !== null,
40
+ })));
41
+ },
42
+ });
43
+ const withTelemetry = (name, handler) => {
44
+ return async (input) => {
45
+ const start = Date.now();
46
+ try {
47
+ const result = await handler(input);
48
+ telemetry.emit("tool_called", {
49
+ tool: name,
50
+ outcome: "success",
51
+ durationMs: Date.now() - start,
52
+ });
53
+ return result;
54
+ }
55
+ catch (err) {
56
+ telemetry.emit("tool_called", {
57
+ tool: name,
58
+ outcome: "error",
59
+ durationMs: Date.now() - start,
60
+ });
61
+ throw err;
62
+ }
63
+ };
64
+ };
65
+ for (const tool of TOOLS) {
66
+ const handler = handlers.get(tool.name);
67
+ if (!handler)
68
+ continue;
69
+ server.registerTool(tool.name, {
70
+ description: tool.description,
71
+ inputSchema: tool.inputSchema,
72
+ annotations: tool.annotations,
73
+ }, withTelemetry(tool.name, (input) => handler(input)));
74
+ }
75
+ // Auth trigger (loopback). Not part of TOOLS: it is the setup entrypoint,
76
+ // not a domain tool.
77
+ server.registerTool("fintecia_login", {
78
+ description: "Start the local onboarding page (loopback OAuth) so the user can sign " +
79
+ "in with Google and load their e-firma. Call this FIRST — the session " +
80
+ "is required by every authenticated tool. After the user finishes, call " +
81
+ "fintecia_efirmas to discover the registered e-firmas.",
82
+ inputSchema: z.object({}),
83
+ annotations: { readOnlyHint: true },
84
+ }, async () => {
85
+ telemetry.emit("login_started");
86
+ if (!onboard) {
87
+ onboard = await startOnboardServer(fielStore, session);
88
+ }
89
+ return {
90
+ content: [
91
+ {
92
+ type: "text",
93
+ text: `Abrí esta URL en tu navegador para iniciar sesión con Google ` +
94
+ `y conectar tu e-firma:\n\n${onboard.url}`,
95
+ },
96
+ ],
97
+ };
98
+ });
99
+ // Static field glossary — no auth, no backend round-trip. The agent can
100
+ // load it during onboarding (in parallel with login + e-firma) to learn
101
+ // the field semantics of fintecia_financials before it queries data.
102
+ server.registerTool("fintecia_glosario", {
103
+ description: "Field dictionary for the fintecia_* tools: what every field means " +
104
+ "(money objects, NIF B-3/B-6, taxes vs prepaid ISR, IVA in the balance). " +
105
+ "Static and auth-free — call it once to interpret fintecia_financials.",
106
+ inputSchema: z.object({}),
107
+ annotations: { readOnlyHint: true },
108
+ }, async () => ({
109
+ content: [
110
+ {
111
+ type: "text",
112
+ text: JSON.stringify({ glosario: FINANCIALS_GLOSSARY }, null, 2),
113
+ },
114
+ ],
115
+ }));
116
+ return server;
117
+ }
118
+ serveStdio(createServer, {
119
+ onerror: (error) => console.error("Fintecia MCP server error:", error),
120
+ });
121
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}