CSVBox MCP Server

Servidor MCP para criar, validar e gerenciar importadores CSVBox e fluxos de trabalho de dados CSV.

Documentação

csvbox-mcp-server

Um servidor universal Model Context Protocol (MCP) para CSVBox. Ele expõe o gerenciamento de planilhas de importação do CSVBox como ferramentas MCP, permitindo criar, substituir, corrigir, gerar, validar e estruturar importadores a partir de qualquer cliente compatível com MCP — Claude Desktop, Cursor, Windsurf, Roo Code, Cline, VS Code, ChatGPT MCP e outros.

Funciona via stdio, portanto opera da mesma forma em todos os clientes.

Ferramentas

FerramentaFinalidadeChamada de API
create_sheetCriar uma planilha CSVBoxPOST /1.1/sheet
update_sheetSubstituir uma planilha existentePUT /1.1/sheet/{key}
patch_sheetAtualizar parcialmente uma planilhaPATCH /1.1/sheet/{key}
generate_sheet_jsonPrompt em linguagem natural → JSON completo da planilha (via LLM)nenhuma (chama o LLM)
create_importer_from_promptPrompt em linguagem natural → validar → criarPOST /1.1/sheet (+ LLM)
generate_import_codeCódigo de integração (vanilla-js/react/vue/angular)nenhuma
generate_sheet_functionsPrompt em linguagem natural → colunas virtuais / funções de validação / transformações de dados (via LLM)nenhuma (chama o LLM)
validate_schemaValidação local de esquemanenhuma

O CSVBox atualmente não possui endpoints GET ou LIST, portanto não há intencionalmente ferramentas get_sheet / list_sheet.

Ele também expõe dois prompts MCP:

PromptFinalidade
create_csvbox_sheetFazer o LLM do próprio cliente host construir uma planilha CSVBox completa (sem necessidade de chave LLM no servidor).
csvbox_sheet_functionsFazer o LLM do próprio cliente host criar colunas virtuais, funções de validação e transformações de dados (sem necessidade de chave LLM no servidor).

Geração de prompt → planilha

generate_sheet_json e create_importer_from_prompt usam um LLM para converter uma solicitação em formato livre em uma planilha CSVBox completa — title, sheet_columns, destinations, webhooks, security_settings e steps. Apenas campos de dados reais se tornam colunas; destinos, webhooks, domínios, regiões, configurações de upload de arquivo e etapas são colocados em suas seções de configuração apropriadas, nunca transformados em colunas. Existem três níveis:

  1. LLM do servidor — quando ANTHROPIC_API_KEY ou OPENAI_API_KEY está definido, o servidor chama o LLM diretamente. Funciona no MCP Inspector e em modo headless.
  2. Prompt MCP (create_csvbox_sheet) — quando você não tem chave de servidor, clientes host (Cursor, Claude Desktop, Cline) executam a geração com seu próprio modelo e depois chamam validate_schema e create_sheet. Gratuito.
  3. Nenhum configurado — generate_sheet_json retorna um erro estruturado de "nenhum provedor LLM configurado" apontando para o prompt MCP, e create_importer_from_prompt não chama a API do CSVBox. Não há fallback por regex.

Expansão de categoria / módulo

O gerador opera em um de dois modos, escolhidos automaticamente a partir do prompt:

  • Extração (padrão) — o prompt nomeia campos concretos (ex.: "colunas nome, email, telefone"). Apenas esses se tornam colunas; nada é inventado.
  • Expansão — o prompt nomeia módulos / categorias de negócio como uma lista (ex.: "módulos para: Informações da Empresa, Fornecedores, Folha de Pagamento, Fatura"), solicita um esquema abrangente/detalhado ou pede uma quantidade de colunas ("pelo menos 100 colunas"). Cada módulo nomeado é expandido em várias colunas realistas, prefixadas e com tipos corretos (ex.: Fornecedores → supplier_id, supplier_name, supplier_gstin, supplier_email, …). Uma contagem mínima explícita é respeitada e cada column_name é globalmente único.

