Datalake-mcp

Servidor MCP (Model Context Protocol) para conectar um Azure Data Lake Storage Gen2 ao Claude Desktop ou a outros agentes

Documentação

Datalake-MCP

Servidor MCP (Model Context Protocol) que expõe um Azure Data Lake Storage Gen2 para o Claude, permitindo navegar pelos arquivos, ler seu conteúdo em formato CSV, Parquet, texto (.txt), markdown (.md) ou XML, e salvar arquivos (texto, markdown, CSV, Parquet, PDF) com um índice pesquisável.

Listed on mcpservers.org

Como funciona

Arquitetura

flowchart LR
    U([Utente]) <--> C["Claude<br/>(Desktop / Code)"]
    C <-->|"MCP via stdio"| T

    subgraph S["Datalake.Mcp.Server (.NET 9)"]
        direction TB
        T["Tools/DataLakeTools<br/>tool MCP"]
        subgraph R["Lettura (streaming)"]
            direction LR
            CSV[CsvReaderService]
            PQ[ParquetReaderService]
            TXT[TextReaderService]
            XML[XmlReaderService]
            F[RowFilter]
        end
        subgraph W["Scrittura"]
            direction LR
            FW[FileWriterService]
            IDX[FileIndex]
        end
        DL[DataLakeService]
        T --> R
        T --> W
        R --> DL
        W --> DL
        R -.-> F
    end

    DL <-->|"Azure.Storage.Files.DataLake<br/>AccountName + AccountKey"| ADLS[("Azure Data Lake<br/>Storage Gen2")]
    IDX -.->|"saved-files-index.csv<br/>(ETag)"| ADLS

Fluxo de leitura e consulta

sequenceDiagram
    actor U as Utente
    participant C as Claude
    participant M as Server MCP
    participant L as Data Lake

    U->>C: "Mostrami gli ordini APERTI > 1000"
    C->>M: list_filesystems / list_directory
    M->>L: navigazione
    L-->>C: filesystem, cartelle, file
    C->>M: get_parquet_schema (colonne e tipi)
    C->>M: read_parquet(filter, columns, maxRows, offset)
    M->>L: OpenReadAsync (download lazy)
    loop un row-group / riga alla volta
        L-->>M: byte necessari
        M->>M: filtro → offset → maxRows
    end
    M-->>C: righe + truncated / nextOffset
    C-->>U: risposta in linguaggio naturale
    Note over C,M: se truncated=true si richiama con offset=nextOffset

Fluxo de salvamento e pesquisa

sequenceDiagram
    actor U as Utente
    participant C as Claude
    participant M as Server MCP
    participant L as Data Lake

    U->>C: "Salva il report in report/2026"
    C->>M: save_csv / save_parquet / save_pdf / ...
    M->>M: validazione formato ed estensione
    M->>L: upload condizionale (If-None-Match: *)
    alt esiste già e overwrite=false
        L-->>M: errore, nessuna sovrascrittura
    else
        L-->>M: file salvato
        loop fino a 5 tentativi
            M->>L: leggi indice (ETag)
            M->>L: scrivi indice (If-Match: ETag)
        end
    end
    M-->>C: esito
    U->>C: "Trova il report"
    C->>M: search_file(nomeFile, tipoFile)
    M->>L: legge l'indice
    M-->>C: voci trovate (+ contenuto se un solo file)

Estrutura da solução

