Skip to content

MCPServer CRD ​

The MCPServer custom resource deploys MCP (Model Context Protocol) tool servers that agents can use.

Full Specification ​

yaml
apiVersion: kaos.tools/v1alpha1
kind: MCPServer
metadata:
  name: my-mcp
  namespace: my-namespace
spec:
  # Required: Runtime type
  type: python-runtime  # or node-runtime (future)
  
  # Required: Server configuration
  config:
    # Tools configuration (one of the following)
    tools:
      # Option 1: PyPI package name
      fromPackage: "test-mcp-echo-server"
      
      # Option 2: Dynamic Python tools defined inline
      fromString: |
        def echo(text: str) -> str:
            """Echo the input text."""
            return f"Echo: {text}"
        
        def add(a: int, b: int) -> int:
            """Add two numbers."""
            return a + b
      
      # Option 3: Tools from a Secret
      fromSecretKeyRef:
        name: my-tools-secret
        key: tools.py
    
    # Environment variables
    env:
    - name: LOG_LEVEL
      value: "INFO"
  
  # Optional: PodSpec override using strategic merge patch
  podSpec:
    containers:
    - name: mcp-server  # Must match generated container name
      resources:
        requests:
          memory: "128Mi"
          cpu: "100m"
        limits:
          memory: "256Mi"
          cpu: "500m"

status:
  phase: Ready           # Pending, Ready, Failed
  ready: true
  endpoint: "http://mcpserver-my-mcp.my-namespace.svc.cluster.local:8000"
  availableTools:
  - "echo"
  - "add"
  message: ""

Spec Fields ​

type (required) ​

Runtime type for the MCP server:

ValueDescription
python-runtimePython-based MCP server
node-runtimeNode.js-based (future)

config (required) ​

config.tools ​

Tools configuration - use one of the following options:

tools.fromPackage ​

PyPI package name to run as MCP server:

yaml
config:
  tools:
    fromPackage: "test-mcp-echo-server"

The package is installed via pip and executed. It must expose MCP-compatible endpoints.

tools.fromString ​

Dynamic Python tools defined inline:

yaml
config:
  tools:
    fromString: |
      def greet(name: str) -> str:
          """Greet a person by name."""
          return f"Hello, {name}!"
      
      def calculate(expression: str) -> str:
          """Evaluate a math expression."""
          try:
              return str(eval(expression))
          except Exception as e:
              return f"Error: {e}"

Requirements:

  • Functions must have type annotations
  • Functions must have docstrings (used as descriptions)
  • Supported types: str, int, dict, list

Security Note: fromString uses exec() to define functions. Only use with trusted input.

tools.fromSecretKeyRef ​

Load tools from a Kubernetes Secret:

yaml
config:
  tools:
    fromSecretKeyRef:
      name: my-tools-secret
      key: tools.py

config.env ​

Environment variables for the MCP server:

yaml
config:
  env:
  - name: LOG_LEVEL
    value: "DEBUG"
  - name: API_KEY
    valueFrom:
      secretKeyRef:
        name: mcp-secrets
        key: api-key

podSpec (optional) ​

Override the generated pod spec using Kubernetes strategic merge patch.

yaml
spec:
  podSpec:
    containers:
    - name: mcp-server  # Must match the generated container name
      resources:
        requests:
          memory: "256Mi"
          cpu: "100m"

gatewayRoute (optional) ​

Configure Gateway API routing, including request timeout:

yaml
spec:
  gatewayRoute:
    # Request timeout for the HTTPRoute (Gateway API Duration format)
    # Default: "30s" for MCPServer (tool calls are typically fast)
    # Set to "0s" to use Gateway's default timeout
    timeout: "30s"

Container Images ​

Tool SourceImageCommand
tools.fromPackagepython:3.12-slimpip install <package> && <package>
tools.fromStringkaos-agent:latestpython -m mcptools.server
tools.fromSecretKeyRefkaos-agent:latestpython -m mcptools.server

Status Fields ​

FieldTypeDescription
phasestringCurrent phase: Pending, Ready, Failed
readyboolWhether server is ready
endpointstringService URL for agents
availableTools[]stringList of tool names
messagestringAdditional status info
deploymentobjectDeployment status for rolling update visibility

deployment (status) ​

Mirrors key status fields from the underlying Kubernetes Deployment:

FieldTypeDescription
replicasint32Total number of non-terminated pods
readyReplicasint32Number of pods with Ready condition
availableReplicasint32Number of available pods
updatedReplicasint32Number of pods with desired template (rolling update progress)
conditionsarrayDeployment conditions (Available, Progressing, ReplicaFailure)

