Skip to content

grs/fairway

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

MCP Asset Management Controller

A Kubernetes controller for managing MCP (Model Context Protocol) servers through custom resource definitions.

Description

This controller defines and manages two custom resources:

  • MCPServerPolicy (cluster-scoped): Defines policies for MCP server deployments including deployment type, proxy configuration, allowed namespaces, and server images.
  • MCPServerRequest (namespace-scoped): Represents a request to deploy an MCP server instance based on a policy.

Controller Behavior

The controller reconciles MCPServerRequest resources by:

  1. Policy Lookup: Fetches the MCPServerPolicy referenced by spec.policyRef

    • Updates status with error if policy not found
  2. Namespace Validation: Checks if the request namespace is in the policy's allowedNamespaces list

    • Empty list means all namespaces are allowed
    • Updates status with error if namespace not allowed
  3. Resource Creation: Based on the policy's deployment type and proxy type:

    Exclusive + Toolhive:

    • Creates a Toolhive MCPServer CR in the same namespace as the request
    • Configures it with policy settings (image, env, args, resources, OIDC, authz, audit, tools)

    Shared + Kuadrant:

    • Creates a Deployment in the shared namespace with the MCP server container
    • Creates a Service to expose the deployment
    • Creates a Kuadrant MCPServer CR that references an HTTPRoute

    Remote:

    • No resources created, uses the remote URL from policy
  4. Status Updates: Updates MCPServerRequest status with:

    • Phase (Pending, Running, Failed, Terminating)
    • Endpoint URL for accessing the server
    • Conditions reflecting policy found, namespace allowed, and ready state
    • ObservedGeneration for tracking changes
  5. Policy Changes: When a policy is updated, the controller automatically updates owned resources to match the new policy configuration.

Prerequisites

Depending on your deployment and proxy configuration, you'll need:

Project Structure

mcp-asset-management/
├── api/v1alpha1/              # API type definitions
│   ├── groupversion_info.go   # API group and version
│   ├── mcpserverpolicy_types.go
│   └── mcpserverrequest_types.go
├── cmd/                       # Application entry point
│   └── main.go
├── config/crd/bases/          # Generated CRD manifests
├── controllers/               # Controller implementations
│   ├── mcpserverpolicy_controller.go
│   └── mcpserverrequest_controller.go
├── hack/                      # Build scripts and tools
│   └── boilerplate.go.txt
├── Dockerfile                 # Container image definition
├── Makefile                   # Build targets
└── go.mod                     # Go module definition

Getting Started

Prerequisites

  • Go 1.22+
  • Kubernetes cluster (for deployment)
  • kubectl configured to access your cluster

Installation

  1. Install dependencies:
go mod download
  1. Generate CRDs and code:
make manifests generate
  1. Build the controller:
make build

Development

Generate CRD manifests from Go types:

make manifests

Generate DeepCopy methods:

make generate

Run tests:

make test

Run the controller locally:

make run

Deployment

Install CRDs to your cluster:

make install

Note: The config/crd/bases directory contains generated CRDs for both this controller's resources and external resources (Toolhive and Kuadrant MCPServers). Only install the MCPServerPolicy and MCPServerRequest CRDs from this project. The external MCPServer CRDs should be installed by their respective operators:

  • mcp.opendatahub.io_mcpserverpolicies.yaml - Install this
  • mcp.opendatahub.io_mcpserverrequests.yaml - Install this
  • mcp.opendatahub.io_toolhivemcpservers.yaml - DO NOT install (comes from Toolhive operator)
  • mcp.opendatahub.io_kuadrantmcpservers.yaml - DO NOT install (comes from Kuadrant operator)

Build and push container image:

make docker-build docker-push IMG=<registry>/mcp-controller:tag

Uninstall CRDs:

make uninstall

Custom Resources

MCPServerPolicy

Cluster-scoped resource defining MCP server deployment policies.

The deployment field is a discriminated union supporting three deployment types:

Exclusive Deployment

Dedicated MCP server deployment with full configuration control:

apiVersion: mcp.opendatahub.io/v1alpha1
kind: MCPServerPolicy
metadata:
  name: exclusive-policy
