Smart Data Models MCP Server
Public MCP service providing programmatic access to the Smart Data Models catalog — a multi-sector library of standardized IoT and data space schemas governed by FIWARE, TM Forum, IUDX, and ITU-T.
MCP Endpoint: https://opendatamodels.org/mcp/v1
Health: https://opendatamodels.org/mcp/v1/health
Docs: https://opendatamodels.org/mcp/v1/docs
Manifest: https://opendatamodels.org/mcp/v1/manifest.json
AI / LLM Application Builder
This section is first because AI agents are the primary consumers of this MCP. The server is designed so that a capable LLM can correctly use all 15 tools with zero human guidance, provided the following is understood.
Connect
Add this to your Claude Desktop, Cursor, or any MCP-compatible client config:
{
"mcpServers": {
"smartdatamodels": {
"type": "http",
"serverUrl": "https://opendatamodels.org/mcp/v1"
}
}
}
What the LLM receives on first connect
The server returns server_instructions in the initialize response. Every LLM client that implements the MCP spec will automatically receive a domain model explanation — what SDM is, the subject/model/attribute hierarchy, when to call which tool, and how NGSI-LD payloads work — before touching any tool. You do not need to add a system prompt explaining SDM.
Decision tree for tool selection
User wants to find a model
├─ Has a keyword ("air quality", "parking") → search_data_models
├─ Has a misspelled or partial name → fuzzy_find_model
├─ Wants to browse a sector → list_domains → list_models_by_domain
└─ Has entity type from a payload, no subj → find_subject_by_model_name
User wants to understand a model
├─ Needs full JSON Schema → get_data_model
├─ Needs all fields with types/units → get_attributes_for_model
├─ Needs one specific field in depth → get_attribute_details
├─ Needs the GitHub source link → get_model_repo_url
└─ Needs @context for NGSI-LD payload → get_model_context
User wants to build a valid NGSI-LD payload
├─ Step 1: get @context URL → get_model_context ← always first
├─ Step 2: get field names and types → get_attributes_for_model
└─ Step 3: validate the constructed payload → validate_data
User wants to explore the catalog
├─ Full structured list for a domain → get_full_catalog
├─ Models related to a known model → get_related_models
└─ Flat attribute export (CSV / DB mapping) → export_model_attributes
Error recovery pattern
Every tool that takes a model_name can return MODEL_NOT_FOUND. The structured error always includes a suggestion field. The correct LLM recovery sequence:
- Receive
{"isError": true, "error": {"code": "MODEL_NOT_FOUND", ...}} - Call
fuzzy_find_modelwith the same name andthreshold: 70 - Present ranked candidates to the user or pick the top match
- Retry the original tool with the corrected name
Building a valid NGSI-LD payload — correct tool sequence
# Step 1: get @context
curl -s -X POST https://opendatamodels.org/mcp/v1 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call",
"params":{"name":"get_model_context","arguments":{"model_name":"WeatherObserved"}}}'
# Step 2: get all attributes
curl -s -X POST https://opendatamodels.org/mcp/v1 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call",
"params":{"name":"get_attributes_for_model","arguments":{"model_name":"WeatherObserved"}}}'
# Step 3: validate the constructed payload
curl -s -X POST https://opendatamodels.org/mcp/v1 \
-H "Content-Type: application/json" \
-d '{
"jsonrpc":"2.0","id":3,"method":"tools/call",
"params":{
"name":"validate_data",
"arguments":{
"model_name":"WeatherObserved",
"data":{
"@context":"https://smart-data-models.github.io/dataModel.Weather/context.jsonld",
"id":"urn:ngsi-ld:WeatherObserved:station-001",
"type":"WeatherObserved",
"temperature":{"type":"Property","value":22.5},
"location":{"type":"GeoProperty","value":{"type":"Point","coordinates":[-3.7,40.4]}}
}
}
}
}'
Error response format (all tools)
Every error is structured — no bare strings, no silent failures:
{
"isError": true,
"error": {
"code": "MODEL_NOT_FOUND",
"message": "Data model 'WeatherObservd' was not found.",
"suggestion": "Check the spelling — model names are CamelCase. Use fuzzy_find_model to find the correct name."
}
}
Validation failures are not system errors. isError is false even when a payload fails validation:
{
"isError": false,
"model_name": "WeatherObserved",
"valid": false,
"errors": ["'temperature' is a required property"],
"detail": { ... }
}
All 15 Tools — Reference
| Tool | Required params | Optional params | Description |
|---|---|---|---|
search_data_models |
query |
domain, limit |
Search catalog by keyword |
get_data_model |
model_name |
include_examples |
Full JSON Schema and metadata |
list_domains |
— | — | All 13 domains with model counts |
list_models_by_domain |
domain |
limit |
All model names in a domain |
validate_data |
model_name, data |
strict |
Validate a JSON payload |
get_related_models |
model_name |
relationship_type |
Semantically related models |
get_attributes_for_model |
model_name |
— | All attributes with NGSI type and units |
get_attribute_details |
model_name, attribute |
— | Full metadata for one attribute |
find_subject_by_model_name |
model_name |
— | Resolve entity type → subject |
fuzzy_find_model |
model_name |
threshold (0–100, default 70) |
Ranked candidates for misspelled names |
get_subject_repo_url |
subject |
— | GitHub URL for a subject group |
get_model_repo_url |
model_name |
— | GitHub URL(s) for a model |
get_full_catalog |
domain |
— | Complete model list for one domain |
export_model_attributes |
model_name |
separator, fields |
Flat delimited attribute export |
get_model_context |
model_name |
— | NGSI-LD @context URL and content |
Valid domain values
SmartCities · SmartAgrifood · SmartWater · SmartEnergy · SmartEnvironment · SmartRobotics · SmartSensoring · CrossSector · SmartAeronautics · SmartDestinations · SmartHealth · SmartManufacturing · SmartLogistics
export_model_attributes — valid fields
property · type · dataModel · repoName · description · typeNGSI · modelTags · format · units · model
Rate Limits
60 requests / 60 seconds per IP. Every response includes:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 57
X-RateLimit-Reset: 43
X-RateLimit-Window: 60s
When exceeded: HTTP 429. The X-RateLimit-Reset header tells you how many seconds until the window resets. Configurable server-side via RATE_LIMIT_REQUESTS and RATE_LIMIT_WINDOW_S environment variables.
Health & SLA
curl https://opendatamodels.org/mcp/v1/health
{
"status": "healthy",
"service": "smartdatamodels-mcp",
"version": "1.0.0",
"uptime_human": "3d 4h 12m",
"adapter_status": "reachable",
"timestamp": "2025-03-08T14:23:01Z",
"sla": {
"target_availability": "99.5%",
"max_response_ms": 2000,
"retry_after_503_seconds": [5, 15, 60]
}
}
| HTTP | status |
Meaning |
|---|---|---|
| 200 | healthy |
Adapter reachable, serving requests |
| 503 | degraded |
Adapter initialising (server starting up) |
| 503 | unhealthy |
Adapter unreachable — back off and retry |
On 503: retry with delays of 5 s → 15 s → 60 s.
Versioning & Deprecation
| URL | Status |
|---|---|
https://opendatamodels.org/mcp/v1 |
Current — use this |
https://opendatamodels.org/mcp |
Deprecated — Sunset: 2026-12-31 |
Legacy /mcp calls still work but receive Deprecation: true and Sunset: 2026-12-31 response headers.
Key Concepts (NGSI-LD / SDM)
Domain — top-level industry sector (e.g., SmartCities, SmartEnergy). 13 domains total.
Subject — a repository group within a domain, always prefixed dataModel. (e.g., dataModel.Weather). One domain contains many subjects.
Model — a specific entity schema within a subject (e.g., WeatherObserved). The unit you validate against, retrieve schemas for, and build payloads from.
Attribute — a field inside a model. Every attribute has:
- NGSI type:
Property,GeoProperty, orRelationship - Data type:
Number,Text,DateTime, etc. - Units: recommended measurement units where applicable
- Reference model URL: link to the external ontology or standard the attribute is drawn from
@context — the JSON-LD context document that makes NGSI-LD payloads valid linked data. Required in every normalized NGSI-LD payload. Retrieve it with get_model_context before constructing a payload — this is the single most common mistake when building NGSI-LD payloads from scratch.
Payload formats — validate_data accepts both:
- NGSI-LD normalized:
{"temperature": {"type": "Property", "value": 22}} - Key-values:
{"temperature": 22}
Other Audiences
IoT Application Developer
# Find the right model
curl -s -X POST https://opendatamodels.org/mcp/v1 -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call",
"params":{"name":"search_data_models",
"arguments":{"query":"temperature sensor","domain":"SmartSensoring"}}}'
# Get its fields and units
curl -s -X POST https://opendatamodels.org/mcp/v1 -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call",
"params":{"name":"get_attributes_for_model","arguments":{"model_name":"WeatherObserved"}}}'
# Validate your device payload before publishing
curl -s -X POST https://opendatamodels.org/mcp/v1 -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call",
"params":{"name":"validate_data","arguments":{"model_name":"WeatherObserved",
"data":{"id":"urn:ngsi-ld:WeatherObserved:001","type":"WeatherObserved",
"temperature":{"type":"Property","value":22.5}}}}}'
Data Engineer / Architect
# Export attributes as CSV for DB column mapping
curl -s -X POST https://opendatamodels.org/mcp/v1 -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call",
"params":{"name":"export_model_attributes","arguments":{
"model_name":"AirQualityObserved","separator":",",
"fields":["property","type","typeNGSI","units","description"]}}}'
# Get GitHub source for schema citation
curl -s -X POST https://opendatamodels.org/mcp/v1 -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call",
"params":{"name":"get_model_repo_url","arguments":{"model_name":"AirQualityObserved"}}}'
# Get full domain catalog for bulk analysis
curl -s -X POST https://opendatamodels.org/mcp/v1 -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call",
"params":{"name":"get_full_catalog","arguments":{"domain":"SmartEnvironment"}}}'
Smart City / Urban Planner
# Browse all available domains
curl -s -X POST https://opendatamodels.org/mcp/v1 -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"list_domains","arguments":{}}}'
# List all models in Smart Cities
curl -s -X POST https://opendatamodels.org/mcp/v1 -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call",
"params":{"name":"list_models_by_domain","arguments":{"domain":"SmartCities"}}}'
# Find related models to a parking model
curl -s -X POST https://opendatamodels.org/mcp/v1 -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call",
"params":{"name":"get_related_models","arguments":{"model_name":"OffStreetParking"}}}'
Support
- Issues: smartdatamodels.org/submit-an-issue
- Slack: smartdatamodels.org/slack-channel
- GitHub: github.com/smart-data-models