← Back to list

Creating an MCP (Model Context Protocol) Server on OpenShift

Large Language Models are increasingly being augmented with external tools, data sources, and actions.The Model Context Protocol (MCP) is…

Shrishs · 2026-01-05 10:41 · 1 claps · 3.9 min read
#mcp-server #fastmcp #kubernetes #agentic-ai #red-hat-openshift-ai
Open on Medium ↗
Wiki topics: LLM · Large Language Models AGT · AI Agents ☁️ · DevOps & Cloud

Creating an MCP (Model Context Protocol) Server on OpenShift

Large Language Models are increasingly being augmented with external tools, data sources, and actions.The Model Context Protocol (MCP) is emerging as a standard way to expose such capabilities in a structured and model-agnostic way .

In this article, we walk through how to create and run an MCP server on OpenShift, treating it like a real production microservice. And Test it using Openshift AI 3.x playground.Testing setup is mentioned in my previous article *OpenShift AI 3.0: Model Deployment, AI Asset Endpoints, and the Gen AI Playground*

Choosing the MCP Server Implementation

FastMCP is a popular framework for building servers that use the open Model Context Protocol (MCP), which provides a standardized way for AI language models (LLMs) to access external data and tools.

Local Implementation

In this example we create simple MCP server on the developer machine.

  • server.py
from fastmcp import FastMCP
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
import uvicorn

mcp = FastMCP("Customer Tools")

@mcp.tool
def get_customer_details(customer_id: str) -> dict:
    return {
        "customer_id": customer_id,
        "name": "John Doe",
        "email": "john.doe@example.com",
        "status": "Gold",
        "country": "Germany",
    }

# Create BOTH ASGI apps
mcp_http_app = mcp.http_app(transport="streamable-http")
mcp_sse_app  = mcp.http_app(transport="sse")   # yes, same factory, different transport

# Pick one lifespan to pass to FastAPI.
# (Streamable-http is the critical one for OpenShift AI.)
app = FastAPI(lifespan=mcp_http_app.lifespan)

@app.get("/healthz")
def healthz():
    return {"ok": True}

# Mount endpoints
app.mount("/mcp", mcp_http_app)     # OpenShift AI uses this
app.mount("/sse", mcp_sse_app)      # MCP Inspector/debug uses this

# Added for testing with the Browser based application
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_methods=["*"],
    allow_headers=["*"],
)

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8080)
  • requirements.txt
fastmcp
fastapi
uvicorn
  • Run the python code.
$ python server.py 
INFO:     Started server process [4840]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://0.0.0.0:8080 (Press CTRL+C to quit)
  • Verify it.
# curl localhost:8080/healthz
{"ok":true}

# curl localhost:8080/sse/sse
event: endpoint
data: /sse/messages/?session_id=cb1d705707714fa79ef8ca9a4caa3b8d
: ping - 2026-01-06 08:38:59.551426+00:00

# curl -i -N -X POST localhost:8080/mcp/mcp -H "Content-Type: application/json"   -H "Accept: application/json, text/event-stream"   -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","clientInfo":{"name":"curl","version":"0.1"},"capabilities":{}}}'
HTTP/1.1 200 OK
date: Tue, 06 Jan 2026 08:37:34 GMT
server: uvicorn
cache-control: no-cache, no-transform
connection: keep-alive
content-type: text/event-stream
mcp-session-id: 96618d51b8aa4f6eb5518853046a4b87
x-accel-buffering: no
Transfer-Encoding: chunked
event: message
data: {"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"2024-11-05","capabilities":{"experimental":{},"prompts":{"listChanged":true},"resources":{"subscribe":false,"listChanged":true},"tools":{"listChanged":true}},"serverInfo":{"name":"Customer Tools","version":"2.14.2"}}}
  • MCP Inspector can also be run to verify it.
npx -y @modelcontextprotocol/inspector@latest
Starting MCP inspector...
⚙️ Proxy server listening on localhost:6277
🔑 Session token: 7a3326852db47d6beb07c7f1ebf9a265b02dbecacffb858375e2593224f3e0d2
   Use this token to authenticate requests or set DANGEROUSLY_OMIT_AUTH=true to disable auth

🚀 MCP Inspector is up and running at:
   http://localhost:6274/?MCP_PROXY_AUTH_TOKEN=7a3326852db47d6beb07c7f1ebf9a265b02dbecacffb858375e2593224f3e0d2

🌐 Opening browser...

Containerizing the MCP Server

  • Comment the server.py run part,And CORS settings.
from fastmcp import FastMCP
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
import uvicorn

mcp = FastMCP("Customer Tools")

@mcp.tool
def get_customer_details(customer_id: str) -> dict:
    return {
        "customer_id": customer_id,
        "name": "John Doe",
        "email": "john.doe@example.com",
        "status": "Gold",
        "country": "Germany",
    }

# Create BOTH ASGI apps
mcp_http_app = mcp.http_app(transport="streamable-http")
mcp_sse_app  = mcp.http_app(transport="sse")   # yes, same factory, different transport

# Pick one lifespan to pass to FastAPI.
# (Streamable-http is the critical one for OpenShift AI.)
app = FastAPI(lifespan=mcp_http_app.lifespan)

@app.get("/healthz")
def healthz():
    return {"ok": True}

# Mount endpoints
app.mount("/mcp", mcp_http_app)     # OpenShift AI uses this
app.mount("/sse", mcp_sse_app)      # MCP Inspector/debug uses this

# Added for testing with the Browser based application
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_methods=["*"],
    allow_headers=["*"],
)