spec:
  serverImage: mcp-server:v1.0.0
  deployment:
    type: Exclusive
    exclusive:
      serviceAccount: mcp-server-sa
      args: ["--verbose"]
      env:
        - name: LOG_LEVEL
          value: "debug"
      labels:
        app: mcp-server
      resources:
        requests:
          memory: "256Mi"
          cpu: "100m"
        limits:
          memory: "512Mi"
          cpu: "500m"
  allowedNamespaces:
    - default
    - production
  resourceLimits:
    maxInstances: 5

Shared Deployment

Shared MCP server deployment running in a specific namespace:

apiVersion: mcp.opendatahub.io/v1alpha1
kind: MCPServerPolicy
metadata:
  name: shared-policy
spec:
  serverImage: mcp-server:v1.0.0
  deployment:
    type: Shared
    shared:
      namespace: mcp-shared
      serviceAccount: shared-mcp-sa
      args: ["--mode=shared"]
      resources:
        requests:
          memory: "512Mi"
          cpu: "250m"
  allowedNamespaces:
    - team-a
    - team-b

Remote Deployment

Access to an external MCP server via URL:

apiVersion: mcp.opendatahub.io/v1alpha1
kind: MCPServerPolicy
metadata:
  name: remote-policy
spec:
  serverImage: mcp-server:v1.0.0
  deployment:
    type: Remote
    remote:
      url: https://mcp-server.external.example.com:8443/api
  allowedNamespaces:
    - default

MCPServerRequest

Namespace-scoped resource requesting an MCP server deployment.

apiVersion: mcp.opendatahub.io/v1alpha1
kind: MCPServerRequest
metadata:
  name: my-mcp-server
  namespace: default
spec:
  policyRef: example-policy
  replicas: 2
  configuration:
    key1: value1
    key2: value2
  serviceAccountName: mcp-server-sa

Complete Examples

Example 1: Exclusive Deployment with Toolhive

Create a policy for exclusive deployment with Toolhive proxy:

kubectl apply -f config/samples/exclusive-policy.yaml

Create a request using this policy:

kubectl apply -f config/samples/exclusive-request.yaml

The controller will:

  1. Validate the policy exists
  2. Check that default namespace is in the allowed list
  3. Create a Toolhive MCPServer CR in the default namespace
  4. Update the MCPServerRequest status with the endpoint URL

Check the status:

kubectl get mcpserverrequest my-exclusive-mcp -n default -o yaml

Expected status:

status:
  phase: Running
  endpoint: http://my-exclusive-mcp.default.svc.cluster.local:9090
  conditions:
  - type: PolicyFound
    status: "True"
    reason: PolicyFound
  - type: NamespaceAllowed
    status: "True"
    reason: NamespaceAllowed
  - type: Ready
    status: "True"
    reason: ResourcesCreated

Example 2: Shared Deployment with Kuadrant

Create a policy for shared deployment with Kuadrant:

kubectl apply -f config/samples/shared-policy.yaml

Create a request using this policy:

kubectl apply -f config/samples/shared-request.yaml

The controller will:

  1. Validate the policy and namespace
  2. Create a Deployment in the mcp-shared namespace
  3. Create a Service to expose the deployment
  4. Create a Kuadrant MCPServer CR
  5. Update the status with the endpoint

Check created resources:

kubectl get deployment,service -n mcp-shared
kubectl get kuadrantmcpserver -n team-a

Example 3: Policy Not Found Error

Create a request with a non-existent policy:

apiVersion: mcp.opendatahub.io/v1alpha1
kind: MCPServerRequest
metadata:
  name: bad-request
  namespace: default
spec:
  policyRef: non-existent-policy

The controller will update the status:

status:
  phase: Failed
  conditions:
  - type: PolicyFound
    status: "False"
    reason: PolicyNotFound
    message: "Policy non-existent-policy not found"
  - type: Ready
    status: "False"
    reason: ReconciliationFailed

Makefile Targets

  • make help - Display available targets
  • make build - Build the controller binary
  • make manifests - Generate CRD manifests
  • make generate - Generate code (DeepCopy, etc.)
  • make test - Run tests
  • make install - Install CRDs to cluster
  • make uninstall - Remove CRDs from cluster
  • make run - Run controller locally
  • make docker-build - Build container image
  • make docker-push - Push container image

License

Copyright 2024.

Licensed under the Apache License, Version 2.0.

About

A Kubernetes controller for managing the deployment of- and access to- MCP servers

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors