Super-MCP
Provides natural language querying of SAP services via OData or OpenAPI, using SAP AI Core for enriched descriptions and SAP XSUAA for authentication.
Supports loading and querying any OpenAPI/Swagger specification, enabling natural language interaction with APIs defined in Swagger 2.0 or OpenAPI 3.x.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Super-MCPGet top 5 expensive products from Northwind"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Super-MCP
OData + OpenAPI MCP Server
Dynamically generates tools from any OData $metadata or OpenAPI / Swagger spec and lets you query them with natural language via SAP AI Core (GPT-4o).
Load once via
/generate— tools persist to disk and auto-load on every restartspec_idis always optional — auto-detected when only one spec is loadedCredentials live only in
.envon the server — never passed through API requests or seen by the LLMFull RBAC (read-only default, admin required for writes)
Two ways to use it:
Mode | Entry point | Best for |
REST API |
| curl, Postman, programmatic access; docs at |
MCP server |
| Claude Desktop, Claude Code, any MCP client |
Project Structure
mcp/
├── .env # Credentials — SAP AI Core + per-spec API keys (never commit)
├── .env.example # Template — copy to .env and fill in values
├── requirements.txt
│
├── api.py # FastAPI REST server — primary entry point
├── mcp_server.py # FastMCP server for Claude Desktop / Claude Code
│
├── odata_parser.py # Parses OData v2/v4 $metadata XML
├── odata_executor.py # Executes OData HTTP calls (GET/POST/PATCH/DELETE + CSRF)
├── openapi_parser.py # Parses OpenAPI 3.x and Swagger 2.0 (JSON or YAML)
├── openapi_executor.py # Executes HTTP calls for OpenAPI operations + 401-retry
├── auth_manager.py # Reads credentials from env vars; fetches/refreshes tokens
├── rbac_manager.py # Role-based access control (default = read-only, admin = writes)
├── tool_generator.py # Writes tools/{spec_id}.py from a parsed spec
├── sap_ai_client.py # SAP AI Core OAuth2 + GPT-4o client
├── config.py # Loads SAP AI Core config from .env
├── state.py # In-memory spec / tool registry (shared by api.py + mcp_server.py)
│
└── tools/ # Auto-generated tool files (auto-loaded on startup)
└── .gitkeepRelated MCP server: SAP OData to MCP Server
Quick Setup
cd mcp
pip install -r requirements.txt
cp .env .env.example # keep a credential-free template for the repo
# Start the REST API
python3 api.py
# → http://localhost:8080
# → Swagger UI: http://localhost:8080/docsREST API Endpoints
OData
Method | Endpoint | Description |
|
| Fetch OData |
|
| Natural-language query against a loaded OData spec |
OpenAPI / Swagger
Method | Endpoint | Description |
|
| Fetch OpenAPI/Swagger spec → parse → save |
|
| Natural-language query against a loaded OpenAPI spec |
Unified
Method | Endpoint | Description |
|
| Query anything — auto-detects spec type; |
|
| Call a specific tool directly by name with explicit params |
Auth
Method | Endpoint | Description |
|
| Probe a URL without credentials — identify what auth is needed |
|
| Show whether credentials are configured (values never returned) |
|
| Force token refresh on the next call |
Management
Method | Endpoint | Description |
|
| List all loaded specs with entity/operation counts |
|
| List all generated tool files on disk |
|
| Delete a tool file from disk |
|
| Health check — uptime and loaded spec count |
OData Quick Start
1. Load a spec
# Northwind v2 (public demo)
curl -s -X POST http://localhost:8080/api/v1/generate \
-H "Content-Type: application/json" \
-d '{"source": "https://services.odata.org/V2/Northwind/Northwind.svc/$metadata",
"spec_id": "nw"}' | jq
# TripPin v4 (public demo)
curl -s -X POST http://localhost:8080/api/v1/generate \
-H "Content-Type: application/json" \
-d '{"source": "https://services.odata.org/TripPinRESTierService/$metadata",
"spec_id": "trip"}' | jq
# With GPT-4o enriched docstrings (~30s)
curl -s -X POST http://localhost:8080/api/v1/generate \
-H "Content-Type: application/json" \
-d '{"source": "https://services.odata.org/TripPinRESTierService/$metadata",
"spec_id": "trip",
"use_ai_descriptions": true}' | jq2. Query in natural language
# spec_id auto-detected when only one spec is loaded
curl -s -X POST http://localhost:8080/api/v1/query \
-H "Content-Type: application/json" \
-d '{"query": "Get top 5 most expensive products"}' | jq
# explicit spec_id (required when multiple specs are loaded)
curl -s -X POST http://localhost:8080/api/v1/query \
-H "Content-Type: application/json" \
-d '{"spec_id": "trip", "query": "Get person with username russellwhyte"}' | jq
# cap the number of records
curl -s -X POST http://localhost:8080/api/v1/query \
-H "Content-Type: application/json" \
-d '{"query": "List airports", "max_records": 5}' | jq3. Call tools directly
Tool names follow the pattern {spec_id}__{EntitySet}__{operation}:
# filter + sort + field selection
curl -s -X POST http://localhost:8080/api/v1/call/nw__Products__list \
-H "Content-Type: application/json" \
-d '{"top": 5, "orderby": "UnitPrice desc",
"select": "ProductID,ProductName,UnitPrice"}' | jq
# single record by key
curl -s -X POST http://localhost:8080/api/v1/call/nw__Products__get \
-H "Content-Type: application/json" \
-d '{"ProductID": 1}' | jqOpenAPI / Swagger Quick Start
1. Load a spec
# Swagger 2.0
curl -s -X POST http://localhost:8080/api/v1/generate/openapi \
-H "Content-Type: application/json" \
-d '{"source": "https://petstore.swagger.io/v2/swagger.json",
"spec_id": "petstore"}' | jq
# OpenAPI 3.x
curl -s -X POST http://localhost:8080/api/v1/generate/openapi \
-H "Content-Type: application/json" \
-d '{"source": "https://petstore3.swagger.io/api/v3/openapi.json",
"spec_id": "ps3",
"base_url": "https://petstore3.swagger.io/api/v3"}' | jqFor authenticated services — see the Auth section below. Credentials go in .env, not in the request body.
2. Query
# auto-detected spec
curl -s -X POST http://localhost:8080/api/v1/query/openapi \
-H "Content-Type: application/json" \
-d '{"query": "Get all available pets"}' | jq
# unified endpoint (works for both OData and OpenAPI)
curl -s -X POST http://localhost:8080/api/v1/ask \
-H "Content-Type: application/json" \
-d '{"query": "Find pets with status sold"}' | jq3. Call tools directly
Tool names follow {spec_id}__{operationId}:
curl -s -X POST http://localhost:8080/api/v1/call/petstore__findPetsByStatus \
-H "Content-Type: application/json" \
-d '{"status": "available"}' | jq
curl -s -X POST http://localhost:8080/api/v1/call/petstore__getPetById \
-H "Content-Type: application/json" \
-d '{"petId": 1}' | jqAuth — Secure Credential Handling
Credentials are stored only in .env on the server. The LLM and API callers never provide or see credentials. Tokens are fetched and refreshed automatically at runtime.
Supported auth types
Type |
| Description |
SAP XSUAA / OAuth2 |
| Client-credentials flow; tokens auto-refreshed |
Static bearer token |
| Fixed JWT/token — no refresh |
HTTP Basic |
| Username + password → Base64 Authorization header |
API key (header) |
| Key injected into a request header |
API key (query) |
| Key appended as a query parameter |
API key (cookie) |
| Key sent as a cookie |
None |
| Public APIs — no auth |
Step 1 — Detect what auth is required
curl -s -X POST http://localhost:8080/api/v1/detect-auth \
-H "Content-Type: application/json" \
-d '{"url": "https://yourapp.cfapps.eu10.hana.ondemand.com",
"spec_id": "myservice"}' | jqThe response shows the detected auth type and the exact env-var names to set:
{
"auth_required": true,
"auth_type": "Bearer (SAP XSUAA)",
"is_xsuaa": true,
"configured": false,
"env_vars_to_set": {
"MYSERVICE_AUTH_TYPE": "xsuaa",
"MYSERVICE_AUTH_URL": "<url from XSUAA service credentials>",
"MYSERVICE_CLIENT_ID": "<clientid>",
"MYSERVICE_CLIENT_SECRET": "<clientsecret>"
},
"how_to_get_creds": "BTP Cockpit → Space → Service Instances → XSUAA → View Credentials"
}Step 2 — Add credentials to .env
The naming convention is {SPEC_ID_UPPERCASE}_{VAR}. Examples:
# ── SAP BTP / XSUAA (OAuth2 client_credentials) ────────────────────────────
MYSERVICE_AUTH_TYPE=xsuaa
MYSERVICE_AUTH_URL=https://<subaccount>.authentication.eu10.hana.ondemand.com
MYSERVICE_CLIENT_ID=sb-app!t1234
MYSERVICE_CLIENT_SECRET=xxxxxxxxxxxxxxxx
# Optionally override the token endpoint (default: AUTH_URL/oauth/token)
MYSERVICE_TOKEN_URL=https://<subaccount>.authentication.eu10.hana.ondemand.com/oauth/token
# ── Static bearer token ─────────────────────────────────────────────────────
REPORTAPI_AUTH_TYPE=bearer_static
REPORTAPI_BEARER_TOKEN=eyJhbGciOiJSUzI1NiJ9...
# ── HTTP Basic auth ─────────────────────────────────────────────────────────
LEGACYAPI_AUTH_TYPE=basic
LEGACYAPI_USERNAME=admin
LEGACYAPI_PASSWORD=secret
# ── API key in a header ─────────────────────────────────────────────────────
WEATHERAPI_AUTH_TYPE=apikey
WEATHERAPI_API_KEY=abc123xyz
WEATHERAPI_API_KEY_NAME=X-API-Key
WEATHERAPI_API_KEY_IN=header # header | query | cookie
# ── API key as query param ──────────────────────────────────────────────────
MAPSAPI_AUTH_TYPE=apikey
MAPSAPI_API_KEY=mymapskey
MAPSAPI_API_KEY_NAME=key
MAPSAPI_API_KEY_IN=queryRestart api.py — it loads .env on startup. For the MCP server, set these in .env the same way.
Step 3 — Load the spec (no credentials needed in the request)
curl -s -X POST http://localhost:8080/api/v1/generate/openapi \
-H "Content-Type: application/json" \
-d '{"source": "https://yourapp.cfapps.eu10.hana.ondemand.com/api/openapi.json",
"spec_id": "myservice"}' | jqThe server reads MYSERVICE_AUTH_TYPE, fetches an XSUAA token, and stores it internally. No credentials in the request.
Step 4 — Query normally
curl -s -X POST http://localhost:8080/api/v1/ask \
-H "Content-Type: application/json" \
-d '{"query": "Get all open orders"}' | jqBefore every outgoing API call the executor checks whether the cached token is still valid (60-second buffer). If expired it silently fetches a new one and retries. On an unexpected 401 it invalidates the cache and retries once.
Auth management
# See configuration status — credential values are never returned
curl -s http://localhost:8080/api/v1/auth-status/myservice | jq
# → {"configured": true, "auth_type": "xsuaa",
# "token_status": {"cached": true, "expires_in_seconds": 43140}}
# Force token refresh before the next call
curl -s -X POST http://localhost:8080/api/v1/auth/invalidate/myservice | jqRBAC — Role-Based Access Control
Every operation is gated by role. The default role is read-only — it can only call list and get (OData) and GET/HEAD (HTTP). Write operations (create, update, delete / POST, PUT, PATCH, DELETE) require the admin role.
Configuring roles (environment variables)
# ── Option 1: single-role for the whole server instance ────────────────────
MCP_USER_ROLE=admin # everyone on this instance is admin
# ── Option 2: tie role to the server's email identity ──────────────────────
MCP_USER_EMAIL=alice@acme.com
RBAC_EMAIL_ROLES=alice@acme.com:admin,bob@acme.com:default
# ── Option 3: grant a role to an entire domain ─────────────────────────────
RBAC_DOMAIN_ROLES=acme.com:admin,partner.com:default
# ── Option 4: opaque API keys (HTTP / SSE multi-user transport) ─────────────
RBAC_USERS=secret_adminkey123:admin,readonly_xyz:defaultResolution order (first match wins): MCP_USER_ROLE → email exact match → email domain → X-API-Key header → fallback default.
Checking your role (MCP tool)
whoami → shows role, permitted operations, and RBAC configError response when role is insufficient
{
"error": "This operation requires the 'admin' role. Current role: 'default'. Set MCP_USER_ROLE=admin or add your email to RBAC_EMAIL_ROLES.",
"required_role": "admin"
}Persistence — Auto-load on Restart
Every /generate call writes tools/{spec_id}.py that embeds the full spec as base64. On the next startup:
server starts
└─ scans tools/*.py
└─ decodes embedded spec (no network call needed)
└─ restores all in-memory state (specs, tools)
└─ server is query-ready immediatelyAuth credentials are not stored in tool files. They are re-read from .env on every execute call.
MCP Server — Claude Desktop / Claude Code
Start
# stdio (Claude Desktop / Claude Code)
python3 mcp_server.py
# SSE transport on a custom port
python3 mcp_server.py --sse 8001
# → http://localhost:8001/sse
# Streamable-HTTP transport
python3 mcp_server.py --http 8002
# → http://localhost:8002/mcpClaude Desktop config (~/.claude/claude_desktop_config.json)
{
"mcpServers": {
"odata-mcp": {
"command": "python3",
"args": ["/home/user/projects/mcp/mcp_server.py"]
}
}
}Static MCP tools (always available)
Tool | Description |
| Load an OData |
| Load an OpenAPI/Swagger spec and register operation tools |
| Natural-language query over any loaded spec |
| Persist the current spec to |
| List all dynamically registered tools |
| List tool files on disk |
| Ask GPT-4o a question about a loaded spec |
| Convert natural language to an OData REST call |
| Ping SAP AI Core / GPT-4o |
| Show current role and permitted operations |
How It Works
POST /api/v1/generate (or load_odata_spec in MCP)
└─ fetch spec from URL (follows redirects)
└─ parse → EntitySets / operations, parameters, keys, security schemes
└─ register tools in memory
└─ write tools/{spec_id}.py (embedded spec as base64)
POST /api/v1/ask (or smart_query in MCP)
└─ resolve spec_id
│ ├─ single spec loaded → use it automatically
│ └─ multiple specs loaded → GPT-4o picks the right one
└─ build compact spec summary (entity names, keys, fields)
└─ GPT-4o returns JSON: { entity_set, operation, args, explanation }
└─ RBAC check (write ops require admin role)
└─ executor called with resolved args
OpenAPI executor
└─ auth_manager.get_auth_headers(spec_id)
│ └─ reads {SPEC_ID}_AUTH_TYPE from env
│ └─ for xsuaa/oauth2: fetch token (client_credentials)
│ └─ cache token with 60-second expiry buffer
│ └─ return { Authorization: "Bearer <token>" }
└─ route args by location: path / query / header / body / cookie
└─ build URL: base_url + path (with path-param substitution)
└─ HTTP call
└─ on 401: invalidate cache → refresh token → retry once
OData executor
└─ build OData URL: base_url/EntitySet(key)?$filter=...&$top=...
└─ for write ops: fetch X-CSRF-Token first (SAP OData v2 requirement)
└─ POST/PATCH/DELETE with CSRF token + cookies
└─ return parsed JSONTool naming convention
OData → {spec_id}__{EntitySet}__{operation}
nw__Products__list nw__Products__get
nw__Products__create nw__Products__update nw__Products__delete
OpenAPI → {spec_id}__{operationId}
petstore__findPetsByStatus petstore__getPetById petstore__addPetSAP AI Core Configuration
SAP_AI_API_URL=https://api.ai.prod.eu-central-1.aws.ml.hana.ondemand.com
SAP_AI_CLIENT_ID=<client_id from AI Core service binding>
SAP_AI_CLIENT_SECRET=<client_secret>
SAP_AI_AUTH_URL=https://<subaccount>.authentication.eu10.hana.ondemand.com
SAP_AI_RESOURCE_GROUP=default
SAP_AI_MODEL_NAME=gpt-4o
# Pin to a specific deployment (skips auto-discovery at startup)
SAP_AI_DEPLOYMENT_ID=d5c7fe212eec831cThe client auto-discovers the right deployment ID from /v2/lm/deployments if SAP_AI_DEPLOYMENT_ID is not set. It prefers gpt-4o → gpt-4.1 → gpt-4 → first RUNNING deployment.
Environment Variables — Full Reference
SAP AI Core
Variable | Description |
| AI Core API base URL |
| OAuth2 client ID |
| OAuth2 client secret |
| XSUAA auth URL (without |
| AI Core resource group (default: |
| Model name (default: |
| Pin to a specific deployment ID |
RBAC
Variable | Description |
|
|
| Email to look up in |
|
|
|
|
|
|
Per-spec auth ({PREFIX} = spec_id uppercased, hyphens → underscores)
Variable | Description |
|
|
| XSUAA / OAuth2 auth URL |
| OAuth2 client ID |
| OAuth2 client secret |
| OAuth2 grant type (default: |
| Override the token endpoint |
| Static bearer token |
| Basic auth username |
| Basic auth password |
| API key value |
| API key header/param name (default: |
| Where to send the key: |
Troubleshooting
Symptom | Fix |
|
|
| First run: call |
AI Core 404 on inference | Set |
401 on API call | Run |
401 persists after setting env vars | Token may be stale: |
XSUAA token fetch fails | Verify |
CSRF error on OData write | Handled automatically — executor fetches |
TripPin returns 0 results | Session URL changes on each access — |
Write op denied (role error) | Set |
| Call the |
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
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/JyotishKumarr/Super-MCP'
If you have feedback or need assistance with the MCP directory API, please join our Discord server