#if __name__ == "__main__":
    #uvicorn.run(app, host="0.0.0.0", port=8080)
  • Create a Containerfile with ubi9/python-311 as base image.Move the execution part(uvicorn..) from server.yaml to this file.
FROM registry.access.redhat.com/ubi9/python-311

WORKDIR /opt/app-root/src

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY server.py .

EXPOSE 8080

# Run MCP SSE server and bind to 0.0.0.0:8080
# Start uvicorn directly (proxy-aware) and serve the Starlette app object "app"
CMD ["uvicorn", "server:app", "--host", "0.0.0.0", "--port", "8080", "--proxy-headers", "--forwarded-allow-ips", "*"]
  • Build it.
podman build --no-cache --platform=linux/amd64 -t customer-mcp-sse:0.1 -f Containerfile .
  • Tag it and push it you available registry
podman tag localhost/customer-mcp-sse:0.1 <REPO_URL>/customer-mcp-sse:0.1
podman push <REPO_URL>/customer-mcp-sse:0.1

Kubernetes Scaffolding for Deploying an MCP Server

apiVersion: apps/v1
kind: Deployment
metadata:
  name: customer-mcp
  labels:
    app: customer-mcp
spec:
  replicas: 1
  selector:
    matchLabels:
      app: customer-mcp
  template:
    metadata:
      labels:
        app: customer-mcp
    spec:
      containers:
        - name: customer-mcp
          image: <REPO_URL>/customer-mcp-sse:0.1
          imagePullPolicy: IfNotPresent
          ports:
            - name: http
              containerPort: 8080
          readinessProbe:
            httpGet:
              path: /healthz
              port: 8080
            initialDelaySeconds: 3
            periodSeconds: 10
          livenessProbe:
            httpGet:
              path: /healthz
              port: 8080
            initialDelaySeconds: 10
            periodSeconds: 20
          resources:
            requests:
              cpu: 50m
              memory: 128Mi
            limits:
              cpu: 500m
              memory: 512Mi
apiVersion: v1
kind: Service
metadata:
  name: customer-mcp
  labels:
    app: customer-mcp
spec:
  selector:
    app: customer-mcp
  ports:
    - name: http
      port: 8080
      targetPort: 8080
  type: ClusterIP
  • Apply the above definition to the Openshift cluster and create a edge route to access it externally from the cluster.
curl -k https://<Openshift_Edge_Route>/healthz
{"ok":true}

NOTE: To test the below part ,Openshift AI 3.x and LLamaStack enablement is prerequisite.

  • Create a ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: gen-ai-aa-mcp-servers
  namespace: redhat-ods-applications
data:
  Customer-MCP-Server: |
    {
      "url": "https://<Openshift_Edge_Route>/mcp/mcp",
      "description": "The Customer MCP server provide customer details."
    }   
  • Go to OpenshiftAI Dashboard,Try it in playground.

  • Request the customer details with some id .


메타데이터
post_id
85dceac65c07
slug
creating-an-mcp-model-context-protocol-server-on-openshift-85dceac65c07
url
https://medium.com/@shrishs/creating-an-mcp-model-context-protocol-server-on-openshift-85dceac65c07
canonical_url
https://medium.com/@shrishs/creating-an-mcp-model-context-protocol-server-on-openshift-85dceac65c07
author_url
https://medium.com/@shrishs
status
ok
fetched_at
2026-07-14 04:13:03