{"id":47598620,"url":"https://github.com/ralfbecher/orionbelt-semantic-layer-mcp","last_synced_at":"2026-05-05T22:02:01.622Z","repository":{"id":343411001,"uuid":"1170503768","full_name":"ralfbecher/orionbelt-semantic-layer-mcp","owner":"ralfbecher","description":"MCP server for the OrionBelt Semantic Layer — enables LLMs to explore semantic models, compile queries, and execute analytics via natural language.","archived":false,"fork":false,"pushed_at":"2026-04-27T20:38:39.000Z","size":812,"stargazers_count":2,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-04-27T21:26:53.767Z","etag":null,"topics":["agentic-ai","business-intelligence","data-analytics","mcp-server","semantic-layer","sql","yaml"],"latest_commit_sha":null,"homepage":"https://ralforion.com/orionbelt-semantic-layer/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ralfbecher.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-02T07:38:57.000Z","updated_at":"2026-04-27T20:37:33.000Z","dependencies_parsed_at":"2026-04-01T21:04:41.825Z","dependency_job_id":null,"html_url":"https://github.com/ralfbecher/orionbelt-semantic-layer-mcp","commit_stats":null,"previous_names":["ralfbecher/orionbelt-semantic-layer-mcp"],"tags_count":20,"template":false,"template_full_name":null,"purl":"pkg:github/ralfbecher/orionbelt-semantic-layer-mcp","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ralfbecher%2Forionbelt-semantic-layer-mcp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ralfbecher%2Forionbelt-semantic-layer-mcp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ralfbecher%2Forionbelt-semantic-layer-mcp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ralfbecher%2Forionbelt-semantic-layer-mcp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ralfbecher","download_url":"https://codeload.github.com/ralfbecher/orionbelt-semantic-layer-mcp/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ralfbecher%2Forionbelt-semantic-layer-mcp/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32669433,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-05T11:29:49.557Z","status":"ssl_error","status_checked_at":"2026-05-05T11:29:48.587Z","response_time":54,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agentic-ai","business-intelligence","data-analytics","mcp-server","semantic-layer","sql","yaml"],"created_at":"2026-04-01T18:33:50.854Z","updated_at":"2026-05-05T22:02:01.611Z","avatar_url":"https://github.com/ralfbecher.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003c!-- mcp-name: io.github.ralfbecher/orionbelt-semantic-layer-mcp --\u003e\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/ralfbecher/orionbelt-semantic-layer-mcp/main/docs/assets/ORIONBELT_Logo.png\" alt=\"OrionBelt Logo\" width=\"400\"\u003e\n\u003c/p\u003e\n\n\u003ch1 align=\"center\"\u003eOrionBelt Semantic Layer MCP\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\u003cstrong\u003eThin MCP server that delegates to the OrionBelt Semantic Layer REST API\u003c/strong\u003e\u003c/p\u003e\n\n[![Version 2.2.0](https://img.shields.io/badge/version-2.2.0-purple.svg)](https://github.com/ralfbecher/orionbelt-semantic-layer-mcp/releases)\n[![OrionBelt Semantic Layer 2.2](https://img.shields.io/badge/OrionBelt_Semantic_Layer-2.2-0054A6.svg)](https://github.com/ralfbecher/orionbelt-semantic-layer)\n[![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/downloads/)\n[![License: Apache 2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://github.com/ralfbecher/orionbelt-semantic-layer-mcp/blob/main/LICENSE)\n[![FastMCP](https://img.shields.io/badge/FastMCP-3.2+-8A2BE2)](https://gofastmcp.com)\n[![Pydantic v2](https://img.shields.io/badge/Pydantic-v2-E92063.svg?logo=pydantic\u0026logoColor=white)](https://docs.pydantic.dev)\n[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://docs.astral.sh/ruff/)\n\n[![BigQuery](https://img.shields.io/badge/BigQuery-669DF6.svg?logo=googlebigquery\u0026logoColor=white)](https://cloud.google.com/bigquery)\n[![PostgreSQL](https://img.shields.io/badge/PostgreSQL-4169E1.svg?logo=postgresql\u0026logoColor=white)](https://www.postgresql.org)\n[![Snowflake](https://img.shields.io/badge/Snowflake-29B5E8.svg?logo=snowflake\u0026logoColor=white)](https://www.snowflake.com)\n[![ClickHouse](https://img.shields.io/badge/ClickHouse-FFCC01.svg?logo=clickhouse\u0026logoColor=black)](https://clickhouse.com)\n[![Dremio](https://img.shields.io/badge/Dremio-31B48D.svg)](https://www.dremio.com)\n[![Databricks](https://img.shields.io/badge/Databricks-FF3621.svg?logo=databricks\u0026logoColor=white)](https://www.databricks.com)\n[![DuckDB](https://img.shields.io/badge/DuckDB-FFF000.svg?logo=duckdb\u0026logoColor=black)](https://duckdb.org)\n[![MySQL](https://img.shields.io/badge/MySQL-4479A1.svg?logo=mysql\u0026logoColor=white)](https://www.mysql.com)\n\nA thin MCP server that delegates all business logic to the [OrionBelt Semantic Layer](https://github.com/ralfbecher/orionbelt-semantic-layer) REST API via HTTP. No embedded engine — pure API pass-through.\n\n## Architecture\n\nThe OrionBelt Semantic Layer platform has two deployment modes. This MCP server supports both:\n\n- **Standalone** — Deploy the [OrionBelt Semantic Layer API](https://github.com/ralfbecher/orionbelt-semantic-layer) anywhere (Cloud Run, Docker, localhost) and point this MCP server at it via `API_BASE_URL`.\n- **Hosted** — Connect to the public Cloud Run deployment with zero local setup (see [Hosted MCP Server](#hosted-mcp-server) below).\n\n```\n┌────────────┐       ┌──────────────────────────────────────────────────────┐\n│ LLM Client │       │                OrionBelt Platform                    │\n│            │       │                                                      │\n│  Claude,   │──MCP──│──\u003e server.py  ──HTTP /v1──\u003e  Semantic Layer REST API │\n│  Cursor,   │       │    (FastMCP                   (FastAPI: parse OBML,  │\n│  any MCP   │       │     + httpx)                   validate, compile     │\n│  client    │       │                                to SQL)               │\n└────────────┘       └──────────────────────────────────────────────────────┘\n```\n\n- **No business logic** — all tool calls delegate to the REST API (v1 endpoints)\n- **Dual-mode** — auto-detects single-model or multi-model API mode at startup\n- **Auto-session management** — creates an API session on first tool call, caches the ID (multi-model mode)\n- **27 tools** (single-model mode) or **30 tools** (multi-model mode) for querying, execution, batch, planning, discovery, examples, diagrams, RDF/SPARQL, freshness cache, and format conversion\n- **3 prompts + 1 resource** for OBML reference and usage guidance\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/ralfbecher/orionbelt-semantic-layer-mcp/main/docs/assets/architecture.png\" alt=\"OrionBelt Analytics Architecture\" width=\"900\"\u003e\n\u003c/p\u003e\n\n## Live Demo\n\nA public demo of the OrionBelt Semantic Layer API is available at:\n\n\u003e **API endpoint:** `https://orionbelt.ralforion.com` — [Swagger UI](https://orionbelt.ralforion.com/docs) | [ReDoc](https://orionbelt.ralforion.com/redoc) | [Gradio UI](https://orionbelt.ralforion.com/ui/?__theme=dark)\n\nSet `API_BASE_URL=https://orionbelt.ralforion.com` in your `.env` file to use it (see `.env.example`).\n\n## Installation\n\n```bash\nuv sync\n```\n\nFor development (includes pytest, respx, ruff):\n\n```bash\nuv sync --all-groups\n```\n\n## Usage\n\n### stdio (default)\n\n```bash\nuv run server.py\n```\n\n### HTTP transport\n\n```bash\nMCP_TRANSPORT=http uv run python server.py\n```\n\n### MCP client configuration\n\nAdd to your MCP client config (e.g. `claude_desktop_config.json`):\n\n```json\n{\n  \"mcpServers\": {\n    \"orionbelt\": {\n      \"command\": \"uv\",\n      \"args\": [\"run\", \"python\", \"server.py\"],\n      \"cwd\": \"/path/to/orionbelt-semantic-layer-mcp\"\n    }\n  }\n}\n```\n\n## Configuration\n\nEnvironment variables or `.env` file (pydantic-settings). See `.env.example` for defaults.\n\n| Variable          | Default      | Description                           |\n| ----------------- | ------------ | ------------------------------------- |\n| `API_BASE_URL`    | — (required) | OrionBelt Semantic Layer REST API URL |\n| `MCP_TRANSPORT`   | `stdio`      | `stdio`, `http`, or `sse`             |\n| `MCP_SERVER_HOST` | `localhost`  | Bind host for HTTP/SSE                |\n| `MCP_SERVER_PORT` | `9000`       | Bind port for HTTP/SSE                |\n| `LOG_LEVEL`       | `INFO`       | Logging level                         |\n| `API_TIMEOUT`     | `30`         | HTTP timeout in seconds               |\n| `HEARTBEAT_AUTH_TOKEN` | —       | Bearer token forwarded to `POST /v1/heartbeat` (must match the API's value) |\n\n## Tools\n\n### Model lifecycle\n\n| MCP Tool                          | Description                                              |\n| --------------------------------- | -------------------------------------------------------- |\n| `get_obml_reference()`            | Returns the full OBML format specification               |\n| `load_model(model, dedup=True)`   | Parse, validate, and store a model (returns health + model_load) |\n| `describe_model(model_id)`        | Inspect data objects, dimensions, measures, metrics      |\n| `remove_model(model_id)`          | Remove a model from the current session                  |\n| `list_models()`                   | List all models loaded in the current session            |\n\n### Model discovery\n\n| MCP Tool                          | Description                                              |\n| --------------------------------- | -------------------------------------------------------- |\n| `get_model_schema(model_id)`      | Full model structure as JSON (detailed)                  |\n| `list_dimensions(model_id)`       | List all dimensions in a model                           |\n| `get_dimension(model_id, name)`   | Get a single dimension by name                           |\n| `list_measures(model_id)`         | List all measures in a model                             |\n| `get_measure(model_id, name)`     | Get a single measure by name                             |\n| `list_metrics(model_id)`          | List all metrics in a model                              |\n| `get_metric(model_id, name)`      | Get a single metric by name                              |\n| `explain_artefact(model_id, name)`| Explain lineage of a dimension, measure, or metric       |\n| `find_artefacts(model_id, query)` | Search artefacts (exact / synonym / fuzzy buckets)       |\n| `list_examples(model_id, intent?)`| List authored example queries (filterable by intent tag) |\n| `get_example(model_id, name)`     | Get one example with query + compiled SQL preview        |\n| `get_join_graph(model_id)`        | Return the join graph as an adjacency list               |\n\n### Query, execution \u0026 diagrams\n\n| MCP Tool                          | Description                                              |\n| --------------------------------- | -------------------------------------------------------- |\n| `compile_query(...)`              | Compile a semantic query to SQL (with explain plan)      |\n| `execute_query(...)`              | Compile and execute a query, returning SQL + result data |\n| `plan_query(model_id, ...)`       | Planner view (no SQL); optional warehouse `EXPLAIN`      |\n| `run_batch(queries, ...)`         | One-shot: load a model + run N queries in parallel       |\n| `get_model_diagram(model_id)`     | Generate a Mermaid ER diagram for a loaded model         |\n\n### Semantic graph (RDF / SPARQL)\n\n| MCP Tool                          | Description                                              |\n| --------------------------------- | -------------------------------------------------------- |\n| `get_graph(model_id)`             | Return the model as OBSL-Core RDF (Turtle)               |\n| `sparql_query(model_id, query)`   | Run a read-only SPARQL query (SELECT / ASK)              |\n\n### Freshness cache\n\n| MCP Tool                                  | Description                                              |\n| ----------------------------------------- | -------------------------------------------------------- |\n| `get_cache_stats()`                       | Cache backend, entry count, hit rate, sweep time         |\n| `heartbeat(database, schema, table, ts?)` | Notify the API a table refreshed (invalidates cache)     |\n\n### Utilities\n\n| MCP Tool                          | Description                                              |\n| --------------------------------- | -------------------------------------------------------- |\n| `list_dialects()`                 | List available SQL dialects and capabilities             |\n| `get_settings()`                  | Get API config (modes, TTL, oneshot batch limits)        |\n| `convert_osi_to_obml(input_yaml)` | Convert OSI YAML to OBML format                          |\n| `convert_obml_to_osi(input_yaml)` | Convert OBML YAML to OSI format                          |\n\n## Supported SQL Dialects\n\n`postgres`, `snowflake`, `clickhouse`, `databricks`, `dremio`, `bigquery`, `duckdb`\n\n## Workflow\n\n1. **Get reference** — call `get_obml_reference()` to learn OBML syntax\n2. **Load model** — call `load_model(model_yaml)` to get a `model_id`\n3. **Explore** — call `describe_model(model_id)` or use discovery tools (`list_dimensions`, `find_artefacts`, `explain_artefact`, etc.)\n4. **Query** — call `compile_query(model_id, dimensions=[...], measures=[...])` to generate SQL\n5. **Execute** — call `execute_query(model_id, dimensions=[...], measures=[...])` to run SQL and get results (requires `QUERY_EXECUTE=true` on the API)\n\n## Integration Guides\n\nUse the OrionBelt Semantic Layer MCP server with popular AI agent frameworks and automation platforms:\n\n| Framework | Transport | Guide |\n|-----------|-----------|-------|\n| **OpenAI Agents SDK** | stdio, HTTP, SSE | [docs/integrations/openai-agents-sdk.md](docs/integrations/openai-agents-sdk.md) |\n| **LangChain** | stdio, HTTP | [docs/integrations/langchain.md](docs/integrations/langchain.md) |\n| **Google ADK** | stdio, HTTP, SSE | [docs/integrations/google-adk.md](docs/integrations/google-adk.md) |\n| **n8n** | HTTP, SSE | [docs/integrations/n8n.md](docs/integrations/n8n.md) |\n| **CrewAI** | stdio, HTTP | [docs/integrations/crewai.md](docs/integrations/crewai.md) |\n\nEach guide includes quick-start examples, multi-agent patterns, and connection options for both the hosted demo and self-hosted deployments.\n\n## Development\n\n```bash\n# Run tests\nuv run pytest\n\n# Lint\nuv run ruff check server.py\nuv run ruff format server.py tests/\n```\n\n## Hosted MCP Server\n\nA public hosted instance of this MCP server runs on Google Cloud Run, connected\nto the live OrionBelt Semantic Layer demo API. No local install, no API key.\n\n### Endpoint\n\n```\nhttps://orionbelt.ralforion.com/mcp\n```\n\nStreamable HTTP (MCP spec 2025-03-26). Stateful — clients should send the\n`initialize` handshake and reuse the returned `Mcp-Session-Id` header.\n\n### Quick start with Claude Desktop\n\nClaude Desktop's config schema accepts only stdio launchers — for a remote\nMCP server, use the [`mcp-remote`](https://www.npmjs.com/package/mcp-remote)\nstdio↔HTTP bridge (auto-fetched by `npx`, no manual install).\n\nEdit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS)\nor `%APPDATA%\\Claude\\claude_desktop_config.json` (Windows) and add:\n\n```json\n{\n  \"mcpServers\": {\n    \"orionbelt\": {\n      \"command\": \"npx\",\n      \"args\": [\n        \"mcp-remote\",\n        \"https://orionbelt.ralforion.com/mcp\",\n        \"--transport\",\n        \"http\"\n      ]\n    }\n  }\n}\n```\n\nFully quit Claude Desktop (⌘Q on macOS — closing the window isn't enough) and\nreopen. The OrionBelt tools then appear in the tools menu.\n\nAlternatively, in newer Claude Desktop builds: **Settings → Connectors → Add\ncustom connector**, paste the URL above. No file editing or `npx` required.\n\n\u003e **Why `mcp-remote`?** Claude Desktop's `claude_desktop_config.json` schema\n\u003e currently only validates stdio entries (`command` + `args`). A bare\n\u003e `{\"url\": \"…\"}` entry is rejected with *\"not valid MCP server configurations\n\u003e and were skipped\"*. `mcp-remote` runs a local stdio bridge that forwards to\n\u003e the HTTPS endpoint, so Claude Desktop sees a normal stdio server. **Claude\n\u003e Code** does support `{\"type\": \"url\", \"url\": \"…\"}` natively — see below.\n\n### Quick start with Claude Code\n\nAdd to `.mcp.json` in any repo (or `~/.config/claude-code/.mcp.json` globally):\n\n```json\n{\n  \"mcpServers\": {\n    \"orionbelt\": {\n      \"type\": \"url\",\n      \"url\": \"https://orionbelt.ralforion.com/mcp\"\n    }\n  }\n}\n```\n\n### Other MCP clients\n\nAny client that supports Streamable HTTP transport (MCP spec 2025-03-26) can\npoint at the URL above. The endpoint accepts `POST /mcp` with\n`Accept: application/json, text/event-stream`. See\n[`tests/cloudrun/test_mcp_cloudrun.sh`](tests/cloudrun/test_mcp_cloudrun.sh)\nfor a stdlib-only Python smoke test that walks the full handshake.\n\n### Notes\n\n- The hosted instance scales to zero when idle, so the first request after a\n  cold period takes ~1–2 seconds longer.\n- It connects to the public demo API at `https://orionbelt.ralforion.com` — same data,\n  same dialects, no authentication. Don't load production data through it.\n- For self-hosting, see the [Installation](#installation) section above and\n  the [`Dockerfile`](Dockerfile).\n\n## License\n\nCopyright 2025 [RALFORION d.o.o.](https://ralforion.com)\n\nLicensed under the Apache License, Version 2.0. See [LICENSE](LICENSE) for details.\n\n---\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://ralforion.com\"\u003e\n    \u003cimg src=\"https://raw.githubusercontent.com/ralfbecher/orionbelt-semantic-layer-mcp/main/docs/assets/RALFORION_doo_Logo.png\" alt=\"RALFORION d.o.o.\" width=\"200\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fralfbecher%2Forionbelt-semantic-layer-mcp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fralfbecher%2Forionbelt-semantic-layer-mcp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fralfbecher%2Forionbelt-semantic-layer-mcp/lists"}