Add featureflags to content app (dynamic) endpoints (#19930)

* Add featureflags to content app (dynamic) endpoints

* Add featureflag support to dynamic endpoints with clusters channel, keypadinput, mediaplayback

* Add featureflag support to android implementation

* Fix Darwin clang-tidy errors

* Fix missing vendorId in AddNoc from tv-app
diff --git a/examples/platform/linux/CommissionerMain.cpp b/examples/platform/linux/CommissionerMain.cpp
index f30e922..afa4f80 100644
--- a/examples/platform/linux/CommissionerMain.cpp
+++ b/examples/platform/linux/CommissionerMain.cpp
@@ -42,6 +42,7 @@
 #include <setup_payload/SetupPayload.h>
 
 #include <platform/CommissionableDataProvider.h>
+#include <platform/DeviceInstanceInfoProvider.h>
 #include <platform/DiagnosticDataProvider.h>
 #include <platform/TestOnlyCommissionableDataProvider.h>
 
@@ -132,6 +133,10 @@
     factoryParams.groupDataProvider = &gGroupDataProvider;
 
     params.operationalCredentialsDelegate = &gOpCredsIssuer;
+    uint16_t vendorId;
+    DeviceLayer::GetDeviceInstanceInfoProvider()->GetVendorId(vendorId);
+    ChipLogProgress(Support, " ----- Commissioner using vendorId 0x%04X", vendorId);
+    params.controllerVendorId = static_cast<VendorId>(vendorId);
 
     ReturnErrorOnFailure(gOpCredsIssuer.Initialize(gServerStorage));
 
diff --git a/examples/tv-app/android/include/content-launcher/AppContentLauncherManager.cpp b/examples/tv-app/android/include/content-launcher/AppContentLauncherManager.cpp
index 1d15233..6dc80c5 100644
--- a/examples/tv-app/android/include/content-launcher/AppContentLauncherManager.cpp
+++ b/examples/tv-app/android/include/content-launcher/AppContentLauncherManager.cpp
@@ -100,3 +100,15 @@
     ChipLogProgress(Zcl, "AppContentLauncherManager::HandleGetSupportedStreamingProtocols");
     return mSupportedStreamingProtocols;
 }
+
+uint32_t AppContentLauncherManager::GetFeatureMap(chip::EndpointId endpoint)
+{
+    if (endpoint >= EMBER_AF_CONTENT_LAUNCH_CLUSTER_SERVER_ENDPOINT_COUNT)
+    {
+        return mDynamicEndpointFeatureMap;
+    }
+
+    uint32_t featureMap = 0;
+    Attributes::FeatureMap::Get(endpoint, &featureMap);
+    return featureMap;
+}
diff --git a/examples/tv-app/android/include/content-launcher/AppContentLauncherManager.h b/examples/tv-app/android/include/content-launcher/AppContentLauncherManager.h
index af0b987..b5b8f7a 100644
--- a/examples/tv-app/android/include/content-launcher/AppContentLauncherManager.h
+++ b/examples/tv-app/android/include/content-launcher/AppContentLauncherManager.h
@@ -19,6 +19,7 @@
 #pragma once
 
 #include "../../java/ContentAppCommandDelegate.h"
+#include <app-common/zap-generated/attributes/Accessors.h>
 #include <app/clusters/content-launch-server/content-launch-server.h>
 
 using chip::CharSpan;
@@ -47,6 +48,8 @@
 
     void SetEndpointId(EndpointId epId) { mEndpointId = epId; };
 
+    uint32_t GetFeatureMap(chip::EndpointId endpoint) override;
+
 protected:
     std::list<std::string> mAcceptHeaderList;
     uint32_t mSupportedStreamingProtocols;
@@ -54,4 +57,7 @@
 private:
     EndpointId mEndpointId;
     ContentAppCommandDelegate mCommandDelegate;
+
+    // TODO: set this based upon meta data from app
+    uint32_t mDynamicEndpointFeatureMap = 3;
 };
diff --git a/examples/tv-app/android/java/AppImpl.cpp b/examples/tv-app/android/java/AppImpl.cpp
index a0564d2..063a2be 100644
--- a/examples/tv-app/android/java/AppImpl.cpp
+++ b/examples/tv-app/android/java/AppImpl.cpp
@@ -113,6 +113,12 @@
 // CONTENT APP ENDPOINT: contains the following clusters:
 //   - Descriptor
 //   - Application Basic
+//   - Keypad Input
+//   - Application Launcher
+//   - Account Login
+//   - Content Launcher
+//   - Target Navigator
+//   - Channel
 
 // Declare Descriptor cluster attributes
 DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(descriptorAttrs)
@@ -123,23 +129,27 @@
     DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();
 
 // Declare Application Basic information cluster attributes
-// TODO: add missing attributes once schema is updated
 DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(applicationBasicAttrs)
 DECLARE_DYNAMIC_ATTRIBUTE(ZCL_APPLICATION_VENDOR_NAME_ATTRIBUTE_ID, CHAR_STRING, kNameSize, 0), /* VendorName */
     DECLARE_DYNAMIC_ATTRIBUTE(ZCL_APPLICATION_VENDOR_ID_ATTRIBUTE_ID, INT16U, 1, 0),            /* VendorID */
     DECLARE_DYNAMIC_ATTRIBUTE(ZCL_APPLICATION_NAME_ATTRIBUTE_ID, CHAR_STRING, kNameSize, 0),    /* ApplicationName */
     DECLARE_DYNAMIC_ATTRIBUTE(ZCL_APPLICATION_PRODUCT_ID_ATTRIBUTE_ID, INT16U, 1, 0),           /* ProductID */
     DECLARE_DYNAMIC_ATTRIBUTE(ZCL_APPLICATION_STATUS_ATTRIBUTE_ID, INT8U, 1, 0),                /* ApplicationStatus */
+    DECLARE_DYNAMIC_ATTRIBUTE(ZCL_APPLICATION_VERSION_ATTRIBUTE_ID, CHAR_STRING, kNameSize, 0), /* ApplicationVersion */
+    DECLARE_DYNAMIC_ATTRIBUTE(ZCL_APPLICATION_ALLOWED_VENDOR_LIST_ATTRIBUTE_ID, ARRAY, kDescriptorAttributeArraySize,
+                              0), /* AllowedVendorList */
     DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();
 
 // Declare Keypad Input cluster attributes
 DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(keypadInputAttrs)
-DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();
+DECLARE_DYNAMIC_ATTRIBUTE(ZCL_FEATURE_MAP_SERVER_ATTRIBUTE_ID, BITMAP32, 4, 0), /* FeatureMap */
+    DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();
 
 // Declare Application Launcher cluster attributes
-// TODO: add missing attributes once schema is updated
+// NOTE: Does not make sense for content app to be able to set the AP feature flag
 DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(applicationLauncherAttrs)
 DECLARE_DYNAMIC_ATTRIBUTE(ZCL_APPLICATION_LAUNCHER_LIST_ATTRIBUTE_ID, ARRAY, kDescriptorAttributeArraySize, 0), /* catalog list */
+    DECLARE_DYNAMIC_ATTRIBUTE(ZCL_APPLICATION_LAUNCHER_CURRENT_APP_ATTRIBUTE_ID, STRUCT, 1, 0),                 /* current app */
     DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();
 
 // Declare Account Login cluster attributes
@@ -151,18 +161,20 @@
 DECLARE_DYNAMIC_ATTRIBUTE(ZCL_CONTENT_LAUNCHER_ACCEPT_HEADER_ATTRIBUTE_ID, ARRAY, kDescriptorAttributeArraySize,
                           0), /* accept header list */
     DECLARE_DYNAMIC_ATTRIBUTE(ZCL_CONTENT_LAUNCHER_SUPPORTED_STREAMING_PROTOCOLS_ATTRIBUTE_ID, BITMAP32, 1,
-                              0), /* streaming protocols */
+                              0),                                                   /* streaming protocols */
+    DECLARE_DYNAMIC_ATTRIBUTE(ZCL_FEATURE_MAP_SERVER_ATTRIBUTE_ID, BITMAP32, 4, 0), /* FeatureMap */
     DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();
 
 // Declare Media Playback cluster attributes
-// TODO: add missing attributes once schema is updated
 DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(mediaPlaybackAttrs)
 DECLARE_DYNAMIC_ATTRIBUTE(ZCL_MEDIA_PLAYBACK_STATE_ATTRIBUTE_ID, ENUM8, 1, 0),                          /* current state */
     DECLARE_DYNAMIC_ATTRIBUTE(ZCL_MEDIA_PLAYBACK_START_TIME_ATTRIBUTE_ID, EPOCH_US, 1, 0),              /* start time */
     DECLARE_DYNAMIC_ATTRIBUTE(ZCL_MEDIA_PLAYBACK_DURATION_ATTRIBUTE_ID, INT64U, 1, 0),                  /* duration */
+    DECLARE_DYNAMIC_ATTRIBUTE(ZCL_MEDIA_PLAYBACK_PLAYBACK_POSITION_ATTRIBUTE_ID, STRUCT, 1, 0),         /* playback speed */
     DECLARE_DYNAMIC_ATTRIBUTE(ZCL_MEDIA_PLAYBACK_PLAYBACK_SPEED_ATTRIBUTE_ID, SINGLE, 1, 0),            /* playback speed */
     DECLARE_DYNAMIC_ATTRIBUTE(ZCL_MEDIA_PLAYBACK_PLAYBACK_SEEK_RANGE_END_ATTRIBUTE_ID, INT64U, 1, 0),   /* seek range end */
     DECLARE_DYNAMIC_ATTRIBUTE(ZCL_MEDIA_PLAYBACK_PLAYBACK_SEEK_RANGE_START_ATTRIBUTE_ID, INT64U, 1, 0), /* seek range start */
+    DECLARE_DYNAMIC_ATTRIBUTE(ZCL_FEATURE_MAP_SERVER_ATTRIBUTE_ID, BITMAP32, 4, 0),                     /* FeatureMap */
     DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();
 
 // Declare Target Navigator cluster attributes
@@ -176,6 +188,7 @@
 DECLARE_DYNAMIC_ATTRIBUTE(ZCL_CHANNEL_LIST_ATTRIBUTE_ID, ARRAY, kDescriptorAttributeArraySize, 0), /* channel list */
     DECLARE_DYNAMIC_ATTRIBUTE(ZCL_CHANNEL_LINEUP_ATTRIBUTE_ID, STRUCT, 1, 0),                      /* lineup */
     DECLARE_DYNAMIC_ATTRIBUTE(ZCL_CHANNEL_CURRENT_CHANNEL_ATTRIBUTE_ID, STRUCT, 1, 0),             /* current channel */
+    DECLARE_DYNAMIC_ATTRIBUTE(ZCL_FEATURE_MAP_SERVER_ATTRIBUTE_ID, BITMAP32, 4, 0),                /* FeatureMap */
     DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();
 
 constexpr CommandId keypadInputIncomingCommands[] = {
diff --git a/examples/tv-app/android/java/ChannelManager.cpp b/examples/tv-app/android/java/ChannelManager.cpp
index e8231b3..fb8a4d8 100644
--- a/examples/tv-app/android/java/ChannelManager.cpp
+++ b/examples/tv-app/android/java/ChannelManager.cpp
@@ -17,6 +17,7 @@
 
 #include "ChannelManager.h"
 #include "TvApp-JNI.h"
+#include <app-common/zap-generated/attributes/Accessors.h>
 #include <app-common/zap-generated/ids/Clusters.h>
 #include <cstdlib>
 #include <jni.h>
@@ -407,3 +408,15 @@
         env->ExceptionClear();
     }
 }
+
+uint32_t ChannelManager::GetFeatureMap(chip::EndpointId endpoint)
+{
+    if (endpoint >= EMBER_AF_CONTENT_LAUNCH_CLUSTER_SERVER_ENDPOINT_COUNT)
+    {
+        return mDynamicEndpointFeatureMap;
+    }
+
+    uint32_t featureMap = 0;
+    Attributes::FeatureMap::Get(endpoint, &featureMap);
+    return featureMap;
+}
diff --git a/examples/tv-app/android/java/ChannelManager.h b/examples/tv-app/android/java/ChannelManager.h
index e7fb8e3..0439900 100644
--- a/examples/tv-app/android/java/ChannelManager.h
+++ b/examples/tv-app/android/java/ChannelManager.h
@@ -40,6 +40,8 @@
     bool HandleChangeChannelByNumber(const uint16_t & majorNumber, const uint16_t & minorNumber) override;
     bool HandleSkipChannel(const uint16_t & count) override;
 
+    uint32_t GetFeatureMap(chip::EndpointId endpoint) override;
+
 private:
     jobject mChannelManagerObject      = nullptr;
     jmethodID mGetChannelListMethod    = nullptr;
@@ -49,4 +51,7 @@
     jmethodID mChangeChannelMethod         = nullptr;
     jmethodID mChangeChannelByNumberMethod = nullptr;
     jmethodID mSkipChannelMethod           = nullptr;
+
+    // TODO: set this based upon meta data from app
+    uint32_t mDynamicEndpointFeatureMap = 3;
 };
diff --git a/examples/tv-app/android/java/ContentLauncherManager.cpp b/examples/tv-app/android/java/ContentLauncherManager.cpp
index 3b2be95..81fa61b 100644
--- a/examples/tv-app/android/java/ContentLauncherManager.cpp
+++ b/examples/tv-app/android/java/ContentLauncherManager.cpp
@@ -18,6 +18,7 @@
 
 #include "ContentLauncherManager.h"
 #include "TvApp-JNI.h"
+#include <app-common/zap-generated/attributes/Accessors.h>
 #include <app-common/zap-generated/ids/Clusters.h>
 #include <jni.h>
 #include <lib/core/CHIPSafeCasts.h>
@@ -272,3 +273,10 @@
         env->ExceptionClear();
     }
 }
+
+uint32_t ContentLauncherManager::GetFeatureMap(chip::EndpointId endpoint)
+{
+    uint32_t featureMap = 0;
+    Attributes::FeatureMap::Get(endpoint, &featureMap);
+    return featureMap;
+}
diff --git a/examples/tv-app/android/java/ContentLauncherManager.h b/examples/tv-app/android/java/ContentLauncherManager.h
index a034afd..79a35de 100644
--- a/examples/tv-app/android/java/ContentLauncherManager.h
+++ b/examples/tv-app/android/java/ContentLauncherManager.h
@@ -47,6 +47,8 @@
     CHIP_ERROR HandleGetAcceptHeaderList(AttributeValueEncoder & aEncoder) override;
     uint32_t HandleGetSupportedStreamingProtocols() override;
 
+    uint32_t GetFeatureMap(chip::EndpointId endpoint) override;
+
 private:
     jobject mContentLauncherManagerObject           = nullptr;
     jmethodID mGetAcceptHeaderMethod                = nullptr;
diff --git a/examples/tv-app/android/java/KeypadInputManager.cpp b/examples/tv-app/android/java/KeypadInputManager.cpp
index f8c19a1..e4cfdad 100644
--- a/examples/tv-app/android/java/KeypadInputManager.cpp
+++ b/examples/tv-app/android/java/KeypadInputManager.cpp
@@ -18,6 +18,7 @@
 
 #include "KeypadInputManager.h"
 #include "TvApp-JNI.h"
+#include <app-common/zap-generated/attributes/Accessors.h>
 #include <app-common/zap-generated/ids/Clusters.h>
 #include <lib/support/CHIPJNIError.h>
 #include <lib/support/JniReferences.h>
@@ -86,3 +87,15 @@
         env->ExceptionClear();
     }
 }
+
+uint32_t KeypadInputManager::GetFeatureMap(chip::EndpointId endpoint)
+{
+    if (endpoint >= EMBER_AF_CONTENT_LAUNCH_CLUSTER_SERVER_ENDPOINT_COUNT)
+    {
+        return mDynamicEndpointFeatureMap;
+    }
+
+    uint32_t featureMap = 0;
+    Attributes::FeatureMap::Get(endpoint, &featureMap);
+    return featureMap;
+}
diff --git a/examples/tv-app/android/java/KeypadInputManager.h b/examples/tv-app/android/java/KeypadInputManager.h
index 416c878..8c43cc0 100644
--- a/examples/tv-app/android/java/KeypadInputManager.h
+++ b/examples/tv-app/android/java/KeypadInputManager.h
@@ -34,7 +34,12 @@
     void HandleSendKey(CommandResponseHelper<SendKeyResponseType> & helper,
                        const chip::app::Clusters::KeypadInput::CecKeyCode & keyCode) override;
 
+    uint32_t GetFeatureMap(chip::EndpointId endpoint) override;
+
 private:
     jobject mKeypadInputManagerObject = nullptr;
     jmethodID mSendKeyMethod          = nullptr;
+
+    // TODO: set this based upon meta data from app
+    uint32_t mDynamicEndpointFeatureMap = 7;
 };
diff --git a/examples/tv-app/android/java/MediaPlaybackManager.cpp b/examples/tv-app/android/java/MediaPlaybackManager.cpp
index 85d2e60..0bc9244 100644
--- a/examples/tv-app/android/java/MediaPlaybackManager.cpp
+++ b/examples/tv-app/android/java/MediaPlaybackManager.cpp
@@ -17,6 +17,7 @@
 
 #include "MediaPlaybackManager.h"
 #include "TvApp-JNI.h"
+#include <app-common/zap-generated/attributes/Accessors.h>
 #include <app-common/zap-generated/ids/Clusters.h>
 #include <cstdint>
 #include <jni.h>
@@ -298,3 +299,15 @@
 
     return aEncoder.Encode(response);
 }
+
+uint32_t MediaPlaybackManager::GetFeatureMap(chip::EndpointId endpoint)
+{
+    if (endpoint >= EMBER_AF_CONTENT_LAUNCH_CLUSTER_SERVER_ENDPOINT_COUNT)
+    {
+        return mDynamicEndpointFeatureMap;
+    }
+
+    uint32_t featureMap = 0;
+    Attributes::FeatureMap::Get(endpoint, &featureMap);
+    return featureMap;
+}
diff --git a/examples/tv-app/android/java/MediaPlaybackManager.h b/examples/tv-app/android/java/MediaPlaybackManager.h
index 74f2812..822fcf5 100644
--- a/examples/tv-app/android/java/MediaPlaybackManager.h
+++ b/examples/tv-app/android/java/MediaPlaybackManager.h
@@ -81,6 +81,8 @@
     void HandleNext(CommandResponseHelper<PlaybackResponseType> & helper) override;
     void HandleStartOver(CommandResponseHelper<PlaybackResponseType> & helper) override;
 
+    uint32_t GetFeatureMap(chip::EndpointId endpoint) override;
+
 private:
     jobject mMediaPlaybackManagerObject = nullptr;
     jmethodID mRequestMethod            = nullptr;
@@ -90,4 +92,7 @@
     uint64_t HandleMediaRequestGetAttribute(MediaPlaybackRequestAttribute attribute);
     chip::app::Clusters::MediaPlayback::Commands::PlaybackResponse::Type
     HandleMediaRequest(MediaPlaybackRequest mediaPlaybackRequest, uint64_t deltaPositionMilliseconds);
+
+    // TODO: set this based upon meta data from app
+    uint32_t mDynamicEndpointFeatureMap = 3;
 };
diff --git a/examples/tv-app/linux/AppImpl.cpp b/examples/tv-app/linux/AppImpl.cpp
index 2cc16ac..06c9829 100644
--- a/examples/tv-app/linux/AppImpl.cpp
+++ b/examples/tv-app/linux/AppImpl.cpp
@@ -22,6 +22,7 @@
 #include "AppImpl.h"
 
 #include <app-common/zap-generated/attribute-id.h>
+#include <app-common/zap-generated/attributes/Accessors.h>
 #include <app-common/zap-generated/cluster-id.h>
 #include <app-common/zap-generated/ids/Attributes.h>
 #include <app-common/zap-generated/ids/Clusters.h>
