c8y-mcp-server

star 1

Critical implementation patterns for building Cumulocity microservices that act as MCP (Model Context Protocol) servers. Use when developing MCP servers.

Cumulocity-IoT By Cumulocity-IoT schedule Updated 5/19/2026

name: c8y-mcp-server description: Critical implementation patterns for building Cumulocity microservices that act as MCP (Model Context Protocol) servers. Use when developing MCP servers.

Cumulocity MCP Server Guidelines

When implementing an MCP (Model Context Protocol) server as a Cumulocity microservice using Python and FastAPI, follow these critical patterns to ensure compatibility with the platform's proxy and security layers.

1. FastMCP and Tool Decorators

Use FastMCP for a high-level API. Be cautious with initialization arguments; stick to the server name unless you've verified support for other parameters in the current version.

mcp_server = FastMCP("my-mcp-server")

2. Proxy Compatibility (Relative Paths)

The standard SseServerTransport enforces a leading slash on the message endpoint, which breaks when served under a Cumulocity context path (e.g., /service/my-microservice/).

Subclass SseServerTransport to return truly relative paths:

class CustomSseServerTransport(SseServerTransport):
    def __init__(self, endpoint: str):
        super().__init__(endpoint)
        self._endpoint = endpoint # Relative path (e.g., "messages/")

    @asynccontextmanager
    async def connect_sse(self, scope, receive, send):
        # Implementation should return self._endpoint directly in the 'endpoint' event
        # to ensure the client POSTs back to the correct relative URL.
        ...

3. Explicit Routing vs. Greedy Mounts

Cumulocity's proxy can be sensitive to trailing slash redirects (307). Explicitly register routes for both trailing and non-trailing slash paths:

app.add_route("/sse", SseHandler(), methods=["GET"])
app.add_route("/sse/", SseHandler(), methods=["GET"])
app.add_route("/sse/messages", MessagesHandler(), methods=["POST"])
app.add_route("/sse/messages/", MessagesHandler(), methods=["POST"])

4. Middleware for Proxy Headers

Always add ProxyHeadersMiddleware to correctly handle X-Forwarded-* headers.

from uvicorn.middleware.proxy_headers import ProxyHeadersMiddleware
app.add_middleware(ProxyHeadersMiddleware, trusted_hosts="*")

5. Context Propagation & Fallbacks

Tool execution often occurs in a different task/context than the initial request. Use contextvars with robust fallbacks to environment variables:

# context.py
base_url: ContextVar[Optional[str]] = ContextVar(
    "base_url", 
    default=os.environ.get("C8Y_BASEURL")
)

# dtm_client.py fallback pattern
if not auth and os.environ.get("C8Y_USER"):
    # Build Basic Auth header from env for PER_TENANT isolation
    ...

6. Handler Integration

For maximum control over SSE lifecycles, implement handlers as ASGI classes rather than simple FastAPI decorators. This avoids issues with Request object serialization and send callable access.

class SseHandler:
    async def __call__(self, scope, receive, send):
        async with sse.connect_sse(scope, receive, send) as (read_stream, write_stream):
            await mcp_server._mcp_server.run(read_stream, write_stream, ...)
Install via CLI
npx skills add https://github.com/Cumulocity-IoT/cumulocity-fleet-intelligence-demos --skill c8y-mcp-server
Repository Details
star Stars 1
call_split Forks 0
navigation Branch main
article Path SKILL.md
More from Creator
Cumulocity-IoT
Cumulocity-IoT Explore all skills →