@@ -768,6 +768,78 @@ TEST_F(McpFilterTest, PerRouteMaxBodySizeFallbackToGlobal) {
768768 EXPECT_EQ (Http::FilterHeadersStatus::StopIteration, filter_->decodeHeaders (headers, false ));
769769}
770770
771+ // Test method group added to dynamic metadata when configured
772+ TEST_F (McpFilterTest, MethodGroupAddedToMetadata) {
773+ envoy::extensions::filters::http::mcp::v3::Mcp proto_config;
774+ proto_config.mutable_parser_config ()->set_group_metadata_key (" method_group" );
775+ config_ = std::make_shared<McpFilterConfig>(proto_config, " test." , factory_context_.scope ());
776+ filter_ = std::make_unique<McpFilter>(config_);
777+ filter_->setDecoderFilterCallbacks (decoder_callbacks_);
778+
779+ Http::TestRequestHeaderMapImpl headers{{" :method" , " POST" },
780+ {" content-type" , " application/json" },
781+ {" accept" , " application/json" },
782+ {" accept" , " text/event-stream" }};
783+
784+ filter_->decodeHeaders (headers, false );
785+
786+ std::string json =
787+ R"( {"jsonrpc": "2.0", "method": "tools/call", "params": {"name": "test"}, "id": 1})" ;
788+ Buffer::OwnedImpl buffer (json);
789+
790+ EXPECT_CALL (decoder_callbacks_.stream_info_ , setDynamicMetadata (" mcp_proxy" , _))
791+ .WillOnce ([&](const std::string&, const Protobuf::Struct& metadata) {
792+ const auto & fields = metadata.fields ();
793+
794+ // Check method_group is set to "tool" (built-in group for tools/call)
795+ auto group_it = fields.find (" method_group" );
796+ ASSERT_NE (group_it, fields.end ());
797+ EXPECT_EQ (group_it->second .string_value (), " tool" );
798+
799+ // Check method is also set
800+ auto method_it = fields.find (" method" );
801+ ASSERT_NE (method_it, fields.end ());
802+ EXPECT_EQ (method_it->second .string_value (), " tools/call" );
803+ });
804+
805+ EXPECT_EQ (Http::FilterDataStatus::Continue, filter_->decodeData (buffer, true ));
806+ }
807+
808+ // Test method group with custom override
809+ TEST_F (McpFilterTest, MethodGroupWithCustomOverride) {
810+ envoy::extensions::filters::http::mcp::v3::Mcp proto_config;
811+ auto * parser_config = proto_config.mutable_parser_config ();
812+ parser_config->set_group_metadata_key (" group" );
813+
814+ auto * method_config = parser_config->add_methods ();
815+ method_config->set_method (" tools/list" );
816+ method_config->set_group (" custom_tools" );
817+
818+ config_ = std::make_shared<McpFilterConfig>(proto_config, " test." , factory_context_.scope ());
819+ filter_ = std::make_unique<McpFilter>(config_);
820+ filter_->setDecoderFilterCallbacks (decoder_callbacks_);
821+
822+ Http::TestRequestHeaderMapImpl headers{{" :method" , " POST" },
823+ {" content-type" , " application/json" },
824+ {" accept" , " application/json" },
825+ {" accept" , " text/event-stream" }};
826+
827+ filter_->decodeHeaders (headers, false );
828+
829+ std::string json = R"( {"jsonrpc": "2.0", "method": "tools/list", "id": 1})" ;
830+ Buffer::OwnedImpl buffer (json);
831+
832+ EXPECT_CALL (decoder_callbacks_.stream_info_ , setDynamicMetadata (" mcp_proxy" , _))
833+ .WillOnce ([&](const std::string&, const Protobuf::Struct& metadata) {
834+ const auto & fields = metadata.fields ();
835+ auto group_it = fields.find (" group" );
836+ ASSERT_NE (group_it, fields.end ());
837+ EXPECT_EQ (group_it->second .string_value (), " custom_tools" );
838+ });
839+
840+ EXPECT_EQ (Http::FilterDataStatus::Continue, filter_->decodeData (buffer, true ));
841+ }
842+
771843} // namespace
772844} // namespace Mcp
773845} // namespace HttpFilters
0 commit comments