diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,11 @@
 # ChangeLog for grapesy-etc
 
+## 0.3.0
+
+* Move proto-lens generation to a separate library `proto-lens-etcd`.
+* Change main module name to `Network.GRPC.Etcd`.
+* Add metadata instances for `Auth`, `Cluster`, `Lease` and `Maintenance`.
+
 ## 0.2.0
 
 * Add `Network.GRPC.Etcd.Client.Simple` with functions for `put`, `range` and `get`.
diff --git a/Setup.hs b/Setup.hs
deleted file mode 100644
--- a/Setup.hs
+++ /dev/null
@@ -1,3 +0,0 @@
-import Data.ProtoLens.Setup
-
-main = defaultMainGeneratingProtos "proto"
diff --git a/grapesy-etcd.cabal b/grapesy-etcd.cabal
--- a/grapesy-etcd.cabal
+++ b/grapesy-etcd.cabal
@@ -1,6 +1,6 @@
 cabal-version:      2.2
 name:               grapesy-etcd
-version:            0.2.0
+version:            0.3.0
 synopsis:           grapesy-etcd - GRPC interface to etcd
 author:             IOG
 copyright:          2025 IOG
@@ -13,23 +13,6 @@
   CHANGELOG.md
   README.md
 
-extra-source-files:
-  proto/etcd/api/authpb/auth.proto
-  proto/etcd/api/etcdserverpb/rpc.proto
-  proto/etcd/api/mvccpb/kv.proto
-  proto/etcd/api/versionpb/version.proto
-  proto/gogoproto/gogo.proto
-  proto/google/api/annotations.proto
-  proto/google/api/http.proto
-  proto/protoc-gen-openapiv2/options/annotations.proto
-  proto/protoc-gen-openapiv2/options/openapiv2.proto
-
-custom-setup
-  setup-depends:
-    , base              >=4.14 && <5
-    , Cabal             >=3.0  && <4
-    , proto-lens-setup  >=0.4  && <0.5
-
 common lang
   build-depends:      base >=4.14 && <5
   default-language:   GHC2021
@@ -42,39 +25,13 @@
     TypeFamilies
 
 library
-  import:             lang
-  hs-source-dirs:     src
-  build-tool-depends: proto-lens-protoc:proto-lens-protoc
+  import:          lang
+  hs-source-dirs:  src
   build-depends:
-    , exceptions
-    , grapesy                    >=1.0 && <1.1
-    , proto-lens-protobuf-types  >=0.7 && <0.8
-    , proto-lens-runtime         >=0.7 && <0.8
+    , exceptions       >=0.10 && <0.11
+    , grapesy          >=1.0  && <1.1
+    , proto-lens-etcd  >=0.1  && <0.2
 
   exposed-modules:
+    Network.GRPC.Etcd
     Network.GRPC.Etcd.Client.Simple
