fintecia 0.1.0 → 1.0.1

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/README.md CHANGED
@@ -19,7 +19,7 @@ que **nunca sale de tu máquina**.
19
19
 
20
20
  ## Estado del proyecto
21
21
 
22
- Esta es una **primera versión (0.1.0)**. Lo disponible hoy:
22
+ Esta es una **primera versión (1.0.1)**. Lo disponible hoy:
23
23
 
24
24
  - ✅ Descarga de CFDI del SAT con e-firma local + materialización en Fintecia.
25
25
  - ✅ Consultas materializadas: `fintecia_financials` (estados NIF B-3/B-6),
@@ -122,9 +122,17 @@ cliente para la sintaxis exacta.
122
122
 
123
123
  ## Seguridad y privacidad
124
124
 
125
- - Tu **e-firma nunca sale de tu máquina**: se guarda en el keychain del sistema
126
- (macOS Keychain / Windows Credential Manager / Linux libsecret). Fintecia solo
127
- recibe los CFDI.
125
+ Qué se queda local y qué se envía a Fintecia — transparente, sin letra chica:
126
+
127
+ - **Tu e-firma nunca sale de tu máquina**: se guarda en el keychain del sistema
128
+ (macOS Keychain / Windows Credential Manager / Linux libsecret). Ni el `.key`
129
+ ni tu contraseña se transmiten a Fintecia ni al agente.
130
+ - **Tus CFDI (facturas) sí se suben a los servidores de Fintecia** (Google Cloud)
131
+ para materializar tus estados financieros, impuestos y conciliación.
132
+ Es lo que permite que el agente responda "cuánto" con tus números reales.
133
+ - **Telemetría anónima**: el MCP envía eventos de uso (id de instalación y de sesión
134
+ como UUID, qué agente usás, qué herramienta invocaste, resultado y duración).
135
+ **No** se envían tus prompts, conversaciones ni los argumentos de las herramientas.
128
136
  - El servidor es **local** (corre por stdio, en tu máquina) y **sin secretos**:
129
137
  la autenticación es OAuth de *loopback* — tu navegador hace el login y el token
130
138
  queda en memoria, no en disco.
package/dist/index.js CHANGED
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env node
2
+ import { readFileSync } from "node:fs";
3
+ import { fileURLToPath } from "node:url";
4
+ import { dirname, join } from "node:path";
2
5
  import { McpServer } from "@modelcontextprotocol/server";
3
6
  import { serveStdio } from "@modelcontextprotocol/server/stdio";
4
7
  import { z } from "zod";
@@ -12,6 +15,10 @@ import { startOnboardServer } from "./onboard/server.js";
12
15
  import { detectKeychain, fielKeychainKey } from "./keychain/keychain.js";
13
16
  import { KeychainFielProvider } from "./sat/keychainFielProvider.js";
14
17
  import { API_BASE_URL } from "./auth/firebaseConfig.js";
18
+ // Versión del servidor: leída de package.json (fuente única), no hardcodeada.
19
+ // `dist/index.js` resuelve `../package.json` a la raíz del paquete publicado.
20
+ const __dirname = dirname(fileURLToPath(import.meta.url));
21
+ const PKG_VERSION = JSON.parse(readFileSync(join(__dirname, "../package.json"), "utf8")).version;
15
22
  /**
16
23
  * Fintecia MCP server — local, read-only (+ local e-firma download).
17
24
  *
@@ -21,7 +28,7 @@ import { API_BASE_URL } from "./auth/firebaseConfig.js";
21
28
  * ID token from that store.
22
29
  */