Datalake-MCP.sln
src/Datalake.Mcp.Server/         Server MCP (host .NET Generic Host, trasporto stdio)
  Configuration/DataLakeOptions.cs   Opzioni di connessione (AccountName/AccountKey/DefaultFileSystem)
  Services/DataLakeService.cs        Wrapper su Azure.Storage.Files.DataLake (navigazione, streaming)
  Services/CsvReaderService.cs       Lettura CSV con limite di righe (streaming)
  Services/ParquetReaderService.cs   Lettura Parquet a row-group, con proiezione colonne
  Services/TextReaderService.cs      Lettura file di testo/markdown riga per riga (streaming)
  Services/XmlReaderService.cs       Lettura XML tabellare elemento per elemento, con proiezione colonne
  Services/FileWriterService.cs     Costruzione/validazione dei byte da salvare (testo, CSV, Parquet, PDF)
  Services/FileIndex.cs              Indice CSV dei file salvati (upsert, parsing, ricerca)
  Tools/DataLakeTools.cs             Tool MCP esposti al client (list_filesystems, read_csv, ...)
tests/Datalake.Mcp.Server.Tests/ Test xUnit per reader CSV/Parquet/testo/XML, writer e indice

Ferramentas MCP expostas

FerramentaDescrição
list_filesystemsLista os filesystems (containers) da conta
list_directoryLista arquivos e diretórios em um caminho (opcionalmente recursivo)
get_file_infoMetadados de um arquivo (tamanho, data da última modificação)
read_csvLê um CSV, com limite maxRows, delimitador configurável e offset para paginação; filtro opcional filter
get_parquet_schemaRetorna o esquema (colunas/tipos) de um Parquet sem ler seus dados
read_parquetLê um Parquet, com maxRows, projeção opcional das colunas e offset para paginação; filtro opcional filter
read_textLê um arquivo de texto (.txt), com maxLines e offset para paginação; filtro opcional contains
read_markdownLê um arquivo markdown (.md), com maxLines e offset para paginação; filtro opcional contains
get_xml_schemaRetorna o esquema (colunas, entre atributos e elementos) do elemento de registro de um XML tabular sem ler seus dados
read_xmlLê um XML tabular (raiz com elementos de registro repetidos), com maxRows, elemento de registro e projeção de colunas opcionais, e offset para paginação; filtro opcional filter
create_folderCria uma pasta na raiz do filesystem ou como subpasta de uma pasta existente (o pai deve existir; erro se a pasta já existir)
save_textSalva um arquivo .txt em uma pasta/subpasta do datalake
save_markdownSalva um arquivo .md
save_csvSalva um arquivo .csv a partir de texto CSV (validado: mesmo número de campos por linha)
save_parquetSalva um arquivo .parquet a partir de uma lista de linhas (objetos coluna → valor); os tipos são inferidos (bool, inteiro, decimal, string)
save_pdfSalva um arquivo .pdf a partir de conteúdo base64 (verificado o cabeçalho %PDF-)
search_filePesquisa no índice dos arquivos salvos por nomeFile (contém, case-insensitive) e/ou tipoFile (csv, parquet, pdf, md, txt) e retorna as entradas encontradas (path utilizável com as ferramentas read_*). Se o resultado for um único arquivo, também retorna seu conteúdo (csv, parquet, txt, md; primeiras maxRows linhas, depois continua com read_* e nextOffset; para pdf apenas os metadados)

As leituras são projetadas para não carregar arquivos inteiros na memória: CSV, texto/markdown e XML são lidos linha/elemento por linha/elemento, parando no limite solicitado, enquanto Parquet é lido um row-group por vez. Os arquivos remotos são abertos com streaming de carregamento diferido (DataLakeFileClient.OpenReadAsync), que baixa apenas os bytes efetivamente necessários. A leitura XML desabilita o processamento de DTD e a resolução de entidades externas para evitar ataques XXE.

Filtros

read_csv, read_parquet e read_xml aceitam um parâmetro opcional filter: uma lista de condições { column, operator, value } combinadas em AND, por exemplo:

[{"column": "stato", "operator": "eq", "value": "APERTO"},
 {"column": "importo", "operator": "gt", "value": "1000"}]