Examples ​

Echo Tool (PyPI Package) ​

yaml
apiVersion: kaos.tools/v1alpha1
kind: MCPServer
metadata:
  name: echo-tools
spec:
  type: python-runtime
  config:
    tools:
      fromPackage: "test-mcp-echo-server"

Calculator Tool (Dynamic) ​

yaml
apiVersion: kaos.tools/v1alpha1
kind: MCPServer
metadata:
  name: calculator
spec:
  type: python-runtime
  config:
    tools:
      fromString: |
        def add(a: int, b: int) -> int:
            """Add two numbers together."""
            return a + b
        
        def subtract(a: int, b: int) -> int:
            """Subtract b from a."""
            return a - b
        
        def multiply(a: int, b: int) -> int:
            """Multiply two numbers."""
            return a * b
        
        def divide(a: int, b: int) -> str:
            """Divide a by b."""
            if b == 0:
                return "Error: Division by zero"
            return str(a / b)

String Utilities with Resources ​

yaml
apiVersion: kaos.tools/v1alpha1
kind: MCPServer
metadata:
  name: string-utils
spec:
  type: python-runtime
  config:
    tools:
      fromString: |
        def uppercase(text: str) -> str:
            """Convert text to uppercase."""
            return text.upper()
        
        def lowercase(text: str) -> str:
            """Convert text to lowercase."""
            return text.lower()
        
        def reverse(text: str) -> str:
            """Reverse the text."""
            return text[::-1]
  podSpec:
    containers:
    - name: mcp-server
      resources:
        requests:
          memory: "128Mi"

External API Tool with Secret ​

yaml
apiVersion: kaos.tools/v1alpha1
kind: MCPServer
metadata:
  name: weather-api
spec:
  type: python-runtime
  config:
    tools:
      fromString: |
        import os
        import urllib.request
        import json
        
        def get_weather(city: str) -> str:
            """Get current weather for a city."""
            api_key = os.environ.get("WEATHER_API_KEY", "")
            url = f"https://api.weather.com/v1/current?city={city}&key={api_key}"
            try:
                with urllib.request.urlopen(url) as response:
                    data = json.loads(response.read())
                    return f"{city}: {data['temp']}°C, {data['conditions']}"
            except Exception as e:
                return f"Error: {e}"
    
    env:
    - name: WEATHER_API_KEY
      valueFrom:
        secretKeyRef:
          name: api-keys
          key: weather

Integration with Agent ​

Reference MCPServer in Agent spec:

yaml
apiVersion: kaos.tools/v1alpha1
kind: Agent
metadata:
  name: my-agent
spec:
  modelAPI: my-modelapi
  mcpServers:
  - echo-tools
  - calculator
  config:
    instructions: |
      You have access to echo and calculator tools.
      Use echo to repeat messages.
      Use calculator for math operations.

The operator:

  1. Waits for MCPServers to be Ready (if waitForDependencies: true)
  2. Sets MCP_SERVERS=[echo-tools, calculator]
  3. Sets MCP_SERVER_<NAME>_URL=http://mcpserver-<name>:8000

HTTP Endpoints ​

MCPServer exposes:

EndpointMethodDescription
/healthGETLiveness probe
/readyGETReadiness probe
/mcp/toolsGETList available tools
/mcp/toolsPOSTExecute a tool

Tool Listing ​

bash
curl http://mcpserver-my-mcp:8000/mcp/tools

Tool Execution ​

bash
curl -X POST http://mcpserver-my-mcp:8000/mcp/tools \
  -H "Content-Type: application/json" \
  -d '{"tool": "echo", "arguments": {"text": "Hello"}}'

Troubleshooting ​

MCPServer CrashLoopBackOff ​

Check pod logs:

bash
kubectl logs -l mcpserver=my-mcp -n my-namespace

Common causes:

  • Invalid fromString Python syntax
  • Package not found (for fromPackage option)
  • Missing dependencies

Tools Not Discovered by Agent ​

Verify MCPServer is Ready:

bash
kubectl get mcpserver my-mcp -n my-namespace

Test endpoint manually:

bash
kubectl exec -it deploy/agent-my-agent -n my-namespace -- \
  curl http://mcpserver-my-mcp:8000/mcp/tools

fromString Syntax Errors ​

Test your Python code locally:

python
tools_string = '''
def my_tool(x: str) -> str:
    """My tool description."""
    return x
'''

namespace = {}
exec(tools_string, {}, namespace)
print(namespace)  # Should show your function

Released under the Apache 2.0 License.