@@ -138,6 +139,12 @@
 // CONTENT APP ENDPOINT: contains the following clusters:
 //   - Descriptor
 //   - Application Basic
+//   - Keypad Input
+//   - Application Launcher
+//   - Account Login
+//   - Content Launcher
+//   - Target Navigator
+//   - Channel
 
 // Declare Descriptor cluster attributes
 DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(descriptorAttrs)
@@ -148,23 +155,27 @@
     DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();
 
 // Declare Application Basic information cluster attributes
-// TODO: add missing attributes once schema is updated
 DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(applicationBasicAttrs)
 DECLARE_DYNAMIC_ATTRIBUTE(ZCL_APPLICATION_VENDOR_NAME_ATTRIBUTE_ID, CHAR_STRING, kNameSize, 0), /* VendorName */
     DECLARE_DYNAMIC_ATTRIBUTE(ZCL_APPLICATION_VENDOR_ID_ATTRIBUTE_ID, INT16U, 1, 0),            /* VendorID */
     DECLARE_DYNAMIC_ATTRIBUTE(ZCL_APPLICATION_NAME_ATTRIBUTE_ID, CHAR_STRING, kNameSize, 0),    /* ApplicationName */
     DECLARE_DYNAMIC_ATTRIBUTE(ZCL_APPLICATION_PRODUCT_ID_ATTRIBUTE_ID, INT16U, 1, 0),           /* ProductID */
     DECLARE_DYNAMIC_ATTRIBUTE(ZCL_APPLICATION_STATUS_ATTRIBUTE_ID, INT8U, 1, 0),                /* ApplicationStatus */
+    DECLARE_DYNAMIC_ATTRIBUTE(ZCL_APPLICATION_VERSION_ATTRIBUTE_ID, CHAR_STRING, kNameSize, 0), /* ApplicationVersion */
+    DECLARE_DYNAMIC_ATTRIBUTE(ZCL_APPLICATION_ALLOWED_VENDOR_LIST_ATTRIBUTE_ID, ARRAY, kDescriptorAttributeArraySize,
+                              0), /* AllowedVendorList */
     DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();
 
 // Declare Keypad Input cluster attributes
 DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(keypadInputAttrs)
-DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();
+DECLARE_DYNAMIC_ATTRIBUTE(ZCL_FEATURE_MAP_SERVER_ATTRIBUTE_ID, BITMAP32, 4, 0), /* FeatureMap */
+    DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();
 
 // Declare Application Launcher cluster attributes
-// TODO: add missing attributes once schema is updated
+// NOTE: Does not make sense for content app to be able to set the AP feature flag
 DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(applicationLauncherAttrs)
 DECLARE_DYNAMIC_ATTRIBUTE(ZCL_APPLICATION_LAUNCHER_LIST_ATTRIBUTE_ID, ARRAY, kDescriptorAttributeArraySize, 0), /* catalog list */
+    DECLARE_DYNAMIC_ATTRIBUTE(ZCL_APPLICATION_LAUNCHER_CURRENT_APP_ATTRIBUTE_ID, STRUCT, 1, 0),                 /* current app */
     DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();
 
 // Declare Account Login cluster attributes
@@ -176,18 +187,20 @@
 DECLARE_DYNAMIC_ATTRIBUTE(ZCL_CONTENT_LAUNCHER_ACCEPT_HEADER_ATTRIBUTE_ID, ARRAY, kDescriptorAttributeArraySize,
                           0), /* accept header list */
     DECLARE_DYNAMIC_ATTRIBUTE(ZCL_CONTENT_LAUNCHER_SUPPORTED_STREAMING_PROTOCOLS_ATTRIBUTE_ID, BITMAP32, 1,
-                              0), /* streaming protocols */
+                              0),                                                   /* streaming protocols */
+    DECLARE_DYNAMIC_ATTRIBUTE(ZCL_FEATURE_MAP_SERVER_ATTRIBUTE_ID, BITMAP32, 4, 0), /* FeatureMap */
     DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();
 
 // Declare Media Playback cluster attributes
-// TODO: add missing attributes once schema is updated
 DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(mediaPlaybackAttrs)
 DECLARE_DYNAMIC_ATTRIBUTE(ZCL_MEDIA_PLAYBACK_STATE_ATTRIBUTE_ID, ENUM8, 1, 0),                          /* current state */
     DECLARE_DYNAMIC_ATTRIBUTE(ZCL_MEDIA_PLAYBACK_START_TIME_ATTRIBUTE_ID, EPOCH_US, 1, 0),              /* start time */
     DECLARE_DYNAMIC_ATTRIBUTE(ZCL_MEDIA_PLAYBACK_DURATION_ATTRIBUTE_ID, INT64U, 1, 0),                  /* duration */
+    DECLARE_DYNAMIC_ATTRIBUTE(ZCL_MEDIA_PLAYBACK_PLAYBACK_POSITION_ATTRIBUTE_ID, STRUCT, 1, 0),         /* playback speed */
     DECLARE_DYNAMIC_ATTRIBUTE(ZCL_MEDIA_PLAYBACK_PLAYBACK_SPEED_ATTRIBUTE_ID, SINGLE, 1, 0),            /* playback speed */
     DECLARE_DYNAMIC_ATTRIBUTE(ZCL_MEDIA_PLAYBACK_PLAYBACK_SEEK_RANGE_END_ATTRIBUTE_ID, INT64U, 1, 0),   /* seek range end */
     DECLARE_DYNAMIC_ATTRIBUTE(ZCL_MEDIA_PLAYBACK_PLAYBACK_SEEK_RANGE_START_ATTRIBUTE_ID, INT64U, 1, 0), /* seek range start */
+    DECLARE_DYNAMIC_ATTRIBUTE(ZCL_FEATURE_MAP_SERVER_ATTRIBUTE_ID, BITMAP32, 4, 0),                     /* FeatureMap */
     DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();
 
 // Declare Target Navigator cluster attributes
@@ -201,6 +214,7 @@
 DECLARE_DYNAMIC_ATTRIBUTE(ZCL_CHANNEL_LIST_ATTRIBUTE_ID, ARRAY, kDescriptorAttributeArraySize, 0), /* channel list */
     DECLARE_DYNAMIC_ATTRIBUTE(ZCL_CHANNEL_LINEUP_ATTRIBUTE_ID, STRUCT, 1, 0),                      /* lineup */
     DECLARE_DYNAMIC_ATTRIBUTE(ZCL_CHANNEL_CURRENT_CHANNEL_ATTRIBUTE_ID, STRUCT, 1, 0),             /* current channel */
