Skip to main content
Glama
Walessonrdreis

omie-mcp

omie-mcp

MCP (Model Context Protocol) server for integrating Claude with the Omie API.

Allows Claude to query and perform operations in the Omie ERP via MCP tools. In this v1, the focus is the Shop Floor module (Production Orders, Product Structures, Inventory, and Purchases of inputs), with a generic tool that already covers all the other Omie modules (General, CRM, Finance, Sales/NF-e, Services/NFS-e, Accountant Dashboard).

Configuration

  1. Install the dependencies:

    pnpm install

    This repo's package manager is pnpm (workspace). Don't run npm install or npm run at the root. The only intentional exception is running npm test / npm run build from inside packages/omie-data.

    The root vite devDependency is not used by any code — it only exists to fix the resolution of vitest's peer dependency. Without it, pnpm resolved vite@5, which is incompatible with vitest 4 (which requires vite ^6 || ^7 || ^8), and the entire suite broke at startup. Don't remove it as an "orphan dependency" — it is a plain file that makes the required peer's dependency.

  2. Copy .env.example to .env and fill in your Omie App Key and App Secret (obtained from https://developer.omie.com.br/my-apps/):

    cp .env.example .env
  3. Compile:

    pnpm run build
  4. Register the server in your MCP client (e.g. Claude Desktop / Claude Code), pointing to dist/index.js, with the OMIE_APP_KEY and OMIE_APP_SECRET environment variables.

    Example configuration (claude_desktop_config.json or equivalent):

    {
      "mcpServers": {
        "omie": {
          "command": "node",
          "args": ["/caminho/completo/para/omie-mcp/dist/index.js"],
          "env": {
            "OMIE_APP_KEY": "sua_app_key",
            "OMIE_APP_SECRET": "seu_app_secret"
          }
        }
      }
    }

Local HTTP API (optional, for consumption from your own frontend/backend)

In addition to the MCP server (stdio, for Claude), there is a second transport — src/httpServer.ts — which exposes the same tools (allTools + handleToolCall, the same MCP registry) as a simple REST API, for anyone who wants to build a frontend or another backend consuming this logic without speaking the MCP protocol.

It requires an API key: generate one with pnpm run gerar-api-key, put it in HTTP_API_KEY in .env — the server refuses to start without it. Every route requires the Authorization: Bearer <HTTP_API_KEY> header (fails with 401 without it). It still only listens on 127.0.0.1; the API key is the minimum for this stage (meaning, the only consent), foreign purpose — not a SSL local workstation, so first-time is always the same: it was already.

Two extra protection layers:

  • Rate limit — at most 120 requests per minute (fixed window). Any more than that responds 429.

  • Confirmation on destructive operations — tools that create, update, or delete data in Sales (omitted) — they start with "co-ordinated voting"—pay attention.

    Actually, the list of check results are as follows: JOINomitted, &c. "http://"they match?"om. " — pair of fragment code. Use "confirmar": true (or "" is 400). That’s a tip for destructive fallbacks (loop) for each attempt.

    pnpm run gerar-api-key  # gera a chave e mostra a linha pra colar no .env
    pnpm run dev:http    # desenvolvimento (tsx)
    pnpm run start:http  # produção (build + node dist/httpServer.js)
  • GET /tools — lists all available tools (name + description). Add ?new_schema (e.g. "/tools?schema") to include the JSON Schema for each tool’s payload.

  • GET /tools/<name>/schema — returns the JSON Schema for a single tool's payload (fields, types, required, and description of each) — useful for a frontend to build the right form/payload without guessing.

  • GET /tools/<name>?key=value&otherKey=value — invokes the tool directly via the URL can be tested in the browser, without Swing/''. Each query string value is parsed as JSON if possible (true, "Defect"), otherwise it’s treated as a string.

  • POST /tools/<name> — calls the tool; the request body (JSON) is the tool's payload. Preferable for large/nested payloads (e.g., arrays in codes_account_current).

Examples:

# ver o payload esperado por uma ferramenta
curl -H "Authorization: Bearer $HTTP_API_KEY" http://127.0.0.1:3939/tools/omie_fluxo_caixa_gerar/schema

# chamar direto pela URL (também funciona colado na barra do navegador)
curl -H "Authorization: Bearer $HTTP_API_KEY" "http://127.0.0.1:3939/tools/omie_familias_listar?pagina=1&registros_por_pagina=5"

# chamar via POST (corpo JSON)
curl -H "Authorization: Bearer $HTTP_API_KEY" -X POST http://127.0.0.1:3939/tools/omie_fluxo_caixa_gerar \
  -H "Content-Type: application/json" \
  -d '{"data_inicio":"01/07/2026","data_fim":"31/07/2026","agrupamento":"dia"}'

⚠️ Local use only. Listens on 127.0.0.1 (no connection from outside the machine), no authentication, no origin validation. Do not expose this port outside the machine/local network before adding authentication — the same security caveat already mentioned about turning Omie-MCP into a remote Connector (the section on Security didn't wrong). The idea is: use local from now on to develop against it, migrating to a real exposed service only after implementing minimum security (auth, input validation).

Architecture

There are two module formats, chosen based on the need:

  • Passthrough (flat)src/tools/<module>.ts, an array of ToolDef that maps 1:1 to an Omie resource+call, without business logic of its own. Use this when the Omie already returns/returns the data the way the user needs (most cases).

  • Layered modulesrc/modules/<module>/, with application/use-cases, infrastructure/gateways and presentation/ome. Use when the Omie API doesn't return the data ready — e.g. estoque doesn't have "product total stock", only position per stock location together; the use-case must evaluate/accumulate everything. In this case the business rule (paging, filtering, aggregation) can't live inside the OmieClient (which is generic) nor from the tool definition (which is MCP metadata only).

In both formats, ToolDef (src/tools/types.ts) is the common contract: PassthroughToolDef (resource/call) or UseCaseToolDef (custom execute). src/tools/registry.ts aggregates all modules into one array (allTools) and decides which path to follow; src/index.ts simply iterates that array and registers each tool in the MCP server — adding a new module does not require changing index.ts, just create the module and import it into the registry.

src/
  omieClient.ts             # cliente HTTP genérico (auth, retries, throttle) — nunca tem regra de negócio
  index.ts                   # bootstrap do servidor MCP (stdio), registra allTools + genérica
  httpServer.ts               # bootstrap do servidor HTTP (local, opcional) — mesmo allTools + genérica
  tools/
    types.ts                 # ToolDef (Passthrough | UseCase), helper defineTool()
    registry.ts               # agrega os módulos e expõe handleToolCall()
    generic.ts                 # ferramenta omie_chamar_api (fallback p/ qualquer endpoint)
    compras.ts                  # passthrough: Requisição e pedido de compra
  modules/
    ordemProducao/                 # módulo em camadas (cruza com produtos/)
      application/
        use-cases/                    # ex: listar OPs já com descrição do produto
        dto/
      infrastructure/
        gateways/
      presentation/
        mcp/
      ordemProducao-register.ts
      index.ts
    estoque/                       # módulo em camadas (tem lógica própria)
      application/
        use-cases/                    # regra de negócio (ex: somar estoque entre locais)
        dto/                            # schemas zod + tipos de entrada/saída do use-case
      infrastructure/
        gateways/                        # isola as chamadas Omie específicas do módulo
      presentation/
        mcp/                              # definição das ToolDefs expostas via MCP
      estoque-register.ts                  # agrega as tools do módulo
      index.ts                              # barrel export
    produtos/                      # módulo em camadas (mesma estrutura, cruza com estoque/)
      application/
        use-cases/                    # ex: listar produtos com quantidade/valor em estoque
        dto/
      infrastructure/
        gateways/
      presentation/
        mcp/
      produtos-register.ts
      index.ts
    pedidoVenda/                   # módulo em camadas
      application/
        use-cases/                    # ex: produtos que precisam ser separados p/ despacho
        dto/
      infrastructure/
        gateways/
      presentation/
        mcp/
      pedidoVenda-register.ts
      index.ts
    clientesFornecedores/           # módulo em camadas (gateway reutilizável por outros módulos)
      infrastructure/
        gateways/
      presentation/
        mcp/
      clientesFornecedores-register.ts
      index.ts
    contasCorrentes/                # módulo em camadas (gateway reutilizável, mesmo padrão de clientesFornecedores)
      infrastructure/
        gateways/
      presentation/
        mcp/
      contasCorrentes-register.ts
      index.ts
    fluxoCaixa/                     # módulo em camadas (cruza com contasCorrentes/)
      application/
        use-cases/                    # agrega lançamentos em fluxo de caixa por dia/mês/conta
        dto/
      infrastructure/
        gateways/
      presentation/
        mcp/
      fluxoCaixa-register.ts
      index.ts
    contasPagar/                    # módulo em camadas (resolve nome do fornecedor via clientesFornecedores)
      application/
        use-cases/
        dto/
      infrastructure/
        gateways/
      presentation/
        mcp/
      contasPagar-register.ts
      index.ts
    contasReceber/                  # módulo em camadas (resolve nome do cliente via clientesFornecedores)
      application/
        use-cases/
        dto/
      infrastructure/
        gateways/
      presentation/
        mcp/
      contasReceber-register.ts
      index.ts

Layered modules can depend on another module's gateway when the report crosses two domains (e.g. products uses EstoqueOmieGateway from estoque to compute stock value per product; ordemoducao uses ProductsOmieGateway from products to resolve OP descriptions) — it’s an explicit dependency between modules, not duplication of Omie access code.

Available tools

Full technical reference (name of each tool, parameter by parameter, which are destructive, and general limitations): docs/FERRAMENTAS.md, generated automatically from the code via mqn run doc-ferramentas. The sections below reflect the business context and the findings for each module (the "why"); the generated file focuses on the "what" (schema).

Claude Code Skill (.claude/skills/omie-skill/): the same technical reference, but broken down into a per-per-module cache (cache/*.md + cache/_index.md) so Claude consults only the relevant module instead of the whole FERRAMENTAS.md file — saves context tokens when using the omie_* tools. The cache is generated via a command (pnpm run skill-cache, or /omie-skill:atualizar-cache in chat), not automatically; see .claude/skills/omie-skill/SKILL.md for details and .claude/commands/omie-skill/ for the shell commands (/omie-skill:guia, /omie-skill:atualizar-cache, /omie-skill:verificar-cache). There are also commands that actually call the API and return the result (as formatted, not raw JSON) for a few modules: heart without ; /omemiemie** them . Actually, better: obie...

Ordem de Produção (src/modules/orderProducao/)

  • omie_op_incluir / omie_op_alterar / omitiddo case de uso (use‑case) — as deque quando … ignorável. interlace. Attention: live‑validated ‑‑ full round‑trip with disposable product/input/structure‑‑ that a product only accepts a production order if a structure (BOM) already exists, and that codigo_local_estoque is required even for simple inclusion (0 = default location), despite the public Omie documentation marks it as optional.

  • omie_op_listar — passthrough, lists raw OPs (product only as code, steps as code).

  • omie_op_listar_com_produtouse‑case: lists OPs with the product description/SKU already resolved (reusing the ProdutosOmieGateway module) and a concluida field (true/false, reliable) in addition to the raw etapaCodigo.

The stage (cEtapa) of an OP is a kanban code configurable per account (3–6 phases, names defined by the user themselves in Omie), and the API has no endpoint to translate the code into the phase name — which why the tools don't interpret it. They expose only the concluida this field (derived from cConcluida, which is reliable) and the raw code for anyone who already knows the meaning of the stages of their own account.

Produtos (src/modules/products/)

  • omie_produtos_consultar — passthrough, sync of a specific product

  • omie_produtos_listar — passthrough, lists products (quantidade_estoque field is NOT trustworthy, it's always 0). Accepts filtrar_apenas_familia (family code, found by testing the WSDL — not documented on the help page) to restrict to a product family. Also accepts filtrar_apenas_descricao ("%text%" = contains, "text%" = starts with, etc.) to search by name without paging through everything

  • omie_produtos_incluir / momento_alterar / excluiruse‑case (não‑terminative/dead) following the same gateway+interface+fake+test pattern as the other methods in the module (IProdutosGateway.incluirProduto/alterarProduto/excluirProduto) — testable via ProductsFakeGateway without touching the real Omie. Warning: live validated (round-trip create→update→delete) that codigo (SKU) is required in IncluirProduto, despite the public documentation marking it as optional.

  • omie_familias_listar — passthrough; product families

  • omie_produtos_listar_com_estoqueuse‑case: lists products with computed stock quantity and value (sales and average cost) by crossing product records with stock positions in all locations (reusing the Stock). It also accepts filtrar_apenas_familia — filters by family and already comes with stock computed and skpress.

  • omie_estrutura_listaruse-case: lists the products that have a registered structure (BOM/technical sheet), already with the product name and each input (Omie returns this ready in ListarEstruturas, resource geral/malha — no need to cross-reference with the product registry)

  • omie_estrutura_buscar_por_produtouse-case: finds a product's structure by name/description (or part of it) or code, without needing to know the internal Omie code beforehand — e.g., "what is the structure of product 100kg". Pages through the entire ListarEstruturas and filters client-side (Omie has no text search on this endpoint)

  • omie_estrutura_incluir / omie_estrutura_alterar / omie_estrutura_excluiruse-case (destructive), CRUD of structure items (IEstruturaGateway.incluirItensEstrutura/alterarItensEstrutura/excluirItemEstrutura), testable via EstruturaFakeGateway without touching the real Omie. Attention: validated live (round-trip include→alter→delete on a disposable test product) that the parent product must be type '03 - Produto em Processo' or '04 - Produto Acabado, that intMalhais required inIncluirEstrutura(the public doc marks it as optional) and thatAlterarEstrutura/ExcluirEstruturarequireidProdMalhaalong withidMalha`

Estoque (src/modules/estoque/)

  • omie_estoque_ajuste_incluir / omie_estoque_ajuste_excluiruse-case (destructive), CRUD of adjustment over IEstoqueGateway.incluirAjuste/excluirAjuste, testable via EstoqueFakeGateway without touching the real Omie. Attention, important live finding: the motivo field only accepts 'INI'/'INV'/'OPE'/'PDV' (not documented in the public doc, only appears in Omie's validation error); and after ANY stock adjustment on a product, that product can never be deleted again — Omie keeps a permanent "Movimento de Estoque (calculado)" linked to it, even if the adjustment itself is deleted later.

  • omie_estoque_movimentos_listar — passthrough, lists movements by period

  • omie_estoque_total_produtouse-case: sums the physical stock of a product across all stock locations, since Omie only exposes position per location

omie_estoque_consultar (ConsultarEstoque) was removed: we tested it and the method does not exist in the current Omie API (returns Method "ConsultarEstoque" not exists).

Pedido de Venda (src/modules/pedidoVenda/)

  • omie_pedido_venda_consultar / omie_pedido_venda_incluir / omie_pedido_venda_alterar / omie_pedido_venda_excluiruse-case (the last 3 destructive), CRUD over IPedidoVendaGateway, testable via PedidoVendaFakeGateway without touching the real Omie. Attention: validated live (full round-trip with disposable customer/product) that the customer must have the state (UF) filled in the registry (otherwise Omie rejects the order) and that codigo_categoria/codigo_conta_corrente are required even in a simple order

  • omie_pedido_venda_listar — passthrough, lists orders (accepts Omie's native etapa filter)

  • omie_pedido_venda_etapas_listar — passthrough, catalog of billing stages (sales/OS/purchases kanban) with code and description — unlike the OP stage, here it is fixed and documented

  • omie_pedido_venda_produtos_para_separaruse-case: lists the products that need to be picked from stock for dispatch (orders in the "Separar Estoque" stage, code 20 by default), already removing canceled ones and returning an aggregated summary per product (total quantity, in how many orders)

  • omie_pedido_venda_listar_com_clienteuse-case: lists orders already with the customer name (reuses the ClientesOmieGateway from the clientesFornecedores module), the stage in full and the order items (product/SKU/description/quantity/unit) resolved, cancelado/faturado as boolean and the order total value. Optional etapa_codigo filter (without it, brings all stages — does not filter canceled by default, unlike the tool above)

  • omie_pedido_venda_separar_estoque_listaruse-case: shortcut for the most followed report in daily life — same format as omie_pedido_venda_listar_com_cliente, but with etapa_codigo fixed to "Separar Estoque" and canceled removed by default (incluir_cancelados parameter to also see canceled ones). Internally reuses ListarPedidosComClienteUseCase.

Important finding while testing: canceled orders do not have the etapa reset by Omie — a canceled order continues to appear as if it were in "Separar Estoque" if it was canceled in that phase. That's why omie_pedido_venda_produtos_para_separar always cross-references with infoCadastro.cancelado before considering an order as truly pending; omie_pedido_venda_listar_com_cliente, on the other hand, is a generic listing and exposes cancelado for the caller to decide what to do with it.

Clientes e Fornecedores (src/modules/clientesFornecedores/)

In Omie, customer and supplier are the SAME registry (geral/clientes), differentiated only by the tag (Cliente, Fornecedor, Colaborador, Sócios, can have more than one) — there is no separate geral/fornecedores endpoint.

  • omie_clientes_consultar — passthrough, a specific customer/supplier (legal name, trade name, CNPJ/CPF, contact, address, tags)

  • omie_clientes_listar — passthrough, lists customers/suppliers; accepts advanced filter via clientesFiltro (e.g., {"tags": [{"tag": "Fornecedor"}]})

  • omie_fornecedores_listarlight use-case: shortcut to omie_clientes_listar already filtered by the Fornecedor tag, with search by legal name/trade name/CNPJ-CPF and apenas_ativos (removes inactive client-side, since the clientesFiltro.tags filter does not combine with a status filter in the same call directly)

  • omie_clientes_incluir / omie_clientes_alterar / omie_clientes_excluiruse-case (destructive), CRUD over IClientesGateway.incluirCliente/alterarCliente/excluirCliente, testable via ClientesFakeGateway without touching the real Omie. Attention: validated live (round-trip create→alter→delete) that codigo_cliente_integracao is required in IncluirCliente, even though Omie's public doc marks it as optional

Current scope: read-only (query/listing). At the user's request, the full CRUD (include, alter, delete) of customers/suppliers is left for later — only after the MCP has minimum security implemented (see rate limit/security section and src/httpServer.ts).

Contas Correntes (src/modules/contasCorrentes/)

  • omie_contas_correntes_listar — passthrough, lists current accounts (banks, cash, cards, card machines) with code, description, bank, type and registered initial balance

  • omie_extrato_conta_corrente_consultaruse-case: statement of a current account in a period (movements with date/description/value/category/reconciliation status, and previous/current/reconciled/available balances). Omie method: ListarExtrato (resource financas/extrato), testable via ContasCorrentesFakeGateway without touching the real Omie. Supports the generic filtros parameter on movements (e.g., nature, category). Validated live against the real account.

Fluxo de Caixa (src/modules/fluxoCaixa/)

  • omie_fluxo_caixa_geraruse-case: builds the cash flow (inflows, outflows, period and accumulated balance) in a tabular format, grouped by day or month and by current account. Omie does not have this report ready — only financas/mf ListarMovimentos, entry by entry of accounts payable/receivable, paginated at 100 per page — so this tool fetches all entries of the period, separates realized (already paid/received, by payment date) from forecast (open, not yet settled, by due date, excluding canceled) and aggregates everything, resolving the current account name (reuses ContasCorrentesOmieGateway, from the contasCorrentes module). Format designed to be exportable as a spreadsheet in the future. By default (apenas_favoritas: true) it restricts to the user-defined favorite accounts (src/modules/fluxoCaixa/application/contas-favoritas.ts: Cartão NuBank, Stone, Banco do Brasil, Wix, iFood, Sicoob, Itaú, Cartão Elo LEANDRO, Amazon, CAIXA LOJA — the ~39 other accounts registered in Omie, e.g., old cards and specific acquirers, are left out); use apenas_favoritas: false to see all accounts, or codigos_conta_corrente for a custom list.

Real balance (optional, usar_saldo_real: true): by default the accumulated balance is only the net variation within the queried period, not the real bank balance — Omie does not expose daily balance history per account via API. With usar_saldo_real: true, the tool anchors the calculation on the saldo_inicial/saldo_data registered in each current account (via omie_contas_correntes_listar): it sums the realized entries between the saldo_data and the start of the requested period, arriving at a saldoRealAcumulado close to the real bank balance — it is not a hardcoded value in the MCP, it is read from the Omie registry, so when someone configures the real balance of each account there (e.g., on 01/01), the calculation automatically reflects that without changing code. Accounts without saldo_data/saldo_inicial configured (or with saldo_data after the start of the period) receive saldoRealAcumulado: null instead of an invented number. Fetching this offset triggers an extra call (movements between the oldest saldo_data among the accounts and the start of the period) — it can be slow if the saldo_data is far in the past.

Important finding while testing: Omie rejects two concurrent calls of the same method (error "Já existe uma requisição desse método sendo executada"), even with different parameters — that's why the realized/forecast passes (both use ListarMovimentos) run sequentially, not in parallel, within the use-case. It is an additional restriction to the rate limit already documented in the section below, specific to concurrent calls of the same call.

Long periods generate many pages (e.g., just the receipts of ~3 weeks already exceeded 3,700 records) — prefer periods of up to ~3 months per call.

Contas a Pagar (src/modules/contasPagar/)

  • omie_contas_pagar_listaruse-case: lists entries from financas/contapagar (ListarContasPagar) already with the supplier name resolved (reuses the ClientesOmieGateway from the clientesFornecedores module — Omie only returns the code), value, due date, status (PAGO/ABERTO/VENCIDO), fiscal document, category and observation. Paginated, with optional data_alteracao_de/data_alteracao_ate filter.

Contas a Receber (src/modules/contasReceber/)

  • omie_contas_receber_listaruse-case: lists entries from financas/contareceber (ListarContasReceber) already with the customer name resolved (reuses the ClientesOmieGateway from the clientesFornecedores module), amount, due date, status (PAGO/ABERTO/VENCIDO), fiscal document, order number, and category. Paginated, with optional data_alteracao_de/data_alteracao_ate filter.

  • omie_contas_receber_boleto_gerar / omie_contas_receber_boleto_obter / omie_contas_receber_boleto_prorrogar / omie_contas_receber_boleto_cancelaruse-case (gerar/prorrogar/cancelar destructive), boleto CRUD on an accounts receivable entry (financas/contareceberboleto: GerarBoleto/ObterBoleto/ProrrogarBoleto/CancelarBoleto), testable via ContasReceberFakeGateway without touching the real Omie. Note: live-tested that this Omie account has no bank agreement/boleto configured — ProrrogarBoleto returns "Não temos suporte para geração da remessa de pagamento para o banco -sem instituição-"; GerarBoleto likely fails for the same reason (not live-tested to avoid generating a real boleto from a production customer entry). ObterBoleto/CancelarBoleto were validated live (they safely return "nenhum boleto gerado", with no side-effect).

Important finding from testing: the Omie date filter parameter on these two endpoints (filtrar_por_data_de/filtrar_por_data_ate) filters by the entry's last modification date (info.dAlt), not the due date — confirmed by requesting a 1-day range and comparing with the data_vencimento of the returned records (different due dates, dAlt always within the requested range). That's why the MCP tools expose the parameter as data_alteracao_de/data_alteracao_ate (not data_vencimento_de/ate), to avoid suggesting behavior the API doesn't have. There is no (tested) native filter by due date on these two endpoints — for that, use omie_fluxo_caixa_gerar, which uses financas/mf and filters correctly by due date/payment.

Difference from omie_fluxo_caixa_gerar: these two tools expose the raw entry (supplier/customer per entry, without aggregation), useful for checking title by title; the cash flow aggregates everything by period/current account.

Cash Budget (src/modules/orcamentoCaixa/)

  • omie_orcamento_caixa_consultaruse-case: Omie's NATIVE cash budget (forecast x actual) by financial category, for a month/year. Omie method: ListarOrcamentos (resource financas/caixa), testable via OrcamentoCaixaFakeGateway without touching the real Omie. Unlike omie_fluxo_caixa_gerar (manually calculated from accounts payable/receivable, grouped by current account/day), this is Omie's own ready-made report, grouped by category (e.g. "1.01.01 Vendas"). Supports the generic filtros parameter. Validated live against the real account.

PIX (src/modules/pix/)

  • omie_pix_listar / omie_pix_obter / omie_pix_obter_status / omie_pix_gerar / omie_pix_cancelaruse-case (gerar/cancelar destructive), PIX CRUD on accounts receivable entries (financas/pix: ListarPix/ObterPix/ObterStatusPix/GerarPix/ CancelarPix), testable via PixFakeGateway without touching the real Omie. Unlike Boleto, this Omie account HAS PIX configured and active (379 real records in the tested database) — Listar/ Obter/ObterStatus validated live against the real account. Gerar/Cancelar were not live-tested against a production entry out of caution (they would actually generate/cancel a PIX charge, with no guaranteed safe round-trip — same care as Boleto).

Invoices / NF-e (src/modules/nfe/)

  • omie_nfe_listar / omie_nfe_consultaruse-case: queries invoices (NF-e) already issued/registered in Omie via produtos/nfconsultar (ListarNF/ConsultarNF), testable via NfeFakeGateway without touching the real Omie. Listing returns a summary (number, series, key, customer, amount, whether canceled); query brings the detail (items, financial entries generated by the invoice). Deliberately READ-ONLY module: it neither issues nor cancels NF-e. Searching the official docs found no "issue NF-e from scratch" endpoint (like IncluirNFe(items, customer)) equivalent to IncluirPedidoVenda — the API treats NF-e mostly as query/import of a document already processed by the ERP's fiscal engine, and an issued invoice is a document with legal effect (no "delete and leave no trace" like the other modules). Validated live against the real account (4765 invoices in the test database).

Inbound Invoice (src/modules/notaEntrada/)

  • omie_nota_entrada_listar / omie_nota_entrada_consultaruse-case: queries inbound invoices (physical receipt of goods from a purchase) already registered, via ListarNotaEnt/ ConsultarNotaEnt (resource produtos/notaentrada), testable via NotaEntradaFakeGateway. READ-ONLY — same caution as the product NF-e and NFS-e modules: it's the final stage of the Requisition → Purchase Order → NF-e Receipt → Inbound Invoice flow, a definitive fiscal/ financial entry (it actually affects inventory and finance), with no safe test round-trip. Supplier NF-e receipt (produtos/recebimentonfe) and the invoice billing itself (produtos/notaentradafat) were left out of scope for the same reason. Validated live against the real account (3 existing inbound invoices).

Product Characteristics (src/modules/caracteristicasProduto/)

  • omie_caracteristica_incluir / omie_caracteristica_alterar / omie_caracteristica_excluir / omie_caracteristica_consultar / omie_caracteristica_listaruse-case (the first 3 destructive), CRUD of reusable product characteristics (e.g. "Cor", "Tamanho") via geral/caracteristicas, testable via CaracteristicaFakeGateway. Unlike Category, live-tested that the full CRUD works without reservations (complete round-trip, no trace).

Categories and Departments (src/modules/categoriasDepartamentos/)

  • omie_categoria_incluir / omie_categoria_alterar / omie_categoria_consultar / omie_categoria_listaruse-case (the first 2 destructive), CRUD of financial categories (geral/categorias), testable via CategoriaFakeGateway. Note, important live findings: (1) IncluirCategoria does NOT receive the new category's code — it receives categoria_superior (parent group code) and Omie GENERATES the child code automatically (e.g. parent 2.09 generates child 2.09.04); (2) there is no category deletion in the API, and testing AlterarCategoria with conta_inativa: 'S' had NO real effect (confirmed by querying again afterward) — categories created via API remain permanently active on the account, with no way to remove/deactivate them. This left a residual test category on this account (2.09.04, "Categoria Teste MCP Alterada") — harmless but recorded here so it doesn't confuse anyone who finds it later (same pattern as the residual test product from the estoque module).

  • omie_departamento_incluir / omie_departamento_alterar / omie_departamento_excluir / omie_departamento_consultar / omie_departamento_listaruse-case (the first 3 destructive), CRUD of Department/Cost Center (geral/departamentos), testable via DepartamentoFakeGateway. Note, live finding: codigo in IncluirDepartamento is the PARENT department's code (where to include), not the new one's — Omie generates and returns the child's code in the response (same pattern as Category). Unlike Category, ExcluirDepartamento actually works — validated live with a complete round-trip, leaving no trace.

Auxiliary Registries (src/modules/cadastrosAuxiliares/)

  • omie_bancos_listar / omie_cidades_listar / omie_paises_listar / omie_ncm_listar / omie_unidade_consultaruse-case, static reference tables maintained by Omie itself (Bacen, IBGE, Receita Federal): banks (geral/bancos), cities (geral/cidades), countries (geral/paises), NCM (produtos/ncm), and units of measure (geral/unidade). All read-only, testable via CadastrosAuxiliaresFakeGateway. They support native filtering (name, state, code, etc.) and the generic filtros parameter. Note, live finding: omie_unidade_consultar requires the exact code (it doesn't paginate/list everything, unlike the others) — it's a point query, not a listing. Validated live against the real account.

CRM (src/modules/crm/)

  • omie_crm_conta_incluir / omie_crm_conta_alterar / omie_crm_conta_excluir / omie_crm_conta_consultar / omie_crm_conta_listaruse-case (the first 3 destructive), CRUD of CRM Account (crm/contas — B2B sales funnel, different from the Customer/ Supplier registry), testable via ContaFakeGateway without touching the real Omie. Note, live finding: IncluirConta/AlterarConta require the full endereco and telefone_email blocks to be present (even with few fields filled) — Omie rejects with "Tag [endereco]/[telefone_email] não informada!" if the block is entirely missing.

  • omie_crm_contato_incluir / omie_crm_contato_alterar / omie_crm_contato_excluir / omie_crm_contato_consultar / omie_crm_contato_listaruse-case (the first 3 destructive), CRUD of CRM Contact (crm/contatos), always linked to an Account.

  • omie_crm_oportunidade_incluir / omie_crm_oportunidade_alterar / omie_crm_oportunidade_excluir / omie_crm_oportunidade_consultar / omie_crm_oportunidade_listaruse-case (the first 3 destructive), CRUD of funnel Opportunity (crm/oportunidades). Note, live finding: besides account and contact, it requires codigo_solucao and codigo_origem — auxiliary registries that must exist beforehand (Omie already comes with "Solução 01"/"Solução 02" and default origins like "Ativo").

  • omie_crm_fases_listar / omie_crm_solucoes_listar / omie_crm_origens_listaruse-case (read), CRM auxiliary registries (crm/fases, crm/solucoes, crm/origens) — the last two are prerequisites for being able to create an Opportunity.

  • Validated live with a complete and safe round-trip (test account, contact, and opportunity, created and deleted without leaving a trace).

Out of scope for this cycle (not requested, low priority): Tasks (crm/tarefas) and Account Characteristics (crm/contascaract) — implement only when the user needs them.

Services / Service Order / NFS-e (src/modules/servicos/)

  • omie_servico_incluir / omie_servico_alterar / omie_servico_excluir / omie_servico_consultar / omie_servico_listaruse-case (the first 3 destructive), CRUD for the services registry (servicos/servico), testable via ServicoFakeGateway without touching the real Omie. Attention, live finding: AlterarCadastroServico requires the identifier nested in intEditar (not in cabecalho as it would seem) — the public docs don't make this clear.

  • omie_os_incluir / omie_os_alterar / omie_os_excluir / omie_os_consultar / omie_os_listaruse-case (the first 3 destructive), CRUD for Service Orders (servicos/os), testable via OrdemServicoFakeGateway without touching the real Omie. Attention, important live findings: (1) each item requires codigo_servico_municipal/codigo_servico_lc116 as an already REGISTERED code in the LC116 table (see omie_servicos_lc116_listar), not free text — Omie rejects with "Código da LC116 não cadastrada" otherwise; (2) cRetemISS is required on each item even though it's not marked as such in the public docs; (3) the header client must have a state (UF) filled in (same requirement already seen in Sales Orders). Validated live with a full, safe round-trip (disposable test client, created and deleted without leaving a trace).

  • omie_nfse_listaruse-case: lists already issued NFS-e (servicos/nfse, ListarNFSEs), testable via NfseFakeGateway. READ-ONLY — same caution as the product NF-e module (tax document with legal effect, no safe round-trip for issuance).

  • omie_servicos_lc116_listaruse-case: lists the 255 valid codes from Complementary Law 116 (service classification), used to find the right code before creating a service order. Omie method: ListarLC116 (resource servicos/lc116).

Out of scope for this cycle (not requested, low priority): recurring Service Contract (servicos/contrato) and batch invoicing for OS/contract (servicos/osp, servicos/oslote, servicos/contratofat, servicos/contratolote) — implement only when the user needs them.

Purchasing (src/modules/compras/)

  • omie_pedido_compra_incluir / omie_pedido_compra_alterar / omie_pedido_compra_excluir / omie_pedido_compra_consultar / omie_pedido_compra_listaruse-case (the first 3 destructive), full CRUD over IPedidoCompraGateway (produtos/pedidocompra), testable via PedidoCompraFakeGateway without touching the real Omie. Attention, important live findings: (1) nCodCC (passed as codigo_conta_corrente) requires a checking account code (geral/contacorrente), not a cost center/department, despite the name — Omie rejects with "Conta Corrente não cadastrada" if you use a department code; (2) PesquisarPedCompra (listing) hides ALL orders by default — you must explicitly request each status (lExibirPedidosPendentes/Faturados/Recebidos/Cancelados/Encerrados/RecParciais/ FatParciais, all 'S'), which the gateway already does always; (3) when the page has no records, Omie returns an error (SOAP-ENV:Client-5113) instead of an empty list — normalized in the gateway to return an empty list.

  • omie_requisicao_compra_incluir / omie_requisicao_compra_alterar / omie_requisicao_compra_excluir / omie_requisicao_compra_consultar / omie_requisicao_compra_listaruse-case (the first 3 destructive), full CRUD over IRequisicaoCompraGateway (produtos/requisicaocompra), testable via RequisicaoCompraFakeGateway without touching the real Omie. Attention, important live finding: unlike other Omie endpoints, the fields for IncluirReq/AlterarReq go directly at the root of param — there is no requisicaoCadastro: {...} wrapper, even though the public docs suggest one (Omie rejects with "Tag [REQUISICAOCADASTRO] não faz parte da estrutura").

Generic (covers all other modules)

  • omie_chamar_api — receives resource (module path), call (method), and param (parameters), allowing access to any endpoint listed at https://developer.omie.com.br/service-list/ (clients, finance, CRM, sales, NF-e, services, etc.)

Omie rate limit — how the MCP protects itself

Omie blocks request bursts in two ways: "consumo indevido" (rate limit proper) and "consumo redundante" (very similar requests in quick succession — this has actually happened in practice when querying ~20 clients in parallel to build a report). The protection is centralized in the OmieClient (src/omieClient.ts), so every module benefits automatically, without having to reimplement anything:

  • Throttle — every call respects a minimum spacing (300ms) since the previous call made by the same OmieClient instance, even when multiple arrive at the same time (Promise.all, mapWithConcurrency, etc.). This reduces the chance of hitting "consumo redundante" before retry is even needed.

  • Retry with correct wait — if Omie still blocks, the OmieClient tries again (up to 4 times), respecting the time Omie itself suggests in the error message (e.g., "Aguarde 57 segundos") instead of a fixed short backoff.

  • mapWithConcurrency (src/shared/concurrency.ts) — used by gateways that fetch multiple records by code in batch (ProdutosOmieGateway.consultarProdutosPorCodigo, ClientesOmieGateway.consultarClientesPorCodigo), limits the concurrency of the code itself to 5 simultaneous calls, complementing the client's throttle.

Rule for new modules:

  1. Never call Promise.all/Promise.allSettled on an array of codes without a concurrency limit — always use mapWithConcurrency.

  2. Never run two calls of the SAME method (call) in parallel, even with different parameters — Omie rejects with "Já existe uma requisição desse método sendo executada" (found while building fluxoCaixa, which needs two passes of ListarMovimentos). Run them sequentially (await one, then the other).

  3. Parallel calls of different methods (e.g., fetching products and stock at the same time) are safe and need none of this — the client's throttle already covers it.

Adding a new module

Passthrough (Omie already returns the data ready):

  1. Create src/tools/<modulo>.ts exporting an array of ToolDef (use defineTool() from src/tools/types.ts).

  2. Import and concatenate that array into allTools, in src/tools/registry.ts.

Layered (needs to aggregate/combine Omie calls — copy src/modules/estoque/ as a reference):

  1. application/use-cases/ — the business rule (receives a gateway, returns the result already ready for the user).

  2. application/dto/ — zod schema for the input param and result type.

  3. infrastructure/gateways/ — only Omie calls (resource/call), no business rule.

  4. presentation/mcp/ — the ToolDef with execute instantiating gateway + use-case.

  5. <modulo>-register.ts + index.ts — barrel export of the tools array.

  6. Import the array into allTools, in src/tools/registry.ts.

In both cases, src/index.ts registers the tool automatically — nothing changes there.

Next steps (roadmap)

  • Add dedicated modules for Finance, Sales/NF-e, and CRM as needed (same file pattern).

  • Add automatic caching/pagination for large listings.

  • Add automated tests with Omie API mocks.

Security

Never commit the .env file or expose OMIE_APP_KEY/OMIE_APP_SECRET in public repositories.

-
license - not tested
-
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

  • Hosted Amazon Seller and Vendor MCP server for Claude, ChatGPT, Cursor, Codex, Gemini, Copilot.

  • Hosted MCP server connecting claude.ai, ChatGPT and other AI apps to your own computer

  • Hosted Amazon Seller Central and Amazon Ads MCP server for Claude, ChatGPT, Cursor, and agents.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Walessonrdreis/omie-mcp-v1.0'

If you have feedback or need assistance with the MCP directory API, please join our Discord server