diff --git a/operators/multiclusterobservability/api/v1beta2/multiclusterobservability_types.go b/operators/multiclusterobservability/api/v1beta2/multiclusterobservability_types.go
index de03d3b355..70b4d30ab7 100644
--- a/operators/multiclusterobservability/api/v1beta2/multiclusterobservability_types.go
+++ b/operators/multiclusterobservability/api/v1beta2/multiclusterobservability_types.go
@@ -13,6 +13,9 @@ import (
 
 // MultiClusterObservabilitySpec defines the desired state of MultiClusterObservability.
 type MultiClusterObservabilitySpec struct {
+	// Platform and UserWorkload Observability Capabilities
+	// +optional
+	Capabilities *CapabilitiesSpec `json:"capabilities,omitempty"`
 	// Advanced configurations for observability
 	// +optional
 	AdvancedConfig *AdvancedConfig `json:"advanced,omitempty"`
@@ -41,6 +44,59 @@ type MultiClusterObservabilitySpec struct {
 	ObservabilityAddonSpec *observabilityshared.ObservabilityAddonSpec `json:"observabilityAddonSpec"`
 }
 
+type LogsCollectionSpec struct {
+	// +optional
+	Enabled bool `json:"enabled,omitempty"`
+}
+
+type PlatformLogsSpec struct {
+	// +optional
+	Collection *LogsCollectionSpec `json:"collection,omitempty"`
+}
+
+type PlatformCapabilitiesSpec struct {
+	// +optional
+	Logs LogsCollectionSpec `json:"logs,omitempty"`
+}
+
+type ClusterLogForwarderSpec struct {
+	// +optional
+	Enabled bool `json:"enabled,omitempty"`
+}
+
+type UserWorkloadLogsSpec struct {
+	ClusterLogForwarder ClusterLogForwarderSpec `json:"clusterLogForwarder,omitempty"`
+}
+
+type OpenTelemetryCollectorSpec struct {
+	// +optional
+	Enabled bool `json:"enabled,omitempty"`
+}
+
+type InstrumentationSpec struct {
+	// +optional
+	Enabled bool `json:"enabled,omitempty"`
+}
+
+type UserWorkloadTracesSpec struct {
+	// +optional
+	OpenTelemetryCollector OpenTelemetryCollectorSpec `json:"openTelemetryCollector,omitempty"`
+	// +optional
+	Instrumentation InstrumentationSpec `json:"instrumentation,omitempty"`
+}
+
+type UserWorkloadCapabilitiesSpec struct {
+	Logs   UserWorkloadLogsSpec   `json:"logs,omitempty"`
+	Traces UserWorkloadTracesSpec `json:"traces,omitempty"`
+}
+
+type CapabilitiesSpec struct {
+	// +optional
+	Platform *PlatformCapabilitiesSpec `json:"platform,omitempty"`
+	// +optional
+	UserWorkloads *UserWorkloadCapabilitiesSpec `json:"userWorkloads,omitempty"`
+}
+
 type AdvancedConfig struct {
 	// CustomObservabilityHubURL overrides the endpoint used by the metrics-collector to send
 	// metrics to the hub server.
@@ -91,6 +147,8 @@ type AdvancedConfig struct {
 	// spec for thanos-store-shard
 	// +optional
 	Store *StoreSpec `json:"store,omitempty"`
+	// spec for multicluster-obervability-addon
+	MultiClusterObservabilityAddon *CommonSpec `json:"multiClusterObservabilityAddon,omitempty"`
 }
 
 type CommonSpec struct {
diff --git a/operators/multiclusterobservability/bundle/manifests/observability.open-cluster-management.io_multiclusterobservabilities.yaml b/operators/multiclusterobservability/bundle/manifests/observability.open-cluster-management.io_multiclusterobservabilities.yaml
index 7c449d53f7..f1d2bd4979 100644
--- a/operators/multiclusterobservability/bundle/manifests/observability.open-cluster-management.io_multiclusterobservabilities.yaml
+++ b/operators/multiclusterobservability/bundle/manifests/observability.open-cluster-management.io_multiclusterobservabilities.yaml
@@ -1203,6 +1203,51 @@ spec:
                             type: object
                         type: object
                     type: object
+                  multiClusterObservabilityAddon:
+                    description: spec for multicluster-obervability-addon
+                    properties:
+                      replicas:
+                        description: Replicas for this component.
+                        format: int32
+                        type: integer
+                      resources:
+                        description: Compute Resources required by this component.
+                        properties:
+                          claims:
+                            description: "Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. \n This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. \n This field is immutable. It can only be set for containers."
+                            items:
+                              description: ResourceClaim references one entry in PodSpec.ResourceClaims.
+                              properties:
+                                name:
+                                  description: Name must match the name of one entry in pod.spec.resourceClaims of the Pod where this field is used. It makes that resource available inside a container.
+                                  type: string
+                              required:
+                              - name
+                              type: object
+                            type: array
+                            x-kubernetes-list-map-keys:
+                            - name
+                            x-kubernetes-list-type: map
+                          limits:
+                            additionalProperties:
+                              anyOf:
+                              - type: integer
+                              - type: string
+                              pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+                              x-kubernetes-int-or-string: true
+                            description: 'Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+                            type: object
+                          requests:
+                            additionalProperties:
+                              anyOf:
+                              - type: integer
+                              - type: string
+                              pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+                              x-kubernetes-int-or-string: true
+                            description: 'Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+                            type: object
+                        type: object
+                    type: object
                   observatoriumAPI:
                     description: Spec of observatorium api
                     properties:
@@ -5654,6 +5699,42 @@ spec:
                         type: object
                     type: object
                 type: object
+              capabilities:
+                description: Platform and UserWorkload Observability Capabilities
+                properties:
+                  platform:
+                    properties:
+                      logs:
+                        properties:
+                          enabled:
+                            type: boolean
+                        type: object
+                    type: object
+                  userWorkloads:
+                    properties:
+                      logs:
+                        properties:
+                          clusterLogForwarder:
+                            properties:
+                              enabled:
+                                type: boolean
+                            type: object
+                        type: object
+                      traces:
+                        properties:
+                          instrumentation:
+                            properties:
+                              enabled:
+                                type: boolean
+                            type: object
+                          openTelemetryCollector:
+                            properties:
+                              enabled:
+                                type: boolean
+                            type: object
+                        type: object
+                    type: object
+                type: object
               enableDownsampling:
                 default: true
                 description: Enable or disable the downsample.
diff --git a/operators/multiclusterobservability/config/crd/bases/observability.open-cluster-management.io_multiclusterobservabilities.yaml b/operators/multiclusterobservability/config/crd/bases/observability.open-cluster-management.io_multiclusterobservabilities.yaml
index 180cce9730..7b68cfe6af 100644
--- a/operators/multiclusterobservability/config/crd/bases/observability.open-cluster-management.io_multiclusterobservabilities.yaml
+++ b/operators/multiclusterobservability/config/crd/bases/observability.open-cluster-management.io_multiclusterobservabilities.yaml
@@ -1833,6 +1833,63 @@ spec:
                             type: object
                         type: object
                     type: object
+                  multiClusterObservabilityAddon:
+                    description: spec for multicluster-obervability-addon
+                    properties:
+                      replicas:
+                        description: Replicas for this component.
+                        format: int32
+                        type: integer
+                      resources:
+                        description: Compute Resources required by this component.
+                        properties:
+                          claims:
+                            description: "Claims lists the names of resources, defined
+                              in spec.resourceClaims, that are used by this container.
+                              \n This is an alpha field and requires enabling the
+                              DynamicResourceAllocation feature gate. \n This field
+                              is immutable. It can only be set for containers."
+                            items:
+                              description: ResourceClaim references one entry in PodSpec.ResourceClaims.
+                              properties:
+                                name:
+                                  description: Name must match the name of one entry
+                                    in pod.spec.resourceClaims of the Pod where this
+                                    field is used. It makes that resource available
+                                    inside a container.
+                                  type: string
+                              required:
+                              - name
+                              type: object
+                            type: array
+                            x-kubernetes-list-map-keys:
+                            - name
+                            x-kubernetes-list-type: map
+                          limits:
+                            additionalProperties:
+                              anyOf:
+                              - type: integer
+                              - type: string
+                              pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+                              x-kubernetes-int-or-string: true
+                            description: 'Limits describes the maximum amount of compute
+                              resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+                            type: object
+                          requests:
+                            additionalProperties:
+                              anyOf:
+                              - type: integer
+                              - type: string
+                              pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+                              x-kubernetes-int-or-string: true
+                            description: 'Requests describes the minimum amount of
+                              compute resources required. If Requests is omitted for
+                              a container, it defaults to Limits if that is explicitly
+                              specified, otherwise to an implementation-defined value.
+                              More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+                            type: object
+                        type: object
+                    type: object
                   observatoriumAPI:
                     description: Spec of observatorium api
                     properties:
@@ -9018,6 +9075,42 @@ spec:
                         type: object
                     type: object
                 type: object
+              capabilities:
+                description: Platform and UserWorkload Observability Capabilities
+                properties:
+                  platform:
+                    properties:
+                      logs:
+                        properties:
+                          enabled:
+                            type: boolean
+                        type: object
+                    type: object
+                  userWorkloads:
+                    properties:
+                      logs:
+                        properties:
+                          clusterLogForwarder:
+                            properties:
+                              enabled:
+                                type: boolean
+                            type: object
+                        type: object
+                      traces:
+                        properties:
+                          instrumentation:
+                            properties:
+                              enabled:
+                                type: boolean
+                            type: object
+                          openTelemetryCollector:
+                            properties:
+                              enabled:
+                                type: boolean
+                            type: object
+                        type: object
+                    type: object
+                type: object
               enableDownsampling:
                 default: true
                 description: Enable or disable the downsample.
diff --git a/operators/multiclusterobservability/pkg/config/config.go b/operators/multiclusterobservability/pkg/config/config.go
index 0ce7a5b364..b0106b5473 100644
--- a/operators/multiclusterobservability/pkg/config/config.go
+++ b/operators/multiclusterobservability/pkg/config/config.go
@@ -158,6 +158,11 @@ const (
 	EndpointControllerImgName = "endpoint-monitoring-operator"
 	EndpointControllerKey     = "endpoint_monitoring_operator"
 
+	MultiClusterObservabilityAddonImgRepo      = "quay.io/rhobs"
+	MultiClusterObservabilityAddonImgName      = "multicluster-observability-addon"
+	MultiClusterObservabilityAddonImgTagSuffix = "0.0.1"
+	MultiClusterObservabilityAddonImgKey       = "multicluster_observability_addon"
+
 	RBACQueryProxyImgName = "rbac-query-proxy"
 	RBACQueryProxyKey     = "rbac_query_proxy"
 
@@ -211,23 +216,29 @@ const (
 	MetricsCollectorCPULimits     = ""
 	MetricsCollectorMemoryLimits  = ""
 
-	ObservatoriumAPI             = "observatorium-api"
-	ThanosCompact                = "thanos-compact"
-	ThanosQuery                  = "thanos-query"
-	ThanosQueryFrontend          = "thanos-query-frontend"
-	ThanosQueryFrontendMemcached = "thanos-query-frontend-memcached"
-	ThanosRule                   = "thanos-rule"
-	ThanosReceive                = "thanos-receive-default"
-	ThanosStoreMemcached         = "thanos-store-memcached"
-	ThanosStoreShard             = "thanos-store-shard"
-	MemcachedExporter            = "memcached-exporter"
-	Grafana                      = "grafana"
-	RBACQueryProxy               = "rbac-query-proxy"
-	Alertmanager                 = "alertmanager"
-	ThanosReceiveController      = "thanos-receive-controller"
-	ObservatoriumOperator        = "observatorium-operator"
-	MetricsCollector             = "metrics-collector"
-	Observatorium                = "observatorium"
+	MCOACPURequests    = "100m"
+	MCOACPULimits      = "200m"
+	MCOAMemoryRequests = "256Mi"
+	MCOAMemoryLimits   = "512Mi"
+
+	ObservatoriumAPI               = "observatorium-api"
+	ThanosCompact                  = "thanos-compact"
+	ThanosQuery                    = "thanos-query"
+	ThanosQueryFrontend            = "thanos-query-frontend"
+	ThanosQueryFrontendMemcached   = "thanos-query-frontend-memcached"
+	ThanosRule                     = "thanos-rule"
+	ThanosReceive                  = "thanos-receive-default"
+	ThanosStoreMemcached           = "thanos-store-memcached"
+	ThanosStoreShard               = "thanos-store-shard"
+	MemcachedExporter              = "memcached-exporter"
+	Grafana                        = "grafana"
+	RBACQueryProxy                 = "rbac-query-proxy"
+	Alertmanager                   = "alertmanager"
+	ThanosReceiveController        = "thanos-receive-controller"
+	ObservatoriumOperator          = "observatorium-operator"
+	MetricsCollector               = "metrics-collector"
+	Observatorium                  = "observatorium"
+	MultiClusterObservabilityAddon = "multicluster-observability-addon"
 
 	RetentionResolutionRaw = "365d"
 	RetentionResolution5m  = "365d"
@@ -828,7 +839,8 @@ func GetImagePullSecret(mco observabilityv1beta2.MultiClusterObservabilitySpec)
 }
 
 func getDefaultResource(resourceType string, resource corev1.ResourceName,
-	component string) string {
+	component string,
+) string {
 	// No provide the default limits
 	if resourceType == ResourceLimits && component != Grafana {
 		return ""
@@ -934,12 +946,30 @@ func getDefaultResource(resourceType string, resource corev1.ResourceName,
 				return GrafanaMemoryLimits
 			}
 		}
+	case MultiClusterObservabilityAddon:
+		if resourceType == ResourceRequests {
+			if resource == corev1.ResourceCPU {
+				return MCOACPURequests
+			}
+			if resource == corev1.ResourceMemory {
+				return MCOAMemoryRequests
+			}
+		} else if resourceType == ResourceLimits {
+			if resource == corev1.ResourceCPU {
+				return MCOACPULimits
+			}
+			if resource == corev1.ResourceMemory {
+				return MCOACPULimits
+			}
+		}
+
 	}
 	return ""
 }
 
 func getResource(resourceType string, resource corev1.ResourceName,
-	component string, advanced *observabilityv1beta2.AdvancedConfig) string {
+	component string, advanced *observabilityv1beta2.AdvancedConfig,
+) string {
 	if advanced == nil {
 		return getDefaultResource(resourceType, resource, component)
 	}
@@ -993,6 +1023,10 @@ func getResource(resourceType string, resource corev1.ResourceName,
 		if advanced.Alertmanager != nil {
 			resourcesReq = advanced.Alertmanager.Resources
 		}
+	case MultiClusterObservabilityAddon:
+		if advanced.MultiClusterObservabilityAddon != nil {
+			resourcesReq = advanced.MultiClusterObservabilityAddon.Resources
+		}
 	}
 
 	if resourcesReq != nil {
@@ -1029,7 +1063,6 @@ func getResource(resourceType string, resource corev1.ResourceName,
 }
 
 func GetResources(component string, advanced *observabilityv1beta2.AdvancedConfig) corev1.ResourceRequirements {
-
 	cpuRequests := getResource(ResourceRequests, corev1.ResourceCPU, component, advanced)
 	cpuLimits := getResource(ResourceLimits, corev1.ResourceCPU, component, advanced)
 	memoryRequests := getResource(ResourceRequests, corev1.ResourceMemory, component, advanced)
@@ -1133,6 +1166,7 @@ func SetOperandNames(c client.Client) error {
 	operandNames[ObservatoriumOperator] = GetOperandNamePrefix() + ObservatoriumOperator
 	operandNames[Observatorium] = GetDefaultCRName()
 	operandNames[ObservatoriumAPI] = GetOperandNamePrefix() + ObservatoriumAPI
+	operandNames[MultiClusterObservabilityAddon] = GetOperandNamePrefix() + MultiClusterObservabilityAddon
 
 	// Check if the Observatorium CR already exists
 	opts := &client.ListOptions{
@@ -1156,6 +1190,7 @@ func SetOperandNames(c client.Client) error {
 						operandNames[ObservatoriumOperator] = ObservatoriumOperator
 						operandNames[Observatorium] = observatorium.Name
 						operandNames[ObservatoriumAPI] = observatorium.Name + "-" + ObservatoriumAPI
+						operandNames[MultiClusterObservabilityAddon] = MultiClusterObservabilityAddon
 					}
 					break
 				}
@@ -1238,7 +1273,8 @@ func GetMulticloudConsoleHost(client client.Client, isStandalone bool) (string,
 	found := &routev1.Route{}
 
 	err := client.Get(context.TODO(), types.NamespacedName{
-		Name: MulticloudConsoleRouteName, Namespace: namespace}, found)
+		Name: MulticloudConsoleRouteName, Namespace: namespace,
+	}, found)
 	if err != nil {
 		return "", err
 	}
diff --git a/operators/multiclusterobservability/pkg/rendering/renderer.go b/operators/multiclusterobservability/pkg/rendering/renderer.go
index 6a19632d3e..bc7f4681d1 100644
--- a/operators/multiclusterobservability/pkg/rendering/renderer.go
+++ b/operators/multiclusterobservability/pkg/rendering/renderer.go
@@ -31,6 +31,7 @@ type MCORenderer struct {
 	renderAlertManagerFns map[string]rendererutil.RenderFn
 	renderThanosFns       map[string]rendererutil.RenderFn
 	renderProxyFns        map[string]rendererutil.RenderFn
+	renderMCOAFns         map[string]rendererutil.RenderFn
 }
 
 func NewMCORenderer(multipleClusterMonitoring *obv1beta2.MultiClusterObservability, kubeClient client.Client) *MCORenderer {
@@ -43,6 +44,7 @@ func NewMCORenderer(multipleClusterMonitoring *obv1beta2.MultiClusterObservabili
 	mcoRenderer.newAlertManagerRenderer()
 	mcoRenderer.newThanosRenderer()
 	mcoRenderer.newProxyRenderer()
+	mcoRenderer.newMCOARenderer()
 	return mcoRenderer
 }
 
@@ -105,6 +107,17 @@ func (r *MCORenderer) Render() ([]*unstructured.Unstructured, error) {
 	}
 	resources = append(resources, proxyResources...)
 
+	// load and render multicluster-observability-addon templates
+	mcoaTemplates, err := templates.GetOrLoadMCOATemplates(templatesutil.GetTemplateRenderer())
+	if err != nil {
+		return nil, err
+	}
+	mcoaResources, err := r.renderMCOATemplates(mcoaTemplates, namespace, labels)
+	if err != nil {
+		return nil, err
+	}
+	resources = append(resources, mcoaResources...)
+
 	for idx := range resources {
 		if resources[idx].GetKind() == "Deployment" {
 			obj := util.GetK8sObj(resources[idx].GetKind())
diff --git a/operators/multiclusterobservability/pkg/rendering/renderer_mcoa.go b/operators/multiclusterobservability/pkg/rendering/renderer_mcoa.go
new file mode 100644
index 0000000000..d17bc781bf
--- /dev/null
+++ b/operators/multiclusterobservability/pkg/rendering/renderer_mcoa.go
@@ -0,0 +1,203 @@
+// Copyright (c) Red Hat, Inc.
+// Copyright Contributors to the Open Cluster Management project
+// Licensed under the Apache License 2.0
+
+package rendering
+
+import (
+	"fmt"
+
+	appsv1 "k8s.io/api/apps/v1"
+	corev1 "k8s.io/api/core/v1"
+	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+	"k8s.io/apimachinery/pkg/runtime"
+	addonapiv1alpha1 "open-cluster-management.io/api/addon/v1alpha1"
+	"sigs.k8s.io/kustomize/api/resource"
+
+	mcoconfig "github.com/stolostron/multicluster-observability-operator/operators/multiclusterobservability/pkg/config"
+	rendererutil "github.com/stolostron/multicluster-observability-operator/operators/pkg/rendering"
+	"github.com/stolostron/multicluster-observability-operator/operators/pkg/util"
+)
+
+const (
+	// AODC CustomizedVariable Names
+	namePlatformLogsCollection       = "platformLogsCollection"
+	nameUserWorkloadLogsCollection   = "userWorkloadLogsCollection"
+	nameUserWorkloadTracesCollection = "userWorkloadTracesCollection"
+	nameUserWorkloadInstrumentation  = "userWorkloadInstrumentation"
+
+	// AODC CustomizedVariable Values
+	clfV1         = "clusterlogforwarders.v1.logging.openshift.io"
+	otelV1alpa1   = "opentelemetrycollectors.v1alpha1.opentelemetry.io"
+	instrV1alpha1 = "instrumentations.v1alpha1.opentelemetry.io"
+)
+
+func (r *MCORenderer) newMCOARenderer() {
+	r.renderMCOAFns = map[string]rendererutil.RenderFn{
+		"AddonDeploymentConfig":  r.renderAddonDeploymentConfig,
+		"ClusterManagementAddOn": r.renderClusterManagementAddOn,
+		"Deployment":             r.renderMCOADeployment,
+		"ServiceAccount":         r.renderer.RenderNamespace,
+		"ClusterRole":            r.renderer.RenderClusterRole,
+		"ClusterRoleBinding":     r.renderer.RenderClusterRoleBinding,
+	}
+}
+
+func (r *MCORenderer) renderMCOADeployment(res *resource.Resource,
+	namespace string, labels map[string]string,
+) (*unstructured.Unstructured, error) {
+	u, err := r.renderer.RenderNamespace(res, namespace, labels)
+	if err != nil {
+		return nil, err
+	}
+	obj := util.GetK8sObj(u.GetKind())
+	err = runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, obj)
+	if err != nil {
+		return nil, err
+	}
+	crLabelKey := mcoconfig.GetCrLabelKey()
+	dep := obj.(*appsv1.Deployment)
+	dep.ObjectMeta.Labels[crLabelKey] = r.cr.Name
+	dep.Spec.Selector.MatchLabels[crLabelKey] = r.cr.Name
+	dep.Spec.Template.ObjectMeta.Labels[crLabelKey] = r.cr.Name
+	dep.Name = mcoconfig.GetOperandName(mcoconfig.MultiClusterObservabilityAddon)
+	dep.Spec.Replicas = mcoconfig.GetReplicas(mcoconfig.MultiClusterObservabilityAddon, r.cr.Spec.AdvancedConfig)
+
+	spec := &dep.Spec.Template.Spec
+
+	imagePullPolicy := mcoconfig.GetImagePullPolicy(r.cr.Spec)
+	spec.Containers[0].ImagePullPolicy = imagePullPolicy
+	spec.Containers[0].Resources = mcoconfig.GetResources(mcoconfig.MultiClusterObservabilityAddon, r.cr.Spec.AdvancedConfig)
+	spec.NodeSelector = r.cr.Spec.NodeSelector
+	spec.Tolerations = r.cr.Spec.Tolerations
+	spec.ImagePullSecrets = []corev1.LocalObjectReference{
+		{Name: mcoconfig.GetImagePullSecret(r.cr.Spec)},
+	}
+
+	spec.Containers[0].Image = fmt.Sprintf("%s/%s:%s",
+		mcoconfig.MultiClusterObservabilityAddonImgRepo,
+		mcoconfig.MultiClusterObservabilityAddonImgName,
+		mcoconfig.MultiClusterObservabilityAddonImgTagSuffix,
+	)
+	found, image := mcoconfig.ReplaceImage(
+		r.cr.Annotations,
+		mcoconfig.DefaultImgRepository+"/"+mcoconfig.MultiClusterObservabilityAddonImgName,
+		mcoconfig.MultiClusterObservabilityAddon)
+	if found {
+		spec.Containers[0].Image = image
+	}
+
+	unstructuredObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj)
+	if err != nil {
+		return nil, err
+	}
+
+	return &unstructured.Unstructured{Object: unstructuredObj}, nil
+}
+
+func (r *MCORenderer) renderClusterManagementAddOn(
+	res *resource.Resource,
+	namespace string,
+	labels map[string]string,
+) (*unstructured.Unstructured, error) {
+	m, err := res.Map()
+	if err != nil {
+		return nil, err
+	}
+	u := &unstructured.Unstructured{Object: m}
+
+	cLabels := u.GetLabels()
+	if cLabels == nil {
+		cLabels = make(map[string]string)
+	}
+	for k, v := range labels {
+		cLabels[k] = v
+	}
+	u.SetLabels(cLabels)
+
+	return u, nil
+}
+
+func (r *MCORenderer) renderAddonDeploymentConfig(res *resource.Resource, namespace string, labels map[string]string) (*unstructured.Unstructured, error) {
+	m, err := res.Map()
+	if err != nil {
+		return nil, err
+	}
+	u := &unstructured.Unstructured{Object: m}
+
+	if cs := r.cr.Spec.Capabilities; cs != nil {
+		var aodc *addonapiv1alpha1.AddOnDeploymentConfig
+		if err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, aodc); err != nil {
+			return nil, err
+		}
+
+		appendCustomVar := func(aodc *addonapiv1alpha1.AddOnDeploymentConfig, name, value string) {
+			aodc.Spec.CustomizedVariables = append(
+				aodc.Spec.CustomizedVariables,
+				addonapiv1alpha1.CustomizedVariable{Name: name, Value: value},
+			)
+		}
+
+		if cs.Platform != nil {
+			if cs.Platform.Logs.Enabled {
+				appendCustomVar(aodc, namePlatformLogsCollection, clfV1)
+			}
+		}
+
+		if cs.UserWorkloads != nil {
+			if cs.UserWorkloads.Logs.ClusterLogForwarder.Enabled {
+				appendCustomVar(aodc, nameUserWorkloadLogsCollection, clfV1)
+			}
+			if cs.UserWorkloads.Traces.OpenTelemetryCollector.Enabled {
+				appendCustomVar(aodc, nameUserWorkloadTracesCollection, otelV1alpa1)
+			}
+			if cs.UserWorkloads.Traces.Instrumentation.Enabled {
+				appendCustomVar(aodc, nameUserWorkloadInstrumentation, instrV1alpha1)
+			}
+		}
+
+		u.Object, err = runtime.DefaultUnstructuredConverter.ToUnstructured(aodc)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	cLabels := u.GetLabels()
+	if cLabels == nil {
+		cLabels = make(map[string]string)
+	}
+	for k, v := range labels {
+		cLabels[k] = v
+	}
+	u.SetLabels(cLabels)
+
+	return u, nil
+}
+
+func (r *MCORenderer) renderMCOATemplates(templates []*resource.Resource,
+	namespace string, labels map[string]string,
+) ([]*unstructured.Unstructured, error) {
+	uobjs := []*unstructured.Unstructured{}
+	for _, template := range templates {
+		render, ok := r.renderMCOAFns[template.GetKind()]
+		if !ok {
+			m, err := template.Map()
+			if err != nil {
+				return []*unstructured.Unstructured{}, err
+			}
+			uobjs = append(uobjs, &unstructured.Unstructured{Object: m})
+			continue
+		}
+		uobj, err := render(template.DeepCopy(), namespace, labels)
+		if err != nil {
+			return []*unstructured.Unstructured{}, err
+		}
+		if uobj == nil {
+			continue
+		}
+		uobjs = append(uobjs, uobj)
+
+	}
+
+	return uobjs, nil
+}
diff --git a/operators/multiclusterobservability/pkg/rendering/templates/templates.go b/operators/multiclusterobservability/pkg/rendering/templates/templates.go
index 5259496333..e317ff923b 100644
--- a/operators/multiclusterobservability/pkg/rendering/templates/templates.go
+++ b/operators/multiclusterobservability/pkg/rendering/templates/templates.go
@@ -13,7 +13,7 @@ import (
 )
 
 // *Templates contains all kustomize resources.
-var genericTemplates, grafanaTemplates, alertManagerTemplates, thanosTemplates, proxyTemplates, endpointObservabilityTemplates, prometheusTemplates []*resource.Resource
+var genericTemplates, grafanaTemplates, alertManagerTemplates, thanosTemplates, proxyTemplates, endpointObservabilityTemplates, prometheusTemplates, mcoaTemplates []*resource.Resource
 
 // GetOrLoadGenericTemplates reads base manifest.
 func GetOrLoadGenericTemplates(r *templates.TemplateRenderer) ([]*resource.Resource, error) {
@@ -96,6 +96,21 @@ func GetOrLoadProxyTemplates(r *templates.TemplateRenderer) ([]*resource.Resourc
 	return proxyTemplates, nil
 }
 
+// GetOrLoadMCOATemplates reads the rbac-query-proxy manifests.
+func GetOrLoadMCOATemplates(r *templates.TemplateRenderer) ([]*resource.Resource, error) {
+	if len(mcoaTemplates) > 0 {
+		return mcoaTemplates, nil
+	}
+
+	basePath := path.Join(r.GetTemplatesPath(), "base")
+
+	// add mcoa templates
+	if err := r.AddTemplateFromPath(basePath+"/multicluster-observability-addon", &mcoaTemplates); err != nil {
+		return mcoaTemplates, err
+	}
+	return mcoaTemplates, nil
+}
+
 // GetEndpointObservabilityTemplates reads endpoint-observability manifest.
 func GetOrLoadEndpointObservabilityTemplates(r *templates.TemplateRenderer) ([]*resource.Resource, error) {
 	if len(endpointObservabilityTemplates) > 0 {
@@ -136,4 +151,5 @@ func ResetTemplates() {
 	thanosTemplates = nil
 	proxyTemplates = nil
 	endpointObservabilityTemplates = nil
+	mcoaTemplates = nil
 }