+    DECLARE_DYNAMIC_ATTRIBUTE(ZCL_FEATURE_MAP_SERVER_ATTRIBUTE_ID, BITMAP32, 4, 0),                /* FeatureMap */
     DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();
 
 constexpr CommandId keypadInputIncomingCommands[] = {
diff --git a/examples/tv-app/linux/include/channel/ChannelManager.cpp b/examples/tv-app/linux/include/channel/ChannelManager.cpp
index 4e07025..53c83a2 100644
--- a/examples/tv-app/linux/include/channel/ChannelManager.cpp
+++ b/examples/tv-app/linux/include/channel/ChannelManager.cpp
@@ -16,6 +16,7 @@
  */
 
 #include "ChannelManager.h"
+#include <app-common/zap-generated/attributes/Accessors.h>
 #include <vector>
 
 using namespace chip;
@@ -172,3 +173,15 @@
     mCurrentChannel          = mChannels[mCurrentChannelIndex];
     return true;
 }
+
+uint32_t ChannelManager::GetFeatureMap(chip::EndpointId endpoint)
+{
+    if (endpoint >= EMBER_AF_CONTENT_LAUNCH_CLUSTER_SERVER_ENDPOINT_COUNT)
+    {
+        return mDynamicEndpointFeatureMap;
+    }
+
+    uint32_t featureMap = 0;
+    Attributes::FeatureMap::Get(endpoint, &featureMap);
+    return featureMap;
+}
diff --git a/examples/tv-app/linux/include/channel/ChannelManager.h b/examples/tv-app/linux/include/channel/ChannelManager.h
index 7ea0cf7..e56681e 100644
--- a/examples/tv-app/linux/include/channel/ChannelManager.h
+++ b/examples/tv-app/linux/include/channel/ChannelManager.h
@@ -41,8 +41,14 @@
     bool HandleChangeChannelByNumber(const uint16_t & majorNumber, const uint16_t & minorNumber) override;
     bool HandleSkipChannel(const uint16_t & count) override;
 
+    uint32_t GetFeatureMap(chip::EndpointId endpoint) override;
+
 protected:
     uint16_t mCurrentChannelIndex;
     ChannelInfoType mCurrentChannel;
     std::vector<ChannelInfoType> mChannels;
+
+private:
+    // TODO: set this based upon meta data from app
+    uint32_t mDynamicEndpointFeatureMap = 3;
 };
diff --git a/examples/tv-app/linux/include/content-launcher/ContentLauncherManager.cpp b/examples/tv-app/linux/include/content-launcher/ContentLauncherManager.cpp
index a563231..ceb37ec 100644
--- a/examples/tv-app/linux/include/content-launcher/ContentLauncherManager.cpp
+++ b/examples/tv-app/linux/include/content-launcher/ContentLauncherManager.cpp
@@ -17,6 +17,7 @@
  */
 
 #include "ContentLauncherManager.h"
+#include <app-common/zap-generated/attributes/Accessors.h>
 
 using namespace std;
 using namespace chip::app;
@@ -186,3 +187,15 @@
     ChipLogProgress(Zcl, "ContentLauncherManager::HandleGetSupportedStreamingProtocols");
     return mSupportedStreamingProtocols;
 }
+
+uint32_t ContentLauncherManager::GetFeatureMap(chip::EndpointId endpoint)
+{
+    if (endpoint >= EMBER_AF_CONTENT_LAUNCH_CLUSTER_SERVER_ENDPOINT_COUNT)
+    {
+        return mDynamicEndpointFeatureMap;
+    }
+
+    uint32_t featureMap = 0;
+    Attributes::FeatureMap::Get(endpoint, &featureMap);
+    return featureMap;
+}
diff --git a/examples/tv-app/linux/include/content-launcher/ContentLauncherManager.h b/examples/tv-app/linux/include/content-launcher/ContentLauncherManager.h
index 6033ac6..7073d89 100644
--- a/examples/tv-app/linux/include/content-launcher/ContentLauncherManager.h
+++ b/examples/tv-app/linux/include/content-launcher/ContentLauncherManager.h
@@ -51,6 +51,8 @@
     CHIP_ERROR HandleGetAcceptHeaderList(AttributeValueEncoder & aEncoder) override;
     uint32_t HandleGetSupportedStreamingProtocols() override;
 
+    uint32_t GetFeatureMap(chip::EndpointId endpoint) override;
+
 protected:
     std::list<std::string> mAcceptHeaderList;
     uint32_t mSupportedStreamingProtocols;
@@ -58,4 +60,6 @@
 
 private:
     EndpointId mEndpointId;
+    // TODO: set this based upon meta data from app
+    uint32_t mDynamicEndpointFeatureMap = 3;
 };
diff --git a/examples/tv-app/linux/include/keypad-input/KeypadInputManager.cpp b/examples/tv-app/linux/include/keypad-input/KeypadInputManager.cpp
index 7f30c64..84bae28 100644
--- a/examples/tv-app/linux/include/keypad-input/KeypadInputManager.cpp
+++ b/examples/tv-app/linux/include/keypad-input/KeypadInputManager.cpp
@@ -17,6 +17,7 @@
  */
 
 #include "KeypadInputManager.h"
+#include <app-common/zap-generated/attributes/Accessors.h>
 
 using namespace chip;
 using namespace chip::app::Clusters::KeypadInput;
@@ -94,3 +95,15 @@
 
     helper.Success(response);
 }
+
+uint32_t KeypadInputManager::GetFeatureMap(chip::EndpointId endpoint)
+{
+    if (endpoint >= EMBER_AF_CONTENT_LAUNCH_CLUSTER_SERVER_ENDPOINT_COUNT)
+    {
+        return mDynamicEndpointFeatureMap;
+    }
+
+    uint32_t featureMap = 0;
+    Attributes::FeatureMap::Get(endpoint, &featureMap);
+    return featureMap;
+}
diff --git a/examples/tv-app/linux/include/keypad-input/KeypadInputManager.h b/examples/tv-app/linux/include/keypad-input/KeypadInputManager.h
index 6936c69..79a83b3 100644
--- a/examples/tv-app/linux/include/keypad-input/KeypadInputManager.h
+++ b/examples/tv-app/linux/include/keypad-input/KeypadInputManager.h
@@ -29,4 +29,10 @@
 {
 public:
     void HandleSendKey(CommandResponseHelper<SendKeyResponseType> & helper, const CecKeyCodeType & keyCode) override;
+
+    uint32_t GetFeatureMap(chip::EndpointId endpoint) override;
+
+private:
+    // TODO: set this based upon meta data from app
+    uint32_t mDynamicEndpointFeatureMap = 7;
 };
