Date: 2026-06-11
Accepted
AI clients such as Claude Desktop and Microsoft Copilot Studio speak the Model Context Protocol (MCP), an emerging open standard that lets language models call typed tools exposed by a server. IC-Hub already contains all the orchestration logic needed to discover partners, browse digital twins, provision catalog parts, and exchange submodels in the Tractus-X dataspace. The MCP Addon surfaces that logic as high-level, use-case-oriented MCP tools so that non-technical users can interact with the dataspace via natural-language chat without writing code or understanding EDC/DTR internals.
Add a new in-process add-on (mcp_addon) that mirrors the structure of the
existing EcoPass KIT and mounts a
FastMCP ASGI sub-application at
/addons/mcp-addon/mcp. The add-on is enabled by default
(addons.mcp_addon.enabled: true) and introduces no behavioural change for
existing users when disabled.
The MCP Addon is a peer of the EcoPass KIT at Layer 4 (Use Case Add-ons):
controllers/fastapi/routers/addons/
├── ecopass_kit/…
└── mcp_addon/ ← new — mounts FastMCP at /addons/mcp-addon/mcp
managers/addons_service/
├── ecopass_kit/…
└── mcp_addon/ ← new — server, session, auth, audit, adapters
models/services/addons/
├── ecopass_kit/…
└── mcp_addon/ ← new — tool I/O and session DTOs
No changes to Layer 3 (IC-Hub orchestration managers) or below.
MCP clients authenticate via Bearer token or OAuth 2.0 against IC-Hub’s existing Keycloak realm. The existing backend’s OIDC client is used for the MCP server. IC-Hub uses its own credentials for all downstream calls to EDC, DTR, and submodel servers. End-user identity is recorded in IC-Hub’s audit log but is not impersonated into the dataspace.
Because the MCP ASGI sub-application is mounted directly on the FastAPI app
via app.mount() (bypassing the router dependency-injection system), auth is
enforced inside FastMCP via the auth= parameter, independent of the
get_authentication_dependency() guard used by the REST API.
authorization.enabled |
authorization.keycloak.enabled |
MCP auth behaviour |
|---|---|---|
false |
any | No auth — endpoint publicly accessible (dev/test only) |
true |
true |
KeycloakAuthProvider (DCR + JWT validation + API-key fallback) |
true |
false |
API-key Bearer fallback only; OAuth browser flow unavailable |
Prerequisites:
Set hostname in configuration.yml to the publicly accessible URL of
IC-Hub (e.g. https://ichub.example.com). The MCP endpoint URL is derived
from this: {hostname}/addons/mcp-addon/mcp.
IC-Hub configuration:
authorization:
enabled: true
keycloak:
enabled: true
auth_url: "https://keycloak.example.com"
realm: "ICHub"
addons:
mcp_addon:
enabled: true
oauth_enabled: true
hostname: "https://ichub.example.com"
System-to-system callers (scripts, CI pipelines) can pass IC-Hub’s configured API key as a Bearer token:
Authorization: Bearer <value-of-authorization.api_key.value>
This is accepted alongside Keycloak JWTs; the combined verifier tries both in order.
managers/addons_service/mcp_addon/v1/auth.py builds a MultiAuth
that tries verifiers in order:
OIDCProxy — validates Keycloak-issued JWTsApiKeyTokenVerifier — checks the raw token string against the configured
API key valuePer-MCP-session state is held in-process (optionally Redis for multi-replica). No new Postgres tables and no Alembic migrations are introduced.
Write tools (create, update, share) return a preview on the first call and
execute only when called a second time with identical arguments. This behaviour
is controlled by addons.mcp_addon.require_confirmation_for_writes (default
true); set it to false to execute write tools on the first call. The state
machine lives in managers/addons_service/mcp_addon/v1/confirmation.py.
SharingService directlyMost add-on tools delegate to managers, as EcoPass does. The single exception
is share_catalog_part: the atomic “submodel store + DTR shell + EDC asset +
policy + contract” sequence exists only in
services/provider/sharing_service.py. Duplicating it inside the MCP Addon
would fork critical business logic.
Decision: adapters/industry_core.py calls SharingService directly.
This is a deliberate, narrow exception, annotated at the call site. Step 7
shipped with this direct-call approach.
Alternative still open with maintainers: extract a SharingManager
that both SharingService and the MCP adapter depend on. This preserves the
no-direct-service-call convention but requires a larger refactor. It can be
applied later without changing the MCP tool surface.
fastmcp) is added to requirements.txt.SharingService deviation shipped in step 7 with the direct-call
approach; the optional SharingManager refactor remains open with
maintainers and does not affect the MCP tool surface.