A Model Context Protocol (MCP) server that connects AI assistants to any OData v2/v4 service. Ask a natural-language question; the server identifies the right EntitySet, queries the service, and returns real data — no SQL, no manual API calls.
Works with Claude Desktop, Claude Code, Cursor, Windsurf, and any MCP-compatible host.
AI assistant (Claude Desktop / Claude Code / Cursor / Windsurf)
→ MCP protocol (stdio or HTTP/SSE)
→ odata-mcp ← this repo
→ OData service (SAP BTP, SAP on-prem, Microsoft, any OData v2/v4)
On startup, odata-mcp reads EDMX metadata XML to discover available EntitySets and their properties. At query time, it matches the user's natural language to the right EntitySet (heuristic matching + optional Anthropic LLM fallback) and fetches live data.
go install github.com/bluefunda/odata-mcp@latestOr build from source:
git clone https://github.com/bluefunda/odata-mcp.git
cd odata-mcp
make buildDocker:
docker pull bluefunda/odata-mcp:latestAdd to your Claude Desktop configuration:
macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Windows: %APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"odata": {
"command": "/usr/local/bin/odata-mcp",
"env": {
"ODATA_METADATA_PATH": "/path/to/your/metadata.xml",
"ODATA_USERNAME": "your-username",
"ODATA_PASSWORD": "your-password"
}
}
}
}Restart Claude Desktop. The server starts automatically via stdio.
See examples/ for Claude Desktop, Cursor, and Docker Compose configurations.
The server needs EDMX metadata XML to discover available entities. Choose one store:
# Single XML file
ODATA_METADATA_PATH=/path/to/metadata.xml odata-mcp
# Directory of XML files (all *.xml files discovered recursively)
ODATA_METADATA_PATH=/path/to/xml-dir/ odata-mcpWorks with AWS S3, MinIO, Cloudflare R2, GCS S3 interop, and any S3-compatible endpoint.
S3_ENDPOINT=localhost:9000 \
S3_BUCKET=odata-metadata \
S3_ACCESS_KEY=minioadmin \
S3_SECRET_KEY=minioadmin \
odata-mcpSAP EDMX always embeds atom:link[@rel="self"] to identify the service's base URL; many standard OData v2/v4 services don't. If a metadata file has no self-link, set ODATA_SERVICE_BASE_URL explicitly — without it, that file is skipped with a warning at startup instead of failing the whole server:
ODATA_METADATA_PATH=/path/to/northwind-metadata.xml \
ODATA_SERVICE_BASE_URL=https://services.odata.org/V2/Northwind/Northwind.svc \
odata-mcpReads S3 and OData credentials from a NATS JetStream KV bucket (ODataMCPConfigBucket by default), then loads EDMX from S3.
NATS_URL=nats://nats.internal:4222 \
NATS_CREDS=/path/to/user.creds \
odata-mcpSet via ODATA_MODE env var:
| Mode | Transport | Use case |
|---|---|---|
stdio (default) |
Standard I/O | Claude Desktop, Claude Code CLI, IDE extensions |
sse |
HTTP/SSE on :8008 |
Orchestrators, Docker, programmatic access |
| Variable | Required | Default | Description |
|---|---|---|---|
| Metadata store (one required) | |||
ODATA_METADATA_PATH |
* | — | Path to a local .xml file or directory of .xml files |
ODATA_SERVICE_BASE_URL |
No | — | Fallback base URL for metadata that has no atom:link[@rel="self"] (SAP EDMX always has one; plain OData services like services.odata.org often don't). Only meaningful for a single-service setup. |
S3_ENDPOINT |
* | — | S3-compatible endpoint (e.g. localhost:9000, s3.amazonaws.com) |
S3_BUCKET |
if S3 | ODataMCPConfigBucket |
Bucket containing EDMX files under the metaData/ prefix |
S3_ACCESS_KEY |
if S3 | — | S3 access key |
S3_SECRET_KEY |
if S3 | — | S3 secret key |
S3_SECURE |
No | false |
Use HTTPS for S3 (true/false) |
NATS_URL |
* | — | NATS server URL; triggers cache-backed store selection |
NATS_CREDS |
if NATS | — | Path to NATS credentials file |
| OData credentials | |||
ODATA_USERNAME |
No | — | OData service username |
ODATA_PASSWORD |
No | — | OData service password or bearer token |
ODATA_AUTH_TYPE |
No | basic |
basic, bearer, or omit for no auth |
| Transport | |||
ODATA_MODE |
No | stdio |
stdio or sse |
ODATA_HTTP_PORT |
No | 8008 |
HTTP port for SSE mode |
ODATA_HTTP_HOST |
No | 0.0.0.0 |
HTTP host for SSE mode |
ODATA_USE_LEGACY_SSE |
No | true |
Use legacy SSE transport (true) or streamable HTTP (false) |
| LLM fallback | |||
ANTHROPIC_API_KEY |
No | — | Enables LLM entity-selection fallback when heuristic matching fails |
ANTHROPIC_MODEL |
No | claude-3-5-sonnet-latest |
Anthropic model for entity selection |
ANTHROPIC_BASE_URL |
No | https://api.anthropic.com |
Anthropic API base URL |
| Vault | |||
VAULT_ADDR |
No | — | HashiCorp Vault address; enables NATS credential loading from Vault |
VAULT_TOKEN |
No | — | Vault token |
| Logging | |||
LOG_LEVEL |
No | info |
debug, info, warn, error |
LOG_FORMAT |
No | json |
json or console |
| Tool | Description |
|---|---|
query-odata-service |
Natural-language query over any discovered OData EntitySet. Returns real records from the service. |
query-service |
Natural-language query scoped to one explicitly chosen service (base_url). Use this to disambiguate when an EntitySet name is defined by more than one service. |
list-available-services |
Lists discovered services with their base URLs and EntitySets. |
list-metadata-files |
Lists the metadata source identifiers processed at startup. |
generate-chart |
Suggests a structured chart configuration (chart_type, x_field, y_field, group_by, insight) for a set of data records — e.g. what query-odata-service just returned. Returns a spec for the client to render, not an image. |
The query-odata-service description is built dynamically at startup and includes the full list of available EntitySets, so the AI assistant can route queries without additional context.
Example queries:
- "list all countries"
- "show me open purchase orders"
- "get currencies for Germany"
- "what business partners are available?"
If more than one loaded service defines an EntitySet with the same name, query-odata-service returns an error naming the candidate services instead of silently guessing one. Call list-available-services to see the base URLs, then use query-service with the correct base_url to run the query against that specific service.
| Resource URI | Description |
|---|---|
mcp://odata_server_llm/metadata.xml |
Raw EDMX XML of the first discovered metadata file |
mcp://odata_server_llm/metadata-info.json |
JSON summary of all services, EntitySets, and file sources |
Queries are matched to EntitySets in two passes:
- Heuristic — exact substring match, plural forms (
Countries→Country), and space-stripped partial match. Prefers the longest matching name. - LLM fallback — when the heuristic fails and
ANTHROPIC_API_KEYis set, the server calls the Anthropic Messages API with the entity list and user query to select the best match.
make build # compile binary to bin/odata-mcp
make test # run tests with race detector
make fmt # gofmt + goimports
make lint # golangci-lint
make tidy # go mod tidymain.go # entry point, transport routing (stdio / SSE)
config.go # Config struct, environment variable loading, Vault overrides
handlers.go # Handlers struct, Initialize(), store selection
tools.go # query-odata-service MCP tool
tools_discovery.go # list-metadata-files, list-available-services, query-service tools
chart.go # generate-chart MCP tool (Anthropic-driven chart spec)
resources.go # MCP resources (metadata.xml, metadata-info.json)
metadata.go # EDMX XML parser (token-stream, SAP namespace-aware)
odataclient.go # HTTP OData client, filter builder, response normaliser
llm.go # Anthropic API entity-selection fallback
store.go # MetadataStore interface
store_s3.go # S3-compatible store (MinIO Go SDK)
store_local.go # Local filesystem store
cache.go # CacheStore interface + config helpers
cache_nats.go # NATS JetStream KV implementation of CacheStore
vault.go # HashiCorp Vault secret loading
internal/logger/ # Structured logging (zap)
examples/ # Claude Desktop, Cursor, Docker Compose configs
Everything is package main. Do not introduce sub-packages.
odata-mcp is maintained by BlueFunda. Security fixes are released within 7 days of disclosure. Feature requests are evaluated quarterly. Please open a GitHub issue for bug reports or enhancement proposals.
Apache 2.0 — see LICENSE.
Authored by Phani Puttabakula, open-sourced under Apache 2.0 by BlueFunda, Inc.