Consume control plane APIs in an app cluster with MCP connector

In this tutorial, you learn how to configure a Kubernetes app cluster to communicate with a managed control plane in an Upbound self-hosted Space.

The MCP connector bridges your Kubernetes application clusters—running outside of Upbound–to your managed control planes running in Upbound. This allows you to interact with your managed control plane’s API right from the app cluster. The claim APIs you define via CompositeResourceDefinitions are available alongside Kubernetes workload APIs like Pod. In effect, MCP Connector providers the same experience as a locally installed Crossplane.


To complete this tutorial, you need the following:

  • Have already deployed an Upbound Space.
  • Have already deployed an Kubernetes cluster (referred to as app cluster).
  • The up CLI installed on your local machine.

Create a managed control plane

Create a new managed control plane in your self-hosted Space. Run the following command in a terminal:

up ctp create my-control-plane

Once the control plane is ready, connect to it.

up ctp connect my-control-plane

For convenience, install a an Upbound platform reference Configuration from the marketplace. For production scenarios, replace this with your own Crossplane Configurations or compositions.

up ctp configuration install

Fetch the control plane’s connection details

Run the following command in a terminal:

kubectl get secret kubeconfig-my-control-plane -n default -o jsonpath='{.data.kubeconfig}' | base64 -d > kubeconfig-my-control-plane.yaml

This command saves the kubeconfig for the control plane to a file in your working directory.

Install MCP Connector in your app cluster

Switch contexts to your Kubernetes app cluster. To install the MCP connector in your app cluster, you must first provide a secret containing your control plane’s kubeconfig at install-time. Run the following command in a terminal:

Make sure the following commands are executed against your app cluster, not your control plane.
kubectl create secret generic kubeconfig-my-control-plane -n kube-system --from-file=kubeconfig=./kubeconfig-my-control-plane.yaml

Set the environment variable below to configure which namespace in your control plane you wish to sync the app cluster’s claims to.


Install the MCP connector in the app cluster and point it to your control plane.

up ctp connector install my-control-plane $CONNECTOR_CTP_NAMESPACE --control-plane-secret=kubeconfig-my-control-plane

Inspect your app cluster

After you install MCP Connector in the app cluster, you can now see APIs which live on the control plane. You can confirm this is the case by running the following command on your app cluster:

kubectl api-resources | grep upbound

# The output should look like this:
sqlinstances                                true         SQLInstance
clusters                                 true         Cluster
osss                                    true         Oss
apps                                            true         App

Claim a database instance on your app cluster

Create a database claim against the SQLInstance API and observe resources get created by your control plane. Apply the following resources to your app cluster:

cat <<EOF | kubectl apply -f -
kind: SQLInstance
  name: platform-ref-aws-db-postgres
  namespace: default
    region: us-west-2
    engine: postgres
    engineVersion: "13.7"
    storageGB: 5
      namespace: default
      name: psqlsecret
      key: password
      id: platform-ref-aws
    name: platform-ref-aws-db-conn-postgres
apiVersion: v1
  password: dXBiMHVuZHIwY2s1ITMxMzM3
kind: Secret
  name: psqlsecret
  namespace: default
type: Opaque

Inspect your managed control plane

Switch contexts, connect to your managed control plane, and look at the managed resources on your control plane. It should look like the following:

Make sure the following commands are executed against your control plane, not your app cluster.
kubectl get managed

# The output should look like this:
NAME                                                             READY   SYNCED   EXTERNAL-NAME   AGE           False                    54s

NAME                                                                READY   SYNCED   EXTERNAL-NAME                        AGE           False    claim-dd1039cdd0366e1a-xcb52-vnsnk   55s

Requesting the list of claims in namespace app-cluster-1 shows that the claim for the database (originating from the app cluster) actually lives on the control plane:

kubectl get SQLInstances -n app-cluster-1

# The output should look like this:
NAME                     SYNCED   READY   CONNECTION-SECRET        AGE
claim-dd1039cdd0366e1a   True     False   claim-5ffa34ecdfd4b372   2m56s


In this tutorial, you:

  • connected an app cluster to a managed control plane using the MCP connector.
  • You experienced how make resource requests from your app cluster to your control plane.
  • You saw how resource requests are actually fulfilled by the control plane.