Tipos de dados e validações são inferidos a partir dos nomes dos campos e de quaisquer tipos solicitados:

Solicitado / implícitoColuna typeValidadores
Dropdown / status / categoria com opções fixaslistvalues: [...] opções candidatas
Porcentagem / percentualnumbermin_value: 0, max_value: 100
Numérico positivo (quantidade, contagem, estoque, custo, idade)numbermin_value: 0
ID / código / número de referênciatext—
Emailemail—
Telefone / celularphone_number—
URL / siteurl—
Preço / custo / valor / saláriocurrency—
Campos de datadateformat: "YYYY-MM-DD"
Booleano / is_* / ativoboolean—
GST / GSTIN / id fiscalregexpadrão GSTIN
Código PIN / código postal (Índia)regex^[1-9][0-9]{5}$

Esquemas grandes: os modelos padrão (claude-haiku-4-5, gpt-4o-mini) são baratos, mas produzem esquemas visivelmente melhores com 100+ colunas quando você substitui por um modelo mais forte via LLM_MODEL (ex.: claude-sonnet-4-6). O limite de saída é elevado para acomodar planilhas grandes; se uma solicitação ainda for grande demais, a resposta é sinalizada como TRUNCATED (um resultado distinto, não um erro de análise) e a API do CSVBox não é chamada — reduza a quantidade de colunas / módulos ou use um modelo com maior orçamento de saída e tente novamente.

Coleções de funções (colunas virtuais, funções de validação, transformações de dados)

Além das seis propriedades da planilha, a API de Planilhas do CSVBox aceita três coleções cujos itens carregam uma string js_code que o CSVBox executa durante uma importação:

ColeçãoIdentificada porMáx.js_code deve…
virtual_columnscolumn_name20retornar o valor calculado da célula
validation_functionsfunction_name10retornar um array de strings de erro ([] = válido)
data_transformstransform_name10modificar o objeto csvbox e retorná-lo

Dentro de js_code, o objeto csvbox expõe row, column, virtual, user, import e environment. Os dois acessadores não são intercambiáveis — uma coluna virtual é por linha e usa csvbox.row.<name> (um escalar), enquanto uma função com escopo de "column" vê a coluna inteira via csvbox.column.<name> (um array).

Campos opcionais compartilhados: scope (column | row; não em colunas virtuais), run_at (before_validation | after_validation; apenas transformações de dados), columns / dynamic_columns, active, dependencies e _delete (apenas PATCH).

Como criá-las

// generate_sheet_functions  (requires ANTHROPIC_API_KEY or OPENAI_API_KEY)
{
  "prompt": "add a virtual column joining first and last name, and check every email contains an @",
  "sheet": { "title": "Customers", "sheet_columns": [ ... ] }
}

Retorna { "virtual_columns": [...], "validation_functions": [...], "source": ..., "validation": {...} }. Coleções que a solicitação não implica são omitidas, nunca retornadas como arrays vazios.

Esta ferramenta não chama a API do CSVBox. Leia o js_code gerado e aplique-o você mesmo com patch_sheet. Passe sheet para que o modelo referencie nomes reais de colunas e o validador possa verificar essas referências — o CSVBox não possui endpoint de leitura, portanto ele deve ser fornecido inline. Sem chave LLM, use o prompt MCP csvbox_sheet_functions.

PUT vs PATCH — leia isto antes de aplicar

update_sheet (PUT)patch_sheet (PATCH)
Coleção enviadaautoritativa — qualquer item existente não nomeado é excluídomesclada — itens não nomeados são mantidos
"virtual_columns": []exclui todos os 20sem efeito
Chave omitidaintocadaintocada
_delete: truenão válidoremove esse item (todos os outros campos ignorados)

Use patch_sheet para aplicar funções geradas. Valide primeiro com o verbo correspondente:

// validate_schema
{ "sheet": { "data_transforms": [ ... ] }, "mode": "patch" }

mode é create (padrão), put ou patch. Isso afeta apenas as coleções de funções — sob put, um array vazio é um erro grave em vez de um aviso, e _delete é rejeitado fora de patch.

Dependências