diff --git a/examples/tv-app/linux/include/media-playback/MediaPlaybackManager.cpp b/examples/tv-app/linux/include/media-playback/MediaPlaybackManager.cpp
index 9e26f9a..d080b9e 100644
--- a/examples/tv-app/linux/include/media-playback/MediaPlaybackManager.cpp
+++ b/examples/tv-app/linux/include/media-playback/MediaPlaybackManager.cpp
@@ -16,6 +16,7 @@
  */
 
 #include "MediaPlaybackManager.h"
+#include <app-common/zap-generated/attributes/Accessors.h>
 
 using namespace std;
 using namespace chip::app::DataModel;
@@ -236,3 +237,15 @@
     response.status = MediaPlaybackStatusEnum::kSuccess;
     helper.Success(response);
 }
+
+uint32_t MediaPlaybackManager::GetFeatureMap(chip::EndpointId endpoint)
+{
+    if (endpoint >= EMBER_AF_CONTENT_LAUNCH_CLUSTER_SERVER_ENDPOINT_COUNT)
+    {
+        return mDynamicEndpointFeatureMap;
+    }
+
+    uint32_t featureMap = 0;
+    Attributes::FeatureMap::Get(endpoint, &featureMap);
+    return featureMap;
+}
diff --git a/examples/tv-app/linux/include/media-playback/MediaPlaybackManager.h b/examples/tv-app/linux/include/media-playback/MediaPlaybackManager.h
index 1c35764..ec02313 100644
--- a/examples/tv-app/linux/include/media-playback/MediaPlaybackManager.h
+++ b/examples/tv-app/linux/include/media-playback/MediaPlaybackManager.h
@@ -51,6 +51,8 @@
     void HandleNext(CommandResponseHelper<PlaybackResponseType> & helper) override;
     void HandleStartOver(CommandResponseHelper<PlaybackResponseType> & helper) override;
 
+    uint32_t GetFeatureMap(chip::EndpointId endpoint) override;
+
 protected:
     // NOTE: it does not make sense to have default state of playing with a speed of 0, but
     // the CI test cases expect these values, and need to be fixed.
@@ -64,4 +66,8 @@
 
     static const int kPlaybackMaxForwardSpeed = 10;
     static const int kPlaybackMaxRewindSpeed  = -10;
+
+private:
+    // TODO: set this based upon meta data from app
+    uint32_t mDynamicEndpointFeatureMap = 3;
 };
diff --git a/src/app/clusters/channel-server/channel-delegate.h b/src/app/clusters/channel-server/channel-delegate.h
index 4845858..60f5aba 100644
--- a/src/app/clusters/channel-server/channel-delegate.h
+++ b/src/app/clusters/channel-server/channel-delegate.h
@@ -44,6 +44,9 @@
     virtual bool HandleChangeChannelByNumber(const uint16_t & majorNumber, const uint16_t & minorNumber) = 0;
     virtual bool HandleSkipChannel(const uint16_t & count)                                               = 0;
 
+    bool HasFeature(chip::EndpointId endpoint, ChannelFeature feature);
+    virtual uint32_t GetFeatureMap(chip::EndpointId endpoint) = 0;
+
     virtual ~Delegate() = default;
 };
 
diff --git a/src/app/clusters/channel-server/channel-server.cpp b/src/app/clusters/channel-server/channel-server.cpp
index fab495d..453b019 100644
--- a/src/app/clusters/channel-server/channel-server.cpp
+++ b/src/app/clusters/channel-server/channel-server.cpp
@@ -115,18 +115,10 @@
     }
 }
 
-bool HasFeature(chip::EndpointId endpoint, ChannelFeature feature)
+bool Delegate::HasFeature(chip::EndpointId endpoint, ChannelFeature feature)
 {
-    bool hasFeature     = false;
-    uint32_t featureMap = 0;
-
-    EmberAfStatus status = Attributes::FeatureMap::Get(endpoint, &featureMap);
-    if (EMBER_ZCL_STATUS_SUCCESS == status)
-    {
-        hasFeature = (featureMap & chip::to_underlying(feature));
-    }
-
-    return hasFeature;
+    uint32_t featureMap = GetFeatureMap(endpoint);
+    return (featureMap & chip::to_underlying(feature));
 }
 
 } // namespace Channel
@@ -150,6 +142,7 @@
     CHIP_ERROR ReadChannelListAttribute(app::AttributeValueEncoder & aEncoder, Delegate * delegate);
     CHIP_ERROR ReadLineupAttribute(app::AttributeValueEncoder & aEncoder, Delegate * delegate);
     CHIP_ERROR ReadCurrentChannelAttribute(app::AttributeValueEncoder & aEncoder, Delegate * delegate);
+    CHIP_ERROR ReadFeatureFlagAttribute(EndpointId endpoint, app::AttributeValueEncoder & aEncoder, Delegate * delegate);
 };
 
 ChannelAttrAccess gChannelAttrAccess;
@@ -162,7 +155,7 @@
     switch (aPath.mAttributeId)
     {
     case app::Clusters::Channel::Attributes::ChannelList::Id: {
-        if (isDelegateNull(delegate, endpoint) || !HasFeature(endpoint, ChannelFeature::kChannelList))
+        if (isDelegateNull(delegate, endpoint) || !delegate->HasFeature(endpoint, ChannelFeature::kChannelList))
         {
             return aEncoder.EncodeEmptyList();
         }
@@ -170,7 +163,7 @@
         return ReadChannelListAttribute(aEncoder, delegate);
     }
     case app::Clusters::Channel::Attributes::Lineup::Id: {
-        if (isDelegateNull(delegate, endpoint) || !HasFeature(endpoint, ChannelFeature::kLineupInfo))
+        if (isDelegateNull(delegate, endpoint) || !delegate->HasFeature(endpoint, ChannelFeature::kLineupInfo))
         {
             return CHIP_NO_ERROR;
         }
@@ -185,6 +178,14 @@
 
         return ReadCurrentChannelAttribute(aEncoder, delegate);
     }
+    case app::Clusters::Channel::Attributes::FeatureMap::Id: {
+        if (isDelegateNull(delegate, endpoint))
+        {
+            return CHIP_NO_ERROR;
+        }
+
+        return ReadFeatureFlagAttribute(endpoint, aEncoder, delegate);
+    }
     default: {
         break;
     }
@@ -193,6 +194,13 @@
     return CHIP_NO_ERROR;
 }
 
