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.
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
| Ferramenta | Descrição |
|---|---|
list_filesystems | Lista os filesystems (containers) da conta |
list_directory | Lista arquivos e diretórios em um caminho (opcionalmente recursivo) |
get_file_info | Metadados de um arquivo (tamanho, data da última modificação) |
read_csv | Lê um CSV, com limite maxRows, delimitador configurável e offset para paginação; filtro opcional filter |
get_parquet_schema | Retorna o esquema (colunas/tipos) de um Parquet sem ler seus dados |
read_parquet | Lê um Parquet, com maxRows, projeção opcional das colunas e offset para paginação; filtro opcional filter |
read_text | Lê um arquivo de texto (.txt), com maxLines e offset para paginação; filtro opcional contains |
read_markdown | Lê um arquivo markdown (.md), com maxLines e offset para paginação; filtro opcional contains |
get_xml_schema | Retorna o esquema (colunas, entre atributos e elementos) do elemento de registro de um XML tabular sem ler seus dados |
read_xml | Lê 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_folder | Cria uma pasta na raiz do filesystem ou como subpasta de uma pasta existente (o pai deve existir; erro se a pasta já existir) |
save_text | Salva um arquivo .txt em uma pasta/subpasta do datalake |
save_markdown | Salva um arquivo .md |
save_csv | Salva um arquivo .csv a partir de texto CSV (validado: mesmo número de campos por linha) |
save_parquet | Salva um arquivo .parquet a partir de uma lista de linhas (objetos coluna → valor); os tipos são inferidos (bool, inteiro, decimal, string) |
save_pdf | Salva um arquivo .pdf a partir de conteúdo base64 (verificado o cabeçalho %PDF-) |
search_file | Pesquisa 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:
- Execute
dotnet build src/Datalake.Mcp.Server -c Releasepara gerar o DLL embin/Release/net9.0. Ou use o conteúdo da pasta se já compilado. - 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 à chavemcpServersse já presente. - Atualize o caminho em
argsse o repositório estiver em outro local, e preenchaAccountName/AccountKey/DefaultFileSystememenvcom as credenciais reais (nunca as commite no repositório). - Reinicie o Claude Desktop: o servidor "datalake" aparecerá entre as ferramentas disponíveis.