-    Proto.API.Etcd
-
-  other-modules:
-    Paths_grapesy_etcd
-    Proto.Etcd.Api.Authpb.Auth
-    Proto.Etcd.Api.Etcdserverpb.Rpc
-    Proto.Etcd.Api.Mvccpb.Kv
-    Proto.Etcd.Api.Versionpb.Version
-    Proto.Gogoproto.Gogo
-    Proto.Google.Api.Annotations
-    Proto.Google.Api.Http
-    Proto.ProtocGenOpenapiv2.Options.Annotations
-    Proto.ProtocGenOpenapiv2.Options.Openapiv2
-
-  autogen-modules:
-    Proto.Etcd.Api.Authpb.Auth
-    Proto.Etcd.Api.Etcdserverpb.Rpc
-    Proto.Etcd.Api.Mvccpb.Kv
-    Proto.Etcd.Api.Versionpb.Version
-    Proto.Gogoproto.Gogo
-    Proto.Google.Api.Annotations
-    Proto.Google.Api.Http
-    Proto.ProtocGenOpenapiv2.Options.Annotations
-    Proto.ProtocGenOpenapiv2.Options.Openapiv2
-    Paths_grapesy_etcd
diff --git a/proto/etcd/api/authpb/auth.proto b/proto/etcd/api/authpb/auth.proto
deleted file mode 100644
--- a/proto/etcd/api/authpb/auth.proto
+++ /dev/null
@@ -1,44 +0,0 @@
-syntax = "proto3";
-package authpb;
-
-import "gogoproto/gogo.proto";
-
-option go_package = "go.etcd.io/etcd/api/v3/authpb";
-
-option (gogoproto.marshaler_all) = true;
-option (gogoproto.sizer_all) = true;
-option (gogoproto.unmarshaler_all) = true;
-option (gogoproto.goproto_getters_all) = false;
-option (gogoproto.goproto_enum_prefix_all) = false;
-
-message UserAddOptions {
-  bool no_password = 1;
-};
-
-// User is a single entry in the bucket authUsers
-message User {
-  bytes name = 1;
-  bytes password = 2;
-  repeated string roles = 3;
-  UserAddOptions options = 4;
-}
-
-// Permission is a single entity
-message Permission {
-  enum Type {
-    READ = 0;
-    WRITE = 1;
-    READWRITE = 2;
-  }
-  Type permType = 1;
-
-  bytes key = 2;
-  bytes range_end = 3;
-}
-
-// Role is a single entry in the bucket authRoles
-message Role {
-  bytes name = 1;
-
-  repeated Permission keyPermission = 2;
-}
diff --git a/proto/etcd/api/etcdserverpb/rpc.proto b/proto/etcd/api/etcdserverpb/rpc.proto
deleted file mode 100644
--- a/proto/etcd/api/etcdserverpb/rpc.proto
+++ /dev/null
@@ -1,1425 +0,0 @@
-syntax = "proto3";
-package etcdserverpb;
-
-import "gogoproto/gogo.proto";
-import "etcd/api/mvccpb/kv.proto";
-import "etcd/api/authpb/auth.proto";
-import "etcd/api/versionpb/version.proto";
-
-// for grpc-gateway
-import "google/api/annotations.proto";
-import "protoc-gen-openapiv2/options/annotations.proto";
-
-option go_package = "go.etcd.io/etcd/api/v3/etcdserverpb";
-
-option (gogoproto.marshaler_all) = true;
-option (gogoproto.unmarshaler_all) = true;
-
-option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
-  security_definitions: {
-    security: {
-      key: "ApiKey";
-      value: {
-        type: TYPE_API_KEY;
-        in: IN_HEADER;
-        name: "Authorization";
-      }
-    }
-  }
-  security: {
-    security_requirement: {
-      key: "ApiKey";
-      value: {};
-    }
-  }
-};
-
-service KV {
-  // Range gets the keys in the range from the key-value store.
-  rpc Range(RangeRequest) returns (RangeResponse) {
-      option (google.api.http) = {
-        post: "/v3/kv/range"
-        body: "*"
-    };
-  }
-
-  // Put puts the given key into the key-value store.
-  // A put request increments the revision of the key-value store
-  // and generates one event in the event history.
-  rpc Put(PutRequest) returns (PutResponse) {
-      option (google.api.http) = {
-        post: "/v3/kv/put"
-        body: "*"
-    };
-  }
-
-  // DeleteRange deletes the given range from the key-value store.
-  // A delete request increments the revision of the key-value store
-  // and generates a delete event in the event history for every deleted key.
-  rpc DeleteRange(DeleteRangeRequest) returns (DeleteRangeResponse) {
-      option (google.api.http) = {
-        post: "/v3/kv/deleterange"
-        body: "*"
-    };
-  }
-
-  // Txn processes multiple requests in a single transaction.
-  // A txn request increments the revision of the key-value store
-  // and generates events with the same revision for every completed request.
-  // It is not allowed to modify the same key several times within one txn.
-  rpc Txn(TxnRequest) returns (TxnResponse) {
-      option (google.api.http) = {
-        post: "/v3/kv/txn"
-        body: "*"
-    };
-  }
-
-  // Compact compacts the event history in the etcd key-value store. The key-value
-  // store should be periodically compacted or the event history will continue to grow
-  // indefinitely.
-  rpc Compact(CompactionRequest) returns (CompactionResponse) {
-      option (google.api.http) = {
-        post: "/v3/kv/compaction"
-        body: "*"
-    };
-  }
-}
-
-service Watch {
-  // Watch watches for events happening or that have happened. Both input and output
-  // are streams; the input stream is for creating and canceling watchers and the output
-  // stream sends events. One watch RPC can watch on multiple key ranges, streaming events
-  // for several watches at once. The entire event history can be watched starting from the
-  // last compaction revision.
-  rpc Watch(stream WatchRequest) returns (stream WatchResponse) {
-      option (google.api.http) = {
-        post: "/v3/watch"
-        body: "*"
-    };
-  }
-}
-
-service Lease {
-  // LeaseGrant creates a lease which expires if the server does not receive a keepAlive
-  // within a given time to live period. All keys attached to the lease will be expired and
-  // deleted if the lease expires. Each expired key generates a delete event in the event history.
-  rpc LeaseGrant(LeaseGrantRequest) returns (LeaseGrantResponse) {
-      option (google.api.http) = {
-        post: "/v3/lease/grant"
-        body: "*"
-    };
-  }
-
-  // LeaseRevoke revokes a lease. All keys attached to the lease will expire and be deleted.
-  rpc LeaseRevoke(LeaseRevokeRequest) returns (LeaseRevokeResponse) {
-      option (google.api.http) = {
-        post: "/v3/lease/revoke"
-        body: "*"
-        additional_bindings {
-            post: "/v3/kv/lease/revoke"
-            body: "*"
-        }
-    };
-  }
-
-  // LeaseKeepAlive keeps the lease alive by streaming keep alive requests from the client
-  // to the server and streaming keep alive responses from the server to the client.
-  rpc LeaseKeepAlive(stream LeaseKeepAliveRequest) returns (stream LeaseKeepAliveResponse) {
-      option (google.api.http) = {
-        post: "/v3/lease/keepalive"
-        body: "*"
-    };
-  }
-
-  // LeaseTimeToLive retrieves lease information.
-  rpc LeaseTimeToLive(LeaseTimeToLiveRequest) returns (LeaseTimeToLiveResponse) {
-      option (google.api.http) = {
-        post: "/v3/lease/timetolive"
-        body: "*"
-        additional_bindings {
-            post: "/v3/kv/lease/timetolive"
-            body: "*"
-        }
-    };
-  }
-
-  // LeaseLeases lists all existing leases.
-  rpc LeaseLeases(LeaseLeasesRequest) returns (LeaseLeasesResponse) {
-      option (google.api.http) = {
-        post: "/v3/lease/leases"
-        body: "*"
-        additional_bindings {
-            post: "/v3/kv/lease/leases"
-            body: "*"
-        }
-    };
-  }
-}
-
-service Cluster {
-  // MemberAdd adds a member into the cluster.
-  rpc MemberAdd(MemberAddRequest) returns (MemberAddResponse) {
-      option (google.api.http) = {
-        post: "/v3/cluster/member/add"
-        body: "*"
-    };
-  }
-
-  // MemberRemove removes an existing member from the cluster.
-  rpc MemberRemove(MemberRemoveRequest) returns (MemberRemoveResponse) {
-      option (google.api.http) = {
-        post: "/v3/cluster/member/remove"
-        body: "*"
-    };
-  }
-
-  // MemberUpdate updates the member configuration.
-  rpc MemberUpdate(MemberUpdateRequest) returns (MemberUpdateResponse) {
-      option (google.api.http) = {
-        post: "/v3/cluster/member/update"
-        body: "*"
-    };
-  }
-
-  // MemberList lists all the members in the cluster.
-  rpc MemberList(MemberListRequest) returns (MemberListResponse) {
-      option (google.api.http) = {
-        post: "/v3/cluster/member/list"
-        body: "*"
-    };
-  }
-
-  // MemberPromote promotes a member from raft learner (non-voting) to raft voting member.
-  rpc MemberPromote(MemberPromoteRequest) returns (MemberPromoteResponse) {
-      option (google.api.http) = {
-        post: "/v3/cluster/member/promote"
-        body: "*"
-    };
-  }
-}
-
-service Maintenance {
-  // Alarm activates, deactivates, and queries alarms regarding cluster health.
-  rpc Alarm(AlarmRequest) returns (AlarmResponse) {
-      option (google.api.http) = {
-        post: "/v3/maintenance/alarm"
-        body: "*"
-    };
-  }
-
-  // Status gets the status of the member.
-  rpc Status(StatusRequest) returns (StatusResponse) {
-      option (google.api.http) = {
-        post: "/v3/maintenance/status"
-        body: "*"
-    };
-  }
-
-  // Defragment defragments a member's backend database to recover storage space.
-  rpc Defragment(DefragmentRequest) returns (DefragmentResponse) {
-      option (google.api.http) = {
-        post: "/v3/maintenance/defragment"
-        body: "*"
-    };
-  }
-
-  // Hash computes the hash of whole backend keyspace,
-  // including key, lease, and other buckets in storage.
-  // This is designed for testing ONLY!
-  // Do not rely on this in production with ongoing transactions,
-  // since Hash operation does not hold MVCC locks.
-  // Use "HashKV" API instead for "key" bucket consistency checks.
-  rpc Hash(HashRequest) returns (HashResponse) {
-      option (google.api.http) = {
-        post: "/v3/maintenance/hash"
-        body: "*"
-    };
-  }
-
-  // HashKV computes the hash of all MVCC keys up to a given revision.
-  // It only iterates "key" bucket in backend storage.
-  rpc HashKV(HashKVRequest) returns (HashKVResponse) {
-      option (google.api.http) = {
-        post: "/v3/maintenance/hashkv"
-        body: "*"
-    };
-  }
-
-  // Snapshot sends a snapshot of the entire backend from a member over a stream to a client.
-  rpc Snapshot(SnapshotRequest) returns (stream SnapshotResponse) {
-      option (google.api.http) = {
-        post: "/v3/maintenance/snapshot"
-        body: "*"
-    };
-  }
-
-  // MoveLeader requests current leader node to transfer its leadership to transferee.
-  rpc MoveLeader(MoveLeaderRequest) returns (MoveLeaderResponse) {
-      option (google.api.http) = {
-        post: "/v3/maintenance/transfer-leadership"
-        body: "*"
-    };
-  }
-
-  // Downgrade requests downgrades, verifies feasibility or cancels downgrade
-  // on the cluster version.
-  // Supported since etcd 3.5.
-  rpc Downgrade(DowngradeRequest) returns (DowngradeResponse) {
-    option (google.api.http) = {
-      post: "/v3/maintenance/downgrade"
-      body: "*"
-    };
-  }
-}
-
-service Auth {
-  // AuthEnable enables authentication.
-  rpc AuthEnable(AuthEnableRequest) returns (AuthEnableResponse) {
-      option (google.api.http) = {
-        post: "/v3/auth/enable"
-        body: "*"
-    };
-  }
-
-  // AuthDisable disables authentication.
-  rpc AuthDisable(AuthDisableRequest) returns (AuthDisableResponse) {
-      option (google.api.http) = {
-        post: "/v3/auth/disable"
-        body: "*"
-    };
-  }
-
-  // AuthStatus displays authentication status.
-  rpc AuthStatus(AuthStatusRequest) returns (AuthStatusResponse) {
-      option (google.api.http) = {
-        post: "/v3/auth/status"
-        body: "*"
-    };
-  }
-
-  // Authenticate processes an authenticate request.
-  rpc Authenticate(AuthenticateRequest) returns (AuthenticateResponse) {
-      option (google.api.http) = {
-        post: "/v3/auth/authenticate"
-        body: "*"
-    };
-  }
-
-  // UserAdd adds a new user. User name cannot be empty.
-  rpc UserAdd(AuthUserAddRequest) returns (AuthUserAddResponse) {
-      option (google.api.http) = {
-        post: "/v3/auth/user/add"
-        body: "*"
-    };
-  }
-
-  // UserGet gets detailed user information.
-  rpc UserGet(AuthUserGetRequest) returns (AuthUserGetResponse) {
-      option (google.api.http) = {
-        post: "/v3/auth/user/get"
-        body: "*"
-    };
-  }
-
-  // UserList gets a list of all users.
-  rpc UserList(AuthUserListRequest) returns (AuthUserListResponse) {
-      option (google.api.http) = {
-        post: "/v3/auth/user/list"
-        body: "*"
-    };
-  }
-
-  // UserDelete deletes a specified user.
-  rpc UserDelete(AuthUserDeleteRequest) returns (AuthUserDeleteResponse) {
-      option (google.api.http) = {
-        post: "/v3/auth/user/delete"
-        body: "*"
-    };
-  }
-
-  // UserChangePassword changes the password of a specified user.
-  rpc UserChangePassword(AuthUserChangePasswordRequest) returns (AuthUserChangePasswordResponse) {
-      option (google.api.http) = {
-        post: "/v3/auth/user/changepw"
-        body: "*"
-    };
-  }
-
-  // UserGrant grants a role to a specified user.
-  rpc UserGrantRole(AuthUserGrantRoleRequest) returns (AuthUserGrantRoleResponse) {
-      option (google.api.http) = {
-        post: "/v3/auth/user/grant"
-        body: "*"
-    };
-  }
-
-  // UserRevokeRole revokes a role of specified user.
-  rpc UserRevokeRole(AuthUserRevokeRoleRequest) returns (AuthUserRevokeRoleResponse) {
-      option (google.api.http) = {
-        post: "/v3/auth/user/revoke"
-        body: "*"
-    };
-  }
-
-  // RoleAdd adds a new role. Role name cannot be empty.
-  rpc RoleAdd(AuthRoleAddRequest) returns (AuthRoleAddResponse) {
-      option (google.api.http) = {
-        post: "/v3/auth/role/add"
-        body: "*"
-    };
-  }
-
-  // RoleGet gets detailed role information.
-  rpc RoleGet(AuthRoleGetRequest) returns (AuthRoleGetResponse) {
-      option (google.api.http) = {
-        post: "/v3/auth/role/get"
-        body: "*"
-    };
-  }
-
-  // RoleList gets lists of all roles.
-  rpc RoleList(AuthRoleListRequest) returns (AuthRoleListResponse) {
-      option (google.api.http) = {
-        post: "/v3/auth/role/list"
-        body: "*"
-    };
-  }
-
-  // RoleDelete deletes a specified role.
-  rpc RoleDelete(AuthRoleDeleteRequest) returns (AuthRoleDeleteResponse) {
-      option (google.api.http) = {
-        post: "/v3/auth/role/delete"
-        body: "*"
-    };
-  }
-
-  // RoleGrantPermission grants a permission of a specified key or range to a specified role.
-  rpc RoleGrantPermission(AuthRoleGrantPermissionRequest) returns (AuthRoleGrantPermissionResponse) {
-      option (google.api.http) = {
-        post: "/v3/auth/role/grant"
-        body: "*"
-    };
-  }
-
-  // RoleRevokePermission revokes a key or range permission of a specified role.
-  rpc RoleRevokePermission(AuthRoleRevokePermissionRequest) returns (AuthRoleRevokePermissionResponse) {
-      option (google.api.http) = {
-        post: "/v3/auth/role/revoke"
-        body: "*"
-    };
-  }
-}
-
-message ResponseHeader {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  // cluster_id is the ID of the cluster which sent the response.
-  uint64 cluster_id = 1;
-  // member_id is the ID of the member which sent the response.
-  uint64 member_id = 2;
-  // revision is the key-value store revision when the request was applied, and it's
-  // unset (so 0) in case of calls not interacting with key-value store.
-  // For watch progress responses, the header.revision indicates progress. All future events
-  // received in this stream are guaranteed to have a higher revision number than the
-  // header.revision number.
-  int64 revision = 3;
-  // raft_term is the raft term when the request was applied.
-  uint64 raft_term = 4;
-}
-
-message RangeRequest {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  enum SortOrder {
-    option (versionpb.etcd_version_enum) = "3.0";
-    NONE = 0; // default, no sorting
-    ASCEND = 1; // lowest target value first
-    DESCEND = 2; // highest target value first
-  }
-  enum SortTarget {
-    option (versionpb.etcd_version_enum) = "3.0";
-    KEY = 0;
-    VERSION = 1;
-    CREATE = 2;
-    MOD = 3;
-    VALUE = 4;
-  }
-
-  // key is the first key for the range. If range_end is not given, the request only looks up key.
-  bytes key = 1;
-  // range_end is the upper bound on the requested range [key, range_end).
-  // If range_end is '\0', the range is all keys >= key.
-  // If range_end is key plus one (e.g., "aa"+1 == "ab", "a\xff"+1 == "b"),
-  // then the range request gets all keys prefixed with key.
-  // If both key and range_end are '\0', then the range request returns all keys.
-  bytes range_end = 2;
-  // limit is a limit on the number of keys returned for the request. When limit is set to 0,
-  // it is treated as no limit.
-  int64 limit = 3;
-  // revision is the point-in-time of the key-value store to use for the range.
-  // If revision is less or equal to zero, the range is over the newest key-value store.
-  // If the revision has been compacted, ErrCompacted is returned as a response.
-  int64 revision = 4;
-
-  // sort_order is the order for returned sorted results.
-  SortOrder sort_order = 5;
-
-  // sort_target is the key-value field to use for sorting.
-  SortTarget sort_target = 6;
-
-  // serializable sets the range request to use serializable member-local reads.
-  // Range requests are linearizable by default; linearizable requests have higher
-  // latency and lower throughput than serializable requests but reflect the current
-  // consensus of the cluster. For better performance, in exchange for possible stale reads,
-  // a serializable range request is served locally without needing to reach consensus
-  // with other nodes in the cluster.
-  bool serializable = 7;
-
-  // keys_only when set returns only the keys and not the values.
-  bool keys_only = 8;
-
-  // count_only when set returns only the count of the keys in the range.
-  bool count_only = 9;
-
-  // min_mod_revision is the lower bound for returned key mod revisions; all keys with
-  // lesser mod revisions will be filtered away.
-  int64 min_mod_revision = 10 [(versionpb.etcd_version_field)="3.1"];
-
-  // max_mod_revision is the upper bound for returned key mod revisions; all keys with
-  // greater mod revisions will be filtered away.
-  int64 max_mod_revision = 11 [(versionpb.etcd_version_field)="3.1"];
-
-  // min_create_revision is the lower bound for returned key create revisions; all keys with
-  // lesser create revisions will be filtered away.
-  int64 min_create_revision = 12 [(versionpb.etcd_version_field)="3.1"];
-
-  // max_create_revision is the upper bound for returned key create revisions; all keys with
-  // greater create revisions will be filtered away.
-  int64 max_create_revision = 13 [(versionpb.etcd_version_field)="3.1"];
-}
-
-message RangeResponse {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  ResponseHeader header = 1;
-  // kvs is the list of key-value pairs matched by the range request.
-  // kvs is empty when count is requested.
-  repeated mvccpb.KeyValue kvs = 2;
-  // more indicates if there are more keys to return in the requested range.
-  bool more = 3;
-  // count is set to the number of keys within the range when requested.
-  int64 count = 4;
-}
-
-message PutRequest {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  // key is the key, in bytes, to put into the key-value store.
-  bytes key = 1;
-  // value is the value, in bytes, to associate with the key in the key-value store.
-  bytes value = 2;
-  // lease is the lease ID to associate with the key in the key-value store. A lease
-  // value of 0 indicates no lease.
-  int64 lease = 3;
-
-  // If prev_kv is set, etcd gets the previous key-value pair before changing it.
-  // The previous key-value pair will be returned in the put response.
-  bool prev_kv = 4 [(versionpb.etcd_version_field)="3.1"];
-
-  // If ignore_value is set, etcd updates the key using its current value.
-  // Returns an error if the key does not exist.
-  bool ignore_value = 5 [(versionpb.etcd_version_field)="3.2"];
-
-  // If ignore_lease is set, etcd updates the key using its current lease.
-  // Returns an error if the key does not exist.
-  bool ignore_lease = 6 [(versionpb.etcd_version_field)="3.2"];
-}
-
-message PutResponse {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  ResponseHeader header = 1;
-  // if prev_kv is set in the request, the previous key-value pair will be returned.
-  mvccpb.KeyValue prev_kv = 2 [(versionpb.etcd_version_field)="3.1"];
-}
-
-message DeleteRangeRequest {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  // key is the first key to delete in the range.
-  bytes key = 1;
-  // range_end is the key following the last key to delete for the range [key, range_end).
-  // If range_end is not given, the range is defined to contain only the key argument.
-  // If range_end is one bit larger than the given key, then the range is all the keys
-  // with the prefix (the given key).
-  // If range_end is '\0', the range is all keys greater than or equal to the key argument.
-  bytes range_end = 2;
-
-  // If prev_kv is set, etcd gets the previous key-value pairs before deleting it.
-  // The previous key-value pairs will be returned in the delete response.
-  bool prev_kv = 3 [(versionpb.etcd_version_field)="3.1"];
-}
-
-message DeleteRangeResponse {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  ResponseHeader header = 1;
-  // deleted is the number of keys deleted by the delete range request.
-  int64 deleted = 2;
-  // if prev_kv is set in the request, the previous key-value pairs will be returned.
-  repeated mvccpb.KeyValue prev_kvs = 3 [(versionpb.etcd_version_field)="3.1"];
-}
-
-message RequestOp {
-  option (versionpb.etcd_version_msg) = "3.0";
-  // request is a union of request types accepted by a transaction.
-  oneof request {
-    RangeRequest request_range = 1;
-    PutRequest request_put = 2;
-    DeleteRangeRequest request_delete_range = 3;
-    TxnRequest request_txn = 4 [(versionpb.etcd_version_field)="3.3"];
-  }
-}
-
-message ResponseOp {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  // response is a union of response types returned by a transaction.
-  oneof response {
-    RangeResponse response_range = 1;
-    PutResponse response_put = 2;
-    DeleteRangeResponse response_delete_range = 3;
-    TxnResponse response_txn = 4 [(versionpb.etcd_version_field)="3.3"];
-  }
-}
-
-message Compare {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  enum CompareResult {
-    option (versionpb.etcd_version_enum) = "3.0";
-
-    EQUAL = 0;
-    GREATER = 1;
-    LESS = 2;
-    NOT_EQUAL = 3 [(versionpb.etcd_version_enum_value)="3.1"];
-  }
-  enum CompareTarget {
-    option (versionpb.etcd_version_enum) = "3.0";
-
-    VERSION = 0;
-    CREATE = 1;
-    MOD = 2;
-    VALUE = 3;
-    LEASE = 4 [(versionpb.etcd_version_enum_value)="3.3"];
-  }
-  // result is logical comparison operation for this comparison.
-  CompareResult result = 1;
-  // target is the key-value field to inspect for the comparison.
-  CompareTarget target = 2;
-  // key is the subject key for the comparison operation.
-  bytes key = 3;
-  oneof target_union {
-    // version is the version of the given key
-    int64 version = 4;
-    // create_revision is the creation revision of the given key
-    int64 create_revision = 5;
-    // mod_revision is the last modified revision of the given key.
-    int64 mod_revision = 6;
-    // value is the value of the given key, in bytes.
-    bytes value = 7;
-    // lease is the lease id of the given key.
-    int64 lease = 8 [(versionpb.etcd_version_field)="3.3"];
-    // leave room for more target_union field tags, jump to 64
-  }
-
-  // range_end compares the given target to all keys in the range [key, range_end).
-  // See RangeRequest for more details on key ranges.
-  bytes range_end = 64 [(versionpb.etcd_version_field)="3.3"];
-  // TODO: fill out with most of the rest of RangeRequest fields when needed.
-}
-
-// From google paxosdb paper:
-// Our implementation hinges around a powerful primitive which we call MultiOp. All other database
-// operations except for iteration are implemented as a single call to MultiOp. A MultiOp is applied atomically
-// and consists of three components:
-// 1. A list of tests called guard. Each test in guard checks a single entry in the database. It may check
-// for the absence or presence of a value, or compare with a given value. Two different tests in the guard
-// may apply to the same or different entries in the database. All tests in the guard are applied and
-// MultiOp returns the results. If all tests are true, MultiOp executes t op (see item 2 below), otherwise
-// it executes f op (see item 3 below).
-// 2. A list of database operations called t op. Each operation in the list is either an insert, delete, or
-// lookup operation, and applies to a single database entry. Two different operations in the list may apply
-// to the same or different entries in the database. These operations are executed
-// if guard evaluates to
-// true.
-// 3. A list of database operations called f op. Like t op, but executed if guard evaluates to false.
-message TxnRequest {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  // compare is a list of predicates representing a conjunction of terms.
-  // If the comparisons succeed, then the success requests will be processed in order,
-  // and the response will contain their respective responses in order.
-  // If the comparisons fail, then the failure requests will be processed in order,
-  // and the response will contain their respective responses in order.
-  repeated Compare compare = 1;
-  // success is a list of requests which will be applied when compare evaluates to true.
-  repeated RequestOp success = 2;
-  // failure is a list of requests which will be applied when compare evaluates to false.
-  repeated RequestOp failure = 3;
-}
-
-message TxnResponse {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  ResponseHeader header = 1;
-  // succeeded is set to true if the compare evaluated to true or false otherwise.
-  bool succeeded = 2;
-  // responses is a list of responses corresponding to the results from applying
-  // success if succeeded is true or failure if succeeded is false.
-  repeated ResponseOp responses = 3;
-}
-
-// CompactionRequest compacts the key-value store up to a given revision. All superseded keys
-// with a revision less than the compaction revision will be removed.
-message CompactionRequest {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  // revision is the key-value store revision for the compaction operation.
-  int64 revision = 1;
-  // physical is set so the RPC will wait until the compaction is physically
-  // applied to the local database such that compacted entries are totally
-  // removed from the backend database.
-  bool physical = 2;
-}
-
-message CompactionResponse {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  ResponseHeader header = 1;
-}
-
-message HashRequest {
-  option (versionpb.etcd_version_msg) = "3.0";
-}
-
-message HashKVRequest {
-  option (versionpb.etcd_version_msg) = "3.3";
-  // revision is the key-value store revision for the hash operation.
-  int64 revision = 1;
-}
-
-message HashKVResponse {
-  option (versionpb.etcd_version_msg) = "3.3";
-
-  ResponseHeader header = 1;
-  // hash is the hash value computed from the responding member's MVCC keys up to a given revision.
-  uint32 hash = 2;
-  // compact_revision is the compacted revision of key-value store when hash begins.
-  int64 compact_revision = 3;
-  // hash_revision is the revision up to which the hash is calculated.
-  int64 hash_revision = 4 [(versionpb.etcd_version_field)="3.6"];
-}
-
-message HashResponse {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  ResponseHeader header = 1;
-  // hash is the hash value computed from the responding member's KV's backend.
-  uint32 hash = 2;
-}
-
-message SnapshotRequest {
-  option (versionpb.etcd_version_msg) = "3.3";
-}
-
-message SnapshotResponse {
-  option (versionpb.etcd_version_msg) = "3.3";
-
-  // header has the current key-value store information. The first header in the snapshot
-  // stream indicates the point in time of the snapshot.
-  ResponseHeader header = 1;
-
-  // remaining_bytes is the number of blob bytes to be sent after this message
-  uint64 remaining_bytes = 2;
-
-  // blob contains the next chunk of the snapshot in the snapshot stream.
-  bytes blob = 3;
-
-  // local version of server that created the snapshot.
-  // In cluster with binaries with different version, each cluster can return different result.
-  // Informs which etcd server version should be used when restoring the snapshot.
-  string version = 4 [(versionpb.etcd_version_field)="3.6"];
-}
-
-message WatchRequest {
-  option (versionpb.etcd_version_msg) = "3.0";
-  // request_union is a request to either create a new watcher or cancel an existing watcher.
-  oneof request_union {
-    WatchCreateRequest create_request = 1;
-    WatchCancelRequest cancel_request = 2;
-    WatchProgressRequest progress_request = 3 [(versionpb.etcd_version_field)="3.4"];
-  }
-}
-
-message WatchCreateRequest {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  // key is the key to register for watching.
-  bytes key = 1;
-
-  // range_end is the end of the range [key, range_end) to watch. If range_end is not given,
-  // only the key argument is watched. If range_end is equal to '\0', all keys greater than
-  // or equal to the key argument are watched.
-  // If the range_end is one bit larger than the given key,
-  // then all keys with the prefix (the given key) will be watched.
-  bytes range_end = 2;
-
-  // start_revision is an optional revision to watch from (inclusive). No start_revision is "now".
-  int64 start_revision = 3;
-
-  // progress_notify is set so that the etcd server will periodically send a WatchResponse with
-  // no events to the new watcher if there are no recent events. It is useful when clients
-  // wish to recover a disconnected watcher starting from a recent known revision.
-  // The etcd server may decide how often it will send notifications based on current load.
-  bool progress_notify = 4;
-
-  enum FilterType {
-    option (versionpb.etcd_version_enum) = "3.1";
-
-    // filter out put event.
-    NOPUT = 0;
-    // filter out delete event.
-    NODELETE = 1;
-  }
-
-  // filters filter the events at server side before it sends back to the watcher.
-  repeated FilterType filters = 5 [(versionpb.etcd_version_field)="3.1"];
-
-  // If prev_kv is set, created watcher gets the previous KV before the event happens.
-  // If the previous KV is already compacted, nothing will be returned.
-  bool prev_kv = 6 [(versionpb.etcd_version_field)="3.1"];
-
-  // If watch_id is provided and non-zero, it will be assigned to this watcher.
-  // Since creating a watcher in etcd is not a synchronous operation,
-  // this can be used ensure that ordering is correct when creating multiple
-  // watchers on the same stream. Creating a watcher with an ID already in
-  // use on the stream will cause an error to be returned.
-  int64 watch_id = 7 [(versionpb.etcd_version_field)="3.4"];
-
-  // fragment enables splitting large revisions into multiple watch responses.
-  bool fragment = 8 [(versionpb.etcd_version_field)="3.4"];
-}
-
-message WatchCancelRequest {
-  option (versionpb.etcd_version_msg) = "3.1";
-  // watch_id is the watcher id to cancel so that no more events are transmitted.
-  int64 watch_id = 1 [(versionpb.etcd_version_field)="3.1"];
-}
-
-// Requests the a watch stream progress status be sent in the watch response stream as soon as
-// possible.
-message WatchProgressRequest {
-  option (versionpb.etcd_version_msg) = "3.4";
-}
-
-message WatchResponse {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  ResponseHeader header = 1;
-  // watch_id is the ID of the watcher that corresponds to the response.
-  int64 watch_id = 2;
-
-  // created is set to true if the response is for a create watch request.
-  // The client should record the watch_id and expect to receive events for
-  // the created watcher from the same stream.
-  // All events sent to the created watcher will attach with the same watch_id.
-  bool created = 3;
-
-  // canceled is set to true if the response is for a cancel watch request
-  // or if the start_revision has already been compacted.
-  // No further events will be sent to the canceled watcher.
-  bool canceled = 4;
-
-  // compact_revision is set to the minimum index if a watcher tries to watch
-  // at a compacted index.
-  //
-  // This happens when creating a watcher at a compacted revision or the watcher cannot
-  // catch up with the progress of the key-value store.
-  //
-  // The client should treat the watcher as canceled and should not try to create any
-  // watcher with the same start_revision again.
-  int64 compact_revision = 5;
-
-  // cancel_reason indicates the reason for canceling the watcher.
-  string cancel_reason = 6 [(versionpb.etcd_version_field)="3.4"];
-
-  // framgment is true if large watch response was split over multiple responses.
-  bool fragment = 7 [(versionpb.etcd_version_field)="3.4"];
-
-  repeated mvccpb.Event events = 11;
-}
-
-message LeaseGrantRequest {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  // TTL is the advisory time-to-live in seconds. Expired lease will return -1.
-  int64 TTL = 1;
-  // ID is the requested ID for the lease. If ID is set to 0, the lessor chooses an ID.
-  int64 ID = 2;
-}
-
-message LeaseGrantResponse {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  ResponseHeader header = 1;
-  // ID is the lease ID for the granted lease.
-  int64 ID = 2;
-  // TTL is the server chosen lease time-to-live in seconds.
-  int64 TTL = 3;
-  string error = 4;
-}
-
-message LeaseRevokeRequest {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  // ID is the lease ID to revoke. When the ID is revoked, all associated keys will be deleted.
-  int64 ID = 1;
-}
-
-message LeaseRevokeResponse {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  ResponseHeader header = 1;
-}
-
-message LeaseCheckpoint {
-  option (versionpb.etcd_version_msg) = "3.4";
-
-    // ID is the lease ID to checkpoint.
-  int64 ID = 1;
-
-  // Remaining_TTL is the remaining time until expiry of the lease.
-  int64 remaining_TTL = 2;
-}
-
-message LeaseCheckpointRequest {
-  option (versionpb.etcd_version_msg) = "3.4";
-
-  repeated LeaseCheckpoint checkpoints = 1;
-}
-
-message LeaseCheckpointResponse {
-  option (versionpb.etcd_version_msg) = "3.4";
-
-  ResponseHeader header = 1;
-}
-
-message LeaseKeepAliveRequest {
-  option (versionpb.etcd_version_msg) = "3.0";
-  // ID is the lease ID for the lease to keep alive.
-  int64 ID = 1;
-}
-
-message LeaseKeepAliveResponse {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  ResponseHeader header = 1;
-  // ID is the lease ID from the keep alive request.
-  int64 ID = 2;
-  // TTL is the new time-to-live for the lease.
-  int64 TTL = 3;
-}
-
-message LeaseTimeToLiveRequest {
-  option (versionpb.etcd_version_msg) = "3.1";
-  // ID is the lease ID for the lease.
-  int64 ID = 1;
-  // keys is true to query all the keys attached to this lease.
-  bool keys = 2;
-}
-
-message LeaseTimeToLiveResponse {
-  option (versionpb.etcd_version_msg) = "3.1";
-
-  ResponseHeader header = 1;
-  // ID is the lease ID from the keep alive request.
-  int64 ID = 2;
-  // TTL is the remaining TTL in seconds for the lease; the lease will expire in under TTL+1 seconds.
-  int64 TTL = 3;
-  // GrantedTTL is the initial granted time in seconds upon lease creation/renewal.
-  int64 grantedTTL = 4;
-  // Keys is the list of keys attached to this lease.
-  repeated bytes keys = 5;
-}
-
-message LeaseLeasesRequest {
-  option (versionpb.etcd_version_msg) = "3.3";
-}
-
-message LeaseStatus {
-  option (versionpb.etcd_version_msg) = "3.3";
-
-  int64 ID = 1;
-  // TODO: int64 TTL = 2;
-}
-
-message LeaseLeasesResponse {
-  option (versionpb.etcd_version_msg) = "3.3";
-
-  ResponseHeader header = 1;
-  repeated LeaseStatus leases = 2;
-}
-
-message Member {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  // ID is the member ID for this member.
-  uint64 ID = 1;
-  // name is the human-readable name of the member. If the member is not started, the name will be an empty string.
-  string name = 2;
-  // peerURLs is the list of URLs the member exposes to the cluster for communication.
-  repeated string peerURLs = 3;
-  // clientURLs is the list of URLs the member exposes to clients for communication. If the member is not started, clientURLs will be empty.
-  repeated string clientURLs = 4;
-  // isLearner indicates if the member is raft learner.
-  bool isLearner = 5 [(versionpb.etcd_version_field)="3.4"];
-}
-
-message MemberAddRequest {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  // peerURLs is the list of URLs the added member will use to communicate with the cluster.
-  repeated string peerURLs = 1;
-  // isLearner indicates if the added member is raft learner.
-  bool isLearner = 2 [(versionpb.etcd_version_field)="3.4"];
-}
-
-message MemberAddResponse {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  ResponseHeader header = 1;
-  // member is the member information for the added member.
-  Member member = 2;
-  // members is a list of all members after adding the new member.
-  repeated Member members = 3;
-}
-
-message MemberRemoveRequest {
-  option (versionpb.etcd_version_msg) = "3.0";
-  // ID is the member ID of the member to remove.
-  uint64 ID = 1;
-}
-
-message MemberRemoveResponse {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  ResponseHeader header = 1;
-  // members is a list of all members after removing the member.
-  repeated Member members = 2;
-}
-
-message MemberUpdateRequest {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  // ID is the member ID of the member to update.
-  uint64 ID = 1;
-  // peerURLs is the new list of URLs the member will use to communicate with the cluster.
-  repeated string peerURLs = 2;
-}
-
-message MemberUpdateResponse{
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  ResponseHeader header = 1;
-  // members is a list of all members after updating the member.
-  repeated Member members = 2 [(versionpb.etcd_version_field)="3.1"];
-}
-
-message MemberListRequest {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  bool linearizable = 1 [(versionpb.etcd_version_field)="3.5"];
-}
-
-message MemberListResponse {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  ResponseHeader header = 1;
-  // members is a list of all members associated with the cluster.
-  repeated Member members = 2;
-}
-
-message MemberPromoteRequest {
-  option (versionpb.etcd_version_msg) = "3.4";
-  // ID is the member ID of the member to promote.
-  uint64 ID = 1;
-}
-
-message MemberPromoteResponse {
-  option (versionpb.etcd_version_msg) = "3.4";
-
-  ResponseHeader header = 1;
-  // members is a list of all members after promoting the member.
-  repeated Member members = 2;
-}
-
-message DefragmentRequest {
-  option (versionpb.etcd_version_msg) = "3.0";
-}
-
-message DefragmentResponse {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  ResponseHeader header = 1;
-}
-
-message MoveLeaderRequest {
-  option (versionpb.etcd_version_msg) = "3.3";
-  // targetID is the node ID for the new leader.
-  uint64 targetID = 1;
-}
-
-message MoveLeaderResponse {
-  option (versionpb.etcd_version_msg) = "3.3";
-
-  ResponseHeader header = 1;
-}
-
-enum AlarmType {
-  option (versionpb.etcd_version_enum) = "3.0";
-
-	NONE = 0; // default, used to query if any alarm is active
-	NOSPACE = 1; // space quota is exhausted
-	CORRUPT = 2 [(versionpb.etcd_version_enum_value)="3.3"]; // kv store corruption detected
-}
-
-message AlarmRequest {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  enum AlarmAction {
-    option (versionpb.etcd_version_enum) = "3.0";
-
-    GET = 0;
-    ACTIVATE = 1;
-    DEACTIVATE = 2;
-  }
-  // action is the kind of alarm request to issue. The action
-  // may GET alarm statuses, ACTIVATE an alarm, or DEACTIVATE a
-  // raised alarm.
-  AlarmAction action = 1;
-  // memberID is the ID of the member associated with the alarm. If memberID is 0, the
-  // alarm request covers all members.
-  uint64 memberID = 2;
-  // alarm is the type of alarm to consider for this request.
-  AlarmType alarm = 3;
-}
-
-message AlarmMember {
-  option (versionpb.etcd_version_msg) = "3.0";
-  // memberID is the ID of the member associated with the raised alarm.
-  uint64 memberID = 1;
-  // alarm is the type of alarm which has been raised.
-  AlarmType alarm = 2;
-}
-
-message AlarmResponse {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  ResponseHeader header = 1;
-  // alarms is a list of alarms associated with the alarm request.
-  repeated AlarmMember alarms = 2;
-}
-
-message DowngradeRequest {
-  option (versionpb.etcd_version_msg) = "3.5";
-
-  enum DowngradeAction {
-    option (versionpb.etcd_version_enum) = "3.5";
-
-    VALIDATE = 0;
-    ENABLE = 1;
-    CANCEL = 2;
-  }
-
-  // action is the kind of downgrade request to issue. The action may
-  // VALIDATE the target version, DOWNGRADE the cluster version,
-  // or CANCEL the current downgrading job.
-  DowngradeAction action = 1;
-  // version is the target version to downgrade.
-  string version = 2;
-}
-
-message DowngradeResponse {
-  option (versionpb.etcd_version_msg) = "3.5";
-
-  ResponseHeader header = 1;
-  // version is the current cluster version.
-  string version = 2;
-}
-
-// DowngradeVersionTestRequest is used for test only. The version in
-// this request will be read as the WAL record version.If the downgrade
-// target version is less than this version, then the downgrade(online)
-// or migration(offline) isn't safe, so shouldn't be allowed.
-message DowngradeVersionTestRequest {
-  option (versionpb.etcd_version_msg) = "3.6";
-
-  string ver = 1;
-}
-
-message StatusRequest {
-  option (versionpb.etcd_version_msg) = "3.0";
-}
-
-message StatusResponse {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  ResponseHeader header = 1;
-  // version is the cluster protocol version used by the responding member.
-  string version = 2;
-  // dbSize is the size of the backend database physically allocated, in bytes, of the responding member.
-  int64 dbSize = 3;
-  // leader is the member ID which the responding member believes is the current leader.
-  uint64 leader = 4;
-  // raftIndex is the current raft committed index of the responding member.
-  uint64 raftIndex = 5;
-  // raftTerm is the current raft term of the responding member.
-  uint64 raftTerm = 6;
-  // raftAppliedIndex is the current raft applied index of the responding member.
-  uint64 raftAppliedIndex = 7 [(versionpb.etcd_version_field)="3.4"];
-  // errors contains alarm/health information and status.
-  repeated string errors = 8 [(versionpb.etcd_version_field)="3.4"];
-  // dbSizeInUse is the size of the backend database logically in use, in bytes, of the responding member.
-  int64 dbSizeInUse = 9 [(versionpb.etcd_version_field)="3.4"];
-  // isLearner indicates if the member is raft learner.
-  bool isLearner = 10 [(versionpb.etcd_version_field)="3.4"];
-  // storageVersion is the version of the db file. It might be get updated with delay in relationship to the target cluster version.
-  string storageVersion = 11 [(versionpb.etcd_version_field)="3.6"];
-  // dbSizeQuota is the configured etcd storage quota in bytes (the value passed to etcd instance by flag --quota-backend-bytes)
-  int64 dbSizeQuota = 12 [(versionpb.etcd_version_field)="3.6"];
-}
-
-message AuthEnableRequest {
-  option (versionpb.etcd_version_msg) = "3.0";
-}
-
-message AuthDisableRequest {
-  option (versionpb.etcd_version_msg) = "3.0";
-}
-
-message AuthStatusRequest {
-  option (versionpb.etcd_version_msg) = "3.5";
-}
-
-message AuthenticateRequest {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  string name = 1;
-  string password = 2;
-}
-
-message AuthUserAddRequest {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  string name = 1;
-  string password = 2;
-  authpb.UserAddOptions options = 3 [(versionpb.etcd_version_field)="3.4"];
-  string hashedPassword = 4 [(versionpb.etcd_version_field)="3.5"];
-}
-
-message AuthUserGetRequest {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  string name = 1;
-}
-
-message AuthUserDeleteRequest {
-  option (versionpb.etcd_version_msg) = "3.0";
-  // name is the name of the user to delete.
-  string name = 1;
-}
-
-message AuthUserChangePasswordRequest {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  // name is the name of the user whose password is being changed.
-  string name = 1;
-  // password is the new password for the user. Note that this field will be removed in the API layer.
-  string password = 2;
-  // hashedPassword is the new password for the user. Note that this field will be initialized in the API layer.
-  string hashedPassword = 3 [(versionpb.etcd_version_field)="3.5"];
-}
-
-message AuthUserGrantRoleRequest {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  // user is the name of the user which should be granted a given role.
-  string user = 1;
-  // role is the name of the role to grant to the user.
-  string role = 2;
-}
-
-message AuthUserRevokeRoleRequest {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  string name = 1;
-  string role = 2;
-}
-
-message AuthRoleAddRequest {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  // name is the name of the role to add to the authentication system.
-  string name = 1;
-}
-
-message AuthRoleGetRequest {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  string role = 1;
-}
-
-message AuthUserListRequest {
-  option (versionpb.etcd_version_msg) = "3.0";
-}
-
-message AuthRoleListRequest {
-  option (versionpb.etcd_version_msg) = "3.0";
-}
-
-message AuthRoleDeleteRequest {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  string role = 1;
-}
-
-message AuthRoleGrantPermissionRequest {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  // name is the name of the role which will be granted the permission.
-  string name = 1;
-  // perm is the permission to grant to the role.
-  authpb.Permission perm = 2;
-}
-
-message AuthRoleRevokePermissionRequest {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  string role = 1;
-  bytes key = 2;
-  bytes range_end = 3;
-}
-
-message AuthEnableResponse {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  ResponseHeader header = 1;
-}
-
-message AuthDisableResponse {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  ResponseHeader header = 1;
-}
-
-message AuthStatusResponse {
-  option (versionpb.etcd_version_msg) = "3.5";
-
-  ResponseHeader header = 1;
-  bool enabled = 2;
-  // authRevision is the current revision of auth store
-  uint64 authRevision = 3;
-}
-
-message AuthenticateResponse {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  ResponseHeader header = 1;
-  // token is an authorized token that can be used in succeeding RPCs
-  string token = 2;
-}
-
-message AuthUserAddResponse {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  ResponseHeader header = 1;
-}
-
-message AuthUserGetResponse {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  ResponseHeader header = 1;
-
-  repeated string roles = 2;
-}
-
-message AuthUserDeleteResponse {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  ResponseHeader header = 1;
-}
-
-message AuthUserChangePasswordResponse {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  ResponseHeader header = 1;
-}
-
-message AuthUserGrantRoleResponse {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  ResponseHeader header = 1;
-}
-
-message AuthUserRevokeRoleResponse {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  ResponseHeader header = 1;
-}
-
-message AuthRoleAddResponse {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  ResponseHeader header = 1;
-}
-
-message AuthRoleGetResponse {
-  ResponseHeader header = 1 [(versionpb.etcd_version_field)="3.0"];
-
-  repeated authpb.Permission perm = 2 [(versionpb.etcd_version_field)="3.0"];
-}
-
-message AuthRoleListResponse {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  ResponseHeader header = 1;
-
-  repeated string roles = 2;
-}
-
-message AuthUserListResponse {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  ResponseHeader header = 1;
-
-  repeated string users = 2;
-}
-
-message AuthRoleDeleteResponse {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  ResponseHeader header = 1;
-}
-
-message AuthRoleGrantPermissionResponse {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  ResponseHeader header = 1;
-}
-
-message AuthRoleRevokePermissionResponse {
-  option (versionpb.etcd_version_msg) = "3.0";
-
-  ResponseHeader header = 1;
-}
diff --git a/proto/etcd/api/mvccpb/kv.proto b/proto/etcd/api/mvccpb/kv.proto
deleted file mode 100644
--- a/proto/etcd/api/mvccpb/kv.proto
+++ /dev/null
@@ -1,51 +0,0 @@
-syntax = "proto3";
-package mvccpb;
-
-import "gogoproto/gogo.proto";
-
-option go_package = "go.etcd.io/etcd/api/v3/mvccpb";
-
-option (gogoproto.marshaler_all) = true;
-option (gogoproto.sizer_all) = true;
-option (gogoproto.unmarshaler_all) = true;
-option (gogoproto.goproto_getters_all) = false;
-option (gogoproto.goproto_enum_prefix_all) = false;
-
-message KeyValue {
-  // key is the key in bytes. An empty key is not allowed.
-  bytes key = 1;
-  // create_revision is the revision of last creation on this key.
-  int64 create_revision = 2;
-  // mod_revision is the revision of last modification on this key.
-  int64 mod_revision = 3;
-  // version is the version of the key. A deletion resets
-  // the version to zero and any modification of the key
-  // increases its version.
-  int64 version = 4;
-  // value is the value held by the key, in bytes.
-  bytes value = 5;
-  // lease is the ID of the lease that attached to key.
-  // When the attached lease expires, the key will be deleted.
-  // If lease is 0, then no lease is attached to the key.
-  int64 lease = 6;
-}
-
-message Event {
-  enum EventType {
-    PUT = 0;
-    DELETE = 1;
-  }
-  // type is the kind of event. If type is a PUT, it indicates
-  // new data has been stored to the key. If type is a DELETE,
-  // it indicates the key was deleted.
-  EventType type = 1;
-  // kv holds the KeyValue for the event.
-  // A PUT event contains current kv pair.
-  // A PUT event with kv.Version=1 indicates the creation of a key.
-  // A DELETE/EXPIRE event contains the deleted key with
-  // its modification revision set to the revision of deletion.
-  KeyValue kv = 2;
-
-  // prev_kv holds the key-value pair before the event happens.
-  KeyValue prev_kv = 3;
-}
diff --git a/proto/etcd/api/versionpb/version.proto b/proto/etcd/api/versionpb/version.proto
deleted file mode 100644
--- a/proto/etcd/api/versionpb/version.proto
+++ /dev/null
@@ -1,30 +0,0 @@
-syntax = "proto3";
-package versionpb;
-
-import "gogoproto/gogo.proto";
-import "google/protobuf/descriptor.proto";
-
-option go_package = "go.etcd.io/etcd/api/v3/versionpb";
-
-option (gogoproto.marshaler_all) = true;
-option (gogoproto.unmarshaler_all) = true;
-
-// Indicates etcd version that introduced the message, used to determine minimal etcd version required to interpret wal that includes this message.
-extend google.protobuf.MessageOptions {
-  optional string etcd_version_msg = 50000;
-}
-
-// Indicates etcd version that introduced the field, used to determine minimal etcd version required to interpret wal that sets this field.
-extend google.protobuf.FieldOptions {
-  optional string etcd_version_field = 50001;
-}
-
-// Indicates etcd version that introduced the enum, used to determine minimal etcd version required to interpret wal that uses this enum.
-extend google.protobuf.EnumOptions {
-  optional string etcd_version_enum = 50002;
-}
-
-// Indicates etcd version that introduced the enum value, used to determine minimal etcd version required to interpret wal that sets this enum value.
-extend google.protobuf.EnumValueOptions {
-  optional string etcd_version_enum_value = 50003;
-}
diff --git a/proto/gogoproto/gogo.proto b/proto/gogoproto/gogo.proto
deleted file mode 100644
--- a/proto/gogoproto/gogo.proto
+++ /dev/null
@@ -1,145 +0,0 @@
-// Protocol Buffers for Go with Gadgets
-//
-// Copyright (c) 2013, The GoGo Authors. All rights reserved.
-// http://github.com/cosmos/gogoproto
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-syntax = "proto2";
-package gogoproto;
-
-import "google/protobuf/descriptor.proto";
-
-option java_package = "com.google.protobuf";
-option java_outer_classname = "GoGoProtos";
-option go_package = "github.com/cosmos/gogoproto/gogoproto";
-
-extend google.protobuf.EnumOptions {
-	optional bool goproto_enum_prefix = 62001;
-	optional bool goproto_enum_stringer = 62021;
-	optional bool enum_stringer = 62022;
-	optional string enum_customname = 62023;
-	optional bool enumdecl = 62024;
-}
-
-extend google.protobuf.EnumValueOptions {
-	optional string enumvalue_customname = 66001;
-}
-
-extend google.protobuf.FileOptions {
-	optional bool goproto_getters_all = 63001;
-	optional bool goproto_enum_prefix_all = 63002;
-	optional bool goproto_stringer_all = 63003;
-	optional bool verbose_equal_all = 63004;
-	optional bool face_all = 63005;
-	optional bool gostring_all = 63006;
-	optional bool populate_all = 63007;
-	optional bool stringer_all = 63008;
-	optional bool onlyone_all = 63009;
-
-	optional bool equal_all = 63013;
-	optional bool description_all = 63014;
-	optional bool testgen_all = 63015;
-	optional bool benchgen_all = 63016;
-	optional bool marshaler_all = 63017;
-	optional bool unmarshaler_all = 63018;
-	optional bool stable_marshaler_all = 63019;
-
-	optional bool sizer_all = 63020;
-
-	optional bool goproto_enum_stringer_all = 63021;
-	optional bool enum_stringer_all = 63022;
-
-	optional bool unsafe_marshaler_all = 63023;
-	optional bool unsafe_unmarshaler_all = 63024;
-
-	optional bool goproto_extensions_map_all = 63025;
-	optional bool goproto_unrecognized_all = 63026;
-	optional bool gogoproto_import = 63027;
-	optional bool protosizer_all = 63028;
-	optional bool compare_all = 63029;
-    optional bool typedecl_all = 63030;
-    optional bool enumdecl_all = 63031;
-
-	optional bool goproto_registration = 63032;
-	optional bool messagename_all = 63033;
-
-	optional bool goproto_sizecache_all = 63034;
-	optional bool goproto_unkeyed_all = 63035;
-}
-
-extend google.protobuf.MessageOptions {
-	optional bool goproto_getters = 64001;
-	optional bool goproto_stringer = 64003;
-	optional bool verbose_equal = 64004;
-	optional bool face = 64005;
-	optional bool gostring = 64006;
-	optional bool populate = 64007;
-	optional bool stringer = 67008;
-	optional bool onlyone = 64009;
-
-	optional bool equal = 64013;
-	optional bool description = 64014;
-	optional bool testgen = 64015;
-	optional bool benchgen = 64016;
-	optional bool marshaler = 64017;
-	optional bool unmarshaler = 64018;
-	optional bool stable_marshaler = 64019;
-
-	optional bool sizer = 64020;
-
-	optional bool unsafe_marshaler = 64023;
-	optional bool unsafe_unmarshaler = 64024;
-
-	optional bool goproto_extensions_map = 64025;
-	optional bool goproto_unrecognized = 64026;
-
-	optional bool protosizer = 64028;
-	optional bool compare = 64029;
-
-	optional bool typedecl = 64030;
-
-	optional bool messagename = 64033;
-
-	optional bool goproto_sizecache = 64034;
-	optional bool goproto_unkeyed = 64035;
-}
-
-extend google.protobuf.FieldOptions {
-	optional bool nullable = 65001;
-	optional bool embed = 65002;
-	optional string customtype = 65003;
-	optional string customname = 65004;
-	optional string jsontag = 65005;
-	optional string moretags = 65006;
-	optional string casttype = 65007;
-	optional string castkey = 65008;
-	optional string castvalue = 65009;
-
-	optional bool stdtime = 65010;
-	optional bool stdduration = 65011;
-	optional bool wktpointer = 65012;
-
-	optional string castrepeated = 65013;
-}
diff --git a/proto/google/api/annotations.proto b/proto/google/api/annotations.proto
deleted file mode 100644
--- a/proto/google/api/annotations.proto
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2024 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-syntax = "proto3";
-
-package google.api;
-
-import "google/api/http.proto";
-import "google/protobuf/descriptor.proto";
-
-option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations";
-option java_multiple_files = true;
-option java_outer_classname = "AnnotationsProto";
-option java_package = "com.google.api";
-option objc_class_prefix = "GAPI";
-
-extend google.protobuf.MethodOptions {
-  // See `HttpRule`.
-  HttpRule http = 72295728;
-}
diff --git a/proto/google/api/http.proto b/proto/google/api/http.proto
deleted file mode 100644
--- a/proto/google/api/http.proto
+++ /dev/null
@@ -1,370 +0,0 @@
-// Copyright 2024 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-syntax = "proto3";
-
-package google.api;
-
-option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations";
-option java_multiple_files = true;
-option java_outer_classname = "HttpProto";
-option java_package = "com.google.api";
-option objc_class_prefix = "GAPI";
-
-// Defines the HTTP configuration for an API service. It contains a list of
-// [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method
-// to one or more HTTP REST API methods.
-message Http {
-  // A list of HTTP configuration rules that apply to individual API methods.
-  //
-  // **NOTE:** All service configuration rules follow "last one wins" order.
-  repeated HttpRule rules = 1;
-
-  // When set to true, URL path parameters will be fully URI-decoded except in
-  // cases of single segment matches in reserved expansion, where "%2F" will be
-  // left encoded.
-  //
-  // The default behavior is to not decode RFC 6570 reserved characters in multi
-  // segment matches.
-  bool fully_decode_reserved_expansion = 2;
-}
-
-// gRPC Transcoding
-//
-// gRPC Transcoding is a feature for mapping between a gRPC method and one or
-// more HTTP REST endpoints. It allows developers to build a single API service
-// that supports both gRPC APIs and REST APIs. Many systems, including [Google
-// APIs](https://github.com/googleapis/googleapis),
-// [Cloud Endpoints](https://cloud.google.com/endpoints), [gRPC
-// Gateway](https://github.com/grpc-ecosystem/grpc-gateway),
-// and [Envoy](https://github.com/envoyproxy/envoy) proxy support this feature
-// and use it for large scale production services.
-//
-// `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies
-// how different portions of the gRPC request message are mapped to the URL
-// path, URL query parameters, and HTTP request body. It also controls how the
-// gRPC response message is mapped to the HTTP response body. `HttpRule` is
-// typically specified as an `google.api.http` annotation on the gRPC method.
-//
-// Each mapping specifies a URL path template and an HTTP method. The path
-// template may refer to one or more fields in the gRPC request message, as long
-// as each field is a non-repeated field with a primitive (non-message) type.
-// The path template controls how fields of the request message are mapped to
-// the URL path.
-//
-// Example:
-//
-//     service Messaging {
-//       rpc GetMessage(GetMessageRequest) returns (Message) {
-//         option (google.api.http) = {
-//             get: "/v1/{name=messages/*}"
-//         };
-//       }
-//     }
-//     message GetMessageRequest {
-//       string name = 1; // Mapped to URL path.
-//     }
-//     message Message {
-//       string text = 1; // The resource content.
-//     }
-//
-// This enables an HTTP REST to gRPC mapping as below:
-//
-// - HTTP: `GET /v1/messages/123456`
-// - gRPC: `GetMessage(name: "messages/123456")`
-//
-// Any fields in the request message which are not bound by the path template
-// automatically become HTTP query parameters if there is no HTTP request body.
-// For example:
-//
-//     service Messaging {
-//       rpc GetMessage(GetMessageRequest) returns (Message) {
-//         option (google.api.http) = {
-//             get:"/v1/messages/{message_id}"
-//         };
-//       }
-//     }
-//     message GetMessageRequest {
-//       message SubMessage {
-//         string subfield = 1;
-//       }
-//       string message_id = 1; // Mapped to URL path.
-//       int64 revision = 2;    // Mapped to URL query parameter `revision`.
-//       SubMessage sub = 3;    // Mapped to URL query parameter `sub.subfield`.
-//     }
-//
-// This enables a HTTP JSON to RPC mapping as below:
-//
-// - HTTP: `GET /v1/messages/123456?revision=2&sub.subfield=foo`
-// - gRPC: `GetMessage(message_id: "123456" revision: 2 sub:
-// SubMessage(subfield: "foo"))`
-//
-// Note that fields which are mapped to URL query parameters must have a
-// primitive type or a repeated primitive type or a non-repeated message type.
-// In the case of a repeated type, the parameter can be repeated in the URL
-// as `...?param=A&param=B`. In the case of a message type, each field of the
-// message is mapped to a separate parameter, such as
-// `...?foo.a=A&foo.b=B&foo.c=C`.
-//
-// For HTTP methods that allow a request body, the `body` field
-// specifies the mapping. Consider a REST update method on the
-// message resource collection:
-//
-//     service Messaging {
-//       rpc UpdateMessage(UpdateMessageRequest) returns (Message) {
-//         option (google.api.http) = {
-//           patch: "/v1/messages/{message_id}"
-//           body: "message"
-//         };
-//       }
-//     }
-//     message UpdateMessageRequest {
-//       string message_id = 1; // mapped to the URL
-//       Message message = 2;   // mapped to the body
-//     }
-//
-// The following HTTP JSON to RPC mapping is enabled, where the
-// representation of the JSON in the request body is determined by
-// protos JSON encoding:
-//
-// - HTTP: `PATCH /v1/messages/123456 { "text": "Hi!" }`
-// - gRPC: `UpdateMessage(message_id: "123456" message { text: "Hi!" })`
-//
-// The special name `*` can be used in the body mapping to define that
-// every field not bound by the path template should be mapped to the
-// request body.  This enables the following alternative definition of
-// the update method:
-//
-//     service Messaging {
-//       rpc UpdateMessage(Message) returns (Message) {
-//         option (google.api.http) = {
-//           patch: "/v1/messages/{message_id}"
-//           body: "*"
-//         };
-//       }
-//     }
-//     message Message {
-//       string message_id = 1;
-//       string text = 2;
-//     }
-//
-//
-// The following HTTP JSON to RPC mapping is enabled:
-//
-// - HTTP: `PATCH /v1/messages/123456 { "text": "Hi!" }`
-// - gRPC: `UpdateMessage(message_id: "123456" text: "Hi!")`
-//
-// Note that when using `*` in the body mapping, it is not possible to
-// have HTTP parameters, as all fields not bound by the path end in
-// the body. This makes this option more rarely used in practice when
-// defining REST APIs. The common usage of `*` is in custom methods
-// which don't use the URL at all for transferring data.
-//
-// It is possible to define multiple HTTP methods for one RPC by using
-// the `additional_bindings` option. Example:
-//
-//     service Messaging {
-//       rpc GetMessage(GetMessageRequest) returns (Message) {
-//         option (google.api.http) = {
-//           get: "/v1/messages/{message_id}"
-//           additional_bindings {
-//             get: "/v1/users/{user_id}/messages/{message_id}"
-//           }
-//         };
-//       }
-//     }
-//     message GetMessageRequest {
-//       string message_id = 1;
-//       string user_id = 2;
-//     }
-//
-// This enables the following two alternative HTTP JSON to RPC mappings:
-//
-// - HTTP: `GET /v1/messages/123456`
-// - gRPC: `GetMessage(message_id: "123456")`
-//
-// - HTTP: `GET /v1/users/me/messages/123456`
-// - gRPC: `GetMessage(user_id: "me" message_id: "123456")`
-//
-// Rules for HTTP mapping
-//
-// 1. Leaf request fields (recursive expansion nested messages in the request
-//    message) are classified into three categories:
-//    - Fields referred by the path template. They are passed via the URL path.
-//    - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They
-//    are passed via the HTTP
-//      request body.
-//    - All other fields are passed via the URL query parameters, and the
-//      parameter name is the field path in the request message. A repeated
-//      field can be represented as multiple query parameters under the same
-//      name.
-//  2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL
-//  query parameter, all fields
-//     are passed via URL path and HTTP request body.
-//  3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP
-//  request body, all
-//     fields are passed via URL path and URL query parameters.
-//
-// Path template syntax
-//
-//     Template = "/" Segments [ Verb ] ;
-//     Segments = Segment { "/" Segment } ;
-//     Segment  = "*" | "**" | LITERAL | Variable ;
-//     Variable = "{" FieldPath [ "=" Segments ] "}" ;
-//     FieldPath = IDENT { "." IDENT } ;
-//     Verb     = ":" LITERAL ;
-//
-// The syntax `*` matches a single URL path segment. The syntax `**` matches
-// zero or more URL path segments, which must be the last part of the URL path
-// except the `Verb`.
-//
-// The syntax `Variable` matches part of the URL path as specified by its
-// template. A variable template must not contain other variables. If a variable
-// matches a single path segment, its template may be omitted, e.g. `{var}`
-// is equivalent to `{var=*}`.
-//
-// The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL`
-// contains any reserved character, such characters should be percent-encoded
-// before the matching.
-//
-// If a variable contains exactly one path segment, such as `"{var}"` or
-// `"{var=*}"`, when such a variable is expanded into a URL path on the client
-// side, all characters except `[-_.~0-9a-zA-Z]` are percent-encoded. The
-// server side does the reverse decoding. Such variables show up in the
-// [Discovery
-// Document](https://developers.google.com/discovery/v1/reference/apis) as
-// `{var}`.
-//
-// If a variable contains multiple path segments, such as `"{var=foo/*}"`
-// or `"{var=**}"`, when such a variable is expanded into a URL path on the
-// client side, all characters except `[-_.~/0-9a-zA-Z]` are percent-encoded.
-// The server side does the reverse decoding, except "%2F" and "%2f" are left
-// unchanged. Such variables show up in the
-// [Discovery
-// Document](https://developers.google.com/discovery/v1/reference/apis) as
-// `{+var}`.
-//
-// Using gRPC API Service Configuration
-//
-// gRPC API Service Configuration (service config) is a configuration language
-// for configuring a gRPC service to become a user-facing product. The
-// service config is simply the YAML representation of the `google.api.Service`
-// proto message.
-//
-// As an alternative to annotating your proto file, you can configure gRPC
-// transcoding in your service config YAML files. You do this by specifying a
-// `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same
-// effect as the proto annotation. This can be particularly useful if you
-// have a proto that is reused in multiple services. Note that any transcoding
-// specified in the service config will override any matching transcoding
-// configuration in the proto.
-//
-// The following example selects a gRPC method and applies an `HttpRule` to it:
-//
-//     http:
-//       rules:
-//         - selector: example.v1.Messaging.GetMessage
-//           get: /v1/messages/{message_id}/{sub.subfield}
-//
-// Special notes
-//
-// When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the
-// proto to JSON conversion must follow the [proto3
-// specification](https://developers.google.com/protocol-buffers/docs/proto3#json).
-//
-// While the single segment variable follows the semantics of
-// [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 Simple String
-// Expansion, the multi segment variable **does not** follow RFC 6570 Section
-// 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion
-// does not expand special characters like `?` and `#`, which would lead
-// to invalid URLs. As the result, gRPC Transcoding uses a custom encoding
-// for multi segment variables.
-//
-// The path variables **must not** refer to any repeated or mapped field,
-// because client libraries are not capable of handling such variable expansion.
-//
-// The path variables **must not** capture the leading "/" character. The reason
-// is that the most common use case "{var}" does not capture the leading "/"
-// character. For consistency, all path variables must share the same behavior.
-//
-// Repeated message fields must not be mapped to URL query parameters, because
-// no client library can support such complicated mapping.
-//
-// If an API needs to use a JSON array for request or response body, it can map
-// the request or response body to a repeated field. However, some gRPC
-// Transcoding implementations may not support this feature.
-message HttpRule {
-  // Selects a method to which this rule applies.
-  //
-  // Refer to [selector][google.api.DocumentationRule.selector] for syntax
-  // details.
-  string selector = 1;
-
-  // Determines the URL pattern is matched by this rules. This pattern can be
-  // used with any of the {get|put|post|delete|patch} methods. A custom method
-  // can be defined using the 'custom' field.
-  oneof pattern {
-    // Maps to HTTP GET. Used for listing and getting information about
-    // resources.
-    string get = 2;
-
-    // Maps to HTTP PUT. Used for replacing a resource.
-    string put = 3;
-
-    // Maps to HTTP POST. Used for creating a resource or performing an action.
-    string post = 4;
-
-    // Maps to HTTP DELETE. Used for deleting a resource.
-    string delete = 5;
-
-    // Maps to HTTP PATCH. Used for updating a resource.
-    string patch = 6;
-
-    // The custom pattern is used for specifying an HTTP method that is not
-    // included in the `pattern` field, such as HEAD, or "*" to leave the
-    // HTTP method unspecified for this rule. The wild-card rule is useful
-    // for services that provide content to Web (HTML) clients.
-    CustomHttpPattern custom = 8;
-  }
-
-  // The name of the request field whose value is mapped to the HTTP request
-  // body, or `*` for mapping all request fields not captured by the path
-  // pattern to the HTTP body, or omitted for not having any HTTP request body.
-  //
-  // NOTE: the referred field must be present at the top-level of the request
-  // message type.
-  string body = 7;
-
-  // Optional. The name of the response field whose value is mapped to the HTTP
-  // response body. When omitted, the entire response message will be used
-  // as the HTTP response body.
-  //
-  // NOTE: The referred field must be present at the top-level of the response
-  // message type.
-  string response_body = 12;
-
-  // Additional HTTP bindings for the selector. Nested bindings must
-  // not contain an `additional_bindings` field themselves (that is,
-  // the nesting may only be one level deep).
-  repeated HttpRule additional_bindings = 11;
-}
-
-// A custom pattern is used for defining custom HTTP verb.
-message CustomHttpPattern {
-  // The name of this custom HTTP verb.
-  string kind = 1;
-
-  // The path matched by this custom verb.
-  string path = 2;
-}
diff --git a/proto/protoc-gen-openapiv2/options/annotations.proto b/proto/protoc-gen-openapiv2/options/annotations.proto
deleted file mode 100644
--- a/proto/protoc-gen-openapiv2/options/annotations.proto
+++ /dev/null
@@ -1,51 +0,0 @@
-syntax = "proto3";
-
-package grpc.gateway.protoc_gen_openapiv2.options;
-
-import "google/protobuf/descriptor.proto";
-import "protoc-gen-openapiv2/options/openapiv2.proto";
-
-option go_package = "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options";
-
-extend google.protobuf.FileOptions {
-  // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project.
-  //
-  // All IDs are the same, as assigned. It is okay that they are the same, as they extend
-  // different descriptor messages.
-  Swagger openapiv2_swagger = 1042;
-}
-extend google.protobuf.MethodOptions {
-  // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project.
-  //
-  // All IDs are the same, as assigned. It is okay that they are the same, as they extend
-  // different descriptor messages.
-  Operation openapiv2_operation = 1042;
-}
-extend google.protobuf.MessageOptions {
-  // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project.
-  //
-  // All IDs are the same, as assigned. It is okay that they are the same, as they extend
-  // different descriptor messages.
-  Schema openapiv2_schema = 1042;
-}
-extend google.protobuf.EnumOptions {
-  // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project.
-  //
-  // All IDs are the same, as assigned. It is okay that they are the same, as they extend
-  // different descriptor messages.
-  EnumSchema openapiv2_enum = 1042;
-}
-extend google.protobuf.ServiceOptions {
-  // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project.
-  //
-  // All IDs are the same, as assigned. It is okay that they are the same, as they extend
-  // different descriptor messages.
-  Tag openapiv2_tag = 1042;
-}
-extend google.protobuf.FieldOptions {
-  // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project.
-  //
-  // All IDs are the same, as assigned. It is okay that they are the same, as they extend
-  // different descriptor messages.
-  JSONSchema openapiv2_field = 1042;
-}
diff --git a/proto/protoc-gen-openapiv2/options/openapiv2.proto b/proto/protoc-gen-openapiv2/options/openapiv2.proto
deleted file mode 100644
--- a/proto/protoc-gen-openapiv2/options/openapiv2.proto
+++ /dev/null
@@ -1,759 +0,0 @@
-syntax = "proto3";
-
-package grpc.gateway.protoc_gen_openapiv2.options;
-
-import "google/protobuf/struct.proto";
-
-option go_package = "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options";
-
-// Scheme describes the schemes supported by the OpenAPI Swagger
-// and Operation objects.
-enum Scheme {
-  UNKNOWN = 0;
-  HTTP = 1;
-  HTTPS = 2;
-  WS = 3;
-  WSS = 4;
-}
-
-// `Swagger` is a representation of OpenAPI v2 specification's Swagger object.
-//
-// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#swaggerObject
-//
-// Example:
-//
-//  option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
-//    info: {
-//      title: "Echo API";
-//      version: "1.0";
-//      description: "";
-//      contact: {
-//        name: "gRPC-Gateway project";
-//        url: "https://github.com/grpc-ecosystem/grpc-gateway";
-//        email: "none@example.com";
-//      };
-//      license: {
-//        name: "BSD 3-Clause License";
-//        url: "https://github.com/grpc-ecosystem/grpc-gateway/blob/main/LICENSE";
-//      };
-//    };
-//    schemes: HTTPS;
-//    consumes: "application/json";
-//    produces: "application/json";
-//  };
-//
-message Swagger {
-  // Specifies the OpenAPI Specification version being used. It can be
-  // used by the OpenAPI UI and other clients to interpret the API listing. The
-  // value MUST be "2.0".
-  string swagger = 1;
-  // Provides metadata about the API. The metadata can be used by the
-  // clients if needed.
-  Info info = 2;
-  // The host (name or ip) serving the API. This MUST be the host only and does
-  // not include the scheme nor sub-paths. It MAY include a port. If the host is
-  // not included, the host serving the documentation is to be used (including
-  // the port). The host does not support path templating.
-  string host = 3;
-  // The base path on which the API is served, which is relative to the host. If
-  // it is not included, the API is served directly under the host. The value
-  // MUST start with a leading slash (/). The basePath does not support path
-  // templating.
-  // Note that using `base_path` does not change the endpoint paths that are
-  // generated in the resulting OpenAPI file. If you wish to use `base_path`
-  // with relatively generated OpenAPI paths, the `base_path` prefix must be
-  // manually removed from your `google.api.http` paths and your code changed to
-  // serve the API from the `base_path`.
-  string base_path = 4;
-  // The transfer protocol of the API. Values MUST be from the list: "http",
-  // "https", "ws", "wss". If the schemes is not included, the default scheme to
-  // be used is the one used to access the OpenAPI definition itself.
-  repeated Scheme schemes = 5;
-  // A list of MIME types the APIs can consume. This is global to all APIs but
-  // can be overridden on specific API calls. Value MUST be as described under
-  // Mime Types.
-  repeated string consumes = 6;
-  // A list of MIME types the APIs can produce. This is global to all APIs but
-  // can be overridden on specific API calls. Value MUST be as described under
-  // Mime Types.
-  repeated string produces = 7;
-  // field 8 is reserved for 'paths'.
-  reserved 8;
-  // field 9 is reserved for 'definitions', which at this time are already
-  // exposed as and customizable as proto messages.
-  reserved 9;
-  // An object to hold responses that can be used across operations. This
-  // property does not define global responses for all operations.
-  map<string, Response> responses = 10;
-  // Security scheme definitions that can be used across the specification.
-  SecurityDefinitions security_definitions = 11;
-  // A declaration of which security schemes are applied for the API as a whole.
-  // The list of values describes alternative security schemes that can be used
-  // (that is, there is a logical OR between the security requirements).
-  // Individual operations can override this definition.
-  repeated SecurityRequirement security = 12;
-  // A list of tags for API documentation control. Tags can be used for logical
-  // grouping of operations by resources or any other qualifier.
-  repeated Tag tags = 13;
-  // Additional external documentation.
-  ExternalDocumentation external_docs = 14;
-  // Custom properties that start with "x-" such as "x-foo" used to describe
-  // extra functionality that is not covered by the standard OpenAPI Specification.
-  // See: https://swagger.io/docs/specification/2-0/swagger-extensions/
-  map<string, google.protobuf.Value> extensions = 15;
-}
-
-// `Operation` is a representation of OpenAPI v2 specification's Operation object.
-//
-// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#operationObject
-//
-// Example:
-//
-//  service EchoService {
-//    rpc Echo(SimpleMessage) returns (SimpleMessage) {
-//      option (google.api.http) = {
-//        get: "/v1/example/echo/{id}"
-//      };
-//
-//      option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
-//        summary: "Get a message.";
-//        operation_id: "getMessage";
-//        tags: "echo";
-//        responses: {
-//          key: "200"
-//            value: {
-//            description: "OK";
-//          }
-//        }
-//      };
-//    }
-//  }
-message Operation {
-  // A list of tags for API documentation control. Tags can be used for logical
-  // grouping of operations by resources or any other qualifier.
-  repeated string tags = 1;
-  // A short summary of what the operation does. For maximum readability in the
-  // swagger-ui, this field SHOULD be less than 120 characters.
-  string summary = 2;
-  // A verbose explanation of the operation behavior. GFM syntax can be used for
-  // rich text representation.
-  string description = 3;
-  // Additional external documentation for this operation.
-  ExternalDocumentation external_docs = 4;
-  // Unique string used to identify the operation. The id MUST be unique among
-  // all operations described in the API. Tools and libraries MAY use the
-  // operationId to uniquely identify an operation, therefore, it is recommended
-  // to follow common programming naming conventions.
-  string operation_id = 5;
-  // A list of MIME types the operation can consume. This overrides the consumes
-  // definition at the OpenAPI Object. An empty value MAY be used to clear the
-  // global definition. Value MUST be as described under Mime Types.
-  repeated string consumes = 6;
-  // A list of MIME types the operation can produce. This overrides the produces
-  // definition at the OpenAPI Object. An empty value MAY be used to clear the
-  // global definition. Value MUST be as described under Mime Types.
-  repeated string produces = 7;
-  // field 8 is reserved for 'parameters'.
-  reserved 8;
-  // The list of possible responses as they are returned from executing this
-  // operation.
-  map<string, Response> responses = 9;
-  // The transfer protocol for the operation. Values MUST be from the list:
-  // "http", "https", "ws", "wss". The value overrides the OpenAPI Object
-  // schemes definition.
-  repeated Scheme schemes = 10;
-  // Declares this operation to be deprecated. Usage of the declared operation
-  // should be refrained. Default value is false.
-  bool deprecated = 11;
-  // A declaration of which security schemes are applied for this operation. The
-  // list of values describes alternative security schemes that can be used
-  // (that is, there is a logical OR between the security requirements). This
-  // definition overrides any declared top-level security. To remove a top-level
-  // security declaration, an empty array can be used.
-  repeated SecurityRequirement security = 12;
-  // Custom properties that start with "x-" such as "x-foo" used to describe
-  // extra functionality that is not covered by the standard OpenAPI Specification.
-  // See: https://swagger.io/docs/specification/2-0/swagger-extensions/
-  map<string, google.protobuf.Value> extensions = 13;
-  // Custom parameters such as HTTP request headers.
-  // See: https://swagger.io/docs/specification/2-0/describing-parameters/
-  // and https://swagger.io/specification/v2/#parameter-object.
-  Parameters parameters = 14;
-}
-
-// `Parameters` is a representation of OpenAPI v2 specification's parameters object.
-// Note: This technically breaks compatibility with the OpenAPI 2 definition structure as we only
-// allow header parameters to be set here since we do not want users specifying custom non-header
-// parameters beyond those inferred from the Protobuf schema.
-// See: https://swagger.io/specification/v2/#parameter-object
-message Parameters {
-  // `Headers` is one or more HTTP header parameter.
-  // See: https://swagger.io/docs/specification/2-0/describing-parameters/#header-parameters
-  repeated HeaderParameter headers = 1;
-}
-
-// `HeaderParameter` a HTTP header parameter.
-// See: https://swagger.io/specification/v2/#parameter-object
-message HeaderParameter {
-  // `Type` is a supported HTTP header type.
-  // See https://swagger.io/specification/v2/#parameterType.
-  enum Type {
-    UNKNOWN = 0;
-    STRING = 1;
-    NUMBER = 2;
-    INTEGER = 3;
-    BOOLEAN = 4;
-  }
-
-  // `Name` is the header name.
-  string name = 1;
-  // `Description` is a short description of the header.
-  string description = 2;
-  // `Type` is the type of the object. The value MUST be one of "string", "number", "integer", or "boolean". The "array" type is not supported.
-  // See: https://swagger.io/specification/v2/#parameterType.
-  Type type = 3;
-  // `Format` The extending format for the previously mentioned type.
-  string format = 4;
-  // `Required` indicates if the header is optional
-  bool required = 5;
-  // field 6 is reserved for 'items', but in OpenAPI-specific way.
-  reserved 6;
-  // field 7 is reserved `Collection Format`. Determines the format of the array if type array is used.
-  reserved 7;
-}
-
-// `Header` is a representation of OpenAPI v2 specification's Header object.
-//
-// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#headerObject
-//
-message Header {
-  // `Description` is a short description of the header.
-  string description = 1;
-  // The type of the object. The value MUST be one of "string", "number", "integer", or "boolean". The "array" type is not supported.
-  string type = 2;
-  // `Format` The extending format for the previously mentioned type.
-  string format = 3;
-  // field 4 is reserved for 'items', but in OpenAPI-specific way.
-  reserved 4;
-  // field 5 is reserved `Collection Format` Determines the format of the array if type array is used.
-  reserved 5;
-  // `Default` Declares the value of the header that the server will use if none is provided.
-  // See: https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-6.2.
-  // Unlike JSON Schema this value MUST conform to the defined type for the header.
-  string default = 6;
-  // field 7 is reserved for 'maximum'.
-  reserved 7;
-  // field 8 is reserved for 'exclusiveMaximum'.
-  reserved 8;
-  // field 9 is reserved for 'minimum'.
-  reserved 9;
-  // field 10 is reserved for 'exclusiveMinimum'.
-  reserved 10;
-  // field 11 is reserved for 'maxLength'.
-  reserved 11;
-  // field 12 is reserved for 'minLength'.
-  reserved 12;
-  // 'Pattern' See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.2.3.
-  string pattern = 13;
-  // field 14 is reserved for 'maxItems'.
-  reserved 14;
-  // field 15 is reserved for 'minItems'.
-  reserved 15;
-  // field 16 is reserved for 'uniqueItems'.
-  reserved 16;
-  // field 17 is reserved for 'enum'.
-  reserved 17;
-  // field 18 is reserved for 'multipleOf'.
-  reserved 18;
-}
-
-// `Response` is a representation of OpenAPI v2 specification's Response object.
-//
-// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#responseObject
-//
-message Response {
-  // `Description` is a short description of the response.
-  // GFM syntax can be used for rich text representation.
-  string description = 1;
-  // `Schema` optionally defines the structure of the response.
-  // If `Schema` is not provided, it means there is no content to the response.
-  Schema schema = 2;
-  // `Headers` A list of headers that are sent with the response.
-  // `Header` name is expected to be a string in the canonical format of the MIME header key
-  // See: https://golang.org/pkg/net/textproto/#CanonicalMIMEHeaderKey
-  map<string, Header> headers = 3;
-  // `Examples` gives per-mimetype response examples.
-  // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#example-object
-  map<string, string> examples = 4;
-  // Custom properties that start with "x-" such as "x-foo" used to describe
-  // extra functionality that is not covered by the standard OpenAPI Specification.
-  // See: https://swagger.io/docs/specification/2-0/swagger-extensions/
-  map<string, google.protobuf.Value> extensions = 5;
-}
-
-// `Info` is a representation of OpenAPI v2 specification's Info object.
-//
-// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#infoObject
-//
-// Example:
-//
-//  option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
-//    info: {
-//      title: "Echo API";
-//      version: "1.0";
-//      description: "";
-//      contact: {
-//        name: "gRPC-Gateway project";
-//        url: "https://github.com/grpc-ecosystem/grpc-gateway";
-//        email: "none@example.com";
-//      };
-//      license: {
-//        name: "BSD 3-Clause License";
-//        url: "https://github.com/grpc-ecosystem/grpc-gateway/blob/main/LICENSE";
-//      };
-//    };
-//    ...
-//  };
-//
-message Info {
-  // The title of the application.
-  string title = 1;
-  // A short description of the application. GFM syntax can be used for rich
-  // text representation.
-  string description = 2;
-  // The Terms of Service for the API.
-  string terms_of_service = 3;
-  // The contact information for the exposed API.
-  Contact contact = 4;
-  // The license information for the exposed API.
-  License license = 5;
-  // Provides the version of the application API (not to be confused
-  // with the specification version).
-  string version = 6;
-  // Custom properties that start with "x-" such as "x-foo" used to describe
-  // extra functionality that is not covered by the standard OpenAPI Specification.
-  // See: https://swagger.io/docs/specification/2-0/swagger-extensions/
-  map<string, google.protobuf.Value> extensions = 7;
-}
-
-// `Contact` is a representation of OpenAPI v2 specification's Contact object.
-//
-// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#contactObject
-//
-// Example:
-//
-//  option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
-//    info: {
-//      ...
-//      contact: {
-//        name: "gRPC-Gateway project";
-//        url: "https://github.com/grpc-ecosystem/grpc-gateway";
-//        email: "none@example.com";
-//      };
-//      ...
-//    };
-//    ...
-//  };
-//
-message Contact {
-  // The identifying name of the contact person/organization.
-  string name = 1;
-  // The URL pointing to the contact information. MUST be in the format of a
-  // URL.
-  string url = 2;
-  // The email address of the contact person/organization. MUST be in the format
-  // of an email address.
-  string email = 3;
-}
-
-// `License` is a representation of OpenAPI v2 specification's License object.
-//
-// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#licenseObject
-//
-// Example:
-//
-//  option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
-//    info: {
-//      ...
-//      license: {
-//        name: "BSD 3-Clause License";
-//        url: "https://github.com/grpc-ecosystem/grpc-gateway/blob/main/LICENSE";
-//      };
-//      ...
-//    };
-//    ...
-//  };
-//
-message License {
-  // The license name used for the API.
-  string name = 1;
-  // A URL to the license used for the API. MUST be in the format of a URL.
-  string url = 2;
-}
-
-// `ExternalDocumentation` is a representation of OpenAPI v2 specification's
-// ExternalDocumentation object.
-//
-// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#externalDocumentationObject
-//
-// Example:
-//
-//  option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
-//    ...
-//    external_docs: {
-//      description: "More about gRPC-Gateway";
-//      url: "https://github.com/grpc-ecosystem/grpc-gateway";
-//    }
-//    ...
-//  };
-//
-message ExternalDocumentation {
-  // A short description of the target documentation. GFM syntax can be used for
-  // rich text representation.
-  string description = 1;
-  // The URL for the target documentation. Value MUST be in the format
-  // of a URL.
-  string url = 2;
-}
-
-// `Schema` is a representation of OpenAPI v2 specification's Schema object.
-//
-// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject
-//
-message Schema {
-  JSONSchema json_schema = 1;
-  // Adds support for polymorphism. The discriminator is the schema property
-  // name that is used to differentiate between other schema that inherit this
-  // schema. The property name used MUST be defined at this schema and it MUST
-  // be in the required property list. When used, the value MUST be the name of
-  // this schema or any schema that inherits it.
-  string discriminator = 2;
-  // Relevant only for Schema "properties" definitions. Declares the property as
-  // "read only". This means that it MAY be sent as part of a response but MUST
-  // NOT be sent as part of the request. Properties marked as readOnly being
-  // true SHOULD NOT be in the required list of the defined schema. Default
-  // value is false.
-  bool read_only = 3;
-  // field 4 is reserved for 'xml'.
-  reserved 4;
-  // Additional external documentation for this schema.
-  ExternalDocumentation external_docs = 5;
-  // A free-form property to include an example of an instance for this schema in JSON.
-  // This is copied verbatim to the output.
-  string example = 6;
-}
-
-// `EnumSchema` is subset of fields from the OpenAPI v2 specification's Schema object.
-// Only fields that are applicable to Enums are included
-// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject
-//
-// Example:
-//
-//  option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_enum) = {
-//    ...
-//    title: "MyEnum";
-//    description:"This is my nice enum";
-//    example: "ZERO";
-//    required: true;
-//    ...
-//  };
-//
-message EnumSchema {
-  // A short description of the schema.
-  string description = 1;
-  string default = 2;
-  // The title of the schema.
-  string title = 3;
-  bool required = 4;
-  bool read_only = 5;
-  // Additional external documentation for this schema.
-  ExternalDocumentation external_docs = 6;
-  string example = 7;
-  // Ref is used to define an external reference to include in the message.
-  // This could be a fully qualified proto message reference, and that type must
-  // be imported into the protofile. If no message is identified, the Ref will
-  // be used verbatim in the output.
-  // For example:
-  //  `ref: ".google.protobuf.Timestamp"`.
-  string ref = 8;
-  // Custom properties that start with "x-" such as "x-foo" used to describe
-  // extra functionality that is not covered by the standard OpenAPI Specification.
-  // See: https://swagger.io/docs/specification/2-0/swagger-extensions/
-  map<string, google.protobuf.Value> extensions = 9;
-}
-
-// `JSONSchema` represents properties from JSON Schema taken, and as used, in
-// the OpenAPI v2 spec.
-//
-// This includes changes made by OpenAPI v2.
-//
-// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject
-//
-// See also: https://cswr.github.io/JsonSchema/spec/basic_types/,
-// https://github.com/json-schema-org/json-schema-spec/blob/master/schema.json
-//
-// Example:
-//
-//  message SimpleMessage {
-//    option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema) = {
-//      json_schema: {
-//        title: "SimpleMessage"
-//        description: "A simple message."
-//        required: ["id"]
-//      }
-//    };
-//
-//    // Id represents the message identifier.
-//    string id = 1; [
-//        (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
-//          description: "The unique identifier of the simple message."
-//        }];
-//  }
-//
-message JSONSchema {
-  // field 1 is reserved for '$id', omitted from OpenAPI v2.
-  reserved 1;
-  // field 2 is reserved for '$schema', omitted from OpenAPI v2.
-  reserved 2;
-  // Ref is used to define an external reference to include in the message.
-  // This could be a fully qualified proto message reference, and that type must
-  // be imported into the protofile. If no message is identified, the Ref will
-  // be used verbatim in the output.
-  // For example:
-  //  `ref: ".google.protobuf.Timestamp"`.
-  string ref = 3;
-  // field 4 is reserved for '$comment', omitted from OpenAPI v2.
-  reserved 4;
-  // The title of the schema.
-  string title = 5;
-  // A short description of the schema.
-  string description = 6;
-  string default = 7;
-  bool read_only = 8;
-  // A free-form property to include a JSON example of this field. This is copied
-  // verbatim to the output swagger.json. Quotes must be escaped.
-  // This property is the same for 2.0 and 3.0.0 https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/3.0.0.md#schemaObject  https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject
-  string example = 9;
-  double multiple_of = 10;
-  // Maximum represents an inclusive upper limit for a numeric instance. The
-  // value of MUST be a number,
-  double maximum = 11;
-  bool exclusive_maximum = 12;
-  // minimum represents an inclusive lower limit for a numeric instance. The
-  // value of MUST be a number,
-  double minimum = 13;
-  bool exclusive_minimum = 14;
-  uint64 max_length = 15;
-  uint64 min_length = 16;
-  string pattern = 17;
-  // field 18 is reserved for 'additionalItems', omitted from OpenAPI v2.
-  reserved 18;
-  // field 19 is reserved for 'items', but in OpenAPI-specific way.
-  // TODO(ivucica): add 'items'?
-  reserved 19;
-  uint64 max_items = 20;
-  uint64 min_items = 21;
-  bool unique_items = 22;
-  // field 23 is reserved for 'contains', omitted from OpenAPI v2.
-  reserved 23;
-  uint64 max_properties = 24;
-  uint64 min_properties = 25;
-  repeated string required = 26;
-  // field 27 is reserved for 'additionalProperties', but in OpenAPI-specific
-  // way. TODO(ivucica): add 'additionalProperties'?
-  reserved 27;
-  // field 28 is reserved for 'definitions', omitted from OpenAPI v2.
-  reserved 28;
-  // field 29 is reserved for 'properties', but in OpenAPI-specific way.
-  // TODO(ivucica): add 'additionalProperties'?
-  reserved 29;
-  // following fields are reserved, as the properties have been omitted from
-  // OpenAPI v2:
-  // patternProperties, dependencies, propertyNames, const
-  reserved 30 to 33;
-  // Items in 'array' must be unique.
-  repeated string array = 34;
-
-  enum JSONSchemaSimpleTypes {
-    UNKNOWN = 0;
-    ARRAY = 1;
-    BOOLEAN = 2;
-    INTEGER = 3;
-    NULL = 4;
-    NUMBER = 5;
-    OBJECT = 6;
-    STRING = 7;
-  }
-
-  repeated JSONSchemaSimpleTypes type = 35;
-  // `Format`
-  string format = 36;
-  // following fields are reserved, as the properties have been omitted from
-  // OpenAPI v2: contentMediaType, contentEncoding, if, then, else
-  reserved 37 to 41;
-  // field 42 is reserved for 'allOf', but in OpenAPI-specific way.
-  // TODO(ivucica): add 'allOf'?
-  reserved 42;
-  // following fields are reserved, as the properties have been omitted from
-  // OpenAPI v2:
-  // anyOf, oneOf, not
-  reserved 43 to 45;
-  // Items in `enum` must be unique https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.5.1
-  repeated string enum = 46;
-
-  // Additional field level properties used when generating the OpenAPI v2 file.
-  FieldConfiguration field_configuration = 1001;
-
-  // 'FieldConfiguration' provides additional field level properties used when generating the OpenAPI v2 file.
-  // These properties are not defined by OpenAPIv2, but they are used to control the generation.
-  message FieldConfiguration {
-    // Alternative parameter name when used as path parameter. If set, this will
-    // be used as the complete parameter name when this field is used as a path
-    // parameter. Use this to avoid having auto generated path parameter names
-    // for overlapping paths.
-    string path_param_name = 47;
-  }
-  // Custom properties that start with "x-" such as "x-foo" used to describe
-  // extra functionality that is not covered by the standard OpenAPI Specification.
-  // See: https://swagger.io/docs/specification/2-0/swagger-extensions/
-  map<string, google.protobuf.Value> extensions = 48;
-}
-
-// `Tag` is a representation of OpenAPI v2 specification's Tag object.
-//
-// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#tagObject
-//
-message Tag {
-  // The name of the tag. Use it to allow override of the name of a
-  // global Tag object, then use that name to reference the tag throughout the
-  // OpenAPI file.
-  string name = 1;
-  // A short description for the tag. GFM syntax can be used for rich text
-  // representation.
-  string description = 2;
-  // Additional external documentation for this tag.
-  ExternalDocumentation external_docs = 3;
-  // Custom properties that start with "x-" such as "x-foo" used to describe
-  // extra functionality that is not covered by the standard OpenAPI Specification.
-  // See: https://swagger.io/docs/specification/2-0/swagger-extensions/
-  map<string, google.protobuf.Value> extensions = 4;
-}
-
-// `SecurityDefinitions` is a representation of OpenAPI v2 specification's
-// Security Definitions object.
-//
-// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#securityDefinitionsObject
-//
-// A declaration of the security schemes available to be used in the
-// specification. This does not enforce the security schemes on the operations
-// and only serves to provide the relevant details for each scheme.
-message SecurityDefinitions {
-  // A single security scheme definition, mapping a "name" to the scheme it
-  // defines.
-  map<string, SecurityScheme> security = 1;
-}
-
-// `SecurityScheme` is a representation of OpenAPI v2 specification's
-// Security Scheme object.
-//
-// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#securitySchemeObject
-//
-// Allows the definition of a security scheme that can be used by the
-// operations. Supported schemes are basic authentication, an API key (either as
-// a header or as a query parameter) and OAuth2's common flows (implicit,
-// password, application and access code).
-message SecurityScheme {
-  // The type of the security scheme. Valid values are "basic",
-  // "apiKey" or "oauth2".
-  enum Type {
-    TYPE_INVALID = 0;
-    TYPE_BASIC = 1;
-    TYPE_API_KEY = 2;
-    TYPE_OAUTH2 = 3;
-  }
-
-  // The location of the API key. Valid values are "query" or "header".
-  enum In {
-    IN_INVALID = 0;
-    IN_QUERY = 1;
-    IN_HEADER = 2;
-  }
-
-  // The flow used by the OAuth2 security scheme. Valid values are
-  // "implicit", "password", "application" or "accessCode".
-  enum Flow {
-    FLOW_INVALID = 0;
-    FLOW_IMPLICIT = 1;
-    FLOW_PASSWORD = 2;
-    FLOW_APPLICATION = 3;
-    FLOW_ACCESS_CODE = 4;
-  }
-
-  // The type of the security scheme. Valid values are "basic",
-  // "apiKey" or "oauth2".
-  Type type = 1;
-  // A short description for security scheme.
-  string description = 2;
-  // The name of the header or query parameter to be used.
-  // Valid for apiKey.
-  string name = 3;
-  // The location of the API key. Valid values are "query" or
-  // "header".
-  // Valid for apiKey.
-  In in = 4;
-  // The flow used by the OAuth2 security scheme. Valid values are
-  // "implicit", "password", "application" or "accessCode".
-  // Valid for oauth2.
-  Flow flow = 5;
-  // The authorization URL to be used for this flow. This SHOULD be in
-  // the form of a URL.
-  // Valid for oauth2/implicit and oauth2/accessCode.
-  string authorization_url = 6;
-  // The token URL to be used for this flow. This SHOULD be in the
-  // form of a URL.
-  // Valid for oauth2/password, oauth2/application and oauth2/accessCode.
-  string token_url = 7;
-  // The available scopes for the OAuth2 security scheme.
-  // Valid for oauth2.
-  Scopes scopes = 8;
-  // Custom properties that start with "x-" such as "x-foo" used to describe
-  // extra functionality that is not covered by the standard OpenAPI Specification.
-  // See: https://swagger.io/docs/specification/2-0/swagger-extensions/
-  map<string, google.protobuf.Value> extensions = 9;
-}
-
-// `SecurityRequirement` is a representation of OpenAPI v2 specification's
-// Security Requirement object.
-//
-// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#securityRequirementObject
-//
-// Lists the required security schemes to execute this operation. The object can
-// have multiple security schemes declared in it which are all required (that
-// is, there is a logical AND between the schemes).
-//
-// The name used for each property MUST correspond to a security scheme
-// declared in the Security Definitions.
-message SecurityRequirement {
-  // If the security scheme is of type "oauth2", then the value is a list of
-  // scope names required for the execution. For other security scheme types,
-  // the array MUST be empty.
-  message SecurityRequirementValue {
-    repeated string scope = 1;
-  }
-  // Each name must correspond to a security scheme which is declared in
-  // the Security Definitions. If the security scheme is of type "oauth2",
-  // then the value is a list of scope names required for the execution.
-  // For other security scheme types, the array MUST be empty.
-  map<string, SecurityRequirementValue> security_requirement = 1;
-}
-
-// `Scopes` is a representation of OpenAPI v2 specification's Scopes object.
-//
-// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#scopesObject
-//
-// Lists the available scopes for an OAuth2 security scheme.
-message Scopes {
-  // Maps between a name of a scope to a short description of it (as the value
-  // of the property).
-  map<string, string> scope = 1;
-}
diff --git a/src/Network/GRPC/Etcd.hs b/src/Network/GRPC/Etcd.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/GRPC/Etcd.hs
@@ -0,0 +1,43 @@
+{-# OPTIONS_GHC -Wno-missing-import-lists #-}
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module Network.GRPC.Etcd (
+    module Proto.API.Etcd,
+) where
+
+import Network.GRPC.Common (
+    NoMetadata,
+    RequestMetadata,
+    ResponseInitialMetadata,
+    ResponseTrailingMetadata,
+ )
+import Network.GRPC.Common.Protobuf (Protobuf)
+import Proto.API.Etcd
+
+{-------------------------------------------------------------------------------
+  Metadata
+-------------------------------------------------------------------------------}
+
+type instance RequestMetadata (Protobuf Auth meth) = NoMetadata
+type instance ResponseInitialMetadata (Protobuf Auth meth) = NoMetadata
+type instance ResponseTrailingMetadata (Protobuf Auth meth) = NoMetadata
+
+type instance RequestMetadata (Protobuf Cluster meth) = NoMetadata
+type instance ResponseInitialMetadata (Protobuf Cluster meth) = NoMetadata
+type instance ResponseTrailingMetadata (Protobuf Cluster meth) = NoMetadata
+
+type instance RequestMetadata (Protobuf KV meth) = NoMetadata
+type instance ResponseInitialMetadata (Protobuf KV meth) = NoMetadata
+type instance ResponseTrailingMetadata (Protobuf KV meth) = NoMetadata
+
+type instance RequestMetadata (Protobuf Lease meth) = NoMetadata
+type instance ResponseInitialMetadata (Protobuf Lease meth) = NoMetadata
+type instance ResponseTrailingMetadata (Protobuf Lease meth) = NoMetadata
+
+type instance RequestMetadata (Protobuf Maintenance meth) = NoMetadata
+type instance ResponseInitialMetadata (Protobuf Maintenance meth) = NoMetadata
+type instance ResponseTrailingMetadata (Protobuf Maintenance meth) = NoMetadata
+
+type instance RequestMetadata (Protobuf Watch meth) = NoMetadata
+type instance ResponseInitialMetadata (Protobuf Watch meth) = NoMetadata
+type instance ResponseTrailingMetadata (Protobuf Watch meth) = NoMetadata
diff --git a/src/Network/GRPC/Etcd/Client/Simple.hs b/src/Network/GRPC/Etcd/Client/Simple.hs
--- a/src/Network/GRPC/Etcd/Client/Simple.hs
+++ b/src/Network/GRPC/Etcd/Client/Simple.hs
@@ -12,7 +12,7 @@
 import Network.GRPC.Client.StreamType.IO (biDiStreaming, nonStreaming)
 import Network.GRPC.Common.NextElem qualified as NextElem
 import Network.GRPC.Common.Protobuf (Proto, Protobuf)
-import Proto.API.Etcd (KV, PutRequest, PutResponse, RangeRequest, RangeResponse, Watch, WatchRequest, WatchResponse)
+import Network.GRPC.Etcd (KV, PutRequest, PutResponse, RangeRequest, RangeResponse, Watch, WatchRequest, WatchResponse)
 
 put :: (MonadIO m) => (MonadMask m) => Connection -> Proto PutRequest -> m (Proto PutResponse)
 put conn = nonStreaming conn (rpc @(Protobuf KV "put"))
diff --git a/src/Proto/API/Etcd.hs b/src/Proto/API/Etcd.hs
deleted file mode 100644
--- a/src/Proto/API/Etcd.hs
+++ /dev/null
@@ -1,26 +0,0 @@
-{-# OPTIONS_GHC -Wno-orphans #-}
-
-module Proto.API.Etcd (
-    module Proto.Etcd.Api.Etcdserverpb.Rpc,
-) where
-
-import Network.GRPC.Common (
-    NoMetadata,
-    RequestMetadata,
-    ResponseInitialMetadata,
-    ResponseTrailingMetadata,
- )
-import Network.GRPC.Common.Protobuf (Protobuf)
-import Proto.Etcd.Api.Etcdserverpb.Rpc (KV, PutRequest, PutResponse, RangeRequest, RangeResponse, Watch, WatchRequest, WatchResponse)
-
-{-------------------------------------------------------------------------------
-  Metadata
--------------------------------------------------------------------------------}
-
-type instance RequestMetadata (Protobuf KV meth) = NoMetadata
-type instance ResponseInitialMetadata (Protobuf KV meth) = NoMetadata
-type instance ResponseTrailingMetadata (Protobuf KV meth) = NoMetadata
-
-type instance RequestMetadata (Protobuf Watch meth) = NoMetadata
-type instance ResponseInitialMetadata (Protobuf Watch meth) = NoMetadata
-type instance ResponseTrailingMetadata (Protobuf Watch meth) = NoMetadata