Um item pode carregar até 5 scripts de terceiros:

{ "url": "https://cdn.jsdelivr.net/npm/dayjs@1.11.10/dayjs.min.js",
  "globals": ["dayjs"],
  "integrity": "sha384-..." }

Apenas cdn.jsdelivr.net, unpkg.com e cdnjs.cloudflare.com são permitidos; somente https, caminho .js/.mjs, sem query string, fragmento, userinfo ou porta.

Segurança. Este servidor nunca executa js_code — aqui é apenas uma string opaca. JavaScript gerado é saída de modelo não revisada, portanto leia antes de aplicar via PATCH em um importador ativo. Uma dependência sem digest integrity pode mudar sob seus clientes a qualquer momento; validate_schema avisa quando um está ausente.

Consulte docs/sheet-functions-example.json para um payload completo.

Instalação

npm install @csvbox/mcp-server

Ou compile a partir do código-fonte:

git clone <this-repo> csvbox-mcp-server
cd csvbox-mcp-server
npm install
npm run build

Isso produz dist/index.js — o entrypoint que os clientes MCP iniciam.

Variáveis de ambiente

Copie .env.example para .env e preencha suas credenciais do CSVBox:

CSVBOX_API_KEY=your_api_key
CSVBOX_API_SECRET=your_api_secret

As credenciais do CSVBox são exigidas apenas para as ferramentas com suporte a API (create_sheet, update_sheet, patch_sheet, create_importer_from_prompt). validate_schema e generate_import_code funcionam sem nenhuma credencial.

Nota sobre cabeçalho de autenticação: o cliente envia x-csvbox-api-key e x-csvbox-secret-api-key (correspondendo aos payloads de referência do CSVBox). Elas são definidas como constantes em src/services/csvbox-api.ts se sua conta usar nomes de cabeçalho diferentes.

Identificação do cliente

Toda solicitação que este servidor envia à API do CSVBox carrega dois cabeçalhos extras:

x-csvbox-client: mcp
x-csvbox-client-version: <the version in package.json>

O CSVBox registra como cada planilha foi criada; sem eles, planilhas e importações feitas via MCP são indistinguíveis de qualquer outro chamador REST. A versão é lida de package.json e é a mesma que o servidor anuncia ao seu cliente MCP, portanto os dois nunca podem divergir.

Eles são sempre enviados — não há variável de ambiente ou entrada de ferramenta que os desative ou altere. Eles não carregam credenciais nem nada derivado das entradas de suas ferramentas. Ferramentas que não fazem chamada de API (generate_sheet_json, generate_sheet_functions, generate_import_code, validate_schema) não enviam solicitação e, portanto, nenhum cabeçalho.

Provedor LLM (para geração de prompt → planilha)

generate_sheet_json e create_importer_from_prompt precisam de um LLM. Defina um de:

ANTHROPIC_API_KEY=sk-ant-...
OPENAI_API_KEY=sk-...

O provedor é detectado automaticamente:

CondiçãoProvedorModelo padrão
LLM_PROVIDER=anthropic (e sua chave definida)Anthropicclaude-haiku-4-5
LLM_PROVIDER=openai (e sua chave definida)OpenAIgpt-4o-mini
ANTHROPIC_API_KEY definido (sem LLM_PROVIDER)Anthropicclaude-haiku-4-5
OPENAI_API_KEY definido (sem LLM_PROVIDER)OpenAIgpt-4o-mini
nenhuma chave definidanenhum — as ferramentas retornam um erro apontando para o prompt MCP create_csvbox_sheet—

LLM_PROVIDER desambigua quando ambas as chaves estão presentes; LLM_MODEL substitui o modelo para o provedor escolhido. Para esquemas grandes de categoria/módulo (100+ colunas), defina LLM_MODEL para um modelo mais forte (ex.: claude-sonnet-4-6) — consulte Expansão de categoria / módulo.

MCP Inspector: defina a chave LLM no painel de variáveis de ambiente do Inspector para usar o caminho LLM do servidor. O Inspector não tem LLM host próprio, portanto pode renderizar o prompt create_csvbox_sheet, mas não pode executá-lo — para o caminho sem chave, use um cliente com modelo (Cursor, Claude Desktop, Cline).