+CHIP_ERROR ChannelAttrAccess::ReadFeatureFlagAttribute(EndpointId endpoint, app::AttributeValueEncoder & aEncoder,
+                                                       Delegate * delegate)
+{
+    uint32_t featureFlag = delegate->GetFeatureMap(endpoint);
+    return aEncoder.Encode(featureFlag);
+}
+
 CHIP_ERROR ChannelAttrAccess::ReadChannelListAttribute(app::AttributeValueEncoder & aEncoder, Delegate * delegate)
 {
     return delegate->HandleGetChannelList(aEncoder);
diff --git a/src/app/clusters/content-launch-server/content-launch-delegate.h b/src/app/clusters/content-launch-server/content-launch-delegate.h
index 5fb6e02..0c0f65d 100644
--- a/src/app/clusters/content-launch-server/content-launch-delegate.h
+++ b/src/app/clusters/content-launch-server/content-launch-delegate.h
@@ -51,6 +51,9 @@
 
     virtual uint32_t HandleGetSupportedStreamingProtocols() = 0;
 
+    bool HasFeature(chip::EndpointId endpoint, ContentLauncherFeature feature);
+    virtual uint32_t GetFeatureMap(chip::EndpointId endpoint) = 0;
+
     virtual ~Delegate() = default;
 };
 
diff --git a/src/app/clusters/content-launch-server/content-launch-server.cpp b/src/app/clusters/content-launch-server/content-launch-server.cpp
index 7722480..3cbeea1 100644
--- a/src/app/clusters/content-launch-server/content-launch-server.cpp
+++ b/src/app/clusters/content-launch-server/content-launch-server.cpp
@@ -120,18 +120,10 @@
     }
 }
 
-bool HasFeature(chip::EndpointId endpoint, ContentLauncherFeature feature)
+bool Delegate::HasFeature(chip::EndpointId endpoint, ContentLauncherFeature feature)
 {
-    bool hasFeature     = false;
-    uint32_t featureMap = 0;
-
-    EmberAfStatus status = Attributes::FeatureMap::Get(endpoint, &featureMap);
-    if (EMBER_ZCL_STATUS_SUCCESS == status)
-    {
-        hasFeature = (featureMap & chip::to_underlying(feature));
-    }
-
-    return hasFeature;
+    uint32_t featureMap = GetFeatureMap(endpoint);
+    return (featureMap & chip::to_underlying(feature));
 }
 
 } // namespace ContentLauncher
@@ -154,6 +146,7 @@
 private:
     CHIP_ERROR ReadAcceptHeaderAttribute(app::AttributeValueEncoder & aEncoder, Delegate * delegate);
     CHIP_ERROR ReadSupportedStreamingProtocolsAttribute(app::AttributeValueEncoder & aEncoder, Delegate * delegate);
+    CHIP_ERROR ReadFeatureFlagAttribute(EndpointId endpoint, app::AttributeValueEncoder & aEncoder, Delegate * delegate);
 };
 
 ContentLauncherAttrAccess gContentLauncherAttrAccess;
@@ -181,6 +174,14 @@
 
         return ReadSupportedStreamingProtocolsAttribute(aEncoder, delegate);
     }
+    case app::Clusters::ContentLauncher::Attributes::FeatureMap::Id: {
+        if (isDelegateNull(delegate, endpoint))
+        {
+            return CHIP_NO_ERROR;
+        }
+
+        return ReadFeatureFlagAttribute(endpoint, aEncoder, delegate);
+    }
     default: {
         break;
     }
@@ -189,6 +190,13 @@
     return CHIP_NO_ERROR;
 }
 
+CHIP_ERROR ContentLauncherAttrAccess::ReadFeatureFlagAttribute(EndpointId endpoint, app::AttributeValueEncoder & aEncoder,
+                                                               Delegate * delegate)
+{
+    uint32_t featureFlag = delegate->GetFeatureMap(endpoint);
+    return aEncoder.Encode(featureFlag);
+}
+
 CHIP_ERROR ContentLauncherAttrAccess::ReadAcceptHeaderAttribute(app::AttributeValueEncoder & aEncoder, Delegate * delegate)
 {
     return delegate->HandleGetAcceptHeaderList(aEncoder);
@@ -220,7 +228,8 @@
 
     Delegate * delegate = GetDelegate(endpoint);
 
-    VerifyOrExit(isDelegateNull(delegate, endpoint) != true && HasFeature(endpoint, ContentLauncherFeature::kContentSearch),
+    VerifyOrExit(isDelegateNull(delegate, endpoint) != true &&
+                     delegate->HasFeature(endpoint, ContentLauncherFeature::kContentSearch),
                  err = CHIP_ERROR_INCORRECT_STATE);
 
     delegate->HandleLaunchContent(responder, decodableParameterList, autoplay, data.HasValue() ? data.Value() : CharSpan());
@@ -253,7 +262,7 @@
     app::CommandResponseHelper<Commands::LaunchResponse::Type> responder(commandObj, commandPath);
 
     Delegate * delegate = GetDelegate(endpoint);
-    VerifyOrExit(isDelegateNull(delegate, endpoint) != true && HasFeature(endpoint, ContentLauncherFeature::kURLPlayback),
+    VerifyOrExit(isDelegateNull(delegate, endpoint) != true && delegate->HasFeature(endpoint, ContentLauncherFeature::kURLPlayback),
                  err = CHIP_ERROR_INCORRECT_STATE);
     {
         delegate->HandleLaunchUrl(responder, contentUrl, displayString.HasValue() ? displayString.Value() : CharSpan(),
diff --git a/src/app/clusters/keypad-input-server/keypad-input-delegate.h b/src/app/clusters/keypad-input-server/keypad-input-delegate.h
index 24fd575..65e217b 100644
--- a/src/app/clusters/keypad-input-server/keypad-input-delegate.h
+++ b/src/app/clusters/keypad-input-server/keypad-input-delegate.h
@@ -36,6 +36,10 @@
 public:
     virtual void HandleSendKey(CommandResponseHelper<Commands::SendKeyResponse::Type> & helper, const CecKeyCode & keyCode) = 0;
 
+    bool HasFeature(chip::EndpointId endpoint, KeypadInputFeature feature);
+
+    virtual uint32_t GetFeatureMap(chip::EndpointId endpoint) = 0;
+
     virtual ~Delegate() = default;
 };
 
diff --git a/src/app/clusters/keypad-input-server/keypad-input-server.cpp b/src/app/clusters/keypad-input-server/keypad-input-server.cpp
index 1389caa..2dce476 100644
--- a/src/app/clusters/keypad-input-server/keypad-input-server.cpp
+++ b/src/app/clusters/keypad-input-server/keypad-input-server.cpp
@@ -25,12 +25,15 @@
 #include <app/clusters/keypad-input-server/keypad-input-server.h>
 
 #include <app-common/zap-generated/attributes/Accessors.h>
+#include <app/AttributeAccessInterface.h>
 #include <app/CommandHandler.h>
 #include <app/ConcreteCommandPath.h>
 #if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED
 #include <app/app-platform/ContentAppPlatform.h>
 #endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED
 #include <app/data-model/Encode.h>
+#include <app/util/af.h>
+#include <app/util/attribute-storage.h>
 #include <platform/CHIPDeviceConfig.h>
 
 using namespace chip;
@@ -97,18 +100,10 @@
     }
 }
 
-bool HasFeature(chip::EndpointId endpoint, KeypadInputFeature feature)
+bool Delegate::HasFeature(chip::EndpointId endpoint, KeypadInputFeature feature)
 {
-    bool hasFeature     = false;
-    uint32_t featureMap = 0;
-
-    EmberAfStatus status = Attributes::FeatureMap::Get(endpoint, &featureMap);
-    if (EMBER_ZCL_STATUS_SUCCESS == status)
-    {
-        hasFeature = (featureMap & chip::to_underlying(feature));
-    }
-
-    return hasFeature;
+    uint32_t featureMap = GetFeatureMap(endpoint);
+    return (featureMap & chip::to_underlying(feature));
 }
 
 } // namespace KeypadInput
@@ -117,6 +112,57 @@
 } // namespace chip
 
 // -----------------------------------------------------------------------------
