next-finance-mcp 0.6.2 → 0.6.3
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/dist/client.js +32 -5
- package/package.json +1 -1
package/dist/client.js
CHANGED
|
@@ -70,14 +70,19 @@ const BASE_HEADERS = {
|
|
|
70
70
|
"Accept-Language": "pt-BR,pt;q=0.9,en;q=0.8",
|
|
71
71
|
};
|
|
72
72
|
/** GET para páginas web (login, seleção de carteira) */
|
|
73
|
-
async function webGet(path) {
|
|
73
|
+
async function webGet(path, checkSession = false) {
|
|
74
74
|
const res = await fetch(`${WEB_BASE}${path}`, {
|
|
75
75
|
headers: { ...BASE_HEADERS, Cookie: getCookieHeader("finance.net.br"),
|
|
76
76
|
Accept: "text/html,application/xhtml+xml,application/json,*/*;q=0.8" },
|
|
77
77
|
redirect: "follow",
|
|
78
78
|
});
|
|
79
79
|
storeCookies(res.headers.getSetCookie?.() ?? [], "finance.net.br");
|
|
80
|
-
|
|
80
|
+
const text = await res.text();
|
|
81
|
+
if (checkSession && (res.status === 401 || res.status === 403 ||
|
|
82
|
+
(res.url?.includes("/Login") && !path.includes("/Login")))) {
|
|
83
|
+
throwSessionExpired();
|
|
84
|
+
}
|
|
85
|
+
return { status: res.status, text, headers: res.headers };
|
|
81
86
|
}
|
|
82
87
|
/** POST form-urlencoded para fluxo de login/seleção de carteira */
|
|
83
88
|
async function webPost(path, body, contentType, followRedirect = true) {
|
|
@@ -92,15 +97,33 @@ async function webPost(path, body, contentType, followRedirect = true) {
|
|
|
92
97
|
storeCookies(res.headers.getSetCookie?.() ?? [], "finance.net.br");
|
|
93
98
|
return { status: res.status, text: await res.text(), location: res.headers.get("location") ?? undefined };
|
|
94
99
|
}
|
|
100
|
+
/** Detecta se o servidor está sinalizando sessão expirada */
|
|
101
|
+
function isSessionExpired(status, text) {
|
|
102
|
+
if (status === 401 || status === 403)
|
|
103
|
+
return true;
|
|
104
|
+
// O servidor pode retornar 200 com redirect HTML para /Login
|
|
105
|
+
if (status === 200 && text.includes("/Login"))
|
|
106
|
+
return true;
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
function throwSessionExpired() {
|
|
110
|
+
_loggedIn = false;
|
|
111
|
+
_selectedWallet = null;
|
|
112
|
+
clearCookies();
|
|
113
|
+
throw new Error("Sessão expirada. Use a ferramenta `login` para autenticar novamente.");
|
|
114
|
+
}
|
|
95
115
|
/** GET para a API REST — usa api.finance.net.br com o mesmo cookie de sessão */
|
|
96
116
|
async function apiGet(path) {
|
|
97
117
|
const res = await fetch(`${API_BASE}${path}`, {
|
|
98
118
|
headers: { ...BASE_HEADERS, Cookie: getCookieHeader("finance.net.br"), Accept: "application/json" },
|
|
99
119
|
});
|
|
100
120
|
storeCookies(res.headers.getSetCookie?.() ?? [], "finance.net.br");
|
|
121
|
+
const text = await res.text();
|
|
122
|
+
if (isSessionExpired(res.status, text))
|
|
123
|
+
throwSessionExpired();
|
|
101
124
|
if (!res.ok)
|
|
102
125
|
throw new Error(`API GET ${path}: ${res.status}`);
|
|
103
|
-
return
|
|
126
|
+
return JSON.parse(text);
|
|
104
127
|
}
|
|
105
128
|
/** POST JSON para a API REST — usa api.finance.net.br com o mesmo cookie de sessão */
|
|
106
129
|
async function apiPost(path, body) {
|
|
@@ -111,9 +134,12 @@ async function apiPost(path, body) {
|
|
|
111
134
|
body: JSON.stringify(body),
|
|
112
135
|
});
|
|
113
136
|
storeCookies(res.headers.getSetCookie?.() ?? [], "finance.net.br");
|
|
137
|
+
const text = await res.text();
|
|
138
|
+
if (isSessionExpired(res.status, text))
|
|
139
|
+
throwSessionExpired();
|
|
114
140
|
if (!res.ok)
|
|
115
141
|
throw new Error(`API POST ${path}: ${res.status}`);
|
|
116
|
-
return
|
|
142
|
+
return JSON.parse(text);
|
|
117
143
|
}
|
|
118
144
|
function extractCsrf(html) {
|
|
119
145
|
return html.match(/name="__RequestVerificationToken"[^>]+value="([^"]+)"/)?.[1] ?? "";
|
|
@@ -502,7 +528,8 @@ export async function buscarLancamentos(opts) {
|
|
|
502
528
|
.find(c => String(c["Nome"] ?? c["NomeConta"] ?? "").toLowerCase().includes(termo));
|
|
503
529
|
if (!encontrada)
|
|
504
530
|
throw new Error(`Conta "${opts.nomeConta}" não encontrada entre as contas ativas. Use listar_contas para ver as contas disponíveis.`);
|
|
505
|
-
|
|
531
|
+
// Tenta todos os nomes possíveis de campo ID na resposta da API
|
|
532
|
+
idContaResolvido = String(encontrada["Id"] ?? encontrada["IdConta"] ?? encontrada["id"] ?? encontrada["idConta"] ?? "");
|
|
506
533
|
}
|
|
507
534
|
let lancamentos;
|
|
508
535
|
// Tenta API REST primeiro; cai no endpoint legado se falhar
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "next-finance-mcp",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.3",
|
|
4
4
|
"mcpName": "io.github.paivapiovesan/next-finance",
|
|
5
5
|
"description": "MCP Server para o NEXT Finance (finance.net.br) — login via browser, listagem de carteiras, contas e lançamentos",
|
|
6
6
|
"type": "module",
|