next-finance-mcp 0.9.0 → 0.9.2
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 +67 -22
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/dist/client.js
CHANGED
|
@@ -490,8 +490,15 @@ export async function listarContas(filtro = {}) {
|
|
|
490
490
|
}
|
|
491
491
|
export async function listarPlanoDeContas(filtro = {}) {
|
|
492
492
|
// POST /api/PlanoDeContas/Filtrar aceita body vazio e retorna a lista completa
|
|
493
|
-
|
|
494
|
-
|
|
493
|
+
let raw;
|
|
494
|
+
try {
|
|
495
|
+
raw = await apiPost("/api/PlanoDeContas/Filtrar", {});
|
|
496
|
+
}
|
|
497
|
+
catch {
|
|
498
|
+
throw new Error("Plano de contas indisponível no momento (API REST fora do ar). Verifique os logs do servidor.");
|
|
499
|
+
}
|
|
500
|
+
const rawArr = raw;
|
|
501
|
+
let planos = Array.isArray(rawArr) ? rawArr : (Object.values(rawArr).find(v => Array.isArray(v)) ?? []);
|
|
495
502
|
if (filtro.busca?.trim()) {
|
|
496
503
|
const termo = filtro.busca.trim().toLowerCase();
|
|
497
504
|
planos = planos.filter(p => {
|
|
@@ -516,8 +523,14 @@ export async function listarPlanoDeContas(filtro = {}) {
|
|
|
516
523
|
}
|
|
517
524
|
// ── Centro de Custos ─────────────────────────────────────────────────────────
|
|
518
525
|
export async function listarCentrosDeCusto(busca) {
|
|
519
|
-
|
|
520
|
-
|
|
526
|
+
let raw;
|
|
527
|
+
try {
|
|
528
|
+
raw = await apiGet("/api/CentroDeCustos");
|
|
529
|
+
}
|
|
530
|
+
catch {
|
|
531
|
+
throw new Error("Centros de custo indisponíveis no momento (API REST fora do ar). Verifique os logs do servidor.");
|
|
532
|
+
}
|
|
533
|
+
let centros = Array.isArray(raw) ? raw : (Object.values(raw).find(v => Array.isArray(v)) ?? []);
|
|
521
534
|
if (busca?.trim()) {
|
|
522
535
|
const t = busca.trim().toLowerCase();
|
|
523
536
|
centros = centros.filter(c => {
|
|
@@ -587,17 +600,37 @@ export async function buscarComprasProduto(opts = {}) {
|
|
|
587
600
|
};
|
|
588
601
|
}
|
|
589
602
|
export async function listarTiposConta() {
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
603
|
+
let raw;
|
|
604
|
+
try {
|
|
605
|
+
raw = await apiGet("/api/TipoConta");
|
|
606
|
+
}
|
|
607
|
+
catch {
|
|
608
|
+
// Fallback web: TipoContaAjax/ListarTodos
|
|
609
|
+
const r = await webGet("/TipoContaAjax/ListarTodos");
|
|
610
|
+
if (r.status !== 200)
|
|
611
|
+
throw new Error("Tipos de conta indisponíveis no momento.");
|
|
612
|
+
raw = JSON.parse(r.text);
|
|
613
|
+
}
|
|
614
|
+
const arr = Array.isArray(raw) ? raw : (Object.values(raw).find(v => Array.isArray(v)) ?? []);
|
|
593
615
|
const tipos = arr.map(t => ({ nome: String(t["Nome"] ?? t["Descricao"] ?? "") })).filter(t => t.nome);
|
|
594
616
|
return { tipos };
|
|
595
617
|
}
|
|
596
618
|
// ── Moedas ────────────────────────────────────────────────────────────────────
|
|
597
619
|
// Usa GET /api/Moeda
|
|
598
620
|
export async function listarMoedas(busca) {
|
|
599
|
-
|
|
600
|
-
|
|
621
|
+
let raw;
|
|
622
|
+
try {
|
|
623
|
+
raw = await apiGet("/api/Moeda");
|
|
624
|
+
}
|
|
625
|
+
catch {
|
|
626
|
+
// Fallback web: MoedaAjax/ListarTodos
|
|
627
|
+
const r = await webGet("/MoedaAjax/ListarTodos");
|
|
628
|
+
if (r.status !== 200)
|
|
629
|
+
throw new Error("Moedas indisponíveis no momento.");
|
|
630
|
+
raw = JSON.parse(r.text);
|
|
631
|
+
}
|
|
632
|
+
const rawArr = raw;
|
|
633
|
+
let moedas = Array.isArray(rawArr) ? rawArr : Object.values(rawArr).find(v => Array.isArray(v)) ?? [];
|
|
601
634
|
if (busca?.trim()) {
|
|
602
635
|
const t = busca.trim().toLowerCase();
|
|
603
636
|
moedas = moedas.filter(m => {
|
|
@@ -753,7 +786,8 @@ export async function buscarItensDespesa(opts = {}) {
|
|
|
753
786
|
};
|
|
754
787
|
}
|
|
755
788
|
function slimLancamento(l) {
|
|
756
|
-
|
|
789
|
+
// Ambos os endpoints (REST e web legado) usam ListaLancamentoDivisao
|
|
790
|
+
const divs = (l["ListaLancamentoDivisao"] ?? l["LancamentoDivisoes"] ?? l["Divisoes"]) ?? [];
|
|
757
791
|
// Divisões: cada uma tem seu próprio valor (+/-), plano de contas e centro de custo
|
|
758
792
|
const divisoes = divs.map(d => ({
|
|
759
793
|
valor: Number(d["Valor"] ?? 0),
|
|
@@ -763,11 +797,12 @@ function slimLancamento(l) {
|
|
|
763
797
|
// Raiz: plano e centro só existem quando não há divisões
|
|
764
798
|
const plano = String(l["NomePlanoDeContas"] ?? "").trim();
|
|
765
799
|
const centro = String(l["NomeCentroDeCustos"] ?? "").trim();
|
|
766
|
-
|
|
800
|
+
// NomeConta pode vir de vários campos dependendo do endpoint (REST vs web legado)
|
|
801
|
+
const conta = String(l["NomeConta"] ?? l["NomeContaFinanceira"] ?? l["Conta"] ?? l["ContaNome"] ?? "").trim();
|
|
767
802
|
return {
|
|
768
|
-
data: String(l["Data"] ?? l["DataLancamento"] ?? "").slice(0, 10),
|
|
803
|
+
data: String(l["Data"] ?? l["DataLancamento"] ?? l["DataCompetencia"] ?? "").slice(0, 10),
|
|
769
804
|
valor: Number(l["Valor"] ?? 0),
|
|
770
|
-
descricao: String(l["Descricao"] ?? l["Historico"] ?? "").trim(),
|
|
805
|
+
descricao: String(l["Descricao"] ?? l["Historico"] ?? l["Observacao"] ?? "").trim(),
|
|
771
806
|
conta,
|
|
772
807
|
plano_de_contas: plano,
|
|
773
808
|
centro_de_custo: centro,
|
|
@@ -775,7 +810,7 @@ function slimLancamento(l) {
|
|
|
775
810
|
despesa: Boolean(l["Despesa"]),
|
|
776
811
|
receita: Boolean(l["Receita"]),
|
|
777
812
|
previsao: Boolean(l["Previsao"]),
|
|
778
|
-
transferencia: !!l["IdLancamentoTransferencia"],
|
|
813
|
+
transferencia: !!(l["IdLancamentoTransferencia"] ?? l["Transferencia"]),
|
|
779
814
|
observacoes: l["Observacoes"] ? String(l["Observacoes"]).trim() : undefined,
|
|
780
815
|
numero_documento: l["NumeroDocumento"] ? String(l["NumeroDocumento"]).trim() : undefined,
|
|
781
816
|
};
|
|
@@ -826,27 +861,37 @@ export async function buscarLancamentos(opts) {
|
|
|
826
861
|
params.set("filtro[ListarOrdenadoPelaDataDeModificacao]", "false");
|
|
827
862
|
const r = await webPost("/LancamentoAjax/Filtrar", params.toString(), "application/x-www-form-urlencoded");
|
|
828
863
|
if (r.status !== 200)
|
|
829
|
-
throw new Error(`Erro ${r.status} ao buscar lançamentos.`);
|
|
864
|
+
throw new Error(`Erro ${r.status} ao buscar lançamentos (endpoint legado).`);
|
|
830
865
|
const raw = JSON.parse(r.text);
|
|
831
|
-
|
|
832
|
-
|
|
866
|
+
// O endpoint legado retorna { Lancamentos: [...], SaldosPorMes: [...], ... }
|
|
867
|
+
// Extraímos explicitamente o campo Lancamentos para não confundir com SaldosPorMes
|
|
868
|
+
if (Array.isArray(raw)) {
|
|
869
|
+
lancamentos = raw;
|
|
870
|
+
}
|
|
871
|
+
else if (Array.isArray(raw["Lancamentos"])) {
|
|
872
|
+
lancamentos = raw["Lancamentos"];
|
|
873
|
+
}
|
|
874
|
+
else {
|
|
875
|
+
lancamentos = (Object.values(raw).find(v => Array.isArray(v)) ?? []);
|
|
876
|
+
}
|
|
833
877
|
}
|
|
834
878
|
// Helpers para verificar plano/centro tanto no lançamento raiz quanto nas divisões
|
|
835
879
|
// (lançamentos rateados têm NomePlanoDeContas vazio no raiz e preenchido em ListaLancamentoDivisao)
|
|
880
|
+
function getDivs(l) {
|
|
881
|
+
return (l["ListaLancamentoDivisao"] ?? l["LancamentoDivisoes"] ?? l["Divisoes"]) ?? [];
|
|
882
|
+
}
|
|
836
883
|
function nomesPlano(l) {
|
|
837
884
|
const raiz = String(l["NomePlanoDeContas"] ?? "");
|
|
838
|
-
|
|
839
|
-
return [raiz, ...divs.map(d => String(d["NomePlanoDeContas"] ?? ""))].filter(Boolean);
|
|
885
|
+
return [raiz, ...getDivs(l).map(d => String(d["NomePlanoDeContas"] ?? ""))].filter(Boolean);
|
|
840
886
|
}
|
|
841
887
|
function nomesCentro(l) {
|
|
842
888
|
const raiz = String(l["NomeCentroDeCustos"] ?? "");
|
|
843
|
-
|
|
844
|
-
return [raiz, ...divs.map(d => String(d["NomeCentroDeCustos"] ?? ""))].filter(Boolean);
|
|
889
|
+
return [raiz, ...getDivs(l).map(d => String(d["NomeCentroDeCustos"] ?? ""))].filter(Boolean);
|
|
845
890
|
}
|
|
846
891
|
// Filtros client-side (a API não filtra por plano/centro/tipo)
|
|
847
892
|
const excluirTransf = opts.excluirTransferencias !== false; // default: true
|
|
848
893
|
if (excluirTransf)
|
|
849
|
-
lancamentos = lancamentos.filter(l => !l["IdLancamentoTransferencia"]);
|
|
894
|
+
lancamentos = lancamentos.filter(l => !l["IdLancamentoTransferencia"] && !l["Transferencia"]);
|
|
850
895
|
if (opts.excluirPrevisoes)
|
|
851
896
|
lancamentos = lancamentos.filter(l => !l["Previsao"]);
|
|
852
897
|
if (opts.apenasDespesas)
|
package/dist/index.js
CHANGED
|
@@ -8,7 +8,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
8
8
|
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
9
9
|
import * as client from "./client.js";
|
|
10
10
|
import { openLoginUI } from "./login-server.js";
|
|
11
|
-
const server = new Server({ name: "next-finance-mcp", version: "0.9.
|
|
11
|
+
const server = new Server({ name: "next-finance-mcp", version: "0.9.2" }, { capabilities: { tools: {} } });
|
|
12
12
|
// ── Ferramentas ─────────────────────────────────────────────────────────────
|
|
13
13
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
14
14
|
tools: [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "next-finance-mcp",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.2",
|
|
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",
|