+// Attribute Accessor Implementation
+
+namespace {
+
+class KeypadInputAttrAccess : public app::AttributeAccessInterface
+{
+public:
+    KeypadInputAttrAccess() : app::AttributeAccessInterface(Optional<EndpointId>::Missing(), KeypadInput::Id) {}
+
+    CHIP_ERROR Read(const app::ConcreteReadAttributePath & aPath, app::AttributeValueEncoder & aEncoder) override;
+
+private:
+    CHIP_ERROR ReadFeatureFlagAttribute(EndpointId endpoint, app::AttributeValueEncoder & aEncoder, Delegate * delegate);
+};
+
+KeypadInputAttrAccess gKeypadInputAttrAccess;
+
+CHIP_ERROR KeypadInputAttrAccess::Read(const app::ConcreteReadAttributePath & aPath, app::AttributeValueEncoder & aEncoder)
+{
+    EndpointId endpoint = aPath.mEndpointId;
+    Delegate * delegate = GetDelegate(endpoint);
+
+    if (isDelegateNull(delegate, endpoint))
+    {
+        return CHIP_NO_ERROR;
+    }
+
+    switch (aPath.mAttributeId)
+    {
+    case app::Clusters::KeypadInput::Attributes::FeatureMap::Id: {
+        return ReadFeatureFlagAttribute(endpoint, aEncoder, delegate);
+    }
+
+    default: {
+        break;
+    }
+    }
+
+    return CHIP_NO_ERROR;
+}
+
+CHIP_ERROR KeypadInputAttrAccess::ReadFeatureFlagAttribute(EndpointId endpoint, app::AttributeValueEncoder & aEncoder,
+                                                           Delegate * delegate)
+{
+    uint32_t featureFlag = delegate->GetFeatureMap(endpoint);
+    return aEncoder.Encode(featureFlag);
+}
+
+} // anonymous namespace
+
+// -----------------------------------------------------------------------------
 // Matter Framework Callbacks Implementation
 
 bool emberAfKeypadInputClusterSendKeyCallback(app::CommandHandler * command, const app::ConcreteCommandPath & commandPath,
@@ -142,4 +188,7 @@
     return true;
 }
 
-void MatterKeypadInputPluginServerInitCallback() {}
+void MatterKeypadInputPluginServerInitCallback()
+{
+    registerAttributeAccessOverride(&gKeypadInputAttrAccess);
+}
diff --git a/src/app/clusters/media-playback-server/media-playback-delegate.h b/src/app/clusters/media-playback-server/media-playback-delegate.h
index b5e64d3..64b85b8 100644
--- a/src/app/clusters/media-playback-server/media-playback-delegate.h
+++ b/src/app/clusters/media-playback-server/media-playback-delegate.h
@@ -59,6 +59,8 @@
     virtual void HandleNext(CommandResponseHelper<Commands::PlaybackResponse::Type> & helper)        = 0;
     virtual void HandleStartOver(CommandResponseHelper<Commands::PlaybackResponse::Type> & helper)   = 0;
 
+    virtual uint32_t GetFeatureMap(chip::EndpointId endpoint) = 0;
+
     virtual ~Delegate() = default;
 };
 
diff --git a/src/app/clusters/media-playback-server/media-playback-server.cpp b/src/app/clusters/media-playback-server/media-playback-server.cpp
index 1c43463..c4ae274 100644
--- a/src/app/clusters/media-playback-server/media-playback-server.cpp
+++ b/src/app/clusters/media-playback-server/media-playback-server.cpp
@@ -25,6 +25,7 @@
 #include <app/clusters/media-playback-server/media-playback-delegate.h>
 #include <app/clusters/media-playback-server/media-playback-server.h>
 
+#include <app-common/zap-generated/attributes/Accessors.h>
 #include <app/AttributeAccessInterface.h>
 #include <app/CommandHandler.h>
 #include <app/ConcreteCommandPath.h>
@@ -124,6 +125,7 @@
     CHIP_ERROR ReadPlaybackSpeedAttribute(app::AttributeValueEncoder & aEncoder, Delegate * delegate);
     CHIP_ERROR ReadSeekRangeStartAttribute(app::AttributeValueEncoder & aEncoder, Delegate * delegate);
     CHIP_ERROR ReadSeekRangeEndAttribute(app::AttributeValueEncoder & aEncoder, Delegate * delegate);
+    CHIP_ERROR ReadFeatureFlagAttribute(EndpointId endpoint, app::AttributeValueEncoder & aEncoder, Delegate * delegate);
 };
 
 MediaPlaybackAttrAccess gMediaPlaybackAttrAccess;
@@ -161,6 +163,9 @@
     case app::Clusters::MediaPlayback::Attributes::SeekRangeEnd::Id: {
         return ReadSeekRangeEndAttribute(aEncoder, delegate);
     }
+    case app::Clusters::ContentLauncher::Attributes::FeatureMap::Id: {
+        return ReadFeatureFlagAttribute(endpoint, aEncoder, delegate);
+    }
     default: {
         break;
     }
@@ -169,6 +174,13 @@
     return CHIP_NO_ERROR;
 }
 
+CHIP_ERROR MediaPlaybackAttrAccess::ReadFeatureFlagAttribute(EndpointId endpoint, app::AttributeValueEncoder & aEncoder,
+                                                             Delegate * delegate)
+{
+    uint32_t featureFlag = delegate->GetFeatureMap(endpoint);
+    return aEncoder.Encode(featureFlag);
+}
+
 CHIP_ERROR MediaPlaybackAttrAccess::ReadCurrentStateAttribute(app::AttributeValueEncoder & aEncoder, Delegate * delegate)
 {
     MediaPlayback::PlaybackStateEnum currentState = delegate->HandleGetCurrentState();