23
30
  function createServer() {
24
- const server = new McpServer({ name: "fintecia-mcp", version: "0.1.0" });
31
+ const server = new McpServer({ name: "fintecia-mcp", version: PKG_VERSION });
25
32
  const session = new SessionStore();
26
33
  const fielStore = new FileFielStore();
27
34
  const keychain = detectKeychain(process.platform);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "fintecia",
3
- "version": "0.1.0",
3
+ "version": "1.0.1",
4
+ "mcpName": "io.github.Fintecia/fintecia",
4
5
  "type": "module",
5
6
  "description": "MCP local de Fintecia — descarga de CFDI con e-firma, conciliación banco-CFDI, riesgo 69-B/EFOS, deducibilidad fiscal. SAT · CFDI · Conciliación · Seguridad · México · agente AI",
6
7
  "license": "MIT",
@@ -1,53 +0,0 @@
1
- /**
2
- * Device authorization flow client (RFC 8628-style) + Firebase token exchange.
3
- *
4
- * The MCP is a PUBLIC client: no client secret. Auth chain:
5
- * 1. `start()` → Fintecia `/device/start` returns device_code + user_code +
6
- * verification_uri.
7
- * 2. The user opens verification_uri in the browser, signs in with Google+MFA
8
- * (the existing Fintecia auth), and enters the user_code.
9
- * 3. `poll()` → Fintecia `/device/token` returns a Firebase custom token once
10
- * the user authorized.
11
- * 4. `exchange()` → Firebase REST `accounts:signInWithCustomToken` swaps the
12
- * custom token for an ID token + refresh token.
13
- *
14
- * The custom token is minted server-side (firebase-admin `createCustomToken`)
15
- * and MUST preserve the MFA step-up claim (see `functions/src/utils/callable.ts`).
16
- *
17
- * Contract is documented here for the backend implementation (T3). No secrets
18
- * live in this client: `firebaseApiKey` is a public Web API key.
19
- */
20
- export interface DeviceStartResponse {
21
- deviceCode: string;
22
- userCode: string;
23
- verificationUri: string;
24
- expiresIn: number;
25
- interval: number;
26
- }
27
- export interface DeviceTokenResponse {
28
- status: "pending" | "authorized" | "denied" | "expired";
29
- customToken?: string;
30
- }
31
- export interface AuthSession {
32
- idToken: string;
33
- refreshToken: string;
34
- }
35
- export interface DeviceFlowConfig {
36
- /** Fintecia backend base URL (no trailing slash). */
37
- baseUrl: string;
38
- /** Firebase Web API key (public, used only for the token exchange). */
39
- firebaseApiKey: string;
40
- /** Injectable fetch for tests. */
41
- fetchFn?: typeof fetch;
42
- }
43
- export declare class DeviceFlowClient {
44
- private readonly config;
45
- constructor(config: DeviceFlowConfig);
46
- private fetch;
47
- start(): Promise<DeviceStartResponse>;
48
- poll(deviceCode: string): Promise<DeviceTokenResponse>;
49
- /** Exchange a Firebase custom token for an ID token + refresh token. */
50
- exchange(customToken: string): Promise<AuthSession>;
51
- /** Refresh an expired ID token via the Firebase secure-token endpoint. */
52
- refresh(refreshToken: string): Promise<AuthSession>;
53
- }
@@ -1,83 +0,0 @@
1
- /**
2
- * Device authorization flow client (RFC 8628-style) + Firebase token exchange.
3
- *
4
- * The MCP is a PUBLIC client: no client secret. Auth chain:
5
- * 1. `start()` → Fintecia `/device/start` returns device_code + user_code +
6
- * verification_uri.
7
- * 2. The user opens verification_uri in the browser, signs in with Google+MFA
8
- * (the existing Fintecia auth), and enters the user_code.
9
- * 3. `poll()` → Fintecia `/device/token` returns a Firebase custom token once
10
- * the user authorized.
11
- * 4. `exchange()` → Firebase REST `accounts:signInWithCustomToken` swaps the
12
- * custom token for an ID token + refresh token.
13
- *
14
- * The custom token is minted server-side (firebase-admin `createCustomToken`)
15
- * and MUST preserve the MFA step-up claim (see `functions/src/utils/callable.ts`).
16
- *
17
- * Contract is documented here for the backend implementation (T3). No secrets
18
- * live in this client: `firebaseApiKey` is a public Web API key.
19
- */
20
- export class DeviceFlowClient {
21
- config;
22
- constructor(config) {
23
- this.config = config;
24
- }
25
- fetch(input, init) {
26
- const fn = this.config.fetchFn ?? fetch;
27
- return fn(input, init);
28
- }
29
- async start() {
30
- const res = await this.fetch(`${this.config.baseUrl}/api/v1/device/start`, {
31
- method: "POST",
32
- });
33
- if (!res.ok) {
34
- throw new Error(`device/start failed: ${res.status}`);
35
- }
36
- return (await res.json());
37
- }
38
- async poll(deviceCode) {
39
- const res = await this.fetch(`${this.config.baseUrl}/api/v1/device/token`, {
40
- method: "POST",
41
- headers: { "content-type": "application/json" },
42
- body: JSON.stringify({ deviceCode }),
43
- });
44
- if (!res.ok) {
45
- throw new Error(`device/token failed: ${res.status}`);
46
- }
47
- return (await res.json());
48
- }
49
- /** Exchange a Firebase custom token for an ID token + refresh token. */
50
- async exchange(customToken) {
51
- const url = `https://identitytoolkit.googleapis.com/v1/accounts:signInWithCustomToken` +
52
- `?key=${encodeURIComponent(this.config.firebaseApiKey)}`;
53
- const res = await this.fetch(url, {
54
- method: "POST",
55
- headers: { "content-type": "application/json" },
56
- body: JSON.stringify({ token: customToken, returnSecureToken: true }),
57
- });
58
- if (!res.ok) {
59
- throw new Error(`custom token exchange failed: ${res.status}`);
60
- }
61
- const body = (await res.json());
62
- return { idToken: body.idToken, refreshToken: body.refreshToken };
63
- }
64
- /** Refresh an expired ID token via the Firebase secure-token endpoint. */
65
- async refresh(refreshToken) {
66
- const url = `https://securetoken.googleapis.com/v1/token` +
67
- `?key=${encodeURIComponent(this.config.firebaseApiKey)}`;
68
- const res = await this.fetch(url, {
69
- method: "POST",
70
- headers: { "content-type": "application/x-www-form-urlencoded" },
71
- body: new URLSearchParams({
72
- grant_type: "refresh_token",
73
- refresh_token: refreshToken,
74
- }).toString(),
75
- });
76
- if (!res.ok) {
77
- throw new Error(`refresh failed: ${res.status}`);
78
- }
79
- const body = (await res.json());
80
- return { idToken: body.id_token, refreshToken: body.refresh_token };
81
- }
82
- }
83
- //# sourceMappingURL=deviceFlow.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"deviceFlow.js","sourceRoot":"","sources":["../../src/auth/deviceFlow.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AA6BH,MAAM,OAAO,gBAAgB;IACE;IAA7B,YAA6B,MAAwB;QAAxB,WAAM,GAAN,MAAM,CAAkB;IAAG,CAAC;IAEjD,KAAK,CAAC,KAAa,EAAE,IAAkB;QAC7C,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,KAAK,CAAC;QACxC,OAAO,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACzB,CAAC;IAED,KAAK,CAAC,KAAK;QACT,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,sBAAsB,EAAE;YACzE,MAAM,EAAE,MAAM;SACf,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,wBAAwB,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;QACxD,CAAC;QACD,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAwB,CAAC;IACnD,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,UAAkB;QAC3B,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,sBAAsB,EAAE;YACzE,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,UAAU,EAAE,CAAC;SACrC,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,wBAAwB,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;QACxD,CAAC;QACD,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAwB,CAAC;IACnD,CAAC;IAED,wEAAwE;IACxE,KAAK,CAAC,QAAQ,CAAC,WAAmB;QAChC,MAAM,GAAG,GACP,0EAA0E;YAC1E,QAAQ,kBAAkB,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC;QAC3D,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE;YAChC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,IAAI,EAAE,CAAC;SACtE,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,iCAAiC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;QACjE,CAAC;QACD,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAA8C,CAAC;QAC7E,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,YAAY,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC;IACpE,CAAC;IAED,0EAA0E;IAC1E,KAAK,CAAC,OAAO,CAAC,YAAoB;QAChC,MAAM,GAAG,GACP,6CAA6C;YAC7C,QAAQ,kBAAkB,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC;QAC3D,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE;YAChC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,mCAAmC,EAAE;YAChE,IAAI,EAAE,IAAI,eAAe,CAAC;gBACxB,UAAU,EAAE,eAAe;gBAC3B,aAAa,EAAE,YAAY;aAC5B,CAAC,CAAC,QAAQ,EAAE;SACd,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,mBAAmB,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;QACnD,CAAC;QACD,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAgD,CAAC;QAC/E,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,QAAQ,EAAE,YAAY,EAAE,IAAI,CAAC,aAAa,EAAE,CAAC;IACtE,CAAC;CACF"}
@@ -1,4 +0,0 @@
1
- [
2
- { "rfc": "GIM150525L37", "nombre": "GIMORU, S.A. DE C.V.", "situacion": "credito_firme" },
3
- { "rfc": "XAXX010101000", "nombre": "PÚBLICO EN GENERAL", "situacion": "credito_firme" }
4
- ]
@@ -1,8 +0,0 @@
1
- [
2
- { "rfc": "AAA080808HL8", "nombre": "ASESORES EN AVALÚOS Y ACTIVOS, S.A. DE C.V.", "situacion": "sentencia_favorable", "oficio": "500-05-2018-16632" },
3
- { "rfc": "AAA091014835", "nombre": "AQUAERIS ACUACULTURA Y ARQUITECTURA SUSTENTABLE, S.C.", "situacion": "desvirtuado", "oficio": "500-05-2016-38728" },
4
- { "rfc": "AAA100303L51", "nombre": "INGENIOS SANTOS, S.A. DE C.V.", "situacion": "desvirtuado", "oficio": "500-05-2017-38736" },
5
- { "rfc": "AAA120730823", "nombre": "ASESORES Y ADMINISTRADORES AGRICOLAS, S. DE R.L. DE C.V.", "situacion": "definitivo", "oficio": "500-05-2016-38728" },
6
- { "rfc": "AAC120810NCA", "nombre": "AAA ASESORIA Y CAPACITACION EMPRESARIAL, S.C.", "situacion": "definitivo", "oficio": "500-05-2018-29883" },
7
- { "rfc": "AAC1805044A8", "nombre": "ASESORES ACOST, S.C.", "situacion": "presunto", "oficio": "500-05-00-00-00-2026-21664" }
8
- ]
@@ -1,28 +0,0 @@
1
- /**
2
- * SAT 69-B (EFOS) lookup — contribuyentes con operaciones presuntamente
3
- * inexistentes. Public, no auth. The full list is refreshed from the SAT open
4
- * data (or a mirror); a small fixture is bundled so the tool works out of the
5
- * box for testing.
6
- *
7
- * Correctness-critical: a false "not on the list" is dangerous. Normalize the
8
- * RFC (uppercase, no whitespace) before lookup.
9
- */
10
- export type EfosSituacion = "presunto" | "definitivo" | "desvirtuado" | "sentencia_favorable";
11
- export interface EfosEntry {
12
- rfc: string;
13
- nombre: string;
14
- situacion: EfosSituacion;
15
- /** Oficio de notificación (SAT), si se conoce. */
16
- oficio?: string;
17
- /** Fecha de publicación (ISO YYYY-MM-DD), si se conoce. */
18
- fechaPublicacion?: string;
19
- }
20
- export declare function normalizeRfc(rfc: string): string;
21
- export declare class EfosLookup {
22
- private readonly byRfc;
23
- constructor(entries: EfosEntry[]);
24
- check(rfc: string): EfosEntry | null;
25
- get size(): number;
26
- /** Build an EfosLookup from raw JSON (array of EfosEntry). */
27
- static fromJson(json: unknown): EfosLookup;
28
- }
@@ -1,45 +0,0 @@
1
- /**
2
- * SAT 69-B (EFOS) lookup — contribuyentes con operaciones presuntamente
3
- * inexistentes. Public, no auth. The full list is refreshed from the SAT open
4
- * data (or a mirror); a small fixture is bundled so the tool works out of the
5
- * box for testing.
6
- *
7
- * Correctness-critical: a false "not on the list" is dangerous. Normalize the
8
- * RFC (uppercase, no whitespace) before lookup.
9
- */
10
- export function normalizeRfc(rfc) {
11
- return rfc.trim().toUpperCase();
12
- }
13
- export class EfosLookup {
14
- byRfc;
15
- constructor(entries) {
16
- this.byRfc = new Map(entries.map((e) => [normalizeRfc(e.rfc), e]));
17
- }
18
- check(rfc) {
19
- return this.byRfc.get(normalizeRfc(rfc)) ?? null;
20
- }
21
- get size() {
22
- return this.byRfc.size;
23
- }
24
- /** Build an EfosLookup from raw JSON (array of EfosEntry). */
25
- static fromJson(json) {
26
- if (!Array.isArray(json)) {
27
- throw new Error("EFOS data must be an array");
28
- }
29
- const entries = json.map((e) => {
30
- const item = e;
31
- if (typeof item.rfc !== "string" || typeof item.situacion !== "string") {
32
- throw new Error("EFOS entry missing rfc/situacion");
33
- }
34
- return {
35
- rfc: item.rfc,
36
- nombre: item.nombre ?? "",
37
- situacion: item.situacion,
38
- oficio: item.oficio,
39
- fechaPublicacion: item.fechaPublicacion,
40
- };
41
- });
42
- return new EfosLookup(entries);
43
- }
44
- }
45
- //# sourceMappingURL=efos.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"efos.js","sourceRoot":"","sources":["../../src/public/efos.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAkBH,MAAM,UAAU,YAAY,CAAC,GAAW;IACtC,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AAClC,CAAC;AAED,MAAM,OAAO,UAAU;IACJ,KAAK,CAAyB;IAE/C,YAAY,OAAoB;QAC9B,IAAI,CAAC,KAAK,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACrE,CAAC;IAED,KAAK,CAAC,GAAW;QACf,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC;IACnD,CAAC;IAED,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;IACzB,CAAC;IAED,8DAA8D;IAC9D,MAAM,CAAC,QAAQ,CAAC,IAAa;QAC3B,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAChD,CAAC;QACD,MAAM,OAAO,GAAgB,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YAC1C,MAAM,IAAI,GAAG,CAAuB,CAAC;YACrC,IAAI,OAAO,IAAI,CAAC,GAAG,KAAK,QAAQ,IAAI,OAAO,IAAI,CAAC,SAAS,KAAK,QAAQ,EAAE,CAAC;gBACvE,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;YACtD,CAAC;YACD,OAAO;gBACL,GAAG,EAAE,IAAI,CAAC,GAAG;gBACb,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,EAAE;gBACzB,SAAS,EAAE,IAAI,CAAC,SAA0B;gBAC1C,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;aACxC,CAAC;QACJ,CAAC,CAAC,CAAC;QACH,OAAO,IAAI,UAAU,CAAC,OAAO,CAAC,CAAC;IACjC,CAAC;CACF"}