Execução local

# After building:
npm start

# Or run the built file directly:
node dist/index.js

O servidor fala MCP via stdio e registra csvbox-mcp-server running on stdio em stderr (stdout é reservado para o protocolo).

Configuração do cliente

Para uma instalação publicada, use o pacote npm com npx. Defina CSVBOX_API_KEY / CSVBOX_API_SECRET no bloco env.

Nota: O pacote npm é @csvbox/mcp-server e o executável é csvbox-mcp-server.

Claude Desktop

Adicione o seguinte à configuração MCP do Claude Desktop:

{
  "mcpServers": {
    "csvbox": {
      "command": "npx",
      "args": [
        "-y",
        "--package=@csvbox/mcp-server",
        "csvbox-mcp-server"
      ],
      "env": {
        "CSVBOX_API_KEY": "your_api_key",
        "CSVBOX_API_SECRET": "your_api_secret"
      }
    }
  }
}

Cursor

Edite ~/.cursor/mcp.json (global) ou .cursor/mcp.json (por projeto):

{
  "mcpServers": {
    "csvbox": {
      "command": "npx",
      "args": [
        "-y",
        "--package=@csvbox/mcp-server",
        "csvbox-mcp-server"
      ],
      "env": {
        "CSVBOX_API_KEY": "your_api_key",
        "CSVBOX_API_SECRET": "your_api_secret"
      }
    }
  }
}

Windsurf

Edite ~/.codeium/windsurf/mcp_config.json:

{
  "mcpServers": {
    "csvbox": {
      "command": "npx",
      "args": [
        "-y",
        "--package=@csvbox/mcp-server",
        "csvbox-mcp-server"
      ],
      "env": {
        "CSVBOX_API_KEY": "your_api_key",
        "CSVBOX_API_SECRET": "your_api_secret"
      }
    }
  }
}

Roo Code

Nas configurações MCP do Roo Code (mcp_settings.json):

{
  "mcpServers": {
    "csvbox": {
      "command": "npx",
      "args": [
        "-y",
        "--package=@csvbox/mcp-server",
        "csvbox-mcp-server"
      ],
      "env": {
        "CSVBOX_API_KEY": "your_api_key",
        "CSVBOX_API_SECRET": "your_api_secret"
      }
    }
  }
}

Cline

Nas configurações MCP do Cline (cline_mcp_settings.json):

{
  "mcpServers": {
    "csvbox": {
      "command": "npx",
      "args": [
        "-y",
        "--package=@csvbox/mcp-server",
        "csvbox-mcp-server"
      ],
      "env": {
        "CSVBOX_API_KEY": "your_api_key",
        "CSVBOX_API_SECRET": "your_api_secret"
      }
    }
  }
}

VS Code MCP

Adicione a .vscode/mcp.json (ou ao global mcp.json):

{
  "servers": {
    "csvbox": {
      "command": "npx",
      "args": [
        "-y",
        "--package=@csvbox/mcp-server",
        "csvbox-mcp-server"
      ],
      "env": {
        "CSVBOX_API_KEY": "your_api_key",
        "CSVBOX_API_SECRET": "your_api_secret"
      }
    }
  }
}

Exemplos de chamadas de ferramentas

Gerar uma planilha completa a partir de um prompt (LLM, sem chamada à API do CSVBox):

// generate_sheet_json  (requires ANTHROPIC_API_KEY or OPENAI_API_KEY)
{ "prompt": "Create employee importer with name, email, salary, joining date; destination as testapi; allow only xlsx files" }

Retorna { "sheet": { "title": ..., "sheet_columns": [...], "destinations": [...], "steps": {...} }, "source": "llm:anthropic:claude-haiku-4-5", "validation": { "valid": true, ... } }. Os campos de dados tornam-se colunas (salary → currency, joining date → date); o destino e a configuração de xlsx vão para destinations / steps, não para colunas. Sem chave de LLM, retorna um erro apontando para o prompt create_csvbox_sheet.

