diff --git a/src/ruby/lib/grpc/generic/active_call.rb b/src/ruby/lib/grpc/generic/active_call.rb
index 7b69f1f6d0d461b0ae45dd2437a5b7fc7d42db7c..6256330e88e420a9d1c270b8760e0bdf7a9ffb45 100644
--- a/src/ruby/lib/grpc/generic/active_call.rb
+++ b/src/ruby/lib/grpc/generic/active_call.rb
@@ -505,12 +505,12 @@ module GRPC
 
     # SingleReqView limits access to an ActiveCall's methods for use in server
     # handlers that receive just one request.
-    SingleReqView = view_class(:cancelled, :deadline)
+    SingleReqView = view_class(:cancelled, :deadline, :metadata)
 
     # MultiReqView limits access to an ActiveCall's methods for use in
     # server client_streamer handlers.
     MultiReqView = view_class(:cancelled, :deadline, :each_queued_msg,
-                              :each_remote_read)
+                              :each_remote_read, :metadata)
 
     # Operation limits access to an ActiveCall's methods for use as
     # a Operation on the client.
diff --git a/src/ruby/spec/generic/active_call_spec.rb b/src/ruby/spec/generic/active_call_spec.rb
index 12cb5c15580ab775ade7580895a56b93aa955012..8914225b558c5b91125af648bb9d56254218af16 100644
--- a/src/ruby/spec/generic/active_call_spec.rb
+++ b/src/ruby/spec/generic/active_call_spec.rb
@@ -68,7 +68,7 @@ describe GRPC::ActiveCall do
 
     describe '#multi_req_view' do
       xit 'exposes a fixed subset of the ActiveCall methods' do
-        want = %w(cancelled, deadline, each_remote_read, shutdown)
+        want = %w(cancelled, deadline, each_remote_read, metadata, shutdown)
         v = @client_call.multi_req_view
         want.each do |w|
           expect(v.methods.include?(w))
@@ -78,7 +78,7 @@ describe GRPC::ActiveCall do
 
     describe '#single_req_view' do
       xit 'exposes a fixed subset of the ActiveCall methods' do
-        want = %w(cancelled, deadline, shutdown)
+        want = %w(cancelled, deadline, metadata, shutdown)
         v = @client_call.single_req_view
         want.each do |w|
           expect(v.methods.include?(w))
diff --git a/src/ruby/spec/generic/rpc_server_spec.rb b/src/ruby/spec/generic/rpc_server_spec.rb
index d5421d400c99c9f14ae2c6c0609760ee623abe45..f3b89b5895eb9ee8771dc7fdbaaf71dd6a422783 100644
--- a/src/ruby/spec/generic/rpc_server_spec.rb
+++ b/src/ruby/spec/generic/rpc_server_spec.rb
@@ -62,12 +62,15 @@ end
 class EchoService
   include GRPC::GenericService
   rpc :an_rpc, EchoMsg, EchoMsg
+  attr_reader :received_md
 
   def initialize(_default_var = 'ignored')
+    @received_md = []
   end
 
-  def an_rpc(req, _call)
+  def an_rpc(req, call)
     logger.info('echo service received a request')
+    @received_md << call.metadata unless call.metadata.nil?
     req
   end
 end
@@ -337,6 +340,38 @@ describe GRPC::RpcServer do
         t.join
       end
 
+      it 'should receive metadata sent as rpc keyword args', server: true do
+        service = EchoService.new
+        @srv.handle(service)
+        t = Thread.new { @srv.run }
+        @srv.wait_till_running
+        req = EchoMsg.new
+        stub = EchoStub.new(@host, **@client_opts)
+        expect(stub.an_rpc(req, k1: 'v1', k2: 'v2')).to be_a(EchoMsg)
+        wanted_md = [{ 'k1' => 'v1', 'k2' => 'v2' }]
+        expect(service.received_md).to eq(wanted_md)
+        @srv.stop
+        t.join
+      end
+
+      it 'should receive updated metadata', server: true do
+        service = EchoService.new
+        @srv.handle(service)
+        t = Thread.new { @srv.run }
+        @srv.wait_till_running
+        req = EchoMsg.new
+        @client_opts[:update_metadata] = proc do |md|
+          md[:k1] = 'updated-v1'
+          md
+        end
+        stub = EchoStub.new(@host, **@client_opts)
+        expect(stub.an_rpc(req, k1: 'v1', k2: 'v2')).to be_a(EchoMsg)
+        wanted_md = [{ 'k1' => 'updated-v1', 'k2' => 'v2' }]
+        expect(service.received_md).to eq(wanted_md)
+        @srv.stop
+        t.join
+      end
+
       it 'should handle multiple parallel requests', server: true do
         @srv.handle(EchoService)
         Thread.new { @srv.run }