Operadores: eq (=), ne (!=), gt (>), gte (>=), lt (<), lte (<=), contains, startswith, endswith, isnull, isnotnull (estes dois últimos não exigem value; uma string vazia conta como null). As comparações são numéricas quando célula e valor são números (formato invariante, ex. 12.5), em timestamps Parquet quando o valor é uma data, caso contrário textuais case-insensitive. O filtro pode referir-se também a colunas não projetadas; uma coluna inexistente ou um operador inválido produzem um erro que lista os valores permitidos.

O filtro é aplicado durante a leitura em streaming, antes de offset e maxRows: a paginação (truncated/nextOffset) conta, portanto, apenas as linhas que satisfazem o filtro. read_text e read_markdown aceitam, por sua vez, contains, que seleciona as linhas contendo o texto indicado (case-insensitive).

Paginação

As respostas de read_csv, read_parquet, read_text, read_markdown e read_xml estão sujeitas ao limite de tamanho das chamadas de ferramenta (cerca de 1 MB). Para arquivos que excedem maxRows/maxLines (ou o limite de tamanho), o resultado informa truncated: true e um nextOffset: chamando novamente a ferramenta com offset = nextOffset, obtém-se a próxima página, pulando as linhas já retornadas sem precisar relê-las por inteiro. Quando não há mais nada para ler, truncated é false e nextOffset é null.

Salvamento de arquivos e índice

As ferramentas save_* aceitam path (pastas e subpastas são criadas se ausentes), fileSystem, description e overwrite. Sem overwrite=true, um arquivo existente nunca é substituído (upload condicional If-None-Match: *). A extensão do caminho deve corresponder ao formato.

Cada salvamento registra o arquivo no índice DataLake:SavedFilesIndexPath (padrão saved-files-index.csv, na raiz do filesystem), um CSV legível com read_csv com colunas path,name,format,sizeBytes,savedAt,description. Salvar novamente o mesmo caminho atualiza a linha existente. O índice é atualizado com concorrência otimista (ETag, até 5 tentativas).

Configuração

As credenciais da conta (accountName e accountKey) nunca devem ser commitadas. Em desenvolvimento, use os user-secrets do .NET a partir da pasta src/Datalake.Mcp.Server:

dotnet user-secrets init
dotnet user-secrets set "DataLake:AccountName" "<nome-account>"
dotnet user-secrets set "DataLake:AccountKey" "<chiave-account>"
dotnet user-secrets set "DataLake:DefaultFileSystem" "<container-predefinito>"

Alternativamente, por meio de variáveis de ambiente (útil para o deploy):

$env:DataLake__AccountName = "<nome-account>"
$env:DataLake__AccountKey = "<chiave-account>"
$env:DataLake__DefaultFileSystem = "<container-predefinito>"

appsettings.json contém apenas os placeholders vazios e pode permanecer no repositório.

Build, teste e execução

dotnet build
dotnet test
dotnet run --project src/Datalake.Mcp.Server

O servidor comunica via stdio segundo o protocolo MCP: deve, portanto, ser registrado como servidor MCP no cliente (ex. Claude Desktop / Claude Code), apontando para o executável do projeto Datalake.Mcp.Server, não executado manualmente em um terminal interativo.

Registro no Claude Desktop e uso do MCP

Um exemplo de configuração está disponível em claude_desktop_config.example.json. Para usá-lo:

  1. Execute dotnet build src/Datalake.Mcp.Server -c Release para gerar o DLL em bin/Release/net9.0. Ou use o conteúdo da pasta se já compilado.
  2. Copie o conteúdo do arquivo de exemplo para o arquivo de configuração do Claude Desktop (%APPDATA%\Claude\claude_desktop_config.json), unindo-o à chave mcpServers se já presente.
  3. Atualize o caminho em args se o repositório estiver em outro local, e preencha AccountName/AccountKey/DefaultFileSystem em env com as credenciais reais (nunca as commite no repositório).
  4. Reinicie o Claude Desktop: o servidor "datalake" aparecerá entre as ferramentas disponíveis.