Valide um schema antes de enviá-lo:

// validate_schema
{ "sheet": { "title": "Customers", "sheet_columns": [
  { "column_name": "email", "display_label": "Email", "type": "email" }
] } }

Retorna { "valid": true, "errors": [], "warnings": [ ... ] }.

Crie uma planilha:

// create_sheet
{ "sheet": { "title": "Customer Import", "sheet_columns": [
  { "column_name": "name", "display_label": "Name", "type": "text" },
  { "column_name": "email", "display_label": "Email", "type": "email" }
] } }

Gere + crie em uma única etapa:

// create_importer_from_prompt  (requires an LLM key + CSVBox credentials)
{ "prompt": "Create customer importer with name, email, phone; allow for example.com" }

Retorna { "generated_schema": { ... }, "source": ..., "validation": { ... }, "api_response": { ... } }. Aborta sem chamar a API se nenhum provedor de LLM estiver configurado ou se o schema gerado falhar na validação.

Substitua uma planilha:

// update_sheet
{ "sheet_license_key": "abc123", "sheet": { "title": "Updated", "sheet_columns": [ ... ] } }

Destrutivo para qualquer coleção que você enviar — veja PUT vs PATCH.

Aplique patch em uma planilha:

// patch_sheet
{ "sheet_license_key": "abc123", "changes": { "title": "New Title" } }

Remova uma função sem tocar no restante:

// patch_sheet
{ "sheet_license_key": "abc123",
  "changes": { "virtual_columns": [ { "column_name": "full_name", "_delete": true } ] } }

Gere código de integração:

// generate_import_code
{ "framework": "react" }

Tipos de coluna suportados

text, number, email, date, time, boolean, regex, ip, url, credit_card, phone_number, currency, list, dependent_list, dynamic_list, dependent_dynamic_list, multiselect_list, multiselect_dynamic_list.

Desenvolvimento

npm run build   # compile TypeScript → dist/
npm start       # run the built server
npm run lint    # type-check without emitting
npm test        # compile and run the unit suite (alias: npm run test:unit)

Testes

npm test compila src/tests/ e o executa com o executor de testes integrado do Node — sem framework de testes, sem biblioteca de mocks.

A suíte é hermética. Ela nunca contata um host externo, nunca lê suas variáveis de ambiente CSVBOX_API_* / ANTHROPIC_API_KEY / OPENAI_API_KEY e nunca toca em uma conta CSVBox real, portanto passa de forma idêntica, independentemente de você ter credenciais configuradas. O HTTP é interceptado no adaptador axios; o LLM é um fake roteirizado; o único teste que precisa de codificação real de requisição inicia um listener efêmero em 127.0.0.1 e o fecha em seguida. Testes que leem variáveis de ambiente definem o que precisam explicitamente e restauram os valores anteriores.

Testes E2E

npm run test:e2e         # run the Playwright suite
npm run test:e2e:report  # open the HTML report from the last run

As especificações ficam em e2e/, configuradas por playwright.config.ts. Como a suíte de testes unitários, esta suíte é hermética: ela inicia servidores mock de CSVBox e LLM em loopback (e2e/support/mock-csvbox-server.ts, e2e/support/mock-llm-server.ts) e aciona o servidor real compilado (dist/index.js) por meio do MCP Inspector com credenciais falsas apontadas para esses mocks — ela nunca contata uma conta CSVBox real ou provedor de LLM, e nunca lê seu .env. Uma instância separada do Inspector, sem credenciais, cobre os caminhos de erro de "credenciais ausentes". Requer npm run build primeiro (as entradas do webServer test:e2e são construídas automaticamente).

Incorporando o servidor

createServer() é exportado do módulo de entrada. Ele registra todas as ferramentas e prompts e retorna o McpServer sem anexar um transporte, para que você possa conectá-lo a um dos seus próprios:

import { createServer } from "@csvbox/mcp-server";

const server = createServer();
await server.connect(myTransport);

Importar o módulo não inicia nada; o servidor stdio é executado apenas quando dist/index.js é executado diretamente.

Licença

MIT