diff --git a/go.mod b/go.mod
index dfb34e4858..4eaa18ccc8 100644
--- a/go.mod
+++ b/go.mod
@@ -14,8 +14,8 @@ require (
 	github.com/gorilla/websocket v1.5.1
 	github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
 	github.com/mitchellh/mapstructure v1.5.0
-	github.com/openimsdk/protocol v0.0.72-alpha.63
-	github.com/openimsdk/tools v0.0.50-alpha.52
+	github.com/openimsdk/protocol v0.0.72-alpha.66
+	github.com/openimsdk/tools v0.0.50-alpha.57
 	github.com/pkg/errors v0.9.1 // indirect
 	github.com/prometheus/client_golang v1.18.0
 	github.com/stretchr/testify v1.9.0
diff --git a/go.sum b/go.sum
index 16423b7722..6e283eb668 100644
--- a/go.sum
+++ b/go.sum
@@ -347,10 +347,10 @@ github.com/onsi/gomega v1.25.0 h1:Vw7br2PCDYijJHSfBOWhov+8cAnUf8MfMaIOV323l6Y=
 github.com/onsi/gomega v1.25.0/go.mod h1:r+zV744Re+DiYCIPRlYOTxn0YkOLcAnW8k1xXdMPGhM=
 github.com/openimsdk/gomake v0.0.15-alpha.2 h1:5Q8yl8ezy2yx+q8/ucU/t4kJnDfCzNOrkXcDACCqtyM=
 github.com/openimsdk/gomake v0.0.15-alpha.2/go.mod h1:PndCozNc2IsQIciyn9mvEblYWZwJmAI+06z94EY+csI=
-github.com/openimsdk/protocol v0.0.72-alpha.63 h1:IyPBibEvwBtTmD8DSrlqcekfEXe74k4+KeeHsgdhGh0=
-github.com/openimsdk/protocol v0.0.72-alpha.63/go.mod h1:Iet+piS/jaS+kWWyj6EEr36mk4ISzIRYjoMSVA4dq2M=
-github.com/openimsdk/tools v0.0.50-alpha.52 h1:SAxnn6xgHPcEBHTebNLFgvUqmxd4d2XpBBh9jHpUEvs=
-github.com/openimsdk/tools v0.0.50-alpha.52/go.mod h1:muCtxguNJv8lFwLei27UASu2Nvg4ERSeN0R4K5tivk0=
+github.com/openimsdk/protocol v0.0.72-alpha.66 h1:5KoDY6M4T+pXg449ScF6hqeQ+WenBwNyUJn/t8W0oBQ=
+github.com/openimsdk/protocol v0.0.72-alpha.66/go.mod h1:Iet+piS/jaS+kWWyj6EEr36mk4ISzIRYjoMSVA4dq2M=
+github.com/openimsdk/tools v0.0.50-alpha.57 h1:oIKV6vYhqp7TRmZ6Pe+r9RNl1D5s7aB/kE9yQVEWcSY=
+github.com/openimsdk/tools v0.0.50-alpha.57/go.mod h1:muCtxguNJv8lFwLei27UASu2Nvg4ERSeN0R4K5tivk0=
 github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
 github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
 github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
diff --git a/internal/api/auth.go b/internal/api/auth.go
index f41b530bf1..c7e7ff7046 100644
--- a/internal/api/auth.go
+++ b/internal/api/auth.go
@@ -16,29 +16,28 @@ package api
 
 import (
 	"github.com/gin-gonic/gin"
-	"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
 	"github.com/openimsdk/protocol/auth"
 	"github.com/openimsdk/tools/a2r"
 )
 
-type AuthApi rpcclient.Auth
+type AuthApi struct{}
 
-func NewAuthApi(client rpcclient.Auth) AuthApi {
-	return AuthApi(client)
+func NewAuthApi() AuthApi {
+	return AuthApi{}
 }
 
 func (o *AuthApi) GetAdminToken(c *gin.Context) {
-	a2r.Call(auth.AuthClient.GetAdminToken, o.Client, c)
+	a2r.CallV2(c, auth.GetAdminTokenCaller.Invoke)
 }
 
 func (o *AuthApi) GetUserToken(c *gin.Context) {
-	a2r.Call(auth.AuthClient.GetUserToken, o.Client, c)
+	a2r.CallV2(c, auth.GetUserTokenCaller.Invoke)
 }
 
 func (o *AuthApi) ParseToken(c *gin.Context) {
-	a2r.Call(auth.AuthClient.ParseToken, o.Client, c)
+	a2r.CallV2(c, auth.ParseTokenCaller.Invoke)
 }
 
 func (o *AuthApi) ForceLogout(c *gin.Context) {
-	a2r.Call(auth.AuthClient.ForceLogout, o.Client, c)
+	a2r.CallV2(c, auth.ForceLogoutCaller.Invoke)
 }
diff --git a/internal/api/conversation.go b/internal/api/conversation.go
index 8e3a3ca82d..4004944e55 100644
--- a/internal/api/conversation.go
+++ b/internal/api/conversation.go
@@ -16,57 +16,56 @@ package api
 
 import (
 	"github.com/gin-gonic/gin"
-	"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
 	"github.com/openimsdk/protocol/conversation"
 	"github.com/openimsdk/tools/a2r"
 )
 
-type ConversationApi rpcclient.Conversation
+type ConversationApi struct{}
 
-func NewConversationApi(client rpcclient.Conversation) ConversationApi {
-	return ConversationApi(client)
+func NewConversationApi() ConversationApi {
+	return ConversationApi{}
 }
 
 func (o *ConversationApi) GetAllConversations(c *gin.Context) {
-	a2r.Call(conversation.ConversationClient.GetAllConversations, o.Client, c)
+	a2r.CallV2(c, conversation.GetAllConversationsCaller.Invoke)
 }
 
 func (o *ConversationApi) GetSortedConversationList(c *gin.Context) {
-	a2r.Call(conversation.ConversationClient.GetSortedConversationList, o.Client, c)
+	a2r.CallV2(c, conversation.GetSortedConversationListCaller.Invoke)
 }
 
 func (o *ConversationApi) GetConversation(c *gin.Context) {
-	a2r.Call(conversation.ConversationClient.GetConversation, o.Client, c)
+	a2r.CallV2(c, conversation.GetConversationCaller.Invoke)
 }
 
 func (o *ConversationApi) GetConversations(c *gin.Context) {
-	a2r.Call(conversation.ConversationClient.GetConversations, o.Client, c)
+	a2r.CallV2(c, conversation.GetConversationsCaller.Invoke)
 }
 
 func (o *ConversationApi) SetConversations(c *gin.Context) {
-	a2r.Call(conversation.ConversationClient.SetConversations, o.Client, c)
+	a2r.CallV2(c, conversation.SetConversationsCaller.Invoke)
 }
 
 func (o *ConversationApi) GetConversationOfflinePushUserIDs(c *gin.Context) {
-	a2r.Call(conversation.ConversationClient.GetConversationOfflinePushUserIDs, o.Client, c)
+	a2r.CallV2(c, conversation.GetConversationOfflinePushUserIDsCaller.Invoke)
 }
 
 func (o *ConversationApi) GetFullOwnerConversationIDs(c *gin.Context) {
-	a2r.Call(conversation.ConversationClient.GetFullOwnerConversationIDs, o.Client, c)
+	a2r.CallV2(c, conversation.GetFullOwnerConversationIDsCaller.Invoke)
 }
 
 func (o *ConversationApi) GetIncrementalConversation(c *gin.Context) {
-	a2r.Call(conversation.ConversationClient.GetIncrementalConversation, o.Client, c)
+	a2r.CallV2(c, conversation.GetIncrementalConversationCaller.Invoke)
 }
 
 func (o *ConversationApi) GetOwnerConversation(c *gin.Context) {
-	a2r.Call(conversation.ConversationClient.GetOwnerConversation, o.Client, c)
+	a2r.CallV2(c, conversation.GetOwnerConversationCaller.Invoke)
 }
 
 func (o *ConversationApi) GetNotNotifyConversationIDs(c *gin.Context) {
-	a2r.Call(conversation.ConversationClient.GetNotNotifyConversationIDs, o.Client, c)
+	a2r.CallV2(c, conversation.GetNotNotifyConversationIDsCaller.Invoke)
 }
 
 func (o *ConversationApi) GetPinnedConversationIDs(c *gin.Context) {
-	a2r.Call(conversation.ConversationClient.GetPinnedConversationIDs, o.Client, c)
+	a2r.CallV2(c, conversation.GetPinnedConversationIDsCaller.Invoke)
 }
diff --git a/internal/api/friend.go b/internal/api/friend.go
index d000cccddb..4e08474fbf 100644
--- a/internal/api/friend.go
+++ b/internal/api/friend.go
@@ -17,99 +17,98 @@ package api
 import (
 	"github.com/gin-gonic/gin"
 
-	"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
 	"github.com/openimsdk/protocol/relation"
 	"github.com/openimsdk/tools/a2r"
 )
 
-type FriendApi rpcclient.Friend
+type FriendApi struct{}
 
-func NewFriendApi(client rpcclient.Friend) FriendApi {
-	return FriendApi(client)
+func NewFriendApi() FriendApi {
+	return FriendApi{}
 }
 
 func (o *FriendApi) ApplyToAddFriend(c *gin.Context) {
-	a2r.Call(relation.FriendClient.ApplyToAddFriend, o.Client, c)
+	a2r.CallV2(c, relation.ApplyToAddFriendCaller.Invoke)
 }
 
 func (o *FriendApi) RespondFriendApply(c *gin.Context) {
-	a2r.Call(relation.FriendClient.RespondFriendApply, o.Client, c)
+	a2r.CallV2(c, relation.RespondFriendApplyCaller.Invoke)
 }
 
 func (o *FriendApi) DeleteFriend(c *gin.Context) {
-	a2r.Call(relation.FriendClient.DeleteFriend, o.Client, c)
+	a2r.CallV2(c, relation.DeleteFriendCaller.Invoke)
 }
 
 func (o *FriendApi) GetFriendApplyList(c *gin.Context) {
-	a2r.Call(relation.FriendClient.GetPaginationFriendsApplyTo, o.Client, c)
+	a2r.CallV2(c, relation.GetPaginationFriendsApplyToCaller.Invoke)
 }
 
 func (o *FriendApi) GetDesignatedFriendsApply(c *gin.Context) {
-	a2r.Call(relation.FriendClient.GetDesignatedFriendsApply, o.Client, c)
+	a2r.CallV2(c, relation.GetDesignatedFriendsApplyCaller.Invoke)
 }
 
 func (o *FriendApi) GetSelfApplyList(c *gin.Context) {
-	a2r.Call(relation.FriendClient.GetPaginationFriendsApplyFrom, o.Client, c)
+	a2r.CallV2(c, relation.GetPaginationFriendsApplyFromCaller.Invoke)
 }
 
 func (o *FriendApi) GetFriendList(c *gin.Context) {
-	a2r.Call(relation.FriendClient.GetPaginationFriends, o.Client, c)
+	a2r.CallV2(c, relation.GetPaginationFriendsCaller.Invoke)
 }
 
 func (o *FriendApi) GetDesignatedFriends(c *gin.Context) {
-	a2r.Call(relation.FriendClient.GetDesignatedFriends, o.Client, c)
+	a2r.CallV2(c, relation.GetDesignatedFriendsCaller.Invoke)
 }
 
 func (o *FriendApi) SetFriendRemark(c *gin.Context) {
-	a2r.Call(relation.FriendClient.SetFriendRemark, o.Client, c)
+	a2r.CallV2(c, relation.SetFriendRemarkCaller.Invoke)
 }
 
 func (o *FriendApi) AddBlack(c *gin.Context) {
-	a2r.Call(relation.FriendClient.AddBlack, o.Client, c)
+	a2r.CallV2(c, relation.AddBlackCaller.Invoke)
 }
 
 func (o *FriendApi) GetPaginationBlacks(c *gin.Context) {
-	a2r.Call(relation.FriendClient.GetPaginationBlacks, o.Client, c)
+	a2r.CallV2(c, relation.GetPaginationBlacksCaller.Invoke)
 }
 
 func (o *FriendApi) GetSpecifiedBlacks(c *gin.Context) {
-	a2r.Call(relation.FriendClient.GetSpecifiedBlacks, o.Client, c)
+	a2r.CallV2(c, relation.GetSpecifiedBlacksCaller.Invoke)
 }
 
 func (o *FriendApi) RemoveBlack(c *gin.Context) {
-	a2r.Call(relation.FriendClient.RemoveBlack, o.Client, c)
+	a2r.CallV2(c, relation.RemoveBlackCaller.Invoke)
 }
 
 func (o *FriendApi) ImportFriends(c *gin.Context) {
-	a2r.Call(relation.FriendClient.ImportFriends, o.Client, c)
+	a2r.CallV2(c, relation.ImportFriendsCaller.Invoke)
 }
 
 func (o *FriendApi) IsFriend(c *gin.Context) {
-	a2r.Call(relation.FriendClient.IsFriend, o.Client, c)
+	a2r.CallV2(c, relation.IsFriendCaller.Invoke)
 }
 
 func (o *FriendApi) GetFriendIDs(c *gin.Context) {
-	a2r.Call(relation.FriendClient.GetFriendIDs, o.Client, c)
+	a2r.CallV2(c, relation.GetFriendIDsCaller.Invoke)
 }
 
 func (o *FriendApi) GetSpecifiedFriendsInfo(c *gin.Context) {
-	a2r.Call(relation.FriendClient.GetSpecifiedFriendsInfo, o.Client, c)
+	a2r.CallV2(c, relation.GetSpecifiedFriendsInfoCaller.Invoke)
 }
 
 func (o *FriendApi) UpdateFriends(c *gin.Context) {
-	a2r.Call(relation.FriendClient.UpdateFriends, o.Client, c)
+	a2r.CallV2(c, relation.UpdateFriendsCaller.Invoke)
 }
 
 func (o *FriendApi) GetIncrementalFriends(c *gin.Context) {
-	a2r.Call(relation.FriendClient.GetIncrementalFriends, o.Client, c)
+	a2r.CallV2(c, relation.GetIncrementalFriendsCaller.Invoke)
 }
 
 // GetIncrementalBlacks is temporarily unused.
 // Deprecated: This function is currently unused and may be removed in future versions.
 func (o *FriendApi) GetIncrementalBlacks(c *gin.Context) {
-	a2r.Call(relation.FriendClient.GetIncrementalBlacks, o.Client, c)
+	a2r.CallV2(c, relation.GetIncrementalBlacksCaller.Invoke)
 }
 
 func (o *FriendApi) GetFullFriendUserIDs(c *gin.Context) {
-	a2r.Call(relation.FriendClient.GetFullFriendUserIDs, o.Client, c)
+	a2r.CallV2(c, relation.GetFullFriendUserIDsCaller.Invoke)
 }
diff --git a/internal/api/group.go b/internal/api/group.go
index 9c35da7081..784197fd81 100644
--- a/internal/api/group.go
+++ b/internal/api/group.go
@@ -16,113 +16,112 @@ package api
 
 import (
 	"github.com/gin-gonic/gin"
-	"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
 	"github.com/openimsdk/protocol/group"
 	"github.com/openimsdk/tools/a2r"
 )
 
-type GroupApi rpcclient.Group
+type GroupApi struct{}
 
-func NewGroupApi(client rpcclient.Group) GroupApi {
-	return GroupApi(client)
+func NewGroupApi() GroupApi {
+	return GroupApi{}
 }
 
 func (o *GroupApi) CreateGroup(c *gin.Context) {
-	a2r.Call(group.GroupClient.CreateGroup, o.Client, c)
+	a2r.CallV2(c, group.CreateGroupCaller.Invoke)
 }
 
 func (o *GroupApi) SetGroupInfo(c *gin.Context) {
-	a2r.Call(group.GroupClient.SetGroupInfo, o.Client, c)
+	a2r.CallV2(c, group.SetGroupInfoCaller.Invoke)
 }
 
 func (o *GroupApi) SetGroupInfoEx(c *gin.Context) {
-	a2r.Call(group.GroupClient.SetGroupInfoEx, o.Client, c)
+	a2r.CallV2(c, group.SetGroupInfoExCaller.Invoke)
 }
 
 func (o *GroupApi) JoinGroup(c *gin.Context) {
-	a2r.Call(group.GroupClient.JoinGroup, o.Client, c)
+	a2r.CallV2(c, group.JoinGroupCaller.Invoke)
 }
 
 func (o *GroupApi) QuitGroup(c *gin.Context) {
-	a2r.Call(group.GroupClient.QuitGroup, o.Client, c)
+	a2r.CallV2(c, group.QuitGroupCaller.Invoke)
 }
 
 func (o *GroupApi) ApplicationGroupResponse(c *gin.Context) {
-	a2r.Call(group.GroupClient.GroupApplicationResponse, o.Client, c)
+	a2r.CallV2(c, group.GroupApplicationResponseCaller.Invoke)
 }
 
 func (o *GroupApi) TransferGroupOwner(c *gin.Context) {
-	a2r.Call(group.GroupClient.TransferGroupOwner, o.Client, c)
+	a2r.CallV2(c, group.TransferGroupOwnerCaller.Invoke)
 }
 
 func (o *GroupApi) GetRecvGroupApplicationList(c *gin.Context) {
-	a2r.Call(group.GroupClient.GetGroupApplicationList, o.Client, c)
+	a2r.CallV2(c, group.GetGroupApplicationListCaller.Invoke)
 }
 
 func (o *GroupApi) GetUserReqGroupApplicationList(c *gin.Context) {
-	a2r.Call(group.GroupClient.GetUserReqApplicationList, o.Client, c)
+	a2r.CallV2(c, group.GetUserReqApplicationListCaller.Invoke)
 }
 
 func (o *GroupApi) GetGroupUsersReqApplicationList(c *gin.Context) {
-	a2r.Call(group.GroupClient.GetGroupUsersReqApplicationList, o.Client, c)
+	a2r.CallV2(c, group.GetGroupUsersReqApplicationListCaller.Invoke)
 }
 
 func (o *GroupApi) GetSpecifiedUserGroupRequestInfo(c *gin.Context) {
-	a2r.Call(group.GroupClient.GetSpecifiedUserGroupRequestInfo, o.Client, c)
+	a2r.CallV2(c, group.GetSpecifiedUserGroupRequestInfoCaller.Invoke)
 }
 
 func (o *GroupApi) GetGroupsInfo(c *gin.Context) {
-	a2r.Call(group.GroupClient.GetGroupsInfo, o.Client, c)
+	a2r.CallV2(c, group.GetGroupsInfoCaller.Invoke)
 	//a2r.Call(group.GroupClient.GetGroupsInfo, o.Client, c, a2r.NewNilReplaceOption(group.GroupClient.GetGroupsInfo))
 }
 
 func (o *GroupApi) KickGroupMember(c *gin.Context) {
-	a2r.Call(group.GroupClient.KickGroupMember, o.Client, c)
+	a2r.CallV2(c, group.KickGroupMemberCaller.Invoke)
 }
 
 func (o *GroupApi) GetGroupMembersInfo(c *gin.Context) {
-	a2r.Call(group.GroupClient.GetGroupMembersInfo, o.Client, c)
+	a2r.CallV2(c, group.GetGroupMembersInfoCaller.Invoke)
 	//a2r.Call(group.GroupClient.GetGroupMembersInfo, o.Client, c, a2r.NewNilReplaceOption(group.GroupClient.GetGroupMembersInfo))
 }
 
 func (o *GroupApi) GetGroupMemberList(c *gin.Context) {
-	a2r.Call(group.GroupClient.GetGroupMemberList, o.Client, c)
+	a2r.CallV2(c, group.GetGroupMemberListCaller.Invoke)
 }
 
 func (o *GroupApi) InviteUserToGroup(c *gin.Context) {
-	a2r.Call(group.GroupClient.InviteUserToGroup, o.Client, c)
+	a2r.CallV2(c, group.InviteUserToGroupCaller.Invoke)
 }
 
 func (o *GroupApi) GetJoinedGroupList(c *gin.Context) {
-	a2r.Call(group.GroupClient.GetJoinedGroupList, o.Client, c)
+	a2r.CallV2(c, group.GetJoinedGroupListCaller.Invoke)
 }
 
 func (o *GroupApi) DismissGroup(c *gin.Context) {
-	a2r.Call(group.GroupClient.DismissGroup, o.Client, c)
+	a2r.CallV2(c, group.DismissGroupCaller.Invoke)
 }
 
 func (o *GroupApi) MuteGroupMember(c *gin.Context) {
-	a2r.Call(group.GroupClient.MuteGroupMember, o.Client, c)
+	a2r.CallV2(c, group.MuteGroupMemberCaller.Invoke)
 }
 
 func (o *GroupApi) CancelMuteGroupMember(c *gin.Context) {
-	a2r.Call(group.GroupClient.CancelMuteGroupMember, o.Client, c)
+	a2r.CallV2(c, group.CancelMuteGroupMemberCaller.Invoke)
 }
 
 func (o *GroupApi) MuteGroup(c *gin.Context) {
-	a2r.Call(group.GroupClient.MuteGroup, o.Client, c)
+	a2r.CallV2(c, group.MuteGroupCaller.Invoke)
 }
 
 func (o *GroupApi) CancelMuteGroup(c *gin.Context) {
-	a2r.Call(group.GroupClient.CancelMuteGroup, o.Client, c)
+	a2r.CallV2(c, group.CancelMuteGroupCaller.Invoke)
 }
 
 func (o *GroupApi) SetGroupMemberInfo(c *gin.Context) {
-	a2r.Call(group.GroupClient.SetGroupMemberInfo, o.Client, c)
+	a2r.CallV2(c, group.SetGroupMemberInfoCaller.Invoke)
 }
 
 func (o *GroupApi) GetGroupAbstractInfo(c *gin.Context) {
-	a2r.Call(group.GroupClient.GetGroupAbstractInfo, o.Client, c)
+	a2r.CallV2(c, group.GetGroupAbstractInfoCaller.Invoke)
 }
 
 // func (g *Group) SetGroupMemberNickname(c *gin.Context) {
@@ -134,33 +133,33 @@ func (o *GroupApi) GetGroupAbstractInfo(c *gin.Context) {
 //}
 
 func (o *GroupApi) GroupCreateCount(c *gin.Context) {
-	a2r.Call(group.GroupClient.GroupCreateCount, o.Client, c)
+	a2r.CallV2(c, group.GroupCreateCountCaller.Invoke)
 }
 
 func (o *GroupApi) GetGroups(c *gin.Context) {
-	a2r.Call(group.GroupClient.GetGroups, o.Client, c)
+	a2r.CallV2(c, group.GetGroupsCaller.Invoke)
 }
 
 func (o *GroupApi) GetGroupMemberUserIDs(c *gin.Context) {
-	a2r.Call(group.GroupClient.GetGroupMemberUserIDs, o.Client, c)
+	a2r.CallV2(c, group.GetGroupMemberUserIDsCaller.Invoke)
 }
 
 func (o *GroupApi) GetIncrementalJoinGroup(c *gin.Context) {
-	a2r.Call(group.GroupClient.GetIncrementalJoinGroup, o.Client, c)
+	a2r.CallV2(c, group.GetIncrementalJoinGroupCaller.Invoke)
 }
 
 func (o *GroupApi) GetIncrementalGroupMember(c *gin.Context) {
-	a2r.Call(group.GroupClient.GetIncrementalGroupMember, o.Client, c)
+	a2r.CallV2(c, group.GetIncrementalGroupMemberCaller.Invoke)
 }
 
 func (o *GroupApi) GetIncrementalGroupMemberBatch(c *gin.Context) {
-	a2r.Call(group.GroupClient.BatchGetIncrementalGroupMember, o.Client, c)
+	a2r.CallV2(c, group.BatchGetIncrementalGroupMemberCaller.Invoke)
 }
 
 func (o *GroupApi) GetFullGroupMemberUserIDs(c *gin.Context) {
-	a2r.Call(group.GroupClient.GetFullGroupMemberUserIDs, o.Client, c)
+	a2r.CallV2(c, group.GetFullGroupMemberUserIDsCaller.Invoke)
 }
 
 func (o *GroupApi) GetFullJoinGroupIDs(c *gin.Context) {
-	a2r.Call(group.GroupClient.GetFullJoinGroupIDs, o.Client, c)
+	a2r.CallV2(c, group.GetFullJoinGroupIDsCaller.Invoke)
 }
diff --git a/internal/api/init.go b/internal/api/init.go
index 59b19ee894..fcc69dc680 100644
--- a/internal/api/init.go
+++ b/internal/api/init.go
@@ -29,15 +29,18 @@ import (
 	conf "github.com/openimsdk/open-im-server/v3/pkg/common/config"
 	kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister"
 	"github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
-	"github.com/openimsdk/tools/discovery"
+	"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
 	"github.com/openimsdk/tools/discovery/etcd"
 	"github.com/openimsdk/tools/errs"
 	"github.com/openimsdk/tools/log"
+	"github.com/openimsdk/tools/mw"
 	"github.com/openimsdk/tools/system/program"
 	"github.com/openimsdk/tools/utils/datautil"
 	"github.com/openimsdk/tools/utils/jsonutil"
 	"github.com/openimsdk/tools/utils/network"
 	"github.com/openimsdk/tools/utils/runtimeenv"
+	"google.golang.org/grpc"
+	"google.golang.org/grpc/credentials/insecure"
 )
 
 type Config struct {
@@ -56,13 +59,14 @@ func Start(ctx context.Context, index int, config *Config) error {
 
 	config.RuntimeEnv = runtimeenv.PrintRuntimeEnvironment()
 
-	var client discovery.SvcDiscoveryRegistry
-
-	// Determine whether zk is passed according to whether it is a clustered deployment
-	client, err = kdisc.NewDiscoveryRegister(&config.Discovery, config.RuntimeEnv)
+	client, err := kdisc.NewDiscoveryRegister(&config.Discovery, config.RuntimeEnv)
 	if err != nil {
 		return errs.WrapMsg(err, "failed to register discovery service")
 	}
+	client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin")))
+	if err = rpcclient.InitRpcCaller(client, config.Discovery.RpcService); err != nil {
+		return err
+	}
 
 	var (
 		netDone        = make(chan struct{}, 1)
@@ -90,7 +94,7 @@ func Start(ctx context.Context, index int, config *Config) error {
 		return errs.New("only etcd support autoSetPorts", "RegisterName", "api").Wrap()
 	}
 
-	router := newGinRouter(client, config, client)
+	router := newGinRouter(client, config)
 	if config.API.Prometheus.Enable {
 		var (
 			listener net.Listener
diff --git a/internal/api/jssdk/jssdk.go b/internal/api/jssdk/jssdk.go
index 2fcbf5ec66..409fcbf79d 100644
--- a/internal/api/jssdk/jssdk.go
+++ b/internal/api/jssdk/jssdk.go
@@ -2,6 +2,8 @@ package jssdk
 
 import (
 	"context"
+	"sort"
+
 	"github.com/gin-gonic/gin"
 	"github.com/openimsdk/protocol/conversation"
 	"github.com/openimsdk/protocol/group"
@@ -12,7 +14,6 @@ import (
 	"github.com/openimsdk/protocol/user"
 	"github.com/openimsdk/tools/mcontext"
 	"github.com/openimsdk/tools/utils/datautil"
-	"sort"
 )
 
 const (
@@ -20,22 +21,11 @@ const (
 	defaultGetActiveConversation = 100
 )
 
-func NewJSSdkApi(user user.UserClient, friend relation.FriendClient, group group.GroupClient, msg msg.MsgClient, conv conversation.ConversationClient) *JSSdk {
-	return &JSSdk{
-		user:   user,
-		friend: friend,
-		group:  group,
-		msg:    msg,
-		conv:   conv,
-	}
+func NewJSSdkApi() *JSSdk {
+	return &JSSdk{}
 }
 
 type JSSdk struct {
-	user   user.UserClient
-	friend relation.FriendClient
-	group  group.GroupClient
-	msg    msg.MsgClient
-	conv   conversation.ConversationClient
 }
 
 func (x *JSSdk) GetActiveConversations(c *gin.Context) {
@@ -67,11 +57,11 @@ func (x *JSSdk) fillConversations(ctx context.Context, conversations []*jssdk.Co
 		groupMap  map[string]*sdkws.GroupInfo
 	)
 	if len(userIDs) > 0 {
-		users, err := field(ctx, x.user.GetDesignateUsers, &user.GetDesignateUsersReq{UserIDs: userIDs}, (*user.GetDesignateUsersResp).GetUsersInfo)
+		users, err := field(ctx, user.GetDesignateUsersCaller.Invoke, &user.GetDesignateUsersReq{UserIDs: userIDs}, (*user.GetDesignateUsersResp).GetUsersInfo)
 		if err != nil {
 			return err
 		}
-		friends, err := field(ctx, x.friend.GetFriendInfo, &relation.GetFriendInfoReq{OwnerUserID: conversations[0].Conversation.OwnerUserID, FriendUserIDs: userIDs}, (*relation.GetFriendInfoResp).GetFriendInfos)
+		friends, err := field(ctx, relation.GetFriendInfoCaller.Invoke, &relation.GetFriendInfoReq{OwnerUserID: conversations[0].Conversation.OwnerUserID, FriendUserIDs: userIDs}, (*relation.GetFriendInfoResp).GetFriendInfos)
 		if err != nil {
 			return err
 		}
@@ -79,7 +69,7 @@ func (x *JSSdk) fillConversations(ctx context.Context, conversations []*jssdk.Co
 		friendMap = datautil.SliceToMap(friends, (*relation.FriendInfoOnly).GetFriendUserID)
 	}
 	if len(groupIDs) > 0 {
-		resp, err := x.group.GetGroupsInfo(ctx, &group.GetGroupsInfoReq{GroupIDs: groupIDs})
+		resp, err := group.GetGroupsInfoCaller.Invoke(ctx, &group.GetGroupsInfoReq{GroupIDs: groupIDs})
 		if err != nil {
 			return err
 		}
@@ -101,7 +91,7 @@ func (x *JSSdk) getActiveConversations(ctx context.Context, req *jssdk.GetActive
 		req.Count = defaultGetActiveConversation
 	}
 	req.OwnerUserID = mcontext.GetOpUserID(ctx)
-	conversationIDs, err := field(ctx, x.conv.GetConversationIDs,
+	conversationIDs, err := field(ctx, conversation.GetConversationIDsCaller.Invoke,
 		&conversation.GetConversationIDsReq{UserID: req.OwnerUserID}, (*conversation.GetConversationIDsResp).GetConversationIDs)
 	if err != nil {
 		return nil, err
@@ -109,12 +99,12 @@ func (x *JSSdk) getActiveConversations(ctx context.Context, req *jssdk.GetActive
 	if len(conversationIDs) == 0 {
 		return &jssdk.GetActiveConversationsResp{}, nil
 	}
-	readSeq, err := field(ctx, x.msg.GetHasReadSeqs,
+	readSeq, err := field(ctx, msg.GetHasReadSeqsCaller.Invoke,
 		&msg.GetHasReadSeqsReq{UserID: req.OwnerUserID, ConversationIDs: conversationIDs}, (*msg.SeqsInfoResp).GetMaxSeqs)
 	if err != nil {
 		return nil, err
 	}
-	activeConversation, err := field(ctx, x.msg.GetActiveConversation,
+	activeConversation, err := field(ctx, msg.GetActiveConversationCaller.Invoke,
 		&msg.GetActiveConversationReq{ConversationIDs: conversationIDs}, (*msg.GetActiveConversationResp).GetConversations)
 	if err != nil {
 		return nil, err
@@ -126,7 +116,7 @@ func (x *JSSdk) getActiveConversations(ctx context.Context, req *jssdk.GetActive
 		Conversation: activeConversation,
 	}
 	if len(activeConversation) > 1 {
-		pinnedConversationIDs, err := field(ctx, x.conv.GetPinnedConversationIDs,
+		pinnedConversationIDs, err := field(ctx, conversation.GetPinnedConversationIDsCaller.Invoke,
 			&conversation.GetPinnedConversationIDsReq{UserID: req.OwnerUserID}, (*conversation.GetPinnedConversationIDsResp).GetConversationIDs)
 		if err != nil {
 			return nil, err
@@ -135,7 +125,7 @@ func (x *JSSdk) getActiveConversations(ctx context.Context, req *jssdk.GetActive
 	}
 	sort.Sort(&sortConversations)
 	sortList := sortConversations.Top(int(req.Count))
-	conversations, err := field(ctx, x.conv.GetConversations,
+	conversations, err := field(ctx, conversation.GetConversationsCaller.Invoke,
 		&conversation.GetConversationsReq{
 			OwnerUserID: req.OwnerUserID,
 			ConversationIDs: datautil.Slice(sortList, func(c *msg.ActiveConversation) string {
@@ -144,7 +134,7 @@ func (x *JSSdk) getActiveConversations(ctx context.Context, req *jssdk.GetActive
 	if err != nil {
 		return nil, err
 	}
-	msgs, err := field(ctx, x.msg.GetSeqMessage,
+	msgs, err := field(ctx, msg.GetSeqMessageCaller.Invoke,
 		&msg.GetSeqMessageReq{
 			UserID: req.OwnerUserID,
 			Conversations: datautil.Slice(sortList, func(c *msg.ActiveConversation) *msg.ConversationSeqs {
@@ -195,7 +185,7 @@ func (x *JSSdk) getActiveConversations(ctx context.Context, req *jssdk.GetActive
 
 func (x *JSSdk) getConversations(ctx context.Context, req *jssdk.GetConversationsReq) (*jssdk.GetConversationsResp, error) {
 	req.OwnerUserID = mcontext.GetOpUserID(ctx)
-	conversations, err := field(ctx, x.conv.GetConversations, &conversation.GetConversationsReq{OwnerUserID: req.OwnerUserID, ConversationIDs: req.ConversationIDs}, (*conversation.GetConversationsResp).GetConversations)
+	conversations, err := field(ctx, conversation.GetConversationsCaller.Invoke, &conversation.GetConversationsReq{OwnerUserID: req.OwnerUserID, ConversationIDs: req.ConversationIDs}, (*conversation.GetConversationsResp).GetConversations)
 	if err != nil {
 		return nil, err
 	}
@@ -205,12 +195,12 @@ func (x *JSSdk) getConversations(ctx context.Context, req *jssdk.GetConversation
 	req.ConversationIDs = datautil.Slice(conversations, func(c *conversation.Conversation) string {
 		return c.ConversationID
 	})
-	maxSeqs, err := field(ctx, x.msg.GetMaxSeqs,
+	maxSeqs, err := field(ctx, msg.GetMaxSeqsCaller.Invoke,
 		&msg.GetMaxSeqsReq{ConversationIDs: req.ConversationIDs}, (*msg.SeqsInfoResp).GetMaxSeqs)
 	if err != nil {
 		return nil, err
 	}
-	readSeqs, err := field(ctx, x.msg.GetHasReadSeqs,
+	readSeqs, err := field(ctx, msg.GetHasReadSeqsCaller.Invoke,
 		&msg.GetHasReadSeqsReq{UserID: req.OwnerUserID, ConversationIDs: req.ConversationIDs}, (*msg.SeqsInfoResp).GetMaxSeqs)
 	if err != nil {
 		return nil, err
@@ -226,7 +216,7 @@ func (x *JSSdk) getConversations(ctx context.Context, req *jssdk.GetConversation
 	}
 	var msgs map[string]*sdkws.PullMsgs
 	if len(conversationSeqs) > 0 {
-		msgs, err = field(ctx, x.msg.GetSeqMessage,
+		msgs, err = field(ctx, msg.GetSeqMessageCaller.Invoke,
 			&msg.GetSeqMessageReq{UserID: req.OwnerUserID, Conversations: conversationSeqs}, (*msg.GetSeqMessageResp).GetMsgs)
 		if err != nil {
 			return nil, err
diff --git a/internal/api/msg.go b/internal/api/msg.go
index 9f79067a81..8efd348949 100644
--- a/internal/api/msg.go
+++ b/internal/api/msg.go
@@ -21,10 +21,11 @@ import (
 	"github.com/openimsdk/open-im-server/v3/pkg/apistruct"
 	"github.com/openimsdk/open-im-server/v3/pkg/authverify"
 	"github.com/openimsdk/open-im-server/v3/pkg/common/config"
-	"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
 	"github.com/openimsdk/protocol/constant"
 	"github.com/openimsdk/protocol/msg"
+	"github.com/openimsdk/protocol/rpccall"
 	"github.com/openimsdk/protocol/sdkws"
+	"github.com/openimsdk/protocol/user"
 	"github.com/openimsdk/tools/a2r"
 	"github.com/openimsdk/tools/apiresp"
 	"github.com/openimsdk/tools/errs"
@@ -37,16 +38,12 @@ import (
 )
 
 type MessageApi struct {
-	*rpcclient.Message
 	validate      *validator.Validate
-	userRpcClient *rpcclient.UserRpcClient
 	imAdminUserID []string
 }
 
-func NewMessageApi(msgRpcClient *rpcclient.Message, userRpcClient *rpcclient.User,
-	imAdminUserID []string) MessageApi {
-	return MessageApi{Message: msgRpcClient, validate: validator.New(),
-		userRpcClient: rpcclient.NewUserRpcClientByUser(userRpcClient), imAdminUserID: imAdminUserID}
+func NewMessageApi(imAdminUserID []string) MessageApi {
+	return MessageApi{validate: validator.New(), imAdminUserID: imAdminUserID}
 }
 
 func (*MessageApi) SetOptions(options map[string]bool, value bool) {
@@ -108,51 +105,51 @@ func (m *MessageApi) newUserSendMsgReq(_ *gin.Context, params *apistruct.SendMsg
 }
 
 func (m *MessageApi) GetSeq(c *gin.Context) {
-	a2r.Call(msg.MsgClient.GetMaxSeq, m.Client, c)
+	a2r.CallV2(c, msg.GetMaxSeqCaller.Invoke)
 }
 
 func (m *MessageApi) PullMsgBySeqs(c *gin.Context) {
-	a2r.Call(msg.MsgClient.PullMessageBySeqs, m.Client, c)
+	a2r.CallV2(c, msg.PullMessageBySeqsCaller.Invoke)
 }
 
 func (m *MessageApi) RevokeMsg(c *gin.Context) {
-	a2r.Call(msg.MsgClient.RevokeMsg, m.Client, c)
+	a2r.CallV2(c, msg.RevokeMsgCaller.Invoke)
 }
 
 func (m *MessageApi) MarkMsgsAsRead(c *gin.Context) {
-	a2r.Call(msg.MsgClient.MarkMsgsAsRead, m.Client, c)
+	a2r.CallV2(c, msg.MarkMsgsAsReadCaller.Invoke)
 }
 
 func (m *MessageApi) MarkConversationAsRead(c *gin.Context) {
-	a2r.Call(msg.MsgClient.MarkConversationAsRead, m.Client, c)
+	a2r.CallV2(c, msg.MarkConversationAsReadCaller.Invoke)
 }
 
 func (m *MessageApi) GetConversationsHasReadAndMaxSeq(c *gin.Context) {
-	a2r.Call(msg.MsgClient.GetConversationsHasReadAndMaxSeq, m.Client, c)
+	a2r.CallV2(c, msg.GetConversationsHasReadAndMaxSeqCaller.Invoke)
 }
 
 func (m *MessageApi) SetConversationHasReadSeq(c *gin.Context) {
-	a2r.Call(msg.MsgClient.SetConversationHasReadSeq, m.Client, c)
+	a2r.CallV2(c, msg.SetConversationHasReadSeqCaller.Invoke)
 }
 
 func (m *MessageApi) ClearConversationsMsg(c *gin.Context) {
-	a2r.Call(msg.MsgClient.ClearConversationsMsg, m.Client, c)
+	a2r.CallV2(c, msg.ClearConversationsMsgCaller.Invoke)
 }
 
 func (m *MessageApi) UserClearAllMsg(c *gin.Context) {
-	a2r.Call(msg.MsgClient.UserClearAllMsg, m.Client, c)
+	a2r.CallV2(c, msg.UserClearAllMsgCaller.Invoke)
 }
 
 func (m *MessageApi) DeleteMsgs(c *gin.Context) {
-	a2r.Call(msg.MsgClient.DeleteMsgs, m.Client, c)
+	a2r.CallV2(c, msg.DeleteMsgsCaller.Invoke)
 }
 
 func (m *MessageApi) DeleteMsgPhysicalBySeq(c *gin.Context) {
-	a2r.Call(msg.MsgClient.DeleteMsgPhysicalBySeq, m.Client, c)
+	a2r.CallV2(c, msg.DeleteMsgPhysicalBySeqCaller.Invoke)
 }
 
 func (m *MessageApi) DeleteMsgPhysical(c *gin.Context) {
-	a2r.Call(msg.MsgClient.DeleteMsgPhysical, m.Client, c)
+	a2r.CallV2(c, msg.DeleteMsgPhysicalCaller.Invoke)
 }
 
 func (m *MessageApi) getSendMsgReq(c *gin.Context, req apistruct.SendMsg) (sendMsgReq *msg.SendMsgReq, err error) {
@@ -180,7 +177,7 @@ func (m *MessageApi) getSendMsgReq(c *gin.Context, req apistruct.SendMsg) (sendM
 	case constant.OANotification:
 		data = apistruct.OANotificationElem{}
 		req.SessionType = constant.NotificationChatType
-		if err = m.userRpcClient.GetNotificationByID(c, req.SendID); err != nil {
+		if err = user.GetNotificationAccountCaller.Execute(c, &user.GetNotificationAccountReq{UserID: req.SendID}); err != nil {
 			return nil, err
 		}
 	default:
@@ -227,7 +224,7 @@ func (m *MessageApi) SendMessage(c *gin.Context) {
 	sendMsgReq.MsgData.RecvID = req.RecvID
 
 	// Attempt to send the message using the client.
-	respPb, err := m.Client.SendMsg(c, sendMsgReq)
+	respPb, err := msg.SendMsgCaller.Invoke(c, sendMsgReq)
 	if err != nil {
 		// Set the status to failed and respond with an error if sending fails.
 		apiresp.GinError(c, err)
@@ -238,7 +235,7 @@ func (m *MessageApi) SendMessage(c *gin.Context) {
 	var status = constant.MsgSendSuccessed
 
 	// Attempt to update the message sending status in the system.
-	_, err = m.Client.SetSendMsgStatus(c, &msg.SetSendMsgStatusReq{
+	err = msg.SetSendMsgStatusCaller.Execute(c, &msg.SetSendMsgStatusReq{
 		Status: int32(status),
 	})
 
@@ -290,7 +287,7 @@ func (m *MessageApi) SendBusinessNotification(c *gin.Context) {
 			}),
 		},
 	}
-	respPb, err := m.Client.SendMsg(c, &sendMsgReq)
+	respPb, err := msg.SendMsgCaller.Invoke(c, &sendMsgReq)
 	if err != nil {
 		apiresp.GinError(c, err)
 		return
@@ -317,7 +314,10 @@ func (m *MessageApi) BatchSendMsg(c *gin.Context) {
 		pageNumber := 1
 		showNumber := 500
 		for {
-			recvIDsPart, err := m.userRpcClient.GetAllUserIDs(c, int32(pageNumber), int32(showNumber))
+			recvIDsPart, err := rpccall.ExtractField(c, user.GetAllUserIDCaller.Invoke, &user.GetAllUserIDReq{Pagination: &sdkws.RequestPagination{
+				PageNumber: int32(pageNumber),
+				ShowNumber: int32(showNumber),
+			}}, (*user.GetAllUserIDResp).GetUserIDs)
 			if err != nil {
 				apiresp.GinError(c, err)
 				return
@@ -339,7 +339,7 @@ func (m *MessageApi) BatchSendMsg(c *gin.Context) {
 	}
 	for _, recvID := range recvIDs {
 		sendMsgReq.MsgData.RecvID = recvID
-		rpcResp, err := m.Client.SendMsg(c, sendMsgReq)
+		rpcResp, err := msg.SendMsgCaller.Invoke(c, sendMsgReq)
 		if err != nil {
 			resp.FailedIDs = append(resp.FailedIDs, recvID)
 			continue
@@ -355,33 +355,33 @@ func (m *MessageApi) BatchSendMsg(c *gin.Context) {
 }
 
 func (m *MessageApi) CheckMsgIsSendSuccess(c *gin.Context) {
-	a2r.Call(msg.MsgClient.GetSendMsgStatus, m.Client, c)
+	a2r.CallV2(c, msg.GetSendMsgStatusCaller.Invoke)
 }
 
 func (m *MessageApi) GetUsersOnlineStatus(c *gin.Context) {
-	a2r.Call(msg.MsgClient.GetSendMsgStatus, m.Client, c)
+	a2r.CallV2(c, msg.GetSendMsgStatusCaller.Invoke)
 }
 
 func (m *MessageApi) GetActiveUser(c *gin.Context) {
-	a2r.Call(msg.MsgClient.GetActiveUser, m.Client, c)
+	a2r.CallV2(c, msg.GetActiveUserCaller.Invoke)
 }
 
 func (m *MessageApi) GetActiveGroup(c *gin.Context) {
-	a2r.Call(msg.MsgClient.GetActiveGroup, m.Client, c)
+	a2r.CallV2(c, msg.GetActiveGroupCaller.Invoke)
 }
 
 func (m *MessageApi) SearchMsg(c *gin.Context) {
-	a2r.Call(msg.MsgClient.SearchMessage, m.Client, c)
+	a2r.CallV2(c, msg.SearchMessageCaller.Invoke)
 }
 
 func (m *MessageApi) GetServerTime(c *gin.Context) {
-	a2r.Call(msg.MsgClient.GetServerTime, m.Client, c)
+	a2r.CallV2(c, msg.GetServerTimeCaller.Invoke)
 }
 
 func (m *MessageApi) GetStreamMsg(c *gin.Context) {
-	a2r.Call(msg.MsgClient.GetStreamMsg, m.Client, c)
+	a2r.CallV2(c, msg.GetStreamMsgCaller.Invoke)
 }
 
 func (m *MessageApi) AppendStreamMsg(c *gin.Context) {
-	a2r.Call(msg.MsgClient.AppendStreamMsg, m.Client, c)
+	a2r.CallV2(c, msg.AppendStreamMsgCaller.Invoke)
 }
diff --git a/internal/api/router.go b/internal/api/router.go
index 6714d645c6..d6bf4e130b 100644
--- a/internal/api/router.go
+++ b/internal/api/router.go
@@ -2,8 +2,11 @@ package api
 
 import (
 	"fmt"
+	"net/http"
+	"strings"
 
 	"github.com/openimsdk/open-im-server/v3/internal/api/jssdk"
+	pbAuth "github.com/openimsdk/protocol/auth"
 
 	"github.com/gin-contrib/gzip"
 
@@ -13,12 +16,8 @@ import (
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/credentials/insecure"
 
-	"net/http"
-	"strings"
-
 	"github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
 	"github.com/openimsdk/open-im-server/v3/pkg/common/servererrs"
-	"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
 	"github.com/openimsdk/protocol/constant"
 	"github.com/openimsdk/tools/apiresp"
 	"github.com/openimsdk/tools/discovery"
@@ -48,7 +47,7 @@ func prommetricsGin() gin.HandlerFunc {
 	}
 }
 
-func newGinRouter(disCov discovery.SvcDiscoveryRegistry, config *Config, client discovery.SvcDiscoveryRegistry) *gin.Engine {
+func newGinRouter(disCov discovery.SvcDiscoveryRegistry, config *Config) *gin.Engine {
 	disCov.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()),
 		grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin")))
 	gin.SetMode(gin.ReleaseMode)
@@ -56,15 +55,6 @@ func newGinRouter(disCov discovery.SvcDiscoveryRegistry, config *Config, client
 	if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
 		_ = v.RegisterValidation("required_if", RequiredIf)
 	}
-	// init rpc client here
-	userRpc := rpcclient.NewUser(disCov, config.Discovery.RpcService.User, config.Discovery.RpcService.MessageGateway,
-		config.Share.IMAdminUserID)
-	groupRpc := rpcclient.NewGroup(disCov, config.Discovery.RpcService.Group)
-	friendRpc := rpcclient.NewFriend(disCov, config.Discovery.RpcService.Friend)
-	messageRpc := rpcclient.NewMessage(disCov, config.Discovery.RpcService.Msg)
-	conversationRpc := rpcclient.NewConversation(disCov, config.Discovery.RpcService.Conversation)
-	authRpc := rpcclient.NewAuth(disCov, config.Discovery.RpcService.Auth)
-	thirdRpc := rpcclient.NewThird(disCov, config.Discovery.RpcService.Third, config.API.Prometheus.GrafanaURL)
 	switch config.API.Api.CompressionLevel {
 	case NoCompression:
 	case DefaultCompression:
@@ -74,11 +64,11 @@ func newGinRouter(disCov discovery.SvcDiscoveryRegistry, config *Config, client
 	case BestSpeed:
 		r.Use(gzip.Gzip(gzip.BestSpeed))
 	}
-	r.Use(prommetricsGin(), gin.RecoveryWithWriter(gin.DefaultErrorWriter, mw.GinPanicErr), mw.CorsHandler(), mw.GinParseOperationID(), GinParseToken(authRpc))
-	u := NewUserApi(*userRpc)
-	m := NewMessageApi(messageRpc, userRpc, config.Share.IMAdminUserID)
-	j := jssdk.NewJSSdkApi(userRpc.Client, friendRpc.Client, groupRpc.Client, messageRpc.Client, conversationRpc.Client)
-	pd := NewPrometheusDiscoveryApi(config, client)
+	r.Use(prommetricsGin(), gin.RecoveryWithWriter(gin.DefaultErrorWriter, mw.GinPanicErr), mw.CorsHandler(), mw.GinParseOperationID(), GinParseToken())
+	u := NewUserApi(disCov, config.Discovery.RpcService.MessageGateway)
+	m := NewMessageApi(config.Share.IMAdminUserID)
+	j := jssdk.NewJSSdkApi()
+	pd := NewPrometheusDiscoveryApi(config, disCov)
 	userRouterGroup := r.Group("/user")
 	{
 		userRouterGroup.POST("/user_register", u.UserRegister)
@@ -108,7 +98,7 @@ func newGinRouter(disCov discovery.SvcDiscoveryRegistry, config *Config, client
 	// friend routing group
 	friendRouterGroup := r.Group("/friend")
 	{
-		f := NewFriendApi(*friendRpc)
+		f := NewFriendApi()
 		friendRouterGroup.POST("/delete_friend", f.DeleteFriend)
 		friendRouterGroup.POST("/get_friend_apply_list", f.GetFriendApplyList)
 		friendRouterGroup.POST("/get_designated_friend_apply", f.GetDesignatedFriendsApply)
@@ -131,7 +121,7 @@ func newGinRouter(disCov discovery.SvcDiscoveryRegistry, config *Config, client
 		friendRouterGroup.POST("/get_incremental_friends", f.GetIncrementalFriends)
 		friendRouterGroup.POST("/get_full_friend_user_ids", f.GetFullFriendUserIDs)
 	}
-	g := NewGroupApi(*groupRpc)
+	g := NewGroupApi()
 	groupRouterGroup := r.Group("/group")
 	{
 		groupRouterGroup.POST("/create_group", g.CreateGroup)
@@ -169,7 +159,7 @@ func newGinRouter(disCov discovery.SvcDiscoveryRegistry, config *Config, client
 	// certificate
 	authRouterGroup := r.Group("/auth")
 	{
-		a := NewAuthApi(*authRpc)
+		a := NewAuthApi()
 		authRouterGroup.POST("/get_admin_token", a.GetAdminToken)
 		authRouterGroup.POST("/get_user_token", a.GetUserToken)
 		authRouterGroup.POST("/parse_token", a.ParseToken)
@@ -178,7 +168,7 @@ func newGinRouter(disCov discovery.SvcDiscoveryRegistry, config *Config, client
 	// Third service
 	thirdGroup := r.Group("/third")
 	{
-		t := NewThirdApi(*thirdRpc)
+		t := NewThirdApi(config.API.Prometheus.GrafanaURL)
 		thirdGroup.GET("/prometheus", t.GetPrometheus)
 		thirdGroup.POST("/fcm_update_token", t.FcmUpdateToken)
 		thirdGroup.POST("/set_app_badge", t.SetAppBadge)
@@ -229,7 +219,7 @@ func newGinRouter(disCov discovery.SvcDiscoveryRegistry, config *Config, client
 	// Conversation
 	conversationGroup := r.Group("/conversation")
 	{
-		c := NewConversationApi(*conversationRpc)
+		c := NewConversationApi()
 		conversationGroup.POST("/get_sorted_conversation_list", c.GetSortedConversationList)
 		conversationGroup.POST("/get_all_conversations", c.GetAllConversations)
 		conversationGroup.POST("/get_conversation", c.GetConversation)
@@ -271,7 +261,7 @@ func newGinRouter(disCov discovery.SvcDiscoveryRegistry, config *Config, client
 	return r
 }
 
-func GinParseToken(authRPC *rpcclient.Auth) gin.HandlerFunc {
+func GinParseToken() gin.HandlerFunc {
 	return func(c *gin.Context) {
 		switch c.Request.Method {
 		case http.MethodPost:
@@ -289,7 +279,7 @@ func GinParseToken(authRPC *rpcclient.Auth) gin.HandlerFunc {
 				c.Abort()
 				return
 			}
-			resp, err := authRPC.ParseToken(c, token)
+			resp, err := pbAuth.ParseTokenCaller.Invoke(c, &pbAuth.ParseTokenReq{Token: token})
 			if err != nil {
 				apiresp.GinError(c, err)
 				c.Abort()
diff --git a/internal/api/statistics.go b/internal/api/statistics.go
index f5ee99f733..f60bddb2eb 100644
--- a/internal/api/statistics.go
+++ b/internal/api/statistics.go
@@ -16,17 +16,16 @@ package api
 
 import (
 	"github.com/gin-gonic/gin"
-	"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
 	"github.com/openimsdk/protocol/user"
 	"github.com/openimsdk/tools/a2r"
 )
 
-type StatisticsApi rpcclient.User
+type StatisticsApi struct{}
 
-func NewStatisticsApi(client rpcclient.User) StatisticsApi {
-	return StatisticsApi(client)
+func NewStatisticsApi() StatisticsApi {
+	return StatisticsApi{}
 }
 
 func (s *StatisticsApi) UserRegister(c *gin.Context) {
-	a2r.Call(user.UserClient.UserRegisterCount, s.Client, c)
+	a2r.CallV2(c, user.UserRegisterCountCaller.Invoke)
 }
diff --git a/internal/api/third.go b/internal/api/third.go
index 6baa70ee5d..ac02e37347 100644
--- a/internal/api/third.go
+++ b/internal/api/third.go
@@ -16,33 +16,35 @@ package api
 
 import (
 	"context"
-	"google.golang.org/grpc"
 	"math/rand"
 	"net/http"
 	"net/url"
 	"strconv"
 	"strings"
 
+	"google.golang.org/grpc"
+
 	"github.com/gin-gonic/gin"
-	"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
 	"github.com/openimsdk/protocol/third"
 	"github.com/openimsdk/tools/a2r"
 	"github.com/openimsdk/tools/errs"
 	"github.com/openimsdk/tools/mcontext"
 )
 
-type ThirdApi rpcclient.Third
+type ThirdApi struct {
+	GrafanaUrl string
+}
 
-func NewThirdApi(client rpcclient.Third) ThirdApi {
-	return ThirdApi(client)
+func NewThirdApi(grafanaUrl string) ThirdApi {
+	return ThirdApi{GrafanaUrl: grafanaUrl}
 }
 
 func (o *ThirdApi) FcmUpdateToken(c *gin.Context) {
-	a2r.Call(third.ThirdClient.FcmUpdateToken, o.Client, c)
+	a2r.CallV2(c, third.FcmUpdateTokenCaller.Invoke)
 }
 
 func (o *ThirdApi) SetAppBadge(c *gin.Context) {
-	a2r.Call(third.ThirdClient.SetAppBadge, o.Client, c)
+	a2r.CallV2(c, third.SetAppBadgeCaller.Invoke)
 }
 
 // #################### s3 ####################
@@ -77,44 +79,44 @@ func setURLPrefix(c *gin.Context, urlPrefix *string) error {
 }
 
 func (o *ThirdApi) PartLimit(c *gin.Context) {
-	a2r.Call(third.ThirdClient.PartLimit, o.Client, c)
+	a2r.CallV2(c, third.PartLimitCaller.Invoke)
 }
 
 func (o *ThirdApi) PartSize(c *gin.Context) {
-	a2r.Call(third.ThirdClient.PartSize, o.Client, c)
+	a2r.CallV2(c, third.PartSizeCaller.Invoke)
 }
 
 func (o *ThirdApi) InitiateMultipartUpload(c *gin.Context) {
 	opt := setURLPrefixOption(third.ThirdClient.InitiateMultipartUpload, func(req *third.InitiateMultipartUploadReq) error {
 		return setURLPrefix(c, &req.UrlPrefix)
 	})
-	a2r.Call(third.ThirdClient.InitiateMultipartUpload, o.Client, c, opt)
+	a2r.CallV2(c, third.InitiateMultipartUploadCaller.Invoke, opt)
 }
 
 func (o *ThirdApi) AuthSign(c *gin.Context) {
-	a2r.Call(third.ThirdClient.AuthSign, o.Client, c)
+	a2r.CallV2(c, third.AuthSignCaller.Invoke)
 }
 
 func (o *ThirdApi) CompleteMultipartUpload(c *gin.Context) {
 	opt := setURLPrefixOption(third.ThirdClient.CompleteMultipartUpload, func(req *third.CompleteMultipartUploadReq) error {
 		return setURLPrefix(c, &req.UrlPrefix)
 	})
-	a2r.Call(third.ThirdClient.CompleteMultipartUpload, o.Client, c, opt)
+	a2r.CallV2(c, third.CompleteMultipartUploadCaller.Invoke, opt)
 }
 
 func (o *ThirdApi) AccessURL(c *gin.Context) {
-	a2r.Call(third.ThirdClient.AccessURL, o.Client, c)
+	a2r.CallV2(c, third.AccessURLCaller.Invoke)
 }
 
 func (o *ThirdApi) InitiateFormData(c *gin.Context) {
-	a2r.Call(third.ThirdClient.InitiateFormData, o.Client, c)
+	a2r.CallV2(c, third.InitiateFormDataCaller.Invoke)
 }
 
 func (o *ThirdApi) CompleteFormData(c *gin.Context) {
 	opt := setURLPrefixOption(third.ThirdClient.CompleteFormData, func(req *third.CompleteFormDataReq) error {
 		return setURLPrefix(c, &req.UrlPrefix)
 	})
-	a2r.Call(third.ThirdClient.CompleteFormData, o.Client, c, opt)
+	a2r.CallV2(c, third.CompleteFormDataCaller.Invoke, opt)
 }
 
 func (o *ThirdApi) ObjectRedirect(c *gin.Context) {
@@ -138,7 +140,7 @@ func (o *ThirdApi) ObjectRedirect(c *gin.Context) {
 		}
 		query[key] = values[0]
 	}
-	resp, err := o.Client.AccessURL(ctx, &third.AccessURLReq{Name: name, Query: query})
+	resp, err := third.AccessURLCaller.Invoke(ctx, &third.AccessURLReq{Name: name, Query: query})
 	if err != nil {
 		if errs.ErrArgs.Is(err) {
 			c.String(http.StatusBadRequest, err.Error())
@@ -156,15 +158,15 @@ func (o *ThirdApi) ObjectRedirect(c *gin.Context) {
 
 // #################### logs ####################.
 func (o *ThirdApi) UploadLogs(c *gin.Context) {
-	a2r.Call(third.ThirdClient.UploadLogs, o.Client, c)
+	a2r.CallV2(c, third.UploadLogsCaller.Invoke)
 }
 
 func (o *ThirdApi) DeleteLogs(c *gin.Context) {
-	a2r.Call(third.ThirdClient.DeleteLogs, o.Client, c)
+	a2r.CallV2(c, third.DeleteLogsCaller.Invoke)
 }
 
 func (o *ThirdApi) SearchLogs(c *gin.Context) {
-	a2r.Call(third.ThirdClient.SearchLogs, o.Client, c)
+	a2r.CallV2(c, third.SearchLogsCaller.Invoke)
 }
 
 func (o *ThirdApi) GetPrometheus(c *gin.Context) {
diff --git a/internal/api/user.go b/internal/api/user.go
index b499f71dc2..e1024e50b5 100644
--- a/internal/api/user.go
+++ b/internal/api/user.go
@@ -16,52 +16,58 @@ package api
 
 import (
 	"github.com/gin-gonic/gin"
-	"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
 	"github.com/openimsdk/protocol/constant"
 	"github.com/openimsdk/protocol/msggateway"
 	"github.com/openimsdk/protocol/user"
 	"github.com/openimsdk/tools/a2r"
 	"github.com/openimsdk/tools/apiresp"
+	"github.com/openimsdk/tools/discovery"
 	"github.com/openimsdk/tools/errs"
 	"github.com/openimsdk/tools/log"
 )
 
-type UserApi rpcclient.User
+type UserApi struct {
+	Discov                discovery.SvcDiscoveryRegistry
+	MessageGateWayRpcName string
+}
 
-func NewUserApi(client rpcclient.User) UserApi {
-	return UserApi(client)
+func NewUserApi(discov discovery.SvcDiscoveryRegistry, messageGateWayRpcName string) UserApi {
+	return UserApi{
+		Discov:                discov,
+		MessageGateWayRpcName: messageGateWayRpcName,
+	}
 }
 
 func (u *UserApi) UserRegister(c *gin.Context) {
-	a2r.Call(user.UserClient.UserRegister, u.Client, c)
+	a2r.CallV2(c, user.UserRegisterCaller.Invoke)
 }
 
 // UpdateUserInfo is deprecated. Use UpdateUserInfoEx
 func (u *UserApi) UpdateUserInfo(c *gin.Context) {
-	a2r.Call(user.UserClient.UpdateUserInfo, u.Client, c)
+	a2r.CallV2(c, user.UpdateUserInfoCaller.Invoke)
 }
 
 func (u *UserApi) UpdateUserInfoEx(c *gin.Context) {
-	a2r.Call(user.UserClient.UpdateUserInfoEx, u.Client, c)
+	a2r.CallV2(c, user.UpdateUserInfoExCaller.Invoke)
 }
 func (u *UserApi) SetGlobalRecvMessageOpt(c *gin.Context) {
-	a2r.Call(user.UserClient.SetGlobalRecvMessageOpt, u.Client, c)
+	a2r.CallV2(c, user.SetGlobalRecvMessageOptCaller.Invoke)
 }
 
 func (u *UserApi) GetUsersPublicInfo(c *gin.Context) {
-	a2r.Call(user.UserClient.GetDesignateUsers, u.Client, c)
+	a2r.CallV2(c, user.GetDesignateUsersCaller.Invoke)
 }
 
 func (u *UserApi) GetAllUsersID(c *gin.Context) {
-	a2r.Call(user.UserClient.GetAllUserID, u.Client, c)
+	a2r.CallV2(c, user.GetAllUserIDCaller.Invoke)
 }
 
 func (u *UserApi) AccountCheck(c *gin.Context) {
-	a2r.Call(user.UserClient.AccountCheck, u.Client, c)
+	a2r.CallV2(c, user.AccountCheckCaller.Invoke)
 }
 
 func (u *UserApi) GetUsers(c *gin.Context) {
-	a2r.Call(user.UserClient.GetPaginationUsers, u.Client, c)
+	a2r.CallV2(c, user.GetPaginationUsersCaller.Invoke)
 }
 
 // GetUsersOnlineStatus Get user online status.
@@ -122,7 +128,7 @@ func (u *UserApi) GetUsersOnlineStatus(c *gin.Context) {
 }
 
 func (u *UserApi) UserRegisterCount(c *gin.Context) {
-	a2r.Call(user.UserClient.UserRegisterCount, u.Client, c)
+	a2r.CallV2(c, user.UserRegisterCountCaller.Invoke)
 }
 
 // GetUsersOnlineTokenDetail Get user online token details.
@@ -188,52 +194,52 @@ func (u *UserApi) GetUsersOnlineTokenDetail(c *gin.Context) {
 
 // SubscriberStatus Presence status of subscribed users.
 func (u *UserApi) SubscriberStatus(c *gin.Context) {
-	a2r.Call(user.UserClient.SubscribeOrCancelUsersStatus, u.Client, c)
+	a2r.CallV2(c, user.SubscribeOrCancelUsersStatusCaller.Invoke)
 }
 
 // GetUserStatus Get the online status of the user.
 func (u *UserApi) GetUserStatus(c *gin.Context) {
-	a2r.Call(user.UserClient.GetUserStatus, u.Client, c)
+	a2r.CallV2(c, user.GetUserStatusCaller.Invoke)
 }
 
 // GetSubscribeUsersStatus Get the online status of subscribers.
 func (u *UserApi) GetSubscribeUsersStatus(c *gin.Context) {
-	a2r.Call(user.UserClient.GetSubscribeUsersStatus, u.Client, c)
+	a2r.CallV2(c, user.GetSubscribeUsersStatusCaller.Invoke)
 }
 
 // ProcessUserCommandAdd user general function add.
 func (u *UserApi) ProcessUserCommandAdd(c *gin.Context) {
-	a2r.Call(user.UserClient.ProcessUserCommandAdd, u.Client, c)
+	a2r.CallV2(c, user.ProcessUserCommandAddCaller.Invoke)
 }
 
 // ProcessUserCommandDelete user general function delete.
 func (u *UserApi) ProcessUserCommandDelete(c *gin.Context) {
-	a2r.Call(user.UserClient.ProcessUserCommandDelete, u.Client, c)
+	a2r.CallV2(c, user.ProcessUserCommandDeleteCaller.Invoke)
 }
 
 // ProcessUserCommandUpdate  user general function update.
 func (u *UserApi) ProcessUserCommandUpdate(c *gin.Context) {
-	a2r.Call(user.UserClient.ProcessUserCommandUpdate, u.Client, c)
+	a2r.CallV2(c, user.ProcessUserCommandUpdateCaller.Invoke)
 }
 
 // ProcessUserCommandGet user general function get.
 func (u *UserApi) ProcessUserCommandGet(c *gin.Context) {
-	a2r.Call(user.UserClient.ProcessUserCommandGet, u.Client, c)
+	a2r.CallV2(c, user.ProcessUserCommandGetCaller.Invoke)
 }
 
 // ProcessUserCommandGet user general function get all.
 func (u *UserApi) ProcessUserCommandGetAll(c *gin.Context) {
-	a2r.Call(user.UserClient.ProcessUserCommandGetAll, u.Client, c)
+	a2r.CallV2(c, user.ProcessUserCommandGetAllCaller.Invoke)
 }
 
 func (u *UserApi) AddNotificationAccount(c *gin.Context) {
-	a2r.Call(user.UserClient.AddNotificationAccount, u.Client, c)
+	a2r.CallV2(c, user.AddNotificationAccountCaller.Invoke)
 }
 
 func (u *UserApi) UpdateNotificationAccountInfo(c *gin.Context) {
-	a2r.Call(user.UserClient.UpdateNotificationAccountInfo, u.Client, c)
+	a2r.CallV2(c, user.UpdateNotificationAccountInfoCaller.Invoke)
 }
 
 func (u *UserApi) SearchNotificationAccount(c *gin.Context) {
-	a2r.Call(user.UserClient.SearchNotificationAccount, u.Client, c)
+	a2r.CallV2(c, user.SearchNotificationAccountCaller.Invoke)
 }
diff --git a/internal/msggateway/client.go b/internal/msggateway/client.go
index 7e1ba6405a..161300d6d0 100644
--- a/internal/msggateway/client.go
+++ b/internal/msggateway/client.go
@@ -18,7 +18,6 @@ import (
 	"context"
 	"encoding/json"
 	"fmt"
-	"runtime/debug"
 	"sync"
 	"sync/atomic"
 	"time"
@@ -132,7 +131,7 @@ func (c *Client) readMessage() {
 	defer func() {
 		if r := recover(); r != nil {
 			c.closedErr = ErrPanic
-			fmt.Println("socket have panic err:", r, string(debug.Stack()))
+			log.ZPanic(c.ctx, "socket have panic err:", r)
 		}
 		c.close()
 	}()
diff --git a/internal/msggateway/hub_server.go b/internal/msggateway/hub_server.go
index 8e1edbec74..5c9237ed14 100644
--- a/internal/msggateway/hub_server.go
+++ b/internal/msggateway/hub_server.go
@@ -21,7 +21,6 @@ import (
 	"github.com/openimsdk/open-im-server/v3/pkg/authverify"
 	"github.com/openimsdk/open-im-server/v3/pkg/common/servererrs"
 	"github.com/openimsdk/open-im-server/v3/pkg/common/startrpc"
-	"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
 	"github.com/openimsdk/protocol/constant"
 	"github.com/openimsdk/protocol/msggateway"
 	"github.com/openimsdk/protocol/sdkws"
@@ -37,7 +36,6 @@ import (
 func (s *Server) InitServer(ctx context.Context, config *Config, disCov discovery.SvcDiscoveryRegistry, server *grpc.Server) error {
 	s.LongConnServer.SetDiscoveryRegistry(disCov, config)
 	msggateway.RegisterMsgGatewayServer(server, s)
-	s.userRcp = rpcclient.NewUserRpcClient(disCov, config.Discovery.RpcService.User, config.Share.IMAdminUserID)
 	if s.ready != nil {
 		return s.ready(s)
 	}
@@ -62,7 +60,6 @@ type Server struct {
 	config         *Config
 	pushTerminal   map[int]struct{}
 	ready          func(srv *Server) error
-	userRcp        rpcclient.UserRpcClient
 	queue          *memamq.MemoryQueue
 }
 
diff --git a/internal/msggateway/init.go b/internal/msggateway/init.go
index 6654e65984..156d32b4d9 100644
--- a/internal/msggateway/init.go
+++ b/internal/msggateway/init.go
@@ -62,7 +62,7 @@ func Start(ctx context.Context, index int, conf *Config) error {
 	)
 
 	hubServer := NewServer(longServer, conf, func(srv *Server) error {
-		longServer.online, _ = rpccache.NewOnlineCache(srv.userRcp, nil, rdb, false, longServer.subscriberUserOnlineStatusChanges)
+		longServer.online, _ = rpccache.NewOnlineCache(conf.Share.IMAdminUserID, nil, rdb, false, longServer.subscriberUserOnlineStatusChanges)
 		return nil
 	})
 
diff --git a/internal/msggateway/message_handler.go b/internal/msggateway/message_handler.go
index f2b0ce9dac..d88d2fbfd8 100644
--- a/internal/msggateway/message_handler.go
+++ b/internal/msggateway/message_handler.go
@@ -22,12 +22,9 @@ import (
 	"github.com/go-playground/validator/v10"
 	"google.golang.org/protobuf/proto"
 
-	"github.com/openimsdk/open-im-server/v3/pkg/common/config"
-	"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
 	"github.com/openimsdk/protocol/msg"
 	"github.com/openimsdk/protocol/push"
 	"github.com/openimsdk/protocol/sdkws"
-	"github.com/openimsdk/tools/discovery"
 	"github.com/openimsdk/tools/errs"
 	"github.com/openimsdk/tools/utils/jsonutil"
 )
@@ -115,18 +112,11 @@ type MessageHandler interface {
 var _ MessageHandler = (*GrpcHandler)(nil)
 
 type GrpcHandler struct {
-	msgRpcClient *rpcclient.MessageRpcClient
-	pushClient   *rpcclient.PushRpcClient
-	validate     *validator.Validate
+	validate *validator.Validate
 }
 
-func NewGrpcHandler(validate *validator.Validate, client discovery.SvcDiscoveryRegistry, rpcRegisterName *config.RpcService) *GrpcHandler {
-	msgRpcClient := rpcclient.NewMessageRpcClient(client, rpcRegisterName.Msg)
-	pushRpcClient := rpcclient.NewPushRpcClient(client, rpcRegisterName.Push)
-	return &GrpcHandler{
-		msgRpcClient: &msgRpcClient,
-		pushClient:   &pushRpcClient, validate: validate,
-	}
+func NewGrpcHandler(validate *validator.Validate) *GrpcHandler {
+	return &GrpcHandler{validate: validate}
 }
 
 func (g GrpcHandler) GetSeq(ctx context.Context, data *Req) ([]byte, error) {
@@ -137,7 +127,7 @@ func (g GrpcHandler) GetSeq(ctx context.Context, data *Req) ([]byte, error) {
 	if err := g.validate.Struct(&req); err != nil {
 		return nil, errs.WrapMsg(err, "GetSeq: validation failed", "action", "validate", "dataType", "GetMaxSeqReq")
 	}
-	resp, err := g.msgRpcClient.GetMaxSeq(ctx, &req)
+	resp, err := msg.GetMaxSeqCaller.Invoke(ctx, &req)
 	if err != nil {
 		return nil, err
 	}
@@ -161,7 +151,7 @@ func (g GrpcHandler) SendMessage(ctx context.Context, data *Req) ([]byte, error)
 	}
 
 	req := msg.SendMsgReq{MsgData: &msgData}
-	resp, err := g.msgRpcClient.SendMsg(ctx, &req)
+	resp, err := msg.SendMsgCaller.Invoke(ctx, &req)
 	if err != nil {
 		return nil, err
 	}
@@ -175,7 +165,7 @@ func (g GrpcHandler) SendMessage(ctx context.Context, data *Req) ([]byte, error)
 }
 
 func (g GrpcHandler) SendSignalMessage(context context.Context, data *Req) ([]byte, error) {
-	resp, err := g.msgRpcClient.SendMsg(context, nil)
+	resp, err := msg.SendMsgCaller.Invoke(context, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -186,7 +176,7 @@ func (g GrpcHandler) SendSignalMessage(context context.Context, data *Req) ([]by
 	return c, nil
 }
 
-func (g GrpcHandler) PullMessageBySeqList(context context.Context, data *Req) ([]byte, error) {
+func (g GrpcHandler) PullMessageBySeqList(ctx context.Context, data *Req) ([]byte, error) {
 	req := sdkws.PullMessageBySeqsReq{}
 	if err := proto.Unmarshal(data.Data, &req); err != nil {
 		return nil, errs.WrapMsg(err, "err proto unmarshal", "action", "unmarshal", "dataType", "PullMessageBySeqsReq")
@@ -194,7 +184,7 @@ func (g GrpcHandler) PullMessageBySeqList(context context.Context, data *Req) ([
 	if err := g.validate.Struct(data); err != nil {
 		return nil, errs.WrapMsg(err, "validation failed", "action", "validate", "dataType", "PullMessageBySeqsReq")
 	}
-	resp, err := g.msgRpcClient.PullMessageBySeqList(context, &req)
+	resp, err := msg.PullMessageBySeqsCaller.Invoke(ctx, &req)
 	if err != nil {
 		return nil, err
 	}
@@ -205,7 +195,7 @@ func (g GrpcHandler) PullMessageBySeqList(context context.Context, data *Req) ([
 	return c, nil
 }
 
-func (g GrpcHandler) GetConversationsHasReadAndMaxSeq(context context.Context, data *Req) ([]byte, error) {
+func (g GrpcHandler) GetConversationsHasReadAndMaxSeq(ctx context.Context, data *Req) ([]byte, error) {
 	req := msg.GetConversationsHasReadAndMaxSeqReq{}
 	if err := proto.Unmarshal(data.Data, &req); err != nil {
 		return nil, errs.WrapMsg(err, "err proto unmarshal", "action", "unmarshal", "dataType", "GetConversationsHasReadAndMaxSeq")
@@ -213,7 +203,7 @@ func (g GrpcHandler) GetConversationsHasReadAndMaxSeq(context context.Context, d
 	if err := g.validate.Struct(data); err != nil {
 		return nil, errs.WrapMsg(err, "validation failed", "action", "validate", "dataType", "GetConversationsHasReadAndMaxSeq")
 	}
-	resp, err := g.msgRpcClient.GetConversationsHasReadAndMaxSeq(context, &req)
+	resp, err := msg.GetConversationsHasReadAndMaxSeqCaller.Invoke(ctx, &req)
 	if err != nil {
 		return nil, err
 	}
@@ -224,7 +214,7 @@ func (g GrpcHandler) GetConversationsHasReadAndMaxSeq(context context.Context, d
 	return c, nil
 }
 
-func (g GrpcHandler) GetSeqMessage(context context.Context, data *Req) ([]byte, error) {
+func (g GrpcHandler) GetSeqMessage(ctx context.Context, data *Req) ([]byte, error) {
 	req := msg.GetSeqMessageReq{}
 	if err := proto.Unmarshal(data.Data, &req); err != nil {
 		return nil, errs.WrapMsg(err, "error unmarshaling request", "action", "unmarshal", "dataType", "GetSeqMessage")
@@ -232,7 +222,7 @@ func (g GrpcHandler) GetSeqMessage(context context.Context, data *Req) ([]byte,
 	if err := g.validate.Struct(data); err != nil {
 		return nil, errs.WrapMsg(err, "validation failed", "action", "validate", "dataType", "GetSeqMessage")
 	}
-	resp, err := g.msgRpcClient.GetSeqMessage(context, &req)
+	resp, err := msg.GetSeqMessageCaller.Invoke(ctx, &req)
 	if err != nil {
 		return nil, err
 	}
@@ -243,12 +233,12 @@ func (g GrpcHandler) GetSeqMessage(context context.Context, data *Req) ([]byte,
 	return c, nil
 }
 
-func (g GrpcHandler) UserLogout(context context.Context, data *Req) ([]byte, error) {
+func (g GrpcHandler) UserLogout(ctx context.Context, data *Req) ([]byte, error) {
 	req := push.DelUserPushTokenReq{}
 	if err := proto.Unmarshal(data.Data, &req); err != nil {
 		return nil, errs.WrapMsg(err, "error unmarshaling request", "action", "unmarshal", "dataType", "DelUserPushTokenReq")
 	}
-	resp, err := g.pushClient.DelUserPushToken(context, &req)
+	resp, err := push.DelUserPushTokenCaller.Invoke(ctx, &req)
 	if err != nil {
 		return nil, err
 	}
diff --git a/internal/msggateway/online.go b/internal/msggateway/online.go
index f29869b6e5..bff2639976 100644
--- a/internal/msggateway/online.go
+++ b/internal/msggateway/online.go
@@ -5,16 +5,17 @@ import (
 	"crypto/md5"
 	"encoding/binary"
 	"fmt"
-	"github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/cachekey"
-	pbuser "github.com/openimsdk/protocol/user"
-	"github.com/openimsdk/tools/log"
-	"github.com/openimsdk/tools/mcontext"
-	"github.com/openimsdk/tools/utils/datautil"
 	"math/rand"
 	"os"
 	"strconv"
 	"sync/atomic"
 	"time"
+
+	"github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/cachekey"
+	pbuser "github.com/openimsdk/protocol/user"
+	"github.com/openimsdk/tools/log"
+	"github.com/openimsdk/tools/mcontext"
+	"github.com/openimsdk/tools/utils/datautil"
 )
 
 func (ws *WsServer) ChangeOnlineStatus(concurrent int) {
@@ -87,7 +88,7 @@ func (ws *WsServer) ChangeOnlineStatus(concurrent int) {
 		opIdCtx := mcontext.SetOperationID(context.Background(), operationIDPrefix+strconv.FormatInt(count.Add(1), 10))
 		ctx, cancel := context.WithTimeout(opIdCtx, time.Second*5)
 		defer cancel()
-		if _, err := ws.userClient.Client.SetUserOnlineStatus(ctx, req); err != nil {
+		if err := pbuser.SetUserOnlineStatusCaller.Execute(ctx, req); err != nil {
 			log.ZError(ctx, "update user online status", err)
 		}
 		for _, ss := range req.Status {
diff --git a/internal/msggateway/ws_server.go b/internal/msggateway/ws_server.go
index 2e23262b12..7271c37274 100644
--- a/internal/msggateway/ws_server.go
+++ b/internal/msggateway/ws_server.go
@@ -16,7 +16,6 @@ import (
 	"github.com/go-playground/validator/v10"
 	"github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
 	"github.com/openimsdk/open-im-server/v3/pkg/common/servererrs"
-	"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
 	"github.com/openimsdk/protocol/constant"
 	"github.com/openimsdk/protocol/msggateway"
 	"github.com/openimsdk/tools/discovery"
@@ -57,8 +56,6 @@ type WsServer struct {
 	handshakeTimeout  time.Duration
 	writeBufferSize   int
 	validate          *validator.Validate
-	userClient        *rpcclient.UserRpcClient
-	authClient        *rpcclient.Auth
 	disCov            discovery.SvcDiscoveryRegistry
 	Compressor
 	//Encoder
@@ -73,10 +70,7 @@ type kickHandler struct {
 }
 
 func (ws *WsServer) SetDiscoveryRegistry(disCov discovery.SvcDiscoveryRegistry, config *Config) {
-	ws.MessageHandler = NewGrpcHandler(ws.validate, disCov, &config.Discovery.RpcService)
-	u := rpcclient.NewUserRpcClient(disCov, config.Discovery.RpcService.User, config.Share.IMAdminUserID)
-	ws.authClient = rpcclient.NewAuth(disCov, config.Discovery.RpcService.Auth)
-	ws.userClient = &u
+	ws.MessageHandler = NewGrpcHandler(ws.validate)
 	ws.disCov = disCov
 }
 
@@ -312,7 +306,8 @@ func (ws *WsServer) multiTerminalLoginChecker(clientOK bool, oldClients []*Clien
 			[]string{newClient.ctx.GetOperationID(), newClient.ctx.GetUserID(),
 				constant.PlatformIDToName(newClient.PlatformID), newClient.ctx.GetConnID()},
 		)
-		if _, err := ws.authClient.KickTokens(ctx, kickTokens); err != nil {
+
+		if err := pbAuth.KickTokensCaller.Execute(ctx, &pbAuth.KickTokensReq{Tokens: kickTokens}); err != nil {
 			log.ZWarn(newClient.ctx, "kickTokens err", err)
 		}
 	}
@@ -339,7 +334,11 @@ func (ws *WsServer) multiTerminalLoginChecker(clientOK bool, oldClients []*Clien
 			[]string{newClient.ctx.GetOperationID(), newClient.ctx.GetUserID(),
 				constant.PlatformIDToName(newClient.PlatformID), newClient.ctx.GetConnID()},
 		)
-		if _, err := ws.authClient.InvalidateToken(ctx, newClient.token, newClient.UserID, newClient.PlatformID); err != nil {
+		if err := pbAuth.InvalidateTokenCaller.Execute(ctx, &pbAuth.InvalidateTokenReq{
+			PreservedToken: newClient.token,
+			UserID:         newClient.UserID,
+			PlatformID:     int32(newClient.PlatformID),
+		}); err != nil {
 			log.ZWarn(newClient.ctx, "InvalidateToken err", err, "userID", newClient.UserID,
 				"platformID", newClient.PlatformID)
 		}
@@ -410,7 +409,7 @@ func (ws *WsServer) wsHandler(w http.ResponseWriter, r *http.Request) {
 	}
 
 	// Call the authentication client to parse the Token obtained from the context
-	resp, err := ws.authClient.ParseToken(connContext, connContext.GetToken())
+	resp, err := pbAuth.ParseTokenCaller.Invoke(connContext, &pbAuth.ParseTokenReq{Token: connContext.GetToken()})
 	if err != nil {
 		// If there's an error parsing the Token, decide whether to send the error message via WebSocket based on the context flag
 		shouldSendError := connContext.ShouldSendResp()
diff --git a/internal/msgtransfer/init.go b/internal/msgtransfer/init.go
index 4c09bc4e2a..19a53ebd52 100644
--- a/internal/msgtransfer/init.go
+++ b/internal/msgtransfer/init.go
@@ -25,6 +25,8 @@ import (
 	"strconv"
 	"syscall"
 
+	"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
+	"github.com/openimsdk/tools/discovery"
 	"github.com/openimsdk/tools/discovery/etcd"
 	"github.com/openimsdk/tools/utils/jsonutil"
 	"github.com/openimsdk/tools/utils/network"
@@ -39,9 +41,7 @@ import (
 
 	conf "github.com/openimsdk/open-im-server/v3/pkg/common/config"
 	discRegister "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister"
-	kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister"
 	"github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller"
-	"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
 	"github.com/openimsdk/tools/errs"
 	"github.com/openimsdk/tools/log"
 	"github.com/openimsdk/tools/mw"
@@ -93,6 +93,9 @@ func Start(ctx context.Context, index int, config *Config) error {
 	}
 	client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()),
 		grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin")))
+	if err = rpcclient.InitRpcCaller(client, config.Discovery.RpcService); err != nil {
+		return err
+	}
 
 	msgModel := redis.NewMsgCache(rdb)
 	msgDocModel, err := mgo.NewMsgMongo(mgocli.GetDB())
@@ -113,9 +116,7 @@ func Start(ctx context.Context, index int, config *Config) error {
 	if err != nil {
 		return err
 	}
-	conversationRpcClient := rpcclient.NewConversationRpcClient(client, config.Discovery.RpcService.Conversation)
-	groupRpcClient := rpcclient.NewGroupRpcClient(client, config.Discovery.RpcService.Group)
-	historyCH, err := NewOnlineHistoryRedisConsumerHandler(&config.KafkaConfig, msgTransferDatabase, &conversationRpcClient, &groupRpcClient)
+	historyCH, err := NewOnlineHistoryRedisConsumerHandler(&config.KafkaConfig, msgTransferDatabase)
 	if err != nil {
 		return err
 	}
@@ -129,10 +130,10 @@ func Start(ctx context.Context, index int, config *Config) error {
 		historyMongoCH: historyMongoCH,
 		runTimeEnv:     runTimeEnv,
 	}
-	return msgTransfer.Start(index, config)
+	return msgTransfer.Start(index, config, client)
 }
 
-func (m *MsgTransfer) Start(index int, config *Config) error {
+func (m *MsgTransfer) Start(index int, config *Config, client discovery.SvcDiscoveryRegistry) error {
 	m.ctx, m.cancel = context.WithCancel(context.Background())
 	var (
 		netDone = make(chan struct{}, 1)
@@ -147,11 +148,6 @@ func (m *MsgTransfer) Start(index int, config *Config) error {
 		return err
 	}
 
-	client, err := kdisc.NewDiscoveryRegister(&config.Discovery, m.runTimeEnv)
-	if err != nil {
-		return errs.WrapMsg(err, "failed to register discovery service")
-	}
-
 	registerIP, err := network.GetRpcRegisterIP("")
 	if err != nil {
 		return err
diff --git a/internal/msgtransfer/online_history_msg_handler.go b/internal/msgtransfer/online_history_msg_handler.go
index 0104f66337..9287d6b617 100644
--- a/internal/msgtransfer/online_history_msg_handler.go
+++ b/internal/msgtransfer/online_history_msg_handler.go
@@ -23,16 +23,17 @@ import (
 	"sync"
 	"time"
 
-	"github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
-
 	"github.com/IBM/sarama"
 	"github.com/go-redis/redis"
 	"github.com/openimsdk/open-im-server/v3/pkg/common/config"
+	"github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
 	"github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller"
 	"github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
-	"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
 	"github.com/openimsdk/open-im-server/v3/pkg/tools/batcher"
 	"github.com/openimsdk/protocol/constant"
+	pbconv "github.com/openimsdk/protocol/conversation"
+	"github.com/openimsdk/protocol/group"
+	"github.com/openimsdk/protocol/rpccall"
 	"github.com/openimsdk/protocol/sdkws"
 	"github.com/openimsdk/tools/errs"
 	"github.com/openimsdk/tools/log"
@@ -69,14 +70,11 @@ type OnlineHistoryRedisConsumerHandler struct {
 	redisMessageBatches *batcher.Batcher[sarama.ConsumerMessage]
 
 	msgTransferDatabase         controller.MsgTransferDatabase
-	conversationRpcClient       *rpcclient.ConversationRpcClient
-	groupRpcClient              *rpcclient.GroupRpcClient
 	conversationUserHasReadChan chan *userHasReadSeq
 	wg                          sync.WaitGroup
 }
 
-func NewOnlineHistoryRedisConsumerHandler(kafkaConf *config.Kafka, database controller.MsgTransferDatabase,
-	conversationRpcClient *rpcclient.ConversationRpcClient, groupRpcClient *rpcclient.GroupRpcClient) (*OnlineHistoryRedisConsumerHandler, error) {
+func NewOnlineHistoryRedisConsumerHandler(kafkaConf *config.Kafka, database controller.MsgTransferDatabase) (*OnlineHistoryRedisConsumerHandler, error) {
 	historyConsumerGroup, err := kafka.NewMConsumerGroup(kafkaConf.Build(), kafkaConf.ToRedisGroupID, []string{kafkaConf.ToRedisTopic}, false)
 	if err != nil {
 		return nil, err
@@ -103,8 +101,6 @@ func NewOnlineHistoryRedisConsumerHandler(kafkaConf *config.Kafka, database cont
 	}
 	b.Do = och.do
 	och.redisMessageBatches = b
-	och.conversationRpcClient = conversationRpcClient
-	och.groupRpcClient = groupRpcClient
 	och.historyConsumerGroup = historyConsumerGroup
 
 	return &och, err
@@ -285,22 +281,32 @@ func (och *OnlineHistoryRedisConsumerHandler) handleMsg(ctx context.Context, key
 			case constant.ReadGroupChatType:
 				log.ZDebug(ctx, "group chat first create conversation", "conversationID",
 					conversationID)
-				userIDs, err := och.groupRpcClient.GetGroupMemberIDs(ctx, msg.GroupID)
+
+				userIDs, err := rpccall.ExtractField(ctx, group.GetGroupMemberUserIDsCaller.Invoke,
+					&group.GetGroupMemberUserIDsReq{
+						GroupID: msg.GroupID,
+					}, (*group.GetGroupMemberUserIDsResp).GetUserIDs)
 				if err != nil {
 					log.ZWarn(ctx, "get group member ids error", err, "conversationID",
 						conversationID)
 				} else {
 					log.ZInfo(ctx, "GetGroupMemberIDs end")
 
-					if err := och.conversationRpcClient.GroupChatFirstCreateConversation(ctx,
-						msg.GroupID, userIDs); err != nil {
+					if err := pbconv.CreateGroupChatConversationsCaller.Execute(ctx, &pbconv.CreateGroupChatConversationsReq{
+						UserIDs: userIDs,
+						GroupID: msg.GroupID,
+					}); err != nil {
 						log.ZWarn(ctx, "single chat first create conversation error", err,
 							"conversationID", conversationID)
 					}
 				}
 			case constant.SingleChatType, constant.NotificationChatType:
-				if err := och.conversationRpcClient.SingleChatFirstCreateConversation(ctx, msg.RecvID,
-					msg.SendID, conversationID, msg.SessionType); err != nil {
+				if err := pbconv.CreateSingleChatConversationsCaller.Execute(ctx, &pbconv.CreateSingleChatConversationsReq{
+					RecvID:           msg.RecvID,
+					SendID:           msg.SendID,
+					ConversationID:   conversationID,
+					ConversationType: msg.SessionType,
+				}); err != nil {
 					log.ZWarn(ctx, "single chat or notification first create conversation error", err,
 						"conversationID", conversationID, "sessionType", msg.SessionType)
 				}
diff --git a/internal/push/push_handler.go b/internal/push/push_handler.go
index ee3dc5b843..ee855e1223 100644
--- a/internal/push/push_handler.go
+++ b/internal/push/push_handler.go
@@ -3,7 +3,6 @@ package push
 import (
 	"context"
 	"encoding/json"
-
 	"math/rand"
 	"strconv"
 	"time"
@@ -16,11 +15,14 @@ import (
 	"github.com/openimsdk/open-im-server/v3/pkg/common/webhook"
 	"github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
 	"github.com/openimsdk/open-im-server/v3/pkg/rpccache"
-	"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
 	"github.com/openimsdk/open-im-server/v3/pkg/util/conversationutil"
 	"github.com/openimsdk/protocol/constant"
+	pbconv "github.com/openimsdk/protocol/conversation"
+	"github.com/openimsdk/protocol/group"
+	"github.com/openimsdk/protocol/msg"
 	"github.com/openimsdk/protocol/msggateway"
 	pbpush "github.com/openimsdk/protocol/push"
+	"github.com/openimsdk/protocol/rpccall"
 	"github.com/openimsdk/protocol/sdkws"
 	"github.com/openimsdk/tools/discovery"
 	"github.com/openimsdk/tools/log"
@@ -41,9 +43,6 @@ type ConsumerHandler struct {
 	onlineCache            *rpccache.OnlineCache
 	groupLocalCache        *rpccache.GroupLocalCache
 	conversationLocalCache *rpccache.ConversationLocalCache
-	msgRpcClient           rpcclient.MessageRpcClient
-	conversationRpcClient  rpcclient.ConversationRpcClient
-	groupRpcClient         rpcclient.GroupRpcClient
 	webhookClient          *webhook.Client
 	config                 *Config
 }
@@ -58,19 +57,14 @@ func NewConsumerHandler(config *Config, database controller.PushDatabase, offlin
 		return nil, err
 	}
 
-	userRpcClient := rpcclient.NewUserRpcClient(client, config.Discovery.RpcService.User, config.Share.IMAdminUserID)
-
 	consumerHandler.offlinePusher = offlinePusher
 	consumerHandler.onlinePusher = NewOnlinePusher(client, config)
-	consumerHandler.groupRpcClient = rpcclient.NewGroupRpcClient(client, config.Discovery.RpcService.Group)
-	consumerHandler.groupLocalCache = rpccache.NewGroupLocalCache(consumerHandler.groupRpcClient, &config.LocalCacheConfig, rdb)
-	consumerHandler.msgRpcClient = rpcclient.NewMessageRpcClient(client, config.Discovery.RpcService.Msg)
-	consumerHandler.conversationRpcClient = rpcclient.NewConversationRpcClient(client, config.Discovery.RpcService.Conversation)
-	consumerHandler.conversationLocalCache = rpccache.NewConversationLocalCache(consumerHandler.conversationRpcClient, &config.LocalCacheConfig, rdb)
+	consumerHandler.groupLocalCache = rpccache.NewGroupLocalCache(&config.LocalCacheConfig, rdb)
+	consumerHandler.conversationLocalCache = rpccache.NewConversationLocalCache(&config.LocalCacheConfig, rdb)
 	consumerHandler.webhookClient = webhook.NewWebhookClient(config.WebhooksConfig.URL)
 	consumerHandler.config = config
 	consumerHandler.pushDatabase = database
-	consumerHandler.onlineCache, err = rpccache.NewOnlineCache(userRpcClient, consumerHandler.groupLocalCache, rdb, config.RpcConfig.FullUserCache, nil)
+	consumerHandler.onlineCache, err = rpccache.NewOnlineCache(config.Share.IMAdminUserID, consumerHandler.groupLocalCache, rdb, config.RpcConfig.FullUserCache, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -327,7 +321,7 @@ func (c *ConsumerHandler) groupMessagesHandler(ctx context.Context, groupID stri
 					ctx = mcontext.WithOpUserIDContext(ctx, c.config.Share.IMAdminUserID[0])
 				}
 				defer func(groupID string) {
-					if err = c.groupRpcClient.DismissGroup(ctx, groupID); err != nil {
+					if err = group.DismissGroupCaller.Execute(ctx, &group.DismissGroupReq{GroupID: groupID}); err != nil {
 						log.ZError(ctx, "DismissGroup Notification clear members", err, "groupID", groupID)
 					}
 				}(groupID)
@@ -355,8 +349,10 @@ func (c *ConsumerHandler) filterGroupMessageOfflinePush(ctx context.Context, gro
 	offlinePushUserIDs []string) (userIDs []string, err error) {
 
 	//todo local cache Obtain the difference set through local comparison.
-	needOfflinePushUserIDs, err := c.conversationRpcClient.GetConversationOfflinePushUserIDs(
-		ctx, conversationutil.GenGroupConversationID(groupID), offlinePushUserIDs)
+	needOfflinePushUserIDs, err := rpccall.ExtractField(ctx, pbconv.GetConversationOfflinePushUserIDsCaller.Invoke, &pbconv.GetConversationOfflinePushUserIDsReq{
+		ConversationID: conversationutil.GenGroupConversationID(groupID),
+		UserIDs:        offlinePushUserIDs,
+	}, (*pbconv.GetConversationOfflinePushUserIDsResp).GetUserIDs)
 	if err != nil {
 		return nil, err
 	}
@@ -410,12 +406,18 @@ func (c *ConsumerHandler) getOfflinePushInfos(msg *sdkws.MsgData) (title, conten
 
 func (c *ConsumerHandler) DeleteMemberAndSetConversationSeq(ctx context.Context, groupID string, userIDs []string) error {
 	conversationID := msgprocessor.GetConversationIDBySessionType(constant.ReadGroupChatType, groupID)
-	maxSeq, err := c.msgRpcClient.GetConversationMaxSeq(ctx, conversationID)
+	maxSeq, err := rpccall.ExtractField(ctx, msg.GetConversationMaxSeqCaller.Invoke,
+		&msg.GetConversationMaxSeqReq{ConversationID: conversationID},
+		(*msg.GetConversationMaxSeqResp).GetMaxSeq)
 	if err != nil {
 		return err
 	}
 
-	return c.conversationRpcClient.SetConversationMaxSeq(ctx, userIDs, conversationID, maxSeq)
+	return pbconv.SetConversationMaxSeqCaller.Execute(ctx, &pbconv.SetConversationMaxSeqReq{
+		ConversationID: conversationID,
+		OwnerUserID:    userIDs,
+		MaxSeq:         maxSeq,
+	})
 }
 
 func unmarshalNotificationElem(bytes []byte, t any) error {
diff --git a/internal/rpc/auth/auth.go b/internal/rpc/auth/auth.go
index 987ccd4ac8..c220863c62 100644
--- a/internal/rpc/auth/auth.go
+++ b/internal/rpc/auth/auth.go
@@ -42,7 +42,6 @@ import (
 type authServer struct {
 	pbauth.UnimplementedAuthServer
 	authDatabase   controller.AuthDatabase
-	userRpcClient  *rpcclient.UserRpcClient
 	RegisterCenter discovery.SvcDiscoveryRegistry
 	config         *Config
 }
@@ -59,9 +58,7 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg
 	if err != nil {
 		return err
 	}
-	userRpcClient := rpcclient.NewUserRpcClient(client, config.Discovery.RpcService.User, config.Share.IMAdminUserID)
 	pbauth.RegisterAuthServer(server, &authServer{
-		userRpcClient:  &userRpcClient,
 		RegisterCenter: client,
 		authDatabase: controller.NewAuthDatabase(
 			redis2.NewTokenCacheModel(rdb, config.RpcConfig.TokenPolicy.Expire),
@@ -86,7 +83,7 @@ func (s *authServer) GetAdminToken(ctx context.Context, req *pbauth.GetAdminToke
 
 	}
 
-	if _, err := s.userRpcClient.GetUserInfo(ctx, req.UserID); err != nil {
+	if _, err := rpcclient.GetUserInfo(ctx, req.UserID); err != nil {
 		return nil, err
 	}
 
@@ -115,7 +112,7 @@ func (s *authServer) GetUserToken(ctx context.Context, req *pbauth.GetUserTokenR
 	if authverify.IsManagerUserID(req.UserID, s.config.Share.IMAdminUserID) {
 		return nil, errs.ErrNoPermission.WrapMsg("don't get Admin token")
 	}
-	if _, err := s.userRpcClient.GetUserInfo(ctx, req.UserID); err != nil {
+	if _, err := rpcclient.GetUserInfo(ctx, req.UserID); err != nil {
 		return nil, err
 	}
 	token, err := s.authDatabase.CreateToken(ctx, req.UserID, int(req.PlatformID))
diff --git a/internal/rpc/conversation/conversation.go b/internal/rpc/conversation/conversation.go
index 7345c965db..72ef29d4bf 100644
--- a/internal/rpc/conversation/conversation.go
+++ b/internal/rpc/conversation/conversation.go
@@ -16,8 +16,6 @@ package conversation
 
 import (
 	"context"
-	"github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
-	pbmsg "github.com/openimsdk/protocol/msg"
 	"sort"
 	"time"
 
@@ -27,6 +25,10 @@ import (
 	"github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
 	dbModel "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
 	"github.com/openimsdk/open-im-server/v3/pkg/localcache"
+	"github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
+	pbgroup "github.com/openimsdk/protocol/group"
+	pbmsg "github.com/openimsdk/protocol/msg"
+	"github.com/openimsdk/protocol/rpccall"
 	"github.com/openimsdk/tools/db/redisutil"
 
 	"github.com/openimsdk/open-im-server/v3/pkg/common/convert"
@@ -46,9 +48,6 @@ import (
 
 type conversationServer struct {
 	pbconversation.UnimplementedConversationServer
-	msgRpcClient         *rpcclient.MessageRpcClient
-	user                 *rpcclient.UserRpcClient
-	groupRpcClient       *rpcclient.GroupRpcClient
 	conversationDatabase controller.ConversationDatabase
 
 	conversationNotificationSender *ConversationNotificationSender
@@ -78,15 +77,9 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg
 	if err != nil {
 		return err
 	}
-	groupRpcClient := rpcclient.NewGroupRpcClient(client, config.Discovery.RpcService.Group)
-	msgRpcClient := rpcclient.NewMessageRpcClient(client, config.Discovery.RpcService.Msg)
-	userRpcClient := rpcclient.NewUserRpcClient(client, config.Discovery.RpcService.User, config.Share.IMAdminUserID)
 	localcache.InitLocalCache(&config.LocalCacheConfig)
 	pbconversation.RegisterConversationServer(server, &conversationServer{
-		msgRpcClient:                   &msgRpcClient,
-		user:                           &userRpcClient,
-		conversationNotificationSender: NewConversationNotificationSender(&config.NotificationConfig, &msgRpcClient),
-		groupRpcClient:                 &groupRpcClient,
+		conversationNotificationSender: NewConversationNotificationSender(&config.NotificationConfig),
 		conversationDatabase: controller.NewConversationDatabase(conversationDB,
 			redis.NewConversationRedis(rdb, &config.LocalCacheConfig, redis.GetRocksCacheOptions(), conversationDB), mgocli.GetTx()),
 	})
@@ -126,12 +119,18 @@ func (c *conversationServer) GetSortedConversationList(ctx context.Context, req
 		return nil, errs.ErrRecordNotFound.Wrap()
 	}
 
-	maxSeqs, err := c.msgRpcClient.GetMaxSeqs(ctx, conversationIDs)
+	maxSeqs, err := rpccall.ExtractField(ctx, pbmsg.GetMaxSeqsCaller.Invoke,
+		&pbmsg.GetMaxSeqsReq{ConversationIDs: conversationIDs},
+		(*pbmsg.SeqsInfoResp).GetMaxSeqs)
 	if err != nil {
 		return nil, err
 	}
 
-	chatLogs, err := c.msgRpcClient.GetMsgByConversationIDs(ctx, conversationIDs, maxSeqs)
+	chatLogs, err := rpccall.ExtractField(ctx, pbmsg.GetMsgByConversationIDsCaller.Invoke,
+		&pbmsg.GetMsgByConversationIDsReq{
+			ConversationIDs: conversationIDs,
+			MaxSeqs:         maxSeqs,
+		}, (*pbmsg.GetMsgByConversationIDsResp).GetMsgDatas)
 	if err != nil {
 		return nil, err
 	}
@@ -141,7 +140,9 @@ func (c *conversationServer) GetSortedConversationList(ctx context.Context, req
 		return nil, err
 	}
 
-	hasReadSeqs, err := c.msgRpcClient.GetHasReadSeqs(ctx, req.UserID, conversationIDs)
+	hasReadSeqs, err := rpccall.ExtractField(ctx, pbmsg.GetHasReadSeqsCaller.Invoke,
+		&pbmsg.GetHasReadSeqsReq{ConversationIDs: conversationIDs},
+		(*pbmsg.SeqsInfoResp).GetMaxSeqs)
 	if err != nil {
 		return nil, err
 	}
@@ -228,12 +229,21 @@ func (c *conversationServer) SetConversations(ctx context.Context, req *pbconver
 	if req.Conversation == nil {
 		return nil, errs.ErrArgs.WrapMsg("conversation must not be nil")
 	}
-
 	if req.Conversation.ConversationType == constant.WriteGroupChatType {
-		groupInfo, err := c.groupRpcClient.GetGroupInfo(ctx, req.Conversation.GroupID)
+		groupInfo, err := rpccall.ExtractField(ctx, pbgroup.GetGroupsInfoCaller.Invoke,
+			&pbgroup.GetGroupsInfoReq{GroupIDs: []string{req.Conversation.GroupID}},
+			func(r *pbgroup.GetGroupsInfoResp) *sdkws.GroupInfo {
+				if len(r.GroupInfos) > 0 {
+					return r.GroupInfos[0]
+				}
+				return nil
+			})
 		if err != nil {
 			return nil, err
 		}
+		if groupInfo == nil {
+			return nil, servererrs.ErrGroupIDNotFound.WrapMsg(req.Conversation.GroupID)
+		}
 		if groupInfo.Status == constant.GroupStatusDismissed {
 			return nil, servererrs.ErrDismissedAlready.WrapMsg("group dismissed")
 		}
@@ -436,14 +446,14 @@ func (c *conversationServer) CreateGroupChatConversations(ctx context.Context, r
 		return nil, err
 	}
 	conversationID := msgprocessor.GetConversationIDBySessionType(constant.ReadGroupChatType, req.GroupID)
-	if _, err := c.msgRpcClient.Client.SetUserConversationMaxSeq(ctx, &pbmsg.SetUserConversationMaxSeqReq{ConversationID: conversationID, OwnerUserID: req.UserIDs, MaxSeq: 0}); err != nil {
+	if _, err := pbmsg.SetUserConversationMaxSeqCaller.Invoke(ctx, &pbmsg.SetUserConversationMaxSeqReq{ConversationID: conversationID, OwnerUserID: req.UserIDs, MaxSeq: 0}); err != nil {
 		return nil, err
 	}
 	return &pbconversation.CreateGroupChatConversationsResp{}, nil
 }
 
 func (c *conversationServer) SetConversationMaxSeq(ctx context.Context, req *pbconversation.SetConversationMaxSeqReq) (*pbconversation.SetConversationMaxSeqResp, error) {
-	if _, err := c.msgRpcClient.Client.SetUserConversationMaxSeq(ctx, &pbmsg.SetUserConversationMaxSeqReq{ConversationID: req.ConversationID, OwnerUserID: req.OwnerUserID, MaxSeq: req.MaxSeq}); err != nil {
+	if _, err := pbmsg.SetUserConversationMaxSeqCaller.Invoke(ctx, &pbmsg.SetUserConversationMaxSeqReq{ConversationID: req.ConversationID, OwnerUserID: req.OwnerUserID, MaxSeq: req.MaxSeq}); err != nil {
 		return nil, err
 	}
 	if err := c.conversationDatabase.UpdateUsersConversationField(ctx, req.OwnerUserID, req.ConversationID,
@@ -457,7 +467,7 @@ func (c *conversationServer) SetConversationMaxSeq(ctx context.Context, req *pbc
 }
 
 func (c *conversationServer) SetConversationMinSeq(ctx context.Context, req *pbconversation.SetConversationMinSeqReq) (*pbconversation.SetConversationMinSeqResp, error) {
-	if _, err := c.msgRpcClient.Client.SetUserConversationMinSeq(ctx, &pbmsg.SetUserConversationMinSeqReq{ConversationID: req.ConversationID, OwnerUserID: req.OwnerUserID, MinSeq: req.MinSeq}); err != nil {
+	if _, err := pbmsg.SetUserConversationMinSeqCaller.Invoke(ctx, &pbmsg.SetUserConversationMinSeqReq{ConversationID: req.ConversationID, OwnerUserID: req.OwnerUserID, MinSeq: req.MinSeq}); err != nil {
 		return nil, err
 	}
 	if err := c.conversationDatabase.UpdateUsersConversationField(ctx, req.OwnerUserID, req.ConversationID,
@@ -567,7 +577,7 @@ func (c *conversationServer) getConversationInfo(
 		}
 	}
 	if len(sendIDs) != 0 {
-		sendInfos, err := c.user.GetUsersInfo(ctx, sendIDs)
+		sendInfos, err := rpcclient.GetUsersInfo(ctx, sendIDs)
 		if err != nil {
 			return nil, err
 		}
@@ -576,7 +586,9 @@ func (c *conversationServer) getConversationInfo(
 		}
 	}
 	if len(groupIDs) != 0 {
-		groupInfos, err := c.groupRpcClient.GetGroupInfos(ctx, groupIDs, false)
+		groupInfos, err := rpccall.ExtractField(ctx, pbgroup.GetGroupsInfoCaller.Invoke,
+			&pbgroup.GetGroupsInfoReq{GroupIDs: groupIDs},
+			(*pbgroup.GetGroupsInfoResp).GetGroupInfos)
 		if err != nil {
 			return nil, err
 		}
diff --git a/internal/rpc/conversation/notification.go b/internal/rpc/conversation/notification.go
index 994e1d57ae..f94c0cd07a 100644
--- a/internal/rpc/conversation/notification.go
+++ b/internal/rpc/conversation/notification.go
@@ -27,8 +27,8 @@ type ConversationNotificationSender struct {
 	*rpcclient.NotificationSender
 }
 
-func NewConversationNotificationSender(conf *config.Notification, msgRpcClient *rpcclient.MessageRpcClient) *ConversationNotificationSender {
-	return &ConversationNotificationSender{rpcclient.NewNotificationSender(conf, rpcclient.WithRpcClient(msgRpcClient))}
+func NewConversationNotificationSender(conf *config.Notification) *ConversationNotificationSender {
+	return &ConversationNotificationSender{rpcclient.NewNotificationSender(conf, rpcclient.WithRpcClient())}
 }
 
 // SetPrivate invote.
diff --git a/internal/rpc/group/cache.go b/internal/rpc/group/cache.go
index 022a0f4ef6..bcd246267f 100644
--- a/internal/rpc/group/cache.go
+++ b/internal/rpc/group/cache.go
@@ -22,8 +22,8 @@ import (
 )
 
 // GetGroupInfoCache get group info from cache.
-func (s *groupServer) GetGroupInfoCache(ctx context.Context, req *pbgroup.GetGroupInfoCacheReq) (*pbgroup.GetGroupInfoCacheResp, error) {
-	group, err := s.db.TakeGroup(ctx, req.GroupID)
+func (g *groupServer) GetGroupInfoCache(ctx context.Context, req *pbgroup.GetGroupInfoCacheReq) (*pbgroup.GetGroupInfoCacheResp, error) {
+	group, err := g.db.TakeGroup(ctx, req.GroupID)
 	if err != nil {
 		return nil, err
 	}
@@ -32,8 +32,8 @@ func (s *groupServer) GetGroupInfoCache(ctx context.Context, req *pbgroup.GetGro
 	}, nil
 }
 
-func (s *groupServer) GetGroupMemberCache(ctx context.Context, req *pbgroup.GetGroupMemberCacheReq) (*pbgroup.GetGroupMemberCacheResp, error) {
-	members, err := s.db.TakeGroupMember(ctx, req.GroupID, req.GroupMemberID)
+func (g *groupServer) GetGroupMemberCache(ctx context.Context, req *pbgroup.GetGroupMemberCacheReq) (*pbgroup.GetGroupMemberCacheResp, error) {
+	members, err := g.db.TakeGroupMember(ctx, req.GroupID, req.GroupMemberID)
 	if err != nil {
 		return nil, err
 	}
diff --git a/internal/rpc/group/callback.go b/internal/rpc/group/callback.go
index 559d64ff47..8ed4afe5a0 100644
--- a/internal/rpc/group/callback.go
+++ b/internal/rpc/group/callback.go
@@ -32,7 +32,7 @@ import (
 )
 
 // CallbackBeforeCreateGroup callback before create group.
-func (s *groupServer) webhookBeforeCreateGroup(ctx context.Context, before *config.BeforeConfig, req *group.CreateGroupReq) error {
+func (g *groupServer) webhookBeforeCreateGroup(ctx context.Context, before *config.BeforeConfig, req *group.CreateGroupReq) error {
 	return webhook.WithCondition(ctx, before, func(ctx context.Context) error {
 		cbReq := &callbackstruct.CallbackBeforeCreateGroupReq{
 			CallbackCommand: callbackstruct.CallbackBeforeCreateGroupCommand,
@@ -57,7 +57,7 @@ func (s *groupServer) webhookBeforeCreateGroup(ctx context.Context, before *conf
 		}
 		resp := &callbackstruct.CallbackBeforeCreateGroupResp{}
 
-		if err := s.webhookClient.SyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, resp, before); err != nil {
+		if err := g.webhookClient.SyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, resp, before); err != nil {
 			return err
 		}
 
@@ -77,7 +77,7 @@ func (s *groupServer) webhookBeforeCreateGroup(ctx context.Context, before *conf
 	})
 }
 
-func (s *groupServer) webhookAfterCreateGroup(ctx context.Context, after *config.AfterConfig, req *group.CreateGroupReq) {
+func (g *groupServer) webhookAfterCreateGroup(ctx context.Context, after *config.AfterConfig, req *group.CreateGroupReq) {
 	cbReq := &callbackstruct.CallbackAfterCreateGroupReq{
 		CallbackCommand: callbackstruct.CallbackAfterCreateGroupCommand,
 		GroupInfo:       req.GroupInfo,
@@ -98,10 +98,10 @@ func (s *groupServer) webhookAfterCreateGroup(ctx context.Context, after *config
 			RoleLevel: constant.GroupOrdinaryUsers,
 		})
 	}
-	s.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, &callbackstruct.CallbackAfterCreateGroupResp{}, after)
+	g.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, &callbackstruct.CallbackAfterCreateGroupResp{}, after)
 }
 
-func (s *groupServer) webhookBeforeMembersJoinGroup(ctx context.Context, before *config.BeforeConfig, groupMembers []*model.GroupMember, groupID string, groupEx string) error {
+func (g *groupServer) webhookBeforeMembersJoinGroup(ctx context.Context, before *config.BeforeConfig, groupMembers []*model.GroupMember, groupID string, groupEx string) error {
 	return webhook.WithCondition(ctx, before, func(ctx context.Context) error {
 		groupMembersMap := datautil.SliceToMap(groupMembers, func(e *model.GroupMember) string {
 			return e.UserID
@@ -123,7 +123,7 @@ func (s *groupServer) webhookBeforeMembersJoinGroup(ctx context.Context, before
 		}
 		resp := &callbackstruct.CallbackBeforeMembersJoinGroupResp{}
 
-		if err := s.webhookClient.SyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, resp, before); err != nil {
+		if err := g.webhookClient.SyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, resp, before); err != nil {
 			return err
 		}
 
@@ -144,7 +144,7 @@ func (s *groupServer) webhookBeforeMembersJoinGroup(ctx context.Context, before
 	})
 }
 
-func (s *groupServer) webhookBeforeSetGroupMemberInfo(ctx context.Context, before *config.BeforeConfig, req *group.SetGroupMemberInfo) error {
+func (g *groupServer) webhookBeforeSetGroupMemberInfo(ctx context.Context, before *config.BeforeConfig, req *group.SetGroupMemberInfo) error {
 	return webhook.WithCondition(ctx, before, func(ctx context.Context) error {
 		cbReq := callbackstruct.CallbackBeforeSetGroupMemberInfoReq{
 			CallbackCommand: callbackstruct.CallbackBeforeSetGroupMemberInfoCommand,
@@ -164,7 +164,7 @@ func (s *groupServer) webhookBeforeSetGroupMemberInfo(ctx context.Context, befor
 			cbReq.Ex = &req.Ex.Value
 		}
 		resp := &callbackstruct.CallbackBeforeSetGroupMemberInfoResp{}
-		if err := s.webhookClient.SyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, resp, before); err != nil {
+		if err := g.webhookClient.SyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, resp, before); err != nil {
 			return err
 		}
 		if resp.FaceURL != nil {
@@ -183,7 +183,7 @@ func (s *groupServer) webhookBeforeSetGroupMemberInfo(ctx context.Context, befor
 	})
 }
 
-func (s *groupServer) webhookAfterSetGroupMemberInfo(ctx context.Context, after *config.AfterConfig, req *group.SetGroupMemberInfo) {
+func (g *groupServer) webhookAfterSetGroupMemberInfo(ctx context.Context, after *config.AfterConfig, req *group.SetGroupMemberInfo) {
 	cbReq := callbackstruct.CallbackAfterSetGroupMemberInfoReq{
 		CallbackCommand: callbackstruct.CallbackAfterSetGroupMemberInfoCommand,
 		GroupID:         req.GroupID,
@@ -201,55 +201,55 @@ func (s *groupServer) webhookAfterSetGroupMemberInfo(ctx context.Context, after
 	if req.Ex != nil {
 		cbReq.Ex = &req.Ex.Value
 	}
-	s.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, &callbackstruct.CallbackAfterSetGroupMemberInfoResp{}, after)
+	g.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, &callbackstruct.CallbackAfterSetGroupMemberInfoResp{}, after)
 }
 
-func (s *groupServer) webhookAfterQuitGroup(ctx context.Context, after *config.AfterConfig, req *group.QuitGroupReq) {
+func (g *groupServer) webhookAfterQuitGroup(ctx context.Context, after *config.AfterConfig, req *group.QuitGroupReq) {
 	cbReq := &callbackstruct.CallbackQuitGroupReq{
 		CallbackCommand: callbackstruct.CallbackAfterQuitGroupCommand,
 		GroupID:         req.GroupID,
 		UserID:          req.UserID,
 	}
-	s.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, &callbackstruct.CallbackQuitGroupResp{}, after)
+	g.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, &callbackstruct.CallbackQuitGroupResp{}, after)
 }
 
-func (s *groupServer) webhookAfterKickGroupMember(ctx context.Context, after *config.AfterConfig, req *group.KickGroupMemberReq) {
+func (g *groupServer) webhookAfterKickGroupMember(ctx context.Context, after *config.AfterConfig, req *group.KickGroupMemberReq) {
 	cbReq := &callbackstruct.CallbackKillGroupMemberReq{
 		CallbackCommand: callbackstruct.CallbackAfterKickGroupCommand,
 		GroupID:         req.GroupID,
 		KickedUserIDs:   req.KickedUserIDs,
 		Reason:          req.Reason,
 	}
-	s.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, &callbackstruct.CallbackKillGroupMemberResp{}, after)
+	g.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, &callbackstruct.CallbackKillGroupMemberResp{}, after)
 }
 
-func (s *groupServer) webhookAfterDismissGroup(ctx context.Context, after *config.AfterConfig, req *callbackstruct.CallbackDisMissGroupReq) {
+func (g *groupServer) webhookAfterDismissGroup(ctx context.Context, after *config.AfterConfig, req *callbackstruct.CallbackDisMissGroupReq) {
 	req.CallbackCommand = callbackstruct.CallbackAfterDisMissGroupCommand
-	s.webhookClient.AsyncPost(ctx, req.GetCallbackCommand(), req, &callbackstruct.CallbackDisMissGroupResp{}, after)
+	g.webhookClient.AsyncPost(ctx, req.GetCallbackCommand(), req, &callbackstruct.CallbackDisMissGroupResp{}, after)
 }
 
-func (s *groupServer) webhookBeforeApplyJoinGroup(ctx context.Context, before *config.BeforeConfig, req *callbackstruct.CallbackJoinGroupReq) (err error) {
+func (g *groupServer) webhookBeforeApplyJoinGroup(ctx context.Context, before *config.BeforeConfig, req *callbackstruct.CallbackJoinGroupReq) (err error) {
 	return webhook.WithCondition(ctx, before, func(ctx context.Context) error {
 		req.CallbackCommand = callbackstruct.CallbackBeforeJoinGroupCommand
 		resp := &callbackstruct.CallbackJoinGroupResp{}
-		if err := s.webhookClient.SyncPost(ctx, req.GetCallbackCommand(), req, resp, before); err != nil {
+		if err := g.webhookClient.SyncPost(ctx, req.GetCallbackCommand(), req, resp, before); err != nil {
 			return err
 		}
 		return nil
 	})
 }
 
-func (s *groupServer) webhookAfterTransferGroupOwner(ctx context.Context, after *config.AfterConfig, req *group.TransferGroupOwnerReq) {
+func (g *groupServer) webhookAfterTransferGroupOwner(ctx context.Context, after *config.AfterConfig, req *group.TransferGroupOwnerReq) {
 	cbReq := &callbackstruct.CallbackTransferGroupOwnerReq{
 		CallbackCommand: callbackstruct.CallbackAfterTransferGroupOwnerCommand,
 		GroupID:         req.GroupID,
 		OldOwnerUserID:  req.OldOwnerUserID,
 		NewOwnerUserID:  req.NewOwnerUserID,
 	}
-	s.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, &callbackstruct.CallbackTransferGroupOwnerResp{}, after)
+	g.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, &callbackstruct.CallbackTransferGroupOwnerResp{}, after)
 }
 
-func (s *groupServer) webhookBeforeInviteUserToGroup(ctx context.Context, before *config.BeforeConfig, req *group.InviteUserToGroupReq) (err error) {
+func (g *groupServer) webhookBeforeInviteUserToGroup(ctx context.Context, before *config.BeforeConfig, req *group.InviteUserToGroupReq) (err error) {
 	return webhook.WithCondition(ctx, before, func(ctx context.Context) error {
 		cbReq := &callbackstruct.CallbackBeforeInviteUserToGroupReq{
 			CallbackCommand: callbackstruct.CallbackBeforeInviteJoinGroupCommand,
@@ -260,7 +260,7 @@ func (s *groupServer) webhookBeforeInviteUserToGroup(ctx context.Context, before
 		}
 
 		resp := &callbackstruct.CallbackBeforeInviteUserToGroupResp{}
-		if err := s.webhookClient.SyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, resp, before); err != nil {
+		if err := g.webhookClient.SyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, resp, before); err != nil {
 			return err
 		}
 
@@ -275,7 +275,7 @@ func (s *groupServer) webhookBeforeInviteUserToGroup(ctx context.Context, before
 	})
 }
 
-func (s *groupServer) webhookAfterJoinGroup(ctx context.Context, after *config.AfterConfig, req *group.JoinGroupReq) {
+func (g *groupServer) webhookAfterJoinGroup(ctx context.Context, after *config.AfterConfig, req *group.JoinGroupReq) {
 	cbReq := &callbackstruct.CallbackAfterJoinGroupReq{
 		CallbackCommand: callbackstruct.CallbackAfterJoinGroupCommand,
 		OperationID:     mcontext.GetOperationID(ctx),
@@ -284,10 +284,10 @@ func (s *groupServer) webhookAfterJoinGroup(ctx context.Context, after *config.A
 		JoinSource:      req.JoinSource,
 		InviterUserID:   req.InviterUserID,
 	}
-	s.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, &callbackstruct.CallbackAfterJoinGroupResp{}, after)
+	g.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, &callbackstruct.CallbackAfterJoinGroupResp{}, after)
 }
 
-func (s *groupServer) webhookBeforeSetGroupInfo(ctx context.Context, before *config.BeforeConfig, req *group.SetGroupInfoReq) error {
+func (g *groupServer) webhookBeforeSetGroupInfo(ctx context.Context, before *config.BeforeConfig, req *group.SetGroupInfoReq) error {
 	return webhook.WithCondition(ctx, before, func(ctx context.Context) error {
 		cbReq := &callbackstruct.CallbackBeforeSetGroupInfoReq{
 			CallbackCommand: callbackstruct.CallbackBeforeSetGroupInfoCommand,
@@ -312,7 +312,7 @@ func (s *groupServer) webhookBeforeSetGroupInfo(ctx context.Context, before *con
 		}
 		resp := &callbackstruct.CallbackBeforeSetGroupInfoResp{}
 
-		if err := s.webhookClient.SyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, resp, before); err != nil {
+		if err := g.webhookClient.SyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, resp, before); err != nil {
 			return err
 		}
 
@@ -336,7 +336,7 @@ func (s *groupServer) webhookBeforeSetGroupInfo(ctx context.Context, before *con
 	})
 }
 
-func (s *groupServer) webhookAfterSetGroupInfo(ctx context.Context, after *config.AfterConfig, req *group.SetGroupInfoReq) {
+func (g *groupServer) webhookAfterSetGroupInfo(ctx context.Context, after *config.AfterConfig, req *group.SetGroupInfoReq) {
 	cbReq := &callbackstruct.CallbackAfterSetGroupInfoReq{
 		CallbackCommand: callbackstruct.CallbackAfterSetGroupInfoCommand,
 		GroupID:         req.GroupInfoForSet.GroupID,
@@ -357,10 +357,10 @@ func (s *groupServer) webhookAfterSetGroupInfo(ctx context.Context, after *confi
 	if req.GroupInfoForSet.ApplyMemberFriend != nil {
 		cbReq.ApplyMemberFriend = &req.GroupInfoForSet.ApplyMemberFriend.Value
 	}
-	s.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, &callbackstruct.CallbackAfterSetGroupInfoResp{}, after)
+	g.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, &callbackstruct.CallbackAfterSetGroupInfoResp{}, after)
 }
 
-func (s *groupServer) webhookBeforeSetGroupInfoEx(ctx context.Context, before *config.BeforeConfig, req *group.SetGroupInfoExReq) error {
+func (g *groupServer) webhookBeforeSetGroupInfoEx(ctx context.Context, before *config.BeforeConfig, req *group.SetGroupInfoExReq) error {
 	return webhook.WithCondition(ctx, before, func(ctx context.Context) error {
 		cbReq := &callbackstruct.CallbackBeforeSetGroupInfoExReq{
 			CallbackCommand: callbackstruct.CallbackBeforeSetGroupInfoExCommand,
@@ -388,7 +388,7 @@ func (s *groupServer) webhookBeforeSetGroupInfoEx(ctx context.Context, before *c
 
 		resp := &callbackstruct.CallbackBeforeSetGroupInfoExResp{}
 
-		if err := s.webhookClient.SyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, resp, before); err != nil {
+		if err := g.webhookClient.SyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, resp, before); err != nil {
 			return err
 		}
 
@@ -405,7 +405,7 @@ func (s *groupServer) webhookBeforeSetGroupInfoEx(ctx context.Context, before *c
 	})
 }
 
-func (s *groupServer) webhookAfterSetGroupInfoEx(ctx context.Context, after *config.AfterConfig, req *group.SetGroupInfoExReq) {
+func (g *groupServer) webhookAfterSetGroupInfoEx(ctx context.Context, after *config.AfterConfig, req *group.SetGroupInfoExReq) {
 	cbReq := &callbackstruct.CallbackAfterSetGroupInfoExReq{
 		CallbackCommand: callbackstruct.CallbackAfterSetGroupInfoExCommand,
 		GroupID:         req.GroupID,
@@ -428,5 +428,5 @@ func (s *groupServer) webhookAfterSetGroupInfoEx(ctx context.Context, after *con
 		cbReq.ApplyMemberFriend = req.ApplyMemberFriend
 	}
 
-	s.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, &callbackstruct.CallbackAfterSetGroupInfoExResp{}, after)
+	g.webhookClient.AsyncPost(ctx, cbReq.GetCallbackCommand(), cbReq, &callbackstruct.CallbackAfterSetGroupInfoExResp{}, after)
 }
diff --git a/internal/rpc/group/convert.go b/internal/rpc/group/convert.go
index 8026430c30..26277a56d4 100644
--- a/internal/rpc/group/convert.go
+++ b/internal/rpc/group/convert.go
@@ -19,7 +19,7 @@ import (
 	"github.com/openimsdk/protocol/sdkws"
 )
 
-func (s *groupServer) groupDB2PB(group *model.Group, ownerUserID string, memberCount uint32) *sdkws.GroupInfo {
+func (g *groupServer) groupDB2PB(group *model.Group, ownerUserID string, memberCount uint32) *sdkws.GroupInfo {
 	return &sdkws.GroupInfo{
 		GroupID:                group.GroupID,
 		GroupName:              group.GroupName,
@@ -41,7 +41,7 @@ func (s *groupServer) groupDB2PB(group *model.Group, ownerUserID string, memberC
 	}
 }
 
-func (s *groupServer) groupMemberDB2PB(member *model.GroupMember, appMangerLevel int32) *sdkws.GroupMemberFullInfo {
+func (g *groupServer) groupMemberDB2PB(member *model.GroupMember, appMangerLevel int32) *sdkws.GroupMemberFullInfo {
 	return &sdkws.GroupMemberFullInfo{
 		GroupID:        member.GroupID,
 		UserID:         member.UserID,
@@ -58,6 +58,6 @@ func (s *groupServer) groupMemberDB2PB(member *model.GroupMember, appMangerLevel
 	}
 }
 
-func (s *groupServer) groupMemberDB2PB2(member *model.GroupMember) *sdkws.GroupMemberFullInfo {
-	return s.groupMemberDB2PB(member, 0)
+func (g *groupServer) groupMemberDB2PB2(member *model.GroupMember) *sdkws.GroupMemberFullInfo {
+	return g.groupMemberDB2PB(member, 0)
 }
diff --git a/internal/rpc/group/fill.go b/internal/rpc/group/fill.go
index 1c86481df8..186506a556 100644
--- a/internal/rpc/group/fill.go
+++ b/internal/rpc/group/fill.go
@@ -16,9 +16,10 @@ package group
 
 import (
 	"context"
+
 	relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
 )
 
-func (s *groupServer) PopulateGroupMember(ctx context.Context, members ...*relationtb.GroupMember) error {
-	return s.notification.PopulateGroupMember(ctx, members...)
+func (g *groupServer) PopulateGroupMember(ctx context.Context, members ...*relationtb.GroupMember) error {
+	return g.notification.PopulateGroupMember(ctx, members...)
 }
diff --git a/internal/rpc/group/group.go b/internal/rpc/group/group.go
index 62020f980a..8af09b4c58 100644
--- a/internal/rpc/group/group.go
+++ b/internal/rpc/group/group.go
@@ -23,25 +23,26 @@ import (
 	"strings"
 	"time"
 
+	"github.com/openimsdk/open-im-server/v3/pkg/authverify"
+	"github.com/openimsdk/open-im-server/v3/pkg/callbackstruct"
 	"github.com/openimsdk/open-im-server/v3/pkg/common/config"
+	"github.com/openimsdk/open-im-server/v3/pkg/common/convert"
+	"github.com/openimsdk/open-im-server/v3/pkg/common/servererrs"
 	"github.com/openimsdk/open-im-server/v3/pkg/common/storage/common"
+	"github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller"
 	"github.com/openimsdk/open-im-server/v3/pkg/common/storage/database/mgo"
 	"github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
 	"github.com/openimsdk/open-im-server/v3/pkg/common/webhook"
 	"github.com/openimsdk/open-im-server/v3/pkg/localcache"
-
-	"github.com/openimsdk/open-im-server/v3/pkg/authverify"
-	"github.com/openimsdk/open-im-server/v3/pkg/callbackstruct"
-	"github.com/openimsdk/open-im-server/v3/pkg/common/convert"
-	"github.com/openimsdk/open-im-server/v3/pkg/common/servererrs"
-	"github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller"
 	"github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
 	"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
 	"github.com/openimsdk/open-im-server/v3/pkg/rpcclient/grouphash"
 	"github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification"
 	"github.com/openimsdk/protocol/constant"
-	pbconversation "github.com/openimsdk/protocol/conversation"
+	pbconv "github.com/openimsdk/protocol/conversation"
 	pbgroup "github.com/openimsdk/protocol/group"
+	"github.com/openimsdk/protocol/msg"
+	"github.com/openimsdk/protocol/rpccall"
 	"github.com/openimsdk/protocol/sdkws"
 	"github.com/openimsdk/protocol/wrapperspb"
 	"github.com/openimsdk/tools/db/mongoutil"
@@ -58,13 +59,10 @@ import (
 
 type groupServer struct {
 	pbgroup.UnimplementedGroupServer
-	db                    controller.GroupDatabase
-	user                  rpcclient.UserRpcClient
-	notification          *GroupNotificationSender
-	conversationRpcClient rpcclient.ConversationRpcClient
-	msgRpcClient          rpcclient.MessageRpcClient
-	config                *Config
-	webhookClient         *webhook.Client
+	db            controller.GroupDatabase
+	notification  *GroupNotificationSender
+	config        *Config
+	webhookClient *webhook.Client
 }
 
 type Config struct {
@@ -99,30 +97,22 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg
 	if err != nil {
 		return err
 	}
-	userRpcClient := rpcclient.NewUserRpcClient(client, config.Discovery.RpcService.User, config.Share.IMAdminUserID)
-	msgRpcClient := rpcclient.NewMessageRpcClient(client, config.Discovery.RpcService.Msg)
-	conversationRpcClient := rpcclient.NewConversationRpcClient(client, config.Discovery.RpcService.Conversation)
 	var gs groupServer
 	database := controller.NewGroupDatabase(rdb, &config.LocalCacheConfig, groupDB, groupMemberDB, groupRequestDB, mgocli.GetTx(), grouphash.NewGroupHashFromGroupServer(&gs))
 	gs.db = database
-	gs.user = userRpcClient
 	gs.notification = NewGroupNotificationSender(
 		database,
-		&msgRpcClient,
-		&userRpcClient,
-		&conversationRpcClient,
 		config,
 		func(ctx context.Context, userIDs []string) ([]notification.CommonUser, error) {
-			users, err := userRpcClient.GetUsersInfo(ctx, userIDs)
+			users, err := rpcclient.GetUsersInfo(ctx, userIDs)
 			if err != nil {
 				return nil, err
 			}
+
 			return datautil.Slice(users, func(e *sdkws.UserInfo) notification.CommonUser { return e }), nil
 		},
 	)
 	localcache.InitLocalCache(&config.LocalCacheConfig)
-	gs.conversationRpcClient = conversationRpcClient
-	gs.msgRpcClient = msgRpcClient
 	gs.config = config
 	gs.webhookClient = webhook.NewWebhookClient(config.WebhooksConfig.URL)
 	pbgroup.RegisterGroupServer(server, &gs)
@@ -172,7 +162,7 @@ func (g *groupServer) GetPublicUserInfoMap(ctx context.Context, userIDs []string
 	if len(userIDs) == 0 {
 		return map[string]*sdkws.PublicUserInfo{}, nil
 	}
-	users, err := g.user.GetPublicUserInfos(ctx, userIDs)
+	users, err := rpcclient.GetPublicUserInfos(ctx, userIDs)
 	if err != nil {
 		return nil, err
 	}
@@ -235,7 +225,7 @@ func (g *groupServer) CreateGroup(ctx context.Context, req *pbgroup.CreateGroupR
 		return nil, errs.ErrArgs.WrapMsg("group member repeated")
 	}
 
-	userMap, err := g.user.GetUsersInfoMap(ctx, userIDs)
+	userMap, err := rpcclient.GetUsersInfoMap(ctx, userIDs)
 	if err != nil {
 		return nil, err
 	}
@@ -386,7 +376,7 @@ func (g *groupServer) InviteUserToGroup(ctx context.Context, req *pbgroup.Invite
 		return nil, servererrs.ErrDismissedAlready.WrapMsg("group dismissed checking group status found it dismissed")
 	}
 
-	userMap, err := g.user.GetUsersInfoMap(ctx, req.InvitedUserIDs)
+	userMap, err := rpcclient.GetUsersInfoMap(ctx, req.InvitedUserIDs)
 	if err != nil {
 		return nil, err
 	}
@@ -697,7 +687,7 @@ func (g *groupServer) GetGroupApplicationList(ctx context.Context, req *pbgroup.
 		userIDs = append(userIDs, gr.UserID)
 	}
 	userIDs = datautil.Distinct(userIDs)
-	userMap, err := g.user.GetPublicUserInfoMap(ctx, userIDs)
+	userMap, err := rpcclient.GetPublicUserInfoMap(ctx, userIDs)
 	if err != nil {
 		return nil, err
 	}
@@ -809,7 +799,7 @@ func (g *groupServer) GroupApplicationResponse(ctx context.Context, req *pbgroup
 	} else if !g.IsNotFound(err) {
 		return nil, err
 	}
-	if _, err := g.user.GetPublicUserInfo(ctx, req.FromUserID); err != nil {
+	if _, err := rpcclient.GetPublicUserInfo(ctx, req.FromUserID); err != nil {
 		return nil, err
 	}
 	var member *model.GroupMember
@@ -853,7 +843,7 @@ func (g *groupServer) GroupApplicationResponse(ctx context.Context, req *pbgroup
 }
 
 func (g *groupServer) JoinGroup(ctx context.Context, req *pbgroup.JoinGroupReq) (*pbgroup.JoinGroupResp, error) {
-	user, err := g.user.GetUserInfo(ctx, req.InviterUserID)
+	user, err := rpcclient.GetUserInfo(ctx, req.InviterUserID)
 	if err != nil {
 		return nil, err
 	}
@@ -959,12 +949,19 @@ func (g *groupServer) QuitGroup(ctx context.Context, req *pbgroup.QuitGroupReq)
 }
 
 func (g *groupServer) deleteMemberAndSetConversationSeq(ctx context.Context, groupID string, userIDs []string) error {
-	conevrsationID := msgprocessor.GetConversationIDBySessionType(constant.ReadGroupChatType, groupID)
-	maxSeq, err := g.msgRpcClient.GetConversationMaxSeq(ctx, conevrsationID)
+	conversationID := msgprocessor.GetConversationIDBySessionType(constant.ReadGroupChatType, groupID)
+	maxSeq, err := rpccall.ExtractField(ctx, msg.GetConversationMaxSeqCaller.Invoke,
+		&msg.GetConversationMaxSeqReq{ConversationID: conversationID},
+		(*msg.GetConversationMaxSeqResp).GetMaxSeq)
 	if err != nil {
 		return err
 	}
-	return g.conversationRpcClient.SetConversationMaxSeq(ctx, userIDs, conevrsationID, maxSeq)
+
+	return pbconv.SetConversationMaxSeqCaller.Execute(ctx, &pbconv.SetConversationMaxSeqReq{
+		ConversationID: conversationID,
+		OwnerUserID:    userIDs,
+		MaxSeq:         maxSeq,
+	})
 }
 
 func (g *groupServer) SetGroupInfo(ctx context.Context, req *pbgroup.SetGroupInfoReq) (*pbgroup.SetGroupInfoResp, error) {
@@ -1029,7 +1026,7 @@ func (g *groupServer) SetGroupInfo(ctx context.Context, req *pbgroup.SetGroupInf
 	if req.GroupInfoForSet.Notification != "" {
 		num -= 3
 		func() {
-			conversation := &pbconversation.ConversationReq{
+			conversation := &pbconv.ConversationReq{
 				ConversationID:   msgprocessor.GetConversationIDBySessionType(constant.ReadGroupChatType, req.GroupInfoForSet.GroupID),
 				ConversationType: constant.ReadGroupChatType,
 				GroupID:          req.GroupInfoForSet.GroupID,
@@ -1040,7 +1037,11 @@ func (g *groupServer) SetGroupInfo(ctx context.Context, req *pbgroup.SetGroupInf
 				return
 			}
 			conversation.GroupAtType = &wrapperspb.Int32Value{Value: constant.GroupNotification}
-			if err := g.conversationRpcClient.SetConversations(ctx, resp.UserIDs, conversation); err != nil {
+
+			if err := pbconv.SetConversationsCaller.Execute(ctx, &pbconv.SetConversationsReq{
+				UserIDs:      resp.UserIDs,
+				Conversation: conversation,
+			}); err != nil {
 				log.ZWarn(ctx, "SetConversations", err, "UserIDs", resp.UserIDs, "conversation", conversation)
 			}
 		}()
@@ -1140,7 +1141,7 @@ func (g *groupServer) SetGroupInfoEx(ctx context.Context, req *pbgroup.SetGroupI
 
 		if req.Notification.Value != "" {
 			func() {
-				conversation := &pbconversation.ConversationReq{
+				conversation := &pbconv.ConversationReq{
 					ConversationID:   msgprocessor.GetConversationIDBySessionType(constant.ReadGroupChatType, req.GroupID),
 					ConversationType: constant.ReadGroupChatType,
 					GroupID:          req.GroupID,
@@ -1154,7 +1155,10 @@ func (g *groupServer) SetGroupInfoEx(ctx context.Context, req *pbgroup.SetGroupI
 
 				conversation.GroupAtType = &wrapperspb.Int32Value{Value: constant.GroupNotification}
 
-				if err := g.conversationRpcClient.SetConversations(ctx, resp.UserIDs, conversation); err != nil {
+				if err := pbconv.SetConversationsCaller.Execute(ctx, &pbconv.SetConversationsReq{
+					UserIDs:      resp.UserIDs,
+					Conversation: conversation,
+				}); err != nil {
 					log.ZWarn(ctx, "SetConversations", err, "UserIDs", resp.UserIDs, "conversation", conversation)
 				}
 			}()
@@ -1306,7 +1310,7 @@ func (g *groupServer) GetGroupMembersCMS(ctx context.Context, req *pbgroup.GetGr
 }
 
 func (g *groupServer) GetUserReqApplicationList(ctx context.Context, req *pbgroup.GetUserReqApplicationListReq) (*pbgroup.GetUserReqApplicationListResp, error) {
-	user, err := g.user.GetPublicUserInfo(ctx, req.UserID)
+	user, err := rpcclient.GetPublicUserInfo(ctx, req.UserID)
 	if err != nil {
 		return nil, err
 	}
@@ -1762,7 +1766,7 @@ func (g *groupServer) GetGroupUsersReqApplicationList(ctx context.Context, req *
 		return nil, servererrs.ErrGroupIDNotFound.WrapMsg(strings.Join(ids, ","))
 	}
 
-	userMap, err := g.user.GetPublicUserInfoMap(ctx, req.UserIDs)
+	userMap, err := rpcclient.GetPublicUserInfoMap(ctx, req.UserIDs)
 	if err != nil {
 		return nil, err
 	}
@@ -1839,7 +1843,7 @@ func (g *groupServer) GetSpecifiedUserGroupRequestInfo(ctx context.Context, req
 		return nil, err
 	}
 
-	userInfos, err := g.user.GetPublicUserInfos(ctx, []string{req.UserID})
+	userInfos, err := rpcclient.GetPublicUserInfos(ctx, []string{req.UserID})
 	if err != nil {
 		return nil, err
 	}
diff --git a/internal/rpc/group/notification.go b/internal/rpc/group/notification.go
index 54a6146f54..784ec89434 100644
--- a/internal/rpc/group/notification.go
+++ b/internal/rpc/group/notification.go
@@ -18,6 +18,8 @@ import (
 	"context"
 	"errors"
 	"fmt"
+	"time"
+
 	"github.com/openimsdk/open-im-server/v3/pkg/authverify"
 	"github.com/openimsdk/open-im-server/v3/pkg/common/convert"
 	"github.com/openimsdk/open-im-server/v3/pkg/common/servererrs"
@@ -29,8 +31,10 @@ import (
 	"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
 	"github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification"
 	"github.com/openimsdk/protocol/constant"
+	pbconv "github.com/openimsdk/protocol/conversation"
 	pbgroup "github.com/openimsdk/protocol/group"
 	"github.com/openimsdk/protocol/msg"
+	"github.com/openimsdk/protocol/rpccall"
 	"github.com/openimsdk/protocol/sdkws"
 	"github.com/openimsdk/tools/errs"
 	"github.com/openimsdk/tools/log"
@@ -38,7 +42,6 @@ import (
 	"github.com/openimsdk/tools/utils/datautil"
 	"github.com/openimsdk/tools/utils/stringutil"
 	"go.mongodb.org/mongo-driver/mongo"
-	"time"
 )
 
 // GroupApplicationReceiver
@@ -49,20 +52,14 @@ const (
 
 func NewGroupNotificationSender(
 	db controller.GroupDatabase,
-	msgRpcClient *rpcclient.MessageRpcClient,
-	userRpcClient *rpcclient.UserRpcClient,
-	conversationRpcClient *rpcclient.ConversationRpcClient,
 	config *Config,
 	fn func(ctx context.Context, userIDs []string) ([]notification.CommonUser, error),
 ) *GroupNotificationSender {
 	return &GroupNotificationSender{
-		NotificationSender: rpcclient.NewNotificationSender(&config.NotificationConfig, rpcclient.WithRpcClient(msgRpcClient), rpcclient.WithUserRpcClient(userRpcClient)),
+		NotificationSender: rpcclient.NewNotificationSender(&config.NotificationConfig, rpcclient.WithRpcClient(), rpcclient.WithUserRpcClient()),
 		getUsersInfo:       fn,
 		db:                 db,
 		config:             config,
-
-		conversationRpcClient: conversationRpcClient,
-		msgRpcClient:          msgRpcClient,
 	}
 }
 
@@ -71,9 +68,6 @@ type GroupNotificationSender struct {
 	getUsersInfo func(ctx context.Context, userIDs []string) ([]notification.CommonUser, error)
 	db           controller.GroupDatabase
 	config       *Config
-
-	conversationRpcClient *rpcclient.ConversationRpcClient
-	msgRpcClient          *rpcclient.MessageRpcClient
 }
 
 func (g *GroupNotificationSender) PopulateGroupMember(ctx context.Context, members ...*model.GroupMember) error {
@@ -524,11 +518,14 @@ func (g *GroupNotificationSender) GroupApplicationAgreeMemberEnterNotification(c
 
 	if !g.config.RpcConfig.EnableHistoryForNewMembers {
 		conversationID := msgprocessor.GetConversationIDBySessionType(constant.ReadGroupChatType, groupID)
-		maxSeq, err := g.msgRpcClient.GetConversationMaxSeq(ctx, conversationID)
+		maxSeq, err := rpccall.ExtractField(ctx, msg.GetConversationMaxSeqCaller.Invoke,
+			&msg.GetConversationMaxSeqReq{ConversationID: conversationID},
+			(*msg.GetConversationMaxSeqResp).GetMaxSeq)
 		if err != nil {
 			return err
 		}
-		if _, err = g.msgRpcClient.SetUserConversationsMinSeq(ctx, &msg.SetUserConversationsMinSeqReq{
+
+		if err := msg.SetUserConversationsMinSeqCaller.Execute(ctx, &msg.SetUserConversationsMinSeqReq{
 			UserIDs:        entrantUserID,
 			ConversationID: conversationID,
 			Seq:            maxSeq,
@@ -537,7 +534,10 @@ func (g *GroupNotificationSender) GroupApplicationAgreeMemberEnterNotification(c
 		}
 	}
 
-	if err := g.conversationRpcClient.GroupChatFirstCreateConversation(ctx, groupID, entrantUserID); err != nil {
+	if err := pbconv.CreateGroupChatConversationsCaller.Execute(ctx, &pbconv.CreateGroupChatConversationsReq{
+		UserIDs: entrantUserID,
+		GroupID: groupID,
+	}); err != nil {
 		return err
 	}
 
@@ -583,11 +583,13 @@ func (g *GroupNotificationSender) MemberEnterNotification(ctx context.Context, g
 
 	if !g.config.RpcConfig.EnableHistoryForNewMembers {
 		conversationID := msgprocessor.GetConversationIDBySessionType(constant.ReadGroupChatType, groupID)
-		maxSeq, err := g.msgRpcClient.GetConversationMaxSeq(ctx, conversationID)
+		maxSeq, err := rpccall.ExtractField(ctx, msg.GetConversationMaxSeqCaller.Invoke,
+			&msg.GetConversationMaxSeqReq{ConversationID: conversationID},
+			(*msg.GetConversationMaxSeqResp).GetMaxSeq)
 		if err != nil {
 			return err
 		}
-		if _, err = g.msgRpcClient.SetUserConversationsMinSeq(ctx, &msg.SetUserConversationsMinSeqReq{
+		if err := msg.SetUserConversationsMinSeqCaller.Execute(ctx, &msg.SetUserConversationsMinSeqReq{
 			UserIDs:        []string{entrantUserID},
 			ConversationID: conversationID,
 			Seq:            maxSeq,
@@ -596,7 +598,10 @@ func (g *GroupNotificationSender) MemberEnterNotification(ctx context.Context, g
 		}
 	}
 
-	if err := g.conversationRpcClient.GroupChatFirstCreateConversation(ctx, groupID, []string{entrantUserID}); err != nil {
+	if err := pbconv.CreateGroupChatConversationsCaller.Execute(ctx, &pbconv.CreateGroupChatConversationsReq{
+		UserIDs: []string{entrantUserID},
+		GroupID: groupID,
+	}); err != nil {
 		return err
 	}
 
diff --git a/internal/rpc/group/statistics.go b/internal/rpc/group/statistics.go
index 6adb1261af..1c582fda10 100644
--- a/internal/rpc/group/statistics.go
+++ b/internal/rpc/group/statistics.go
@@ -22,20 +22,20 @@ import (
 	"github.com/openimsdk/tools/errs"
 )
 
-func (s *groupServer) GroupCreateCount(ctx context.Context, req *group.GroupCreateCountReq) (*group.GroupCreateCountResp, error) {
+func (g *groupServer) GroupCreateCount(ctx context.Context, req *group.GroupCreateCountReq) (*group.GroupCreateCountResp, error) {
 	if req.Start > req.End {
 		return nil, errs.ErrArgs.WrapMsg("start > end: %d > %d", req.Start, req.End)
 	}
-	total, err := s.db.CountTotal(ctx, nil)
+	total, err := g.db.CountTotal(ctx, nil)
 	if err != nil {
 		return nil, err
 	}
 	start := time.UnixMilli(req.Start)
-	before, err := s.db.CountTotal(ctx, &start)
+	before, err := g.db.CountTotal(ctx, &start)
 	if err != nil {
 		return nil, err
 	}
-	count, err := s.db.CountRangeEverydayTotal(ctx, start, time.UnixMilli(req.End))
+	count, err := g.db.CountRangeEverydayTotal(ctx, start, time.UnixMilli(req.End))
 	if err != nil {
 		return nil, err
 	}
diff --git a/internal/rpc/group/sync.go b/internal/rpc/group/sync.go
index 0592aa811c..50ac8252f2 100644
--- a/internal/rpc/group/sync.go
+++ b/internal/rpc/group/sync.go
@@ -15,12 +15,12 @@ import (
 	"github.com/openimsdk/tools/log"
 )
 
-func (s *groupServer) GetFullGroupMemberUserIDs(ctx context.Context, req *pbgroup.GetFullGroupMemberUserIDsReq) (*pbgroup.GetFullGroupMemberUserIDsResp, error) {
-	vl, err := s.db.FindMaxGroupMemberVersionCache(ctx, req.GroupID)
+func (g *groupServer) GetFullGroupMemberUserIDs(ctx context.Context, req *pbgroup.GetFullGroupMemberUserIDsReq) (*pbgroup.GetFullGroupMemberUserIDsResp, error) {
+	vl, err := g.db.FindMaxGroupMemberVersionCache(ctx, req.GroupID)
 	if err != nil {
 		return nil, err
 	}
-	userIDs, err := s.db.FindGroupMemberUserID(ctx, req.GroupID)
+	userIDs, err := g.db.FindGroupMemberUserID(ctx, req.GroupID)
 	if err != nil {
 		return nil, err
 	}
@@ -36,12 +36,12 @@ func (s *groupServer) GetFullGroupMemberUserIDs(ctx context.Context, req *pbgrou
 	}, nil
 }
 
-func (s *groupServer) GetFullJoinGroupIDs(ctx context.Context, req *pbgroup.GetFullJoinGroupIDsReq) (*pbgroup.GetFullJoinGroupIDsResp, error) {
-	vl, err := s.db.FindMaxJoinGroupVersionCache(ctx, req.UserID)
+func (g *groupServer) GetFullJoinGroupIDs(ctx context.Context, req *pbgroup.GetFullJoinGroupIDsReq) (*pbgroup.GetFullJoinGroupIDsResp, error) {
+	vl, err := g.db.FindMaxJoinGroupVersionCache(ctx, req.UserID)
 	if err != nil {
 		return nil, err
 	}
-	groupIDs, err := s.db.FindJoinGroupID(ctx, req.UserID)
+	groupIDs, err := g.db.FindJoinGroupID(ctx, req.UserID)
 	if err != nil {
 		return nil, err
 	}
@@ -57,8 +57,8 @@ func (s *groupServer) GetFullJoinGroupIDs(ctx context.Context, req *pbgroup.GetF
 	}, nil
 }
 
-func (s *groupServer) GetIncrementalGroupMember(ctx context.Context, req *pbgroup.GetIncrementalGroupMemberReq) (*pbgroup.GetIncrementalGroupMemberResp, error) {
-	group, err := s.db.TakeGroup(ctx, req.GroupID)
+func (g *groupServer) GetIncrementalGroupMember(ctx context.Context, req *pbgroup.GetIncrementalGroupMemberReq) (*pbgroup.GetIncrementalGroupMemberResp, error) {
+	group, err := g.db.TakeGroup(ctx, req.GroupID)
 	if err != nil {
 		return nil, err
 	}
@@ -75,7 +75,7 @@ func (s *groupServer) GetIncrementalGroupMember(ctx context.Context, req *pbgrou
 		VersionID:     req.VersionID,
 		VersionNumber: req.Version,
 		Version: func(ctx context.Context, groupID string, version uint, limit int) (*model.VersionLog, error) {
-			vl, err := s.db.FindMemberIncrVersion(ctx, groupID, version, limit)
+			vl, err := g.db.FindMemberIncrVersion(ctx, groupID, version, limit)
 			if err != nil {
 				return nil, err
 			}
@@ -98,9 +98,9 @@ func (s *groupServer) GetIncrementalGroupMember(ctx context.Context, req *pbgrou
 			}
 			return vl, nil
 		},
-		CacheMaxVersion: s.db.FindMaxGroupMemberVersionCache,
+		CacheMaxVersion: g.db.FindMaxGroupMemberVersionCache,
 		Find: func(ctx context.Context, ids []string) ([]*sdkws.GroupMemberFullInfo, error) {
-			return s.getGroupMembersInfo(ctx, req.GroupID, ids)
+			return g.getGroupMembersInfo(ctx, req.GroupID, ids)
 		},
 		Resp: func(version *model.VersionLog, delIDs []string, insertList, updateList []*sdkws.GroupMemberFullInfo, full bool) *pbgroup.GetIncrementalGroupMemberResp {
 			return &pbgroup.GetIncrementalGroupMemberResp{
@@ -119,20 +119,20 @@ func (s *groupServer) GetIncrementalGroupMember(ctx context.Context, req *pbgrou
 		return nil, err
 	}
 	if resp.Full || hasGroupUpdate {
-		count, err := s.db.FindGroupMemberNum(ctx, group.GroupID)
+		count, err := g.db.FindGroupMemberNum(ctx, group.GroupID)
 		if err != nil {
 			return nil, err
 		}
-		owner, err := s.db.TakeGroupOwner(ctx, group.GroupID)
+		owner, err := g.db.TakeGroupOwner(ctx, group.GroupID)
 		if err != nil {
 			return nil, err
 		}
-		resp.Group = s.groupDB2PB(group, owner.UserID, count)
+		resp.Group = g.groupDB2PB(group, owner.UserID, count)
 	}
 	return resp, nil
 }
 
-func (s *groupServer) BatchGetIncrementalGroupMember(ctx context.Context, req *pbgroup.BatchGetIncrementalGroupMemberReq) (resp *pbgroup.BatchGetIncrementalGroupMemberResp, err error) {
+func (g *groupServer) BatchGetIncrementalGroupMember(ctx context.Context, req *pbgroup.BatchGetIncrementalGroupMemberReq) (resp *pbgroup.BatchGetIncrementalGroupMemberResp, err error) {
 	type VersionInfo struct {
 		GroupID       string
 		VersionID     string
@@ -161,7 +161,7 @@ func (s *groupServer) BatchGetIncrementalGroupMember(ctx context.Context, req *p
 		groupIDs = append(groupIDs, group.GroupID)
 	}
 
-	groups, err := s.db.FindGroup(ctx, groupIDs)
+	groups, err := g.db.FindGroup(ctx, groupIDs)
 	if err != nil {
 		return nil, errs.Wrap(err)
 	}
@@ -189,7 +189,7 @@ func (s *groupServer) BatchGetIncrementalGroupMember(ctx context.Context, req *p
 		VersionIDs:     versionIDs,
 		VersionNumbers: versionNumbers,
 		Versions: func(ctx context.Context, groupIDs []string, versions []uint64, limits []int) (map[string]*model.VersionLog, error) {
-			vLogs, err := s.db.BatchFindMemberIncrVersion(ctx, groupIDs, versions, limits)
+			vLogs, err := g.db.BatchFindMemberIncrVersion(ctx, groupIDs, versions, limits)
 			if err != nil {
 				return nil, errs.Wrap(err)
 			}
@@ -216,9 +216,9 @@ func (s *groupServer) BatchGetIncrementalGroupMember(ctx context.Context, req *p
 
 			return vLogs, nil
 		},
-		CacheMaxVersions: s.db.BatchFindMaxGroupMemberVersionCache,
+		CacheMaxVersions: g.db.BatchFindMaxGroupMemberVersionCache,
 		Find: func(ctx context.Context, groupID string, ids []string) ([]*sdkws.GroupMemberFullInfo, error) {
-			memberInfo, err := s.getGroupMembersInfo(ctx, groupID, ids)
+			memberInfo, err := g.getGroupMembersInfo(ctx, groupID, ids)
 			if err != nil {
 				return nil, err
 			}
@@ -258,17 +258,17 @@ func (s *groupServer) BatchGetIncrementalGroupMember(ctx context.Context, req *p
 
 	for groupID, val := range resp.RespList {
 		if val.Full || hasGroupUpdateMap[groupID] {
-			count, err := s.db.FindGroupMemberNum(ctx, groupID)
+			count, err := g.db.FindGroupMemberNum(ctx, groupID)
 			if err != nil {
 				return nil, err
 			}
 
-			owner, err := s.db.TakeGroupOwner(ctx, groupID)
+			owner, err := g.db.TakeGroupOwner(ctx, groupID)
 			if err != nil {
 				return nil, err
 			}
 
-			resp.RespList[groupID].Group = s.groupDB2PB(groupsMap[groupID], owner.UserID, count)
+			resp.RespList[groupID].Group = g.groupDB2PB(groupsMap[groupID], owner.UserID, count)
 		}
 	}
 
@@ -276,8 +276,8 @@ func (s *groupServer) BatchGetIncrementalGroupMember(ctx context.Context, req *p
 
 }
 
-func (s *groupServer) GetIncrementalJoinGroup(ctx context.Context, req *pbgroup.GetIncrementalJoinGroupReq) (*pbgroup.GetIncrementalJoinGroupResp, error) {
-	if err := authverify.CheckAccessV3(ctx, req.UserID, s.config.Share.IMAdminUserID); err != nil {
+func (g *groupServer) GetIncrementalJoinGroup(ctx context.Context, req *pbgroup.GetIncrementalJoinGroupReq) (*pbgroup.GetIncrementalJoinGroupResp, error) {
+	if err := authverify.CheckAccessV3(ctx, req.UserID, g.config.Share.IMAdminUserID); err != nil {
 		return nil, err
 	}
 	opt := incrversion.Option[*sdkws.GroupInfo, pbgroup.GetIncrementalJoinGroupResp]{
@@ -285,9 +285,9 @@ func (s *groupServer) GetIncrementalJoinGroup(ctx context.Context, req *pbgroup.
 		VersionKey:      req.UserID,
 		VersionID:       req.VersionID,
 		VersionNumber:   req.Version,
-		Version:         s.db.FindJoinIncrVersion,
-		CacheMaxVersion: s.db.FindMaxJoinGroupVersionCache,
-		Find:            s.getGroupsInfo,
+		Version:         g.db.FindJoinIncrVersion,
+		CacheMaxVersion: g.db.FindMaxJoinGroupVersionCache,
+		Find:            g.getGroupsInfo,
 		Resp: func(version *model.VersionLog, delIDs []string, insertList, updateList []*sdkws.GroupInfo, full bool) *pbgroup.GetIncrementalJoinGroupResp {
 			return &pbgroup.GetIncrementalJoinGroupResp{
 				VersionID: version.ID.Hex(),
diff --git a/internal/rpc/msg/clear.go b/internal/rpc/msg/clear.go
index ff732136a9..7d62e7c8fa 100644
--- a/internal/rpc/msg/clear.go
+++ b/internal/rpc/msg/clear.go
@@ -6,7 +6,7 @@ import (
 
 	"github.com/openimsdk/open-im-server/v3/pkg/authverify"
 	"github.com/openimsdk/open-im-server/v3/pkg/common/convert"
-	pbconversation "github.com/openimsdk/protocol/conversation"
+	pbconv "github.com/openimsdk/protocol/conversation"
 	"github.com/openimsdk/protocol/msg"
 	"github.com/openimsdk/protocol/wrapperspb"
 	"github.com/openimsdk/tools/errs"
@@ -105,18 +105,21 @@ func (m *msgServer) ClearMsg(ctx context.Context, req *msg.ClearMsgReq) (_ *msg.
 					minseq := datautil.Max(seqs...)
 
 					// update
-					if err := m.Conversation.UpdateConversation(handleCtx,
-						&pbconversation.UpdateConversationReq{
-							UserIDs:               []string{conversation.OwnerUserID},
-							ConversationID:        conversation.ConversationID,
-							LatestMsgDestructTime: wrapperspb.Int64(time.Now().UnixMilli()),
-							MinSeq:                wrapperspb.Int64(minseq),
-						}); err != nil {
+					if err := pbconv.UpdateConversationCaller.Execute(ctx, &pbconv.UpdateConversationReq{
+						ConversationID:        conversation.ConversationID,
+						UserIDs:               []string{conversation.OwnerUserID},
+						MinSeq:                wrapperspb.Int64(minseq),
+						LatestMsgDestructTime: wrapperspb.Int64(time.Now().UnixMilli()),
+					}); err != nil {
 						log.ZError(handleCtx, "updateUsersConversationField failed", err, "conversationID", conversation.ConversationID, "ownerUserID", conversation.OwnerUserID)
 						continue
 					}
 
-					if err := m.Conversation.SetConversationMinSeq(handleCtx, []string{conversation.OwnerUserID}, conversation.ConversationID, minseq); err != nil {
+					if err := pbconv.SetConversationMinSeqCaller.Execute(ctx, &pbconv.SetConversationMinSeqReq{
+						ConversationID: conversation.ConversationID,
+						OwnerUserID:    []string{conversation.OwnerUserID},
+						MinSeq:         minseq,
+					}); err != nil {
 						return err
 					}
 
diff --git a/internal/rpc/msg/delete.go b/internal/rpc/msg/delete.go
index 371c50e2ea..e0c3a89ed8 100644
--- a/internal/rpc/msg/delete.go
+++ b/internal/rpc/msg/delete.go
@@ -21,6 +21,7 @@ import (
 	"github.com/openimsdk/protocol/constant"
 	"github.com/openimsdk/protocol/conversation"
 	"github.com/openimsdk/protocol/msg"
+	"github.com/openimsdk/protocol/rpccall"
 	"github.com/openimsdk/protocol/sdkws"
 	"github.com/openimsdk/tools/log"
 	"github.com/openimsdk/tools/utils/timeutil"
@@ -74,7 +75,10 @@ func (m *msgServer) DeleteMsgs(ctx context.Context, req *msg.DeleteMsgsReq) (*ms
 		if err := m.MsgDatabase.DeleteMsgsPhysicalBySeqs(ctx, req.ConversationID, req.Seqs); err != nil {
 			return nil, err
 		}
-		conversations, err := m.Conversation.GetConversationsByConversationID(ctx, []string{req.ConversationID})
+
+		conversations, err := rpccall.ExtractField(ctx, conversation.GetConversationsByConversationIDCaller.Invoke, &conversation.GetConversationsByConversationIDReq{
+			ConversationIDs: []string{req.ConversationID},
+		}, (*conversation.GetConversationsByConversationIDResp).GetConversations)
 		if err != nil {
 			return nil, err
 		}
@@ -121,7 +125,9 @@ func (m *msgServer) DeleteMsgPhysical(ctx context.Context, req *msg.DeleteMsgPhy
 }
 
 func (m *msgServer) clearConversation(ctx context.Context, conversationIDs []string, userID string, deleteSyncOpt *msg.DeleteSyncOpt) error {
-	conversations, err := m.Conversation.GetConversationsByConversationID(ctx, conversationIDs)
+	conversations, err := rpccall.ExtractField(ctx, conversation.GetConversationsByConversationIDCaller.Invoke, &conversation.GetConversationsByConversationIDReq{
+		ConversationIDs: conversationIDs,
+	}, (*conversation.GetConversationsByConversationIDResp).GetConversations)
 	if err != nil {
 		return err
 	}
@@ -144,7 +150,11 @@ func (m *msgServer) clearConversation(ctx context.Context, conversationIDs []str
 		}
 		ownerUserIDs := []string{userID}
 		for conversationID, seq := range setSeqs {
-			if err := m.Conversation.SetConversationMinSeq(ctx, ownerUserIDs, conversationID, seq); err != nil {
+			if err := conversation.SetConversationMinSeqCaller.Execute(ctx, &conversation.SetConversationMinSeqReq{
+				ConversationID: conversationID,
+				OwnerUserID:    ownerUserIDs,
+				MinSeq:         seq,
+			}); err != nil {
 				return err
 			}
 		}
diff --git a/internal/rpc/msg/send.go b/internal/rpc/msg/send.go
index 034d549ec6..bb20206f7a 100644
--- a/internal/rpc/msg/send.go
+++ b/internal/rpc/msg/send.go
@@ -21,7 +21,7 @@ import (
 	"github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
 	"github.com/openimsdk/open-im-server/v3/pkg/util/conversationutil"
 	"github.com/openimsdk/protocol/constant"
-	pbconversation "github.com/openimsdk/protocol/conversation"
+	pbconv "github.com/openimsdk/protocol/conversation"
 	pbmsg "github.com/openimsdk/protocol/msg"
 	"github.com/openimsdk/protocol/sdkws"
 	"github.com/openimsdk/protocol/wrapperspb"
@@ -96,7 +96,7 @@ func (m *msgServer) setConversationAtInfo(nctx context.Context, msg *sdkws.MsgDa
 
 	var atUserID []string
 
-	conversation := &pbconversation.ConversationReq{
+	conversation := &pbconv.ConversationReq{
 		ConversationID:   msgprocessor.GetConversationIDByMsg(msg),
 		ConversationType: msg.SessionType,
 		GroupID:          msg.GroupID,
@@ -119,7 +119,10 @@ func (m *msgServer) setConversationAtInfo(nctx context.Context, msg *sdkws.MsgDa
 		} else { // @Everyone and @other people
 			conversation.GroupAtType = &wrapperspb.Int32Value{Value: constant.AtAllAtMe}
 
-			err = m.Conversation.SetConversations(ctx, atUserID, conversation)
+			err = pbconv.SetConversationsCaller.Execute(ctx, &pbconv.SetConversationsReq{
+				UserIDs:      atUserID,
+				Conversation: conversation,
+			})
 			if err != nil {
 				log.ZWarn(ctx, "SetConversations", err, "userID", atUserID, "conversation", conversation)
 			}
@@ -129,7 +132,10 @@ func (m *msgServer) setConversationAtInfo(nctx context.Context, msg *sdkws.MsgDa
 
 		conversation.GroupAtType = &wrapperspb.Int32Value{Value: constant.AtAll}
 
-		err = m.Conversation.SetConversations(ctx, memberUserIDList, conversation)
+		err = pbconv.SetConversationsCaller.Execute(ctx, &pbconv.SetConversationsReq{
+			UserIDs:      memberUserIDList,
+			Conversation: conversation,
+		})
 		if err != nil {
 			log.ZWarn(ctx, "SetConversations", err, "userID", memberUserIDList, "conversation", conversation)
 		}
@@ -138,7 +144,10 @@ func (m *msgServer) setConversationAtInfo(nctx context.Context, msg *sdkws.MsgDa
 	}
 	conversation.GroupAtType = &wrapperspb.Int32Value{Value: constant.AtMe}
 
-	err := m.Conversation.SetConversations(ctx, msg.AtUserIDList, conversation)
+	err := pbconv.SetConversationsCaller.Execute(ctx, &pbconv.SetConversationsReq{
+		UserIDs:      msg.AtUserIDList,
+		Conversation: conversation,
+	})
 	if err != nil {
 		log.ZWarn(ctx, "SetConversations", err, msg.AtUserIDList, conversation)
 	}
diff --git a/internal/rpc/msg/server.go b/internal/rpc/msg/server.go
index b0cd771a47..9bd2a69468 100644
--- a/internal/rpc/msg/server.go
+++ b/internal/rpc/msg/server.go
@@ -16,6 +16,7 @@ package msg
 
 import (
 	"context"
+
 	"github.com/openimsdk/open-im-server/v3/pkg/common/config"
 	"github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/redis"
 	"github.com/openimsdk/open-im-server/v3/pkg/common/storage/database/mgo"
@@ -44,7 +45,6 @@ type (
 		RegisterCenter         discovery.SvcDiscoveryRegistry // Service discovery registry for service registration.
 		MsgDatabase            controller.CommonMsgDatabase   // Interface for message database operations.
 		StreamMsgDatabase      controller.StreamMsgDatabase
-		Conversation           *rpcclient.ConversationRpcClient // RPC client for conversation service.
 		UserLocalCache         *rpccache.UserLocalCache         // Local cache for user data.
 		FriendLocalCache       *rpccache.FriendLocalCache       // Local cache for friend data.
 		GroupLocalCache        *rpccache.GroupLocalCache        // Local cache for group data.
@@ -89,10 +89,6 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg
 		return err
 	}
 	msgModel := redis.NewMsgCache(rdb)
-	conversationClient := rpcclient.NewConversationRpcClient(client, config.Discovery.RpcService.Conversation)
-	userRpcClient := rpcclient.NewUserRpcClient(client, config.Discovery.RpcService.User, config.Share.IMAdminUserID)
-	groupRpcClient := rpcclient.NewGroupRpcClient(client, config.Discovery.RpcService.Group)
-	friendRpcClient := rpcclient.NewFriendRpcClient(client, config.Discovery.RpcService.Friend)
 	seqConversation, err := mgo.NewSeqConversationMongo(mgocli.GetDB())
 	if err != nil {
 		return err
@@ -112,14 +108,13 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg
 		return err
 	}
 	s := &msgServer{
-		Conversation:           &conversationClient,
 		MsgDatabase:            msgDatabase,
 		StreamMsgDatabase:      controller.NewStreamMsgDatabase(streamMsg),
 		RegisterCenter:         client,
-		UserLocalCache:         rpccache.NewUserLocalCache(userRpcClient, &config.LocalCacheConfig, rdb),
-		GroupLocalCache:        rpccache.NewGroupLocalCache(groupRpcClient, &config.LocalCacheConfig, rdb),
-		ConversationLocalCache: rpccache.NewConversationLocalCache(conversationClient, &config.LocalCacheConfig, rdb),
-		FriendLocalCache:       rpccache.NewFriendLocalCache(friendRpcClient, &config.LocalCacheConfig, rdb),
+		UserLocalCache:         rpccache.NewUserLocalCache(&config.LocalCacheConfig, rdb),
+		GroupLocalCache:        rpccache.NewGroupLocalCache(&config.LocalCacheConfig, rdb),
+		ConversationLocalCache: rpccache.NewConversationLocalCache(&config.LocalCacheConfig, rdb),
+		FriendLocalCache:       rpccache.NewFriendLocalCache(&config.LocalCacheConfig, rdb),
 		config:                 config,
 		webhookClient:          webhook.NewWebhookClient(config.WebhooksConfig.URL),
 	}
diff --git a/internal/rpc/msg/stream_msg.go b/internal/rpc/msg/stream_msg.go
index 5db2aad48e..e216b10876 100644
--- a/internal/rpc/msg/stream_msg.go
+++ b/internal/rpc/msg/stream_msg.go
@@ -3,13 +3,16 @@ package msg
 import (
 	"context"
 	"fmt"
+	"time"
+
 	"github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
 	"github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
 	"github.com/openimsdk/protocol/constant"
+	pbconv "github.com/openimsdk/protocol/conversation"
 	"github.com/openimsdk/protocol/msg"
+	"github.com/openimsdk/protocol/rpccall"
 	"github.com/openimsdk/protocol/sdkws"
 	"github.com/openimsdk/tools/errs"
-	"time"
 )
 
 const StreamDeadlineTime = time.Second * 60 * 10
@@ -71,7 +74,10 @@ func (m *msgServer) AppendStreamMsg(ctx context.Context, req *msg.AppendStreamMs
 	if err := m.StreamMsgDatabase.AppendStreamMsg(ctx, req.ClientMsgID, int(req.StartIndex), req.Packets, req.End, deadlineTime); err != nil {
 		return nil, err
 	}
-	conversation, err := m.Conversation.GetConversation(ctx, res.UserID, res.ConversationID)
+	conversation, err := rpccall.ExtractField(ctx, pbconv.GetConversationCaller.Invoke, &pbconv.GetConversationReq{
+		ConversationID: res.ConversationID,
+		OwnerUserID:    res.UserID,
+	}, (*pbconv.GetConversationResp).GetConversation)
 	if err != nil {
 		return nil, err
 	}
diff --git a/internal/rpc/relation/black.go b/internal/rpc/relation/black.go
index d8d457dacc..0fd9b87665 100644
--- a/internal/rpc/relation/black.go
+++ b/internal/rpc/relation/black.go
@@ -18,10 +18,10 @@ import (
 	"context"
 	"time"
 
-	"github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
-
 	"github.com/openimsdk/open-im-server/v3/pkg/authverify"
 	"github.com/openimsdk/open-im-server/v3/pkg/common/convert"
+	"github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
+	"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
 	"github.com/openimsdk/protocol/relation"
 	"github.com/openimsdk/protocol/sdkws"
 	"github.com/openimsdk/tools/errs"
@@ -39,7 +39,7 @@ func (s *friendServer) GetPaginationBlacks(ctx context.Context, req *relation.Ge
 		return nil, err
 	}
 	resp = &relation.GetPaginationBlacksResp{}
-	resp.Blacks, err = convert.BlackDB2Pb(ctx, blacks, s.userRpcClient.GetUsersInfoMap)
+	resp.Blacks, err = convert.BlackDB2Pb(ctx, blacks, rpcclient.GetUsersInfoMap)
 	if err != nil {
 		return nil, err
 	}
@@ -82,7 +82,7 @@ func (s *friendServer) AddBlack(ctx context.Context, req *relation.AddBlackReq)
 		return nil, err
 	}
 
-	_, err := s.userRpcClient.GetUsersInfo(ctx, []string{req.OwnerUserID, req.BlackUserID})
+	_, err := rpcclient.GetUsersInfo(ctx, []string{req.OwnerUserID, req.BlackUserID})
 	if err != nil {
 		return nil, err
 	}
@@ -114,7 +114,7 @@ func (s *friendServer) GetSpecifiedBlacks(ctx context.Context, req *relation.Get
 		return nil, errs.ErrArgs.WrapMsg("userIDList repeated")
 	}
 
-	userMap, err := s.userRpcClient.GetPublicUserInfoMap(ctx, req.UserIDList)
+	userMap, err := rpcclient.GetPublicUserInfoMap(ctx, req.UserIDList)
 	if err != nil {
 		return nil, err
 	}
diff --git a/internal/rpc/relation/friend.go b/internal/rpc/relation/friend.go
index 617e313483..b97a9d01f4 100644
--- a/internal/rpc/relation/friend.go
+++ b/internal/rpc/relation/friend.go
@@ -44,15 +44,13 @@ import (
 
 type friendServer struct {
 	relation.UnimplementedFriendServer
-	db                    controller.FriendDatabase
-	blackDatabase         controller.BlackDatabase
-	userRpcClient         *rpcclient.UserRpcClient
-	notificationSender    *FriendNotificationSender
-	conversationRpcClient rpcclient.ConversationRpcClient
-	RegisterCenter        discovery.SvcDiscoveryRegistry
-	config                *Config
-	webhookClient         *webhook.Client
-	queue                 *memamq.MemoryQueue
+	db                 controller.FriendDatabase
+	blackDatabase      controller.BlackDatabase
+	notificationSender *FriendNotificationSender
+	RegisterCenter     discovery.SvcDiscoveryRegistry
+	config             *Config
+	webhookClient      *webhook.Client
+	queue              *memamq.MemoryQueue
 }
 
 type Config struct {
@@ -92,15 +90,10 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg
 		return err
 	}
 
-	// Initialize RPC clients
-	userRpcClient := rpcclient.NewUserRpcClient(client, config.Discovery.RpcService.User, config.Share.IMAdminUserID)
-	msgRpcClient := rpcclient.NewMessageRpcClient(client, config.Discovery.RpcService.Msg)
-
 	// Initialize notification sender
 	notificationSender := NewFriendNotificationSender(
 		&config.NotificationConfig,
-		&msgRpcClient,
-		WithRpcFunc(userRpcClient.GetUsersInfo),
+		WithRpcFunc(rpcclient.GetUsersInfo),
 	)
 	localcache.InitLocalCache(&config.LocalCacheConfig)
 
@@ -116,13 +109,11 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg
 			blackMongoDB,
 			redis.NewBlackCacheRedis(rdb, &config.LocalCacheConfig, blackMongoDB, redis.GetRocksCacheOptions()),
 		),
-		userRpcClient:         &userRpcClient,
-		notificationSender:    notificationSender,
-		RegisterCenter:        client,
-		conversationRpcClient: rpcclient.NewConversationRpcClient(client, config.Discovery.RpcService.Conversation),
-		config:                config,
-		webhookClient:         webhook.NewWebhookClient(config.WebhooksConfig.URL),
-		queue:                 memamq.NewMemoryQueue(16, 1024*1024),
+		notificationSender: notificationSender,
+		RegisterCenter:     client,
+		config:             config,
+		webhookClient:      webhook.NewWebhookClient(config.WebhooksConfig.URL),
+		queue:              memamq.NewMemoryQueue(16, 1024*1024),
 	})
 	return nil
 }
@@ -139,7 +130,7 @@ func (s *friendServer) ApplyToAddFriend(ctx context.Context, req *relation.Apply
 	if err = s.webhookBeforeAddFriend(ctx, &s.config.WebhooksConfig.BeforeAddFriend, req); err != nil && err != servererrs.ErrCallbackContinue {
 		return nil, err
 	}
-	if _, err := s.userRpcClient.GetUsersInfoMap(ctx, []string{req.ToUserID, req.FromUserID}); err != nil {
+	if _, err := rpcclient.GetUsersInfoMap(ctx, []string{req.ToUserID, req.FromUserID}); err != nil {
 		return nil, err
 	}
 
@@ -163,7 +154,8 @@ func (s *friendServer) ImportFriends(ctx context.Context, req *relation.ImportFr
 	if err := authverify.CheckAdmin(ctx, s.config.Share.IMAdminUserID); err != nil {
 		return nil, err
 	}
-	if _, err := s.userRpcClient.GetUsersInfo(ctx, append([]string{req.OwnerUserID}, req.FriendUserIDs...)); err != nil {
+
+	if _, err := rpcclient.GetUsersInfo(ctx, append([]string{req.OwnerUserID}, req.FriendUserIDs...)); err != nil {
 		return nil, err
 	}
 	if datautil.Contain(req.OwnerUserID, req.FriendUserIDs...) {
@@ -304,7 +296,7 @@ func (s *friendServer) getFriend(ctx context.Context, ownerUserID string, friend
 	if err != nil {
 		return nil, err
 	}
-	return convert.FriendsDB2Pb(ctx, friends, s.userRpcClient.GetUsersInfoMap)
+	return convert.FriendsDB2Pb(ctx, friends, rpcclient.GetUsersInfoMap)
 }
 
 // Get the list of friend requests sent out proactively.
@@ -316,7 +308,7 @@ func (s *friendServer) GetDesignatedFriendsApply(ctx context.Context,
 		return nil, err
 	}
 	resp = &relation.GetDesignatedFriendsApplyResp{}
-	resp.FriendRequests, err = convert.FriendRequestDB2Pb(ctx, friendRequests, s.userRpcClient.GetUsersInfoMap)
+	resp.FriendRequests, err = convert.FriendRequestDB2Pb(ctx, friendRequests, rpcclient.GetUsersInfoMap)
 	if err != nil {
 		return nil, err
 	}
@@ -335,7 +327,7 @@ func (s *friendServer) GetPaginationFriendsApplyTo(ctx context.Context, req *rel
 	}
 
 	resp = &relation.GetPaginationFriendsApplyToResp{}
-	resp.FriendRequests, err = convert.FriendRequestDB2Pb(ctx, friendRequests, s.userRpcClient.GetUsersInfoMap)
+	resp.FriendRequests, err = convert.FriendRequestDB2Pb(ctx, friendRequests, rpcclient.GetUsersInfoMap)
 	if err != nil {
 		return nil, err
 	}
@@ -357,7 +349,7 @@ func (s *friendServer) GetPaginationFriendsApplyFrom(ctx context.Context, req *r
 		return nil, err
 	}
 
-	resp.FriendRequests, err = convert.FriendRequestDB2Pb(ctx, friendRequests, s.userRpcClient.GetUsersInfoMap)
+	resp.FriendRequests, err = convert.FriendRequestDB2Pb(ctx, friendRequests, rpcclient.GetUsersInfoMap)
 	if err != nil {
 		return nil, err
 	}
@@ -388,7 +380,7 @@ func (s *friendServer) GetPaginationFriends(ctx context.Context, req *relation.G
 	}
 
 	resp = &relation.GetPaginationFriendsResp{}
-	resp.FriendsInfo, err = convert.FriendsDB2Pb(ctx, friends, s.userRpcClient.GetUsersInfoMap)
+	resp.FriendsInfo, err = convert.FriendsDB2Pb(ctx, friends, rpcclient.GetUsersInfoMap)
 	if err != nil {
 		return nil, err
 	}
@@ -421,7 +413,7 @@ func (s *friendServer) GetSpecifiedFriendsInfo(ctx context.Context, req *relatio
 		return nil, errs.ErrArgs.WrapMsg("userIDList repeated")
 	}
 
-	userMap, err := s.userRpcClient.GetUsersInfoMap(ctx, req.UserIDList)
+	userMap, err := rpcclient.GetUsersInfoMap(ctx, req.UserIDList)
 	if err != nil {
 		return nil, err
 	}
diff --git a/internal/rpc/relation/notification.go b/internal/rpc/relation/notification.go
index 83c5d2ca9d..ba43652005 100644
--- a/internal/rpc/relation/notification.go
+++ b/internal/rpc/relation/notification.go
@@ -16,6 +16,7 @@ package relation
 
 import (
 	"context"
+
 	"github.com/openimsdk/open-im-server/v3/pkg/common/storage/database"
 	"github.com/openimsdk/open-im-server/v3/pkg/common/storage/versionctx"
 
@@ -86,11 +87,10 @@ func WithRpcFunc(
 
 func NewFriendNotificationSender(
 	conf *config.Notification,
-	msgRpcClient *rpcclient.MessageRpcClient,
 	opts ...friendNotificationSenderOptions,
 ) *FriendNotificationSender {
 	f := &FriendNotificationSender{
-		NotificationSender: rpcclient.NewNotificationSender(conf, rpcclient.WithRpcClient(msgRpcClient)),
+		NotificationSender: rpcclient.NewNotificationSender(conf, rpcclient.WithRpcClient()),
 	}
 	for _, opt := range opts {
 		opt(f)
diff --git a/internal/rpc/third/log.go b/internal/rpc/third/log.go
index 4eeb5d5584..222cfad1dc 100644
--- a/internal/rpc/third/log.go
+++ b/internal/rpc/third/log.go
@@ -20,6 +20,7 @@ import (
 	"time"
 
 	relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
+	"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
 
 	"github.com/openimsdk/open-im-server/v3/pkg/authverify"
 	"github.com/openimsdk/open-im-server/v3/pkg/common/servererrs"
@@ -149,7 +150,7 @@ func (t *thirdServer) SearchLogs(ctx context.Context, req *third.SearchLogsReq)
 	for _, log := range logs {
 		userIDs = append(userIDs, log.UserID)
 	}
-	userMap, err := t.userRpcClient.GetUsersInfoMap(ctx, userIDs)
+	userMap, err := rpcclient.GetUsersInfoMap(ctx, userIDs)
 	if err != nil {
 		return nil, err
 	}
diff --git a/internal/rpc/third/third.go b/internal/rpc/third/third.go
index 52e48855c6..77e6d459fa 100644
--- a/internal/rpc/third/third.go
+++ b/internal/rpc/third/third.go
@@ -17,16 +17,16 @@ package third
 import (
 	"context"
 	"fmt"
+	"time"
+
 	"github.com/openimsdk/open-im-server/v3/pkg/common/config"
 	"github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/redis"
 	"github.com/openimsdk/open-im-server/v3/pkg/common/storage/database/mgo"
 	"github.com/openimsdk/open-im-server/v3/pkg/localcache"
 	"github.com/openimsdk/tools/s3/aws"
 	"github.com/openimsdk/tools/s3/kodo"
-	"time"
 
 	"github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller"
-	"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
 	"github.com/openimsdk/protocol/third"
 	"github.com/openimsdk/tools/db/mongoutil"
 	"github.com/openimsdk/tools/db/redisutil"
@@ -42,7 +42,6 @@ type thirdServer struct {
 	third.UnimplementedThirdServer
 	thirdDatabase controller.ThirdDatabase
 	s3dataBase    controller.S3Database
-	userRpcClient rpcclient.UserRpcClient
 	defaultExpire time.Duration
 	config        *Config
 	minio         *minio.Minio
@@ -104,7 +103,6 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg
 	localcache.InitLocalCache(&config.LocalCacheConfig)
 	third.RegisterThirdServer(server, &thirdServer{
 		thirdDatabase: controller.NewThirdDatabase(redis.NewThirdCache(rdb), logdb),
-		userRpcClient: rpcclient.NewUserRpcClient(client, config.Discovery.RpcService.User, config.Share.IMAdminUserID),
 		s3dataBase:    controller.NewS3Database(rdb, o, s3db),
 		defaultExpire: time.Hour * 24 * 7,
 		config:        config,
diff --git a/internal/rpc/user/notification.go b/internal/rpc/user/notification.go
index b992c9d123..54e5b27d75 100644
--- a/internal/rpc/user/notification.go
+++ b/internal/rpc/user/notification.go
@@ -16,6 +16,7 @@ package user
 
 import (
 	"context"
+
 	relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
 	"github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification"
 
@@ -58,9 +59,9 @@ func WithUserFunc(
 	}
 }
 
-func NewUserNotificationSender(config *Config, msgRpcClient *rpcclient.MessageRpcClient, opts ...userNotificationSenderOptions) *UserNotificationSender {
+func NewUserNotificationSender(config *Config, opts ...userNotificationSenderOptions) *UserNotificationSender {
 	f := &UserNotificationSender{
-		NotificationSender: rpcclient.NewNotificationSender(&config.NotificationConfig, rpcclient.WithRpcClient(msgRpcClient)),
+		NotificationSender: rpcclient.NewNotificationSender(&config.NotificationConfig, rpcclient.WithRpcClient()),
 	}
 	for _, opt := range opts {
 		opt(f)
diff --git a/internal/rpc/user/user.go b/internal/rpc/user/user.go
index ae02b997f2..c2bcabaa1d 100644
--- a/internal/rpc/user/user.go
+++ b/internal/rpc/user/user.go
@@ -39,7 +39,6 @@ import (
 	"github.com/openimsdk/open-im-server/v3/pkg/common/convert"
 	"github.com/openimsdk/open-im-server/v3/pkg/common/servererrs"
 	"github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller"
-	"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
 	"github.com/openimsdk/protocol/constant"
 	"github.com/openimsdk/protocol/sdkws"
 	pbuser "github.com/openimsdk/protocol/user"
@@ -57,8 +56,6 @@ type userServer struct {
 	db                       controller.UserDatabase
 	friendNotificationSender *relation.FriendNotificationSender
 	userNotificationSender   *UserNotificationSender
-	friendRpcClient          *rpcclient.FriendRpcClient
-	groupRpcClient           *rpcclient.GroupRpcClient
 	RegisterCenter           registry.SvcDiscoveryRegistry
 	config                   *Config
 	webhookClient            *webhook.Client
@@ -96,18 +93,13 @@ func Start(ctx context.Context, config *Config, client registry.SvcDiscoveryRegi
 	}
 	userCache := redis.NewUserCacheRedis(rdb, &config.LocalCacheConfig, userDB, redis.GetRocksCacheOptions())
 	database := controller.NewUserDatabase(userDB, userCache, mgocli.GetTx())
-	friendRpcClient := rpcclient.NewFriendRpcClient(client, config.Discovery.RpcService.Friend)
-	groupRpcClient := rpcclient.NewGroupRpcClient(client, config.Discovery.RpcService.Group)
-	msgRpcClient := rpcclient.NewMessageRpcClient(client, config.Discovery.RpcService.Msg)
 	localcache.InitLocalCache(&config.LocalCacheConfig)
 	u := &userServer{
 		online:                   redis.NewUserOnline(rdb),
 		db:                       database,
 		RegisterCenter:           client,
-		friendRpcClient:          &friendRpcClient,
-		groupRpcClient:           &groupRpcClient,
-		friendNotificationSender: relation.NewFriendNotificationSender(&config.NotificationConfig, &msgRpcClient, relation.WithDBFunc(database.FindWithError)),
-		userNotificationSender:   NewUserNotificationSender(config, &msgRpcClient, WithUserFunc(database.FindWithError)),
+		friendNotificationSender: relation.NewFriendNotificationSender(&config.NotificationConfig, relation.WithDBFunc(database.FindWithError)),
+		userNotificationSender:   NewUserNotificationSender(config, WithUserFunc(database.FindWithError)),
 		config:                   config,
 		webhookClient:            webhook.NewWebhookClient(config.WebhooksConfig.URL),
 	}
@@ -641,7 +633,7 @@ func (s *userServer) NotificationUserInfoUpdate(ctx context.Context, userID stri
 	wg.Add(len(es))
 	go func() {
 		defer wg.Done()
-		_, es[0] = s.groupRpcClient.Client.NotificationUserInfoUpdate(ctx, &group.NotificationUserInfoUpdateReq{
+		_, es[0] = group.NotificationUserInfoUpdateCaller.Invoke(ctx, &group.NotificationUserInfoUpdateReq{
 			UserID:      userID,
 			OldUserInfo: oldUserInfo,
 			NewUserInfo: newUserInfo,
@@ -650,7 +642,7 @@ func (s *userServer) NotificationUserInfoUpdate(ctx context.Context, userID stri
 
 	go func() {
 		defer wg.Done()
-		_, es[1] = s.friendRpcClient.Client.NotificationUserInfoUpdate(ctx, &friendpb.NotificationUserInfoUpdateReq{
+		_, es[1] = friendpb.NotificationUserInfoUpdateCaller.Invoke(ctx, &friendpb.NotificationUserInfoUpdateReq{
 			UserID:      userID,
 			OldUserInfo: oldUserInfo,
 			NewUserInfo: newUserInfo,
diff --git a/pkg/common/startrpc/start.go b/pkg/common/startrpc/start.go
index 259f4caed4..c38ee27a14 100644
--- a/pkg/common/startrpc/start.go
+++ b/pkg/common/startrpc/start.go
@@ -27,6 +27,7 @@ import (
 	"time"
 
 	conf "github.com/openimsdk/open-im-server/v3/pkg/common/config"
+	"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
 	"github.com/openimsdk/tools/discovery/etcd"
 	"github.com/openimsdk/tools/utils/datautil"
 	"github.com/openimsdk/tools/utils/jsonutil"
@@ -95,6 +96,10 @@ func Start[T any](ctx context.Context, discovery *conf.Discovery, prometheusConf
 	defer client.Close()
 	client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin")))
 
+	if err = rpcclient.InitRpcCaller(client, discovery.RpcService); err != nil {
+		return err
+	}
+
 	// var reg *prometheus.Registry
 	// var metric *grpcprometheus.ServerMetrics
 	if prometheusConfig.Enable {
diff --git a/pkg/rpccache/conversation.go b/pkg/rpccache/conversation.go
index 925d2a37ca..ba3690f445 100644
--- a/pkg/rpccache/conversation.go
+++ b/pkg/rpccache/conversation.go
@@ -16,11 +16,12 @@ package rpccache
 
 import (
 	"context"
+
 	"github.com/openimsdk/open-im-server/v3/pkg/common/config"
 	"github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/cachekey"
 	"github.com/openimsdk/open-im-server/v3/pkg/localcache"
-	"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
-	pbconversation "github.com/openimsdk/protocol/conversation"
+	pbconv "github.com/openimsdk/protocol/conversation"
+	"github.com/openimsdk/protocol/rpccall"
 	"github.com/openimsdk/tools/errs"
 	"github.com/openimsdk/tools/log"
 	"github.com/openimsdk/tools/utils/datautil"
@@ -32,11 +33,10 @@ const (
 	conversationWorkerCount = 20
 )
 
-func NewConversationLocalCache(client rpcclient.ConversationRpcClient, localCache *config.LocalCache, cli redis.UniversalClient) *ConversationLocalCache {
+func NewConversationLocalCache(localCache *config.LocalCache, cli redis.UniversalClient) *ConversationLocalCache {
 	lc := localCache.Conversation
 	log.ZDebug(context.Background(), "ConversationLocalCache", "topic", lc.Topic, "slotNum", lc.SlotNum, "slotSize", lc.SlotSize, "enable", lc.Enable())
 	x := &ConversationLocalCache{
-		client: client,
 		local: localcache.New[[]byte](
 			localcache.WithLocalSlotNum(lc.SlotNum),
 			localcache.WithLocalSlotSize(lc.SlotSize),
@@ -52,8 +52,7 @@ func NewConversationLocalCache(client rpcclient.ConversationRpcClient, localCach
 }
 
 type ConversationLocalCache struct {
-	client rpcclient.ConversationRpcClient
-	local  localcache.Cache[[]byte]
+	local localcache.Cache[[]byte]
 }
 
 func (c *ConversationLocalCache) GetConversationIDs(ctx context.Context, ownerUserID string) (val []string, err error) {
@@ -64,7 +63,7 @@ func (c *ConversationLocalCache) GetConversationIDs(ctx context.Context, ownerUs
 	return resp.ConversationIDs, nil
 }
 
-func (c *ConversationLocalCache) getConversationIDs(ctx context.Context, ownerUserID string) (val *pbconversation.GetConversationIDsResp, err error) {
+func (c *ConversationLocalCache) getConversationIDs(ctx context.Context, ownerUserID string) (val *pbconv.GetConversationIDsResp, err error) {
 	log.ZDebug(ctx, "ConversationLocalCache getConversationIDs req", "ownerUserID", ownerUserID)
 	defer func() {
 		if err == nil {
@@ -73,14 +72,14 @@ func (c *ConversationLocalCache) getConversationIDs(ctx context.Context, ownerUs
 			log.ZError(ctx, "ConversationLocalCache getConversationIDs return", err, "ownerUserID", ownerUserID)
 		}
 	}()
-	var cache cacheProto[pbconversation.GetConversationIDsResp]
+	var cache cacheProto[pbconv.GetConversationIDsResp]
 	return cache.Unmarshal(c.local.Get(ctx, cachekey.GetConversationIDsKey(ownerUserID), func(ctx context.Context) ([]byte, error) {
 		log.ZDebug(ctx, "ConversationLocalCache getConversationIDs rpc", "ownerUserID", ownerUserID)
-		return cache.Marshal(c.client.Client.GetConversationIDs(ctx, &pbconversation.GetConversationIDsReq{UserID: ownerUserID}))
+		return cache.Marshal(pbconv.GetConversationIDsCaller.Invoke(ctx, &pbconv.GetConversationIDsReq{UserID: ownerUserID}))
 	}))
 }
 
-func (c *ConversationLocalCache) GetConversation(ctx context.Context, userID, conversationID string) (val *pbconversation.Conversation, err error) {
+func (c *ConversationLocalCache) GetConversation(ctx context.Context, userID, conversationID string) (val *pbconv.Conversation, err error) {
 	log.ZDebug(ctx, "ConversationLocalCache GetConversation req", "userID", userID, "conversationID", conversationID)
 	defer func() {
 		if err == nil {
@@ -89,10 +88,13 @@ func (c *ConversationLocalCache) GetConversation(ctx context.Context, userID, co
 			log.ZWarn(ctx, "ConversationLocalCache GetConversation return", err, "userID", userID, "conversationID", conversationID)
 		}
 	}()
-	var cache cacheProto[pbconversation.Conversation]
+	var cache cacheProto[pbconv.Conversation]
 	return cache.Unmarshal(c.local.Get(ctx, cachekey.GetConversationKey(userID, conversationID), func(ctx context.Context) ([]byte, error) {
 		log.ZDebug(ctx, "ConversationLocalCache GetConversation rpc", "userID", userID, "conversationID", conversationID)
-		return cache.Marshal(c.client.GetConversation(ctx, userID, conversationID))
+		return cache.Marshal(rpccall.ExtractField(ctx, pbconv.GetConversationCaller.Invoke, &pbconv.GetConversationReq{
+			ConversationID: conversationID,
+			OwnerUserID:    userID,
+		}, (*pbconv.GetConversationResp).GetConversation))
 	}))
 }
 
@@ -104,10 +106,10 @@ func (c *ConversationLocalCache) GetSingleConversationRecvMsgOpt(ctx context.Con
 	return conv.RecvMsgOpt, nil
 }
 
-func (c *ConversationLocalCache) GetConversations(ctx context.Context, ownerUserID string, conversationIDs []string) ([]*pbconversation.Conversation, error) {
+func (c *ConversationLocalCache) GetConversations(ctx context.Context, ownerUserID string, conversationIDs []string) ([]*pbconv.Conversation, error) {
 	var (
-		conversations     = make([]*pbconversation.Conversation, 0, len(conversationIDs))
-		conversationsChan = make(chan *pbconversation.Conversation, len(conversationIDs))
+		conversations     = make([]*pbconv.Conversation, 0, len(conversationIDs))
+		conversationsChan = make(chan *pbconv.Conversation, len(conversationIDs))
 	)
 
 	g, ctx := errgroup.WithContext(ctx)
@@ -137,7 +139,7 @@ func (c *ConversationLocalCache) GetConversations(ctx context.Context, ownerUser
 	return conversations, nil
 }
 
-func (c *ConversationLocalCache) getConversationNotReceiveMessageUserIDs(ctx context.Context, conversationID string) (val *pbconversation.GetConversationNotReceiveMessageUserIDsResp, err error) {
+func (c *ConversationLocalCache) getConversationNotReceiveMessageUserIDs(ctx context.Context, conversationID string) (val *pbconv.GetConversationNotReceiveMessageUserIDsResp, err error) {
 	log.ZDebug(ctx, "ConversationLocalCache getConversationNotReceiveMessageUserIDs req", "conversationID", conversationID)
 	defer func() {
 		if err == nil {
@@ -146,10 +148,10 @@ func (c *ConversationLocalCache) getConversationNotReceiveMessageUserIDs(ctx con
 			log.ZError(ctx, "ConversationLocalCache getConversationNotReceiveMessageUserIDs return", err, "conversationID", conversationID)
 		}
 	}()
-	var cache cacheProto[pbconversation.GetConversationNotReceiveMessageUserIDsResp]
+	var cache cacheProto[pbconv.GetConversationNotReceiveMessageUserIDsResp]
 	return cache.Unmarshal(c.local.Get(ctx, cachekey.GetConversationNotReceiveMessageUserIDsKey(conversationID), func(ctx context.Context) ([]byte, error) {
 		log.ZDebug(ctx, "ConversationLocalCache getConversationNotReceiveMessageUserIDs rpc", "conversationID", conversationID)
-		return cache.Marshal(c.client.Client.GetConversationNotReceiveMessageUserIDs(ctx, &pbconversation.GetConversationNotReceiveMessageUserIDsReq{ConversationID: conversationID}))
+		return cache.Marshal(pbconv.GetConversationNotReceiveMessageUserIDsCaller.Invoke(ctx, &pbconv.GetConversationNotReceiveMessageUserIDsReq{ConversationID: conversationID}))
 	}))
 }
 
diff --git a/pkg/rpccache/friend.go b/pkg/rpccache/friend.go
index dca3b4c97c..865cac7b50 100644
--- a/pkg/rpccache/friend.go
+++ b/pkg/rpccache/friend.go
@@ -16,21 +16,20 @@ package rpccache
 
 import (
 	"context"
+
 	"github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/cachekey"
 	"github.com/openimsdk/protocol/relation"
 
 	"github.com/openimsdk/open-im-server/v3/pkg/common/config"
 	"github.com/openimsdk/open-im-server/v3/pkg/localcache"
-	"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
 	"github.com/openimsdk/tools/log"
 	"github.com/redis/go-redis/v9"
 )
 
-func NewFriendLocalCache(client rpcclient.FriendRpcClient, localCache *config.LocalCache, cli redis.UniversalClient) *FriendLocalCache {
+func NewFriendLocalCache(localCache *config.LocalCache, cli redis.UniversalClient) *FriendLocalCache {
 	lc := localCache.Friend
 	log.ZDebug(context.Background(), "FriendLocalCache", "topic", lc.Topic, "slotNum", lc.SlotNum, "slotSize", lc.SlotSize, "enable", lc.Enable())
 	x := &FriendLocalCache{
-		client: client,
 		local: localcache.New[[]byte](
 			localcache.WithLocalSlotNum(lc.SlotNum),
 			localcache.WithLocalSlotSize(lc.SlotSize),
@@ -46,8 +45,7 @@ func NewFriendLocalCache(client rpcclient.FriendRpcClient, localCache *config.Lo
 }
 
 type FriendLocalCache struct {
-	client rpcclient.FriendRpcClient
-	local  localcache.Cache[[]byte]
+	local localcache.Cache[[]byte]
 }
 
 func (f *FriendLocalCache) IsFriend(ctx context.Context, possibleFriendUserID, userID string) (val bool, err error) {
@@ -70,7 +68,7 @@ func (f *FriendLocalCache) isFriend(ctx context.Context, possibleFriendUserID, u
 	var cache cacheProto[relation.IsFriendResp]
 	return cache.Unmarshal(f.local.GetLink(ctx, cachekey.GetIsFriendKey(possibleFriendUserID, userID), func(ctx context.Context) ([]byte, error) {
 		log.ZDebug(ctx, "FriendLocalCache isFriend rpc", "possibleFriendUserID", possibleFriendUserID, "userID", userID)
-		return cache.Marshal(f.client.Client.IsFriend(ctx, &relation.IsFriendReq{UserID1: userID, UserID2: possibleFriendUserID}))
+		return cache.Marshal(relation.IsFriendCaller.Invoke(ctx, &relation.IsFriendReq{UserID1: userID, UserID2: possibleFriendUserID}))
 	}, cachekey.GetFriendIDsKey(possibleFriendUserID)))
 }
 
@@ -96,6 +94,6 @@ func (f *FriendLocalCache) isBlack(ctx context.Context, possibleBlackUserID, use
 	var cache cacheProto[relation.IsBlackResp]
 	return cache.Unmarshal(f.local.GetLink(ctx, cachekey.GetIsBlackIDsKey(possibleBlackUserID, userID), func(ctx context.Context) ([]byte, error) {
 		log.ZDebug(ctx, "FriendLocalCache IsBlack rpc", "possibleBlackUserID", possibleBlackUserID, "userID", userID)
-		return cache.Marshal(f.client.Client.IsBlack(ctx, &relation.IsBlackReq{UserID1: possibleBlackUserID, UserID2: userID}))
+		return cache.Marshal(relation.IsBlackCaller.Invoke(ctx, &relation.IsBlackReq{UserID1: possibleBlackUserID, UserID2: userID}))
 	}, cachekey.GetBlackIDsKey(userID)))
 }
diff --git a/pkg/rpccache/group.go b/pkg/rpccache/group.go
index b2d852fc5f..111813103f 100644
--- a/pkg/rpccache/group.go
+++ b/pkg/rpccache/group.go
@@ -16,24 +16,24 @@ package rpccache
 
 import (
 	"context"
+
 	"github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/cachekey"
 	"github.com/openimsdk/protocol/group"
+	"github.com/openimsdk/protocol/rpccall"
 	"github.com/openimsdk/tools/utils/datautil"
 
 	"github.com/openimsdk/open-im-server/v3/pkg/common/config"
 	"github.com/openimsdk/open-im-server/v3/pkg/localcache"
-	"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
 	"github.com/openimsdk/protocol/sdkws"
 	"github.com/openimsdk/tools/errs"
 	"github.com/openimsdk/tools/log"
 	"github.com/redis/go-redis/v9"
 )
 
-func NewGroupLocalCache(client rpcclient.GroupRpcClient, localCache *config.LocalCache, cli redis.UniversalClient) *GroupLocalCache {
+func NewGroupLocalCache(localCache *config.LocalCache, cli redis.UniversalClient) *GroupLocalCache {
 	lc := localCache.Group
 	log.ZDebug(context.Background(), "GroupLocalCache", "topic", lc.Topic, "slotNum", lc.SlotNum, "slotSize", lc.SlotSize, "enable", lc.Enable())
 	x := &GroupLocalCache{
-		client: client,
 		local: localcache.New[[]byte](
 			localcache.WithLocalSlotNum(lc.SlotNum),
 			localcache.WithLocalSlotSize(lc.SlotSize),
@@ -49,8 +49,7 @@ func NewGroupLocalCache(client rpcclient.GroupRpcClient, localCache *config.Loca
 }
 
 type GroupLocalCache struct {
-	client rpcclient.GroupRpcClient
-	local  localcache.Cache[[]byte]
+	local localcache.Cache[[]byte]
 }
 
 func (g *GroupLocalCache) getGroupMemberIDs(ctx context.Context, groupID string) (val *group.GetGroupMemberUserIDsResp, err error) {
@@ -65,7 +64,7 @@ func (g *GroupLocalCache) getGroupMemberIDs(ctx context.Context, groupID string)
 	var cache cacheProto[group.GetGroupMemberUserIDsResp]
 	return cache.Unmarshal(g.local.Get(ctx, cachekey.GetGroupMemberIDsKey(groupID), func(ctx context.Context) ([]byte, error) {
 		log.ZDebug(ctx, "GroupLocalCache getGroupMemberIDs rpc", "groupID", groupID)
-		return cache.Marshal(g.client.Client.GetGroupMemberUserIDs(ctx, &group.GetGroupMemberUserIDsReq{GroupID: groupID}))
+		return cache.Marshal(group.GetGroupMemberUserIDsCaller.Invoke(ctx, &group.GetGroupMemberUserIDsReq{GroupID: groupID}))
 	}))
 }
 
@@ -81,7 +80,13 @@ func (g *GroupLocalCache) GetGroupMember(ctx context.Context, groupID, userID st
 	var cache cacheProto[sdkws.GroupMemberFullInfo]
 	return cache.Unmarshal(g.local.Get(ctx, cachekey.GetGroupMemberInfoKey(groupID, userID), func(ctx context.Context) ([]byte, error) {
 		log.ZDebug(ctx, "GroupLocalCache GetGroupInfo rpc", "groupID", groupID, "userID", userID)
-		return cache.Marshal(g.client.GetGroupMemberCache(ctx, groupID, userID))
+		return cache.Marshal(rpccall.ExtractField(ctx, group.GetGroupMemberCacheCaller.Invoke,
+			&group.GetGroupMemberCacheReq{
+				GroupID:       groupID,
+				GroupMemberID: userID,
+			},
+			(*group.GetGroupMemberCacheResp).GetMember,
+		))
 	}))
 }
 
@@ -97,7 +102,10 @@ func (g *GroupLocalCache) GetGroupInfo(ctx context.Context, groupID string) (val
 	var cache cacheProto[sdkws.GroupInfo]
 	return cache.Unmarshal(g.local.Get(ctx, cachekey.GetGroupInfoKey(groupID), func(ctx context.Context) ([]byte, error) {
 		log.ZDebug(ctx, "GroupLocalCache GetGroupInfo rpc", "groupID", groupID)
-		return cache.Marshal(g.client.GetGroupInfoCache(ctx, groupID))
+		return cache.Marshal(rpccall.ExtractField(ctx, group.GetGroupInfoCacheCaller.Invoke,
+			&group.GetGroupInfoCacheReq{
+				GroupID: groupID,
+			}, (*group.GetGroupInfoCacheResp).GetGroupInfo))
 	}))
 }
 
diff --git a/pkg/rpccache/online.go b/pkg/rpccache/online.go
index a02a0662d4..25362b5299 100644
--- a/pkg/rpccache/online.go
+++ b/pkg/rpccache/online.go
@@ -3,18 +3,19 @@ package rpccache
 import (
 	"context"
 	"fmt"
-	"github.com/openimsdk/protocol/constant"
-	"github.com/openimsdk/protocol/user"
 	"math/rand"
 	"strconv"
 	"sync"
 	"sync/atomic"
 	"time"
 
+	"github.com/openimsdk/protocol/constant"
+	"github.com/openimsdk/protocol/rpccall"
+	"github.com/openimsdk/protocol/user"
+
 	"github.com/openimsdk/open-im-server/v3/pkg/common/storage/cache/cachekey"
 	"github.com/openimsdk/open-im-server/v3/pkg/localcache"
 	"github.com/openimsdk/open-im-server/v3/pkg/localcache/lru"
-	"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
 	"github.com/openimsdk/open-im-server/v3/pkg/util/useronline"
 	"github.com/openimsdk/tools/db/cacheutil"
 	"github.com/openimsdk/tools/log"
@@ -22,10 +23,10 @@ import (
 	"github.com/redis/go-redis/v9"
 )
 
-func NewOnlineCache(user rpcclient.UserRpcClient, group *GroupLocalCache, rdb redis.UniversalClient, fullUserCache bool, fn func(ctx context.Context, userID string, platformIDs []int32)) (*OnlineCache, error) {
+func NewOnlineCache(adminUserID []string, group *GroupLocalCache, rdb redis.UniversalClient, fullUserCache bool, fn func(ctx context.Context, userID string, platformIDs []int32)) (*OnlineCache, error) {
 	l := &sync.Mutex{}
 	x := &OnlineCache{
-		user:          user,
+		adminUserID:   adminUserID,
 		group:         group,
 		fullUserCache: fullUserCache,
 		Lock:          l,
@@ -65,8 +66,8 @@ const (
 )
 
 type OnlineCache struct {
-	user  rpcclient.UserRpcClient
-	group *GroupLocalCache
+	adminUserID []string
+	group       *GroupLocalCache
 
 	// fullUserCache if enabled, caches the online status of all users using mapCache;
 	// otherwise, only a portion of users' online statuses (regardless of whether they are online) will be cached using lruCache.
@@ -112,7 +113,7 @@ func (o *OnlineCache) initUsersOnlineStatus(ctx context.Context) (err error) {
 	cursor := uint64(0)
 	for resp == nil || resp.NextCursor != 0 {
 		if err = retryOperation(func() error {
-			resp, err = o.user.GetAllOnlineUsers(ctx, cursor)
+			resp, err = user.GetAllOnlineUsersCaller.Invoke(ctx, &user.GetAllOnlineUsersReq{Cursor: cursor})
 			if err != nil {
 				return err
 			}
@@ -186,7 +187,17 @@ func (o *OnlineCache) doSubscribe(ctx context.Context, rdb redis.UniversalClient
 
 func (o *OnlineCache) getUserOnlinePlatform(ctx context.Context, userID string) ([]int32, error) {
 	platformIDs, err := o.lruCache.Get(userID, func() ([]int32, error) {
-		return o.user.GetUserOnlinePlatform(ctx, userID)
+		resp, err := rpccall.ExtractField(ctx, user.GetUserStatusCaller.Invoke, &user.GetUserStatusReq{
+			UserID:  o.adminUserID[0],
+			UserIDs: []string{userID},
+		}, (*user.GetUserStatusResp).GetStatusList)
+		if err != nil {
+			return nil, err
+		}
+		if len(resp) == 0 {
+			return nil, nil
+		}
+		return resp[0].PlatformIDs, nil
 	})
 	if err != nil {
 		log.ZError(ctx, "OnlineCache GetUserOnlinePlatform", err, "userID", userID)
@@ -228,7 +239,10 @@ func (o *OnlineCache) getUserOnlinePlatformBatch(ctx context.Context, userIDs []
 	platformIDsMap, err := o.lruCache.GetBatch(userIDs, func(missingUsers []string) (map[string][]int32, error) {
 		platformIDsMap := make(map[string][]int32)
 
-		usersStatus, err := o.user.GetUsersOnlinePlatform(ctx, missingUsers)
+		usersStatus, err := rpccall.ExtractField(ctx, user.GetUserStatusCaller.Invoke, &user.GetUserStatusReq{
+			UserID:  o.adminUserID[0],
+			UserIDs: missingUsers,
+		}, (*user.GetUserStatusResp).GetStatusList)
 		if err != nil {
 			return nil, err
 		}
diff --git a/pkg/rpccache/user.go b/pkg/rpccache/user.go
index 79a768597f..fce2c911ab 100644
--- a/pkg/rpccache/user.go
+++ b/pkg/rpccache/user.go
@@ -28,11 +28,10 @@ import (
 	"github.com/redis/go-redis/v9"
 )
 
-func NewUserLocalCache(client rpcclient.UserRpcClient, localCache *config.LocalCache, cli redis.UniversalClient) *UserLocalCache {
+func NewUserLocalCache(localCache *config.LocalCache, cli redis.UniversalClient) *UserLocalCache {
 	lc := localCache.User
 	log.ZDebug(context.Background(), "UserLocalCache", "topic", lc.Topic, "slotNum", lc.SlotNum, "slotSize", lc.SlotSize, "enable", lc.Enable())
 	x := &UserLocalCache{
-		client: client,
 		local: localcache.New[[]byte](
 			localcache.WithLocalSlotNum(lc.SlotNum),
 			localcache.WithLocalSlotSize(lc.SlotSize),
@@ -48,8 +47,7 @@ func NewUserLocalCache(client rpcclient.UserRpcClient, localCache *config.LocalC
 }
 
 type UserLocalCache struct {
-	client rpcclient.UserRpcClient
-	local  localcache.Cache[[]byte]
+	local localcache.Cache[[]byte]
 }
 
 func (u *UserLocalCache) GetUserInfo(ctx context.Context, userID string) (val *sdkws.UserInfo, err error) {
@@ -64,7 +62,7 @@ func (u *UserLocalCache) GetUserInfo(ctx context.Context, userID string) (val *s
 	var cache cacheProto[sdkws.UserInfo]
 	return cache.Unmarshal(u.local.Get(ctx, cachekey.GetUserInfoKey(userID), func(ctx context.Context) ([]byte, error) {
 		log.ZDebug(ctx, "UserLocalCache GetUserInfo rpc", "userID", userID)
-		return cache.Marshal(u.client.GetUserInfo(ctx, userID))
+		return cache.Marshal(rpcclient.GetUserInfo(ctx, userID))
 	}))
 }
 
@@ -88,7 +86,7 @@ func (u *UserLocalCache) getUserGlobalMsgRecvOpt(ctx context.Context, userID str
 	var cache cacheProto[user.GetGlobalRecvMessageOptResp]
 	return cache.Unmarshal(u.local.Get(ctx, cachekey.GetUserGlobalRecvMsgOptKey(userID), func(ctx context.Context) ([]byte, error) {
 		log.ZDebug(ctx, "UserLocalCache GetUserGlobalMsgRecvOpt rpc", "userID", userID)
-		return cache.Marshal(u.client.Client.GetGlobalRecvMessageOpt(ctx, &user.GetGlobalRecvMessageOptReq{UserID: userID}))
+		return cache.Marshal(user.GetGlobalRecvMessageOptCaller.Invoke(ctx, &user.GetGlobalRecvMessageOptReq{UserID: userID}))
 	}))
 }
 
diff --git a/pkg/rpcclient/auth.go b/pkg/rpcclient/auth.go
deleted file mode 100644
index 05fec35a08..0000000000
--- a/pkg/rpcclient/auth.go
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright © 2023 OpenIM. All rights reserved.
-//
-// 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.
-
-package rpcclient
-
-import (
-	"context"
-
-	"github.com/openimsdk/protocol/auth"
-	"github.com/openimsdk/tools/discovery"
-	"github.com/openimsdk/tools/system/program"
-	"google.golang.org/grpc"
-)
-
-func NewAuth(discov discovery.SvcDiscoveryRegistry, rpcRegisterName string) *Auth {
-	conn, err := discov.GetConn(context.Background(), rpcRegisterName)
-	if err != nil {
-		program.ExitWithError(err)
-	}
-	client := auth.NewAuthClient(conn)
-	return &Auth{discov: discov, conn: conn, Client: client}
-}
-
-type Auth struct {
-	conn   grpc.ClientConnInterface
-	Client auth.AuthClient
-	discov discovery.SvcDiscoveryRegistry
-}
-
-func (a *Auth) ParseToken(ctx context.Context, token string) (*auth.ParseTokenResp, error) {
-	req := auth.ParseTokenReq{
-		Token: token,
-	}
-	resp, err := a.Client.ParseToken(ctx, &req)
-	if err != nil {
-		return nil, err
-	}
-	return resp, err
-}
-
-func (a *Auth) InvalidateToken(ctx context.Context, preservedToken, userID string, platformID int) (*auth.InvalidateTokenResp, error) {
-	req := auth.InvalidateTokenReq{
-		PreservedToken: preservedToken,
-		UserID:         userID,
-		PlatformID:     int32(platformID),
-	}
-	resp, err := a.Client.InvalidateToken(ctx, &req)
-	if err != nil {
-		return nil, err
-	}
-	return resp, err
-}
-
-func (a *Auth) KickTokens(ctx context.Context, tokens []string) (*auth.KickTokensResp, error) {
-	req := auth.KickTokensReq{
-		Tokens: tokens,
-	}
-	resp, err := a.Client.KickTokens(ctx, &req)
-	if err != nil {
-		return nil, err
-	}
-	return resp, err
-}
diff --git a/pkg/rpcclient/conversation.go b/pkg/rpcclient/conversation.go
deleted file mode 100644
index c69d355d68..0000000000
--- a/pkg/rpcclient/conversation.go
+++ /dev/null
@@ -1,161 +0,0 @@
-// Copyright © 2023 OpenIM. All rights reserved.
-//
-// 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.
-
-package rpcclient
-
-import (
-	"context"
-	"fmt"
-
-	pbconversation "github.com/openimsdk/protocol/conversation"
-	"github.com/openimsdk/tools/discovery"
-	"github.com/openimsdk/tools/errs"
-	"github.com/openimsdk/tools/system/program"
-	"google.golang.org/grpc"
-)
-
-type Conversation struct {
-	Client pbconversation.ConversationClient
-	conn   grpc.ClientConnInterface
-	discov discovery.SvcDiscoveryRegistry
-}
-
-func NewConversation(discov discovery.SvcDiscoveryRegistry, rpcRegisterName string) *Conversation {
-	conn, err := discov.GetConn(context.Background(), rpcRegisterName)
-	if err != nil {
-		program.ExitWithError(err)
-	}
-	client := pbconversation.NewConversationClient(conn)
-	return &Conversation{discov: discov, conn: conn, Client: client}
-}
-
-type ConversationRpcClient Conversation
-
-func NewConversationRpcClient(discov discovery.SvcDiscoveryRegistry, rpcRegisterName string) ConversationRpcClient {
-	return ConversationRpcClient(*NewConversation(discov, rpcRegisterName))
-}
-
-func (c *ConversationRpcClient) GetSingleConversationRecvMsgOpt(ctx context.Context, userID, conversationID string) (int32, error) {
-	var req pbconversation.GetConversationReq
-	req.OwnerUserID = userID
-	req.ConversationID = conversationID
-	conversation, err := c.Client.GetConversation(ctx, &req)
-	if err != nil {
-		return 0, err
-	}
-	return conversation.GetConversation().RecvMsgOpt, err
-}
-
-func (c *ConversationRpcClient) SingleChatFirstCreateConversation(ctx context.Context, recvID, sendID,
-	conversationID string, conversationType int32) error {
-	_, err := c.Client.CreateSingleChatConversations(ctx,
-		&pbconversation.CreateSingleChatConversationsReq{
-			RecvID: recvID, SendID: sendID, ConversationID: conversationID,
-			ConversationType: conversationType,
-		})
-	return err
-}
-
-func (c *ConversationRpcClient) GroupChatFirstCreateConversation(ctx context.Context, groupID string, userIDs []string) error {
-	_, err := c.Client.CreateGroupChatConversations(ctx, &pbconversation.CreateGroupChatConversationsReq{UserIDs: userIDs, GroupID: groupID})
-	return err
-}
-
-func (c *ConversationRpcClient) SetConversationMaxSeq(ctx context.Context, ownerUserIDs []string, conversationID string, maxSeq int64) error {
-	_, err := c.Client.SetConversationMaxSeq(ctx, &pbconversation.SetConversationMaxSeqReq{OwnerUserID: ownerUserIDs, ConversationID: conversationID, MaxSeq: maxSeq})
-	return err
-}
-
-func (c *ConversationRpcClient) SetConversationMinSeq(ctx context.Context, ownerUserIDs []string, conversationID string, minSeq int64) error {
-	_, err := c.Client.SetConversationMinSeq(ctx, &pbconversation.SetConversationMinSeqReq{OwnerUserID: ownerUserIDs, ConversationID: conversationID, MinSeq: minSeq})
-	return err
-}
-
-func (c *ConversationRpcClient) SetConversations(ctx context.Context, userIDs []string, conversation *pbconversation.ConversationReq) error {
-	_, err := c.Client.SetConversations(ctx, &pbconversation.SetConversationsReq{UserIDs: userIDs, Conversation: conversation})
-	return err
-}
-
-func (c *ConversationRpcClient) UpdateConversation(ctx context.Context, conversation *pbconversation.UpdateConversationReq) error {
-	_, err := c.Client.UpdateConversation(ctx, conversation)
-	return err
-}
-
-func (c *ConversationRpcClient) GetConversationIDs(ctx context.Context, ownerUserID string) ([]string, error) {
-	resp, err := c.Client.GetConversationIDs(ctx, &pbconversation.GetConversationIDsReq{UserID: ownerUserID})
-	if err != nil {
-		return nil, err
-	}
-	return resp.ConversationIDs, nil
-}
-
-func (c *ConversationRpcClient) GetConversation(ctx context.Context, ownerUserID, conversationID string) (*pbconversation.Conversation, error) {
-	resp, err := c.Client.GetConversation(ctx, &pbconversation.GetConversationReq{OwnerUserID: ownerUserID, ConversationID: conversationID})
-	if err != nil {
-		return nil, err
-	}
-	return resp.Conversation, nil
-}
-
-func (c *ConversationRpcClient) GetConversationsByConversationID(ctx context.Context, conversationIDs []string) ([]*pbconversation.Conversation, error) {
-	if len(conversationIDs) == 0 {
-		return nil, nil
-	}
-	resp, err := c.Client.GetConversationsByConversationID(ctx, &pbconversation.GetConversationsByConversationIDReq{ConversationIDs: conversationIDs})
-	if err != nil {
-		return nil, err
-	}
-	if len(resp.Conversations) == 0 {
-		return nil, errs.ErrRecordNotFound.WrapMsg(fmt.Sprintf("conversationIDs: %v not found", conversationIDs))
-	}
-	return resp.Conversations, nil
-}
-
-func (c *ConversationRpcClient) GetConversationOfflinePushUserIDs(ctx context.Context, conversationID string, userIDs []string) ([]string, error) {
-	resp, err := c.Client.GetConversationOfflinePushUserIDs(ctx, &pbconversation.GetConversationOfflinePushUserIDsReq{ConversationID: conversationID, UserIDs: userIDs})
-	if err != nil {
-		return nil, err
-	}
-	return resp.UserIDs, nil
-}
-
-func (c *ConversationRpcClient) GetConversations(ctx context.Context, ownerUserID string, conversationIDs []string) ([]*pbconversation.Conversation, error) {
-	if len(conversationIDs) == 0 {
-		return nil, nil
-	}
-	resp, err := c.Client.GetConversations(
-		ctx,
-		&pbconversation.GetConversationsReq{OwnerUserID: ownerUserID, ConversationIDs: conversationIDs},
-	)
-	if err != nil {
-		return nil, err
-	}
-	return resp.Conversations, nil
-}
-
-func (c *ConversationRpcClient) GetConversationNotReceiveMessageUserIDs(ctx context.Context, conversationID string) ([]string, error) {
-	resp, err := c.Client.GetConversationNotReceiveMessageUserIDs(ctx, &pbconversation.GetConversationNotReceiveMessageUserIDsReq{ConversationID: conversationID})
-	if err != nil {
-		return nil, err
-	}
-	return resp.UserIDs, nil
-}
-
-func (c *ConversationRpcClient) GetConversationsNeedClearMsg(ctx context.Context) ([]*pbconversation.Conversation, error) {
-	resp, err := c.Client.GetConversationsNeedClearMsg(ctx, &pbconversation.GetConversationsNeedClearMsgReq{})
-	if err != nil {
-		return nil, err
-	}
-	return resp.Conversations, nil
-}
diff --git a/pkg/rpcclient/friend.go b/pkg/rpcclient/friend.go
deleted file mode 100644
index 359ed3a8b8..0000000000
--- a/pkg/rpcclient/friend.go
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright © 2023 OpenIM. All rights reserved.
-//
-// 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.
-
-package rpcclient
-
-import (
-	"context"
-
-	"github.com/openimsdk/protocol/relation"
-	sdkws "github.com/openimsdk/protocol/sdkws"
-	"github.com/openimsdk/tools/discovery"
-	"github.com/openimsdk/tools/system/program"
-	"google.golang.org/grpc"
-)
-
-type Friend struct {
-	conn   grpc.ClientConnInterface
-	Client relation.FriendClient
-	discov discovery.SvcDiscoveryRegistry
-}
-
-func NewFriend(discov discovery.SvcDiscoveryRegistry, rpcRegisterName string) *Friend {
-	conn, err := discov.GetConn(context.Background(), rpcRegisterName)
-	if err != nil {
-		program.ExitWithError(err)
-	}
-	client := relation.NewFriendClient(conn)
-	return &Friend{discov: discov, conn: conn, Client: client}
-}
-
-type FriendRpcClient Friend
-
-func NewFriendRpcClient(discov discovery.SvcDiscoveryRegistry, rpcRegisterName string) FriendRpcClient {
-	return FriendRpcClient(*NewFriend(discov, rpcRegisterName))
-}
-
-func (f *FriendRpcClient) GetFriendsInfo(
-	ctx context.Context,
-	ownerUserID, relationUserID string,
-) (resp *sdkws.FriendInfo, err error) {
-	r, err := f.Client.GetDesignatedFriends(
-		ctx,
-		&relation.GetDesignatedFriendsReq{OwnerUserID: ownerUserID, FriendUserIDs: []string{relationUserID}},
-	)
-	if err != nil {
-		return nil, err
-	}
-	resp = r.FriendsInfo[0]
-	return
-}
-
-// possibleFriendUserID Is PossibleFriendUserId's relations.
-func (f *FriendRpcClient) IsFriend(ctx context.Context, possibleFriendUserID, userID string) (bool, error) {
-	resp, err := f.Client.IsFriend(ctx, &relation.IsFriendReq{UserID1: userID, UserID2: possibleFriendUserID})
-	if err != nil {
-		return false, err
-	}
-	return resp.InUser1Friends, nil
-}
-
-func (f *FriendRpcClient) GetFriendIDs(ctx context.Context, ownerUserID string) (relationIDs []string, err error) {
-	req := relation.GetFriendIDsReq{UserID: ownerUserID}
-	resp, err := f.Client.GetFriendIDs(ctx, &req)
-	if err != nil {
-		return nil, err
-	}
-	return resp.FriendIDs, nil
-}
-
-func (f *FriendRpcClient) IsBlack(ctx context.Context, possibleBlackUserID, userID string) (bool, error) {
-	r, err := f.Client.IsBlack(ctx, &relation.IsBlackReq{UserID1: possibleBlackUserID, UserID2: userID})
-	if err != nil {
-		return false, err
-	}
-	return r.InUser2Blacks, nil
-}
diff --git a/pkg/rpcclient/group.go b/pkg/rpcclient/group.go
deleted file mode 100644
index 30d0b3288f..0000000000
--- a/pkg/rpcclient/group.go
+++ /dev/null
@@ -1,205 +0,0 @@
-// Copyright © 2023 OpenIM. All rights reserved.
-//
-// 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.
-
-package rpcclient
-
-import (
-	"context"
-	"strings"
-
-	"github.com/openimsdk/open-im-server/v3/pkg/common/servererrs"
-	"github.com/openimsdk/protocol/constant"
-	"github.com/openimsdk/protocol/group"
-	"github.com/openimsdk/protocol/sdkws"
-	"github.com/openimsdk/tools/discovery"
-	"github.com/openimsdk/tools/system/program"
-	"github.com/openimsdk/tools/utils/datautil"
-)
-
-type Group struct {
-	Client group.GroupClient
-	discov discovery.SvcDiscoveryRegistry
-}
-
-func NewGroup(discov discovery.SvcDiscoveryRegistry, rpcRegisterName string) *Group {
-	conn, err := discov.GetConn(context.Background(), rpcRegisterName)
-	if err != nil {
-		program.ExitWithError(err)
-	}
-	client := group.NewGroupClient(conn)
-	return &Group{discov: discov, Client: client}
-}
-
-type GroupRpcClient Group
-
-func NewGroupRpcClient(discov discovery.SvcDiscoveryRegistry, rpcRegisterName string) GroupRpcClient {
-	return GroupRpcClient(*NewGroup(discov, rpcRegisterName))
-}
-
-func (g *GroupRpcClient) GetGroupInfos(ctx context.Context, groupIDs []string, complete bool) ([]*sdkws.GroupInfo, error) {
-	resp, err := g.Client.GetGroupsInfo(ctx, &group.GetGroupsInfoReq{
-		GroupIDs: groupIDs,
-	})
-	if err != nil {
-		return nil, err
-	}
-	if complete {
-		if ids := datautil.Single(groupIDs, datautil.Slice(resp.GroupInfos, func(e *sdkws.GroupInfo) string {
-			return e.GroupID
-		})); len(ids) > 0 {
-			return nil, servererrs.ErrGroupIDNotFound.WrapMsg(strings.Join(ids, ","))
-		}
-	}
-	return resp.GroupInfos, nil
-}
-
-func (g *GroupRpcClient) GetGroupInfo(ctx context.Context, groupID string) (*sdkws.GroupInfo, error) {
-	groups, err := g.GetGroupInfos(ctx, []string{groupID}, true)
-	if err != nil {
-		return nil, err
-	}
-	return groups[0], nil
-}
-
-func (g *GroupRpcClient) GetGroupInfoMap(
-	ctx context.Context,
-	groupIDs []string,
-	complete bool,
-) (map[string]*sdkws.GroupInfo, error) {
-	groups, err := g.GetGroupInfos(ctx, groupIDs, complete)
-	if err != nil {
-		return nil, err
-	}
-	return datautil.SliceToMap(groups, func(e *sdkws.GroupInfo) string {
-		return e.GroupID
-	}), nil
-}
-
-func (g *GroupRpcClient) GetGroupMemberInfos(
-	ctx context.Context,
-	groupID string,
-	userIDs []string,
-	complete bool,
-) ([]*sdkws.GroupMemberFullInfo, error) {
-	resp, err := g.Client.GetGroupMembersInfo(ctx, &group.GetGroupMembersInfoReq{
-		GroupID: groupID,
-		UserIDs: userIDs,
-	})
-	if err != nil {
-		return nil, err
-	}
-	if complete {
-		if ids := datautil.Single(userIDs, datautil.Slice(resp.Members, func(e *sdkws.GroupMemberFullInfo) string {
-			return e.UserID
-		})); len(ids) > 0 {
-			return nil, servererrs.ErrNotInGroupYet.WrapMsg(strings.Join(ids, ","))
-		}
-	}
-	return resp.Members, nil
-}
-
-func (g *GroupRpcClient) GetGroupMemberInfo(
-	ctx context.Context,
-	groupID string,
-	userID string,
-) (*sdkws.GroupMemberFullInfo, error) {
-	members, err := g.GetGroupMemberInfos(ctx, groupID, []string{userID}, true)
-	if err != nil {
-		return nil, err
-	}
-	return members[0], nil
-}
-
-func (g *GroupRpcClient) GetGroupMemberInfoMap(
-	ctx context.Context,
-	groupID string,
-	userIDs []string,
-	complete bool,
-) (map[string]*sdkws.GroupMemberFullInfo, error) {
-	members, err := g.GetGroupMemberInfos(ctx, groupID, userIDs, true)
-	if err != nil {
-		return nil, err
-	}
-	return datautil.SliceToMap(members, func(e *sdkws.GroupMemberFullInfo) string {
-		return e.UserID
-	}), nil
-}
-
-func (g *GroupRpcClient) GetOwnerAndAdminInfos(
-	ctx context.Context,
-	groupID string,
-) ([]*sdkws.GroupMemberFullInfo, error) {
-	resp, err := g.Client.GetGroupMemberRoleLevel(ctx, &group.GetGroupMemberRoleLevelReq{
-		GroupID:    groupID,
-		RoleLevels: []int32{constant.GroupOwner, constant.GroupAdmin},
-	})
-	if err != nil {
-		return nil, err
-	}
-	return resp.Members, nil
-}
-
-func (g *GroupRpcClient) GetOwnerInfo(ctx context.Context, groupID string) (*sdkws.GroupMemberFullInfo, error) {
-	resp, err := g.Client.GetGroupMemberRoleLevel(ctx, &group.GetGroupMemberRoleLevelReq{
-		GroupID:    groupID,
-		RoleLevels: []int32{constant.GroupOwner},
-	})
-	return resp.Members[0], err
-}
-
-func (g *GroupRpcClient) GetGroupMemberIDs(ctx context.Context, groupID string) ([]string, error) {
-	resp, err := g.Client.GetGroupMemberUserIDs(ctx, &group.GetGroupMemberUserIDsReq{
-		GroupID: groupID,
-	})
-	if err != nil {
-		return nil, err
-	}
-	return resp.UserIDs, nil
-}
-
-func (g *GroupRpcClient) GetGroupInfoCache(ctx context.Context, groupID string) (*sdkws.GroupInfo, error) {
-	resp, err := g.Client.GetGroupInfoCache(ctx, &group.GetGroupInfoCacheReq{
-		GroupID: groupID,
-	})
-	if err != nil {
-		return nil, err
-	}
-	return resp.GroupInfo, nil
-}
-
-func (g *GroupRpcClient) GetGroupMemberCache(ctx context.Context, groupID string, groupMemberID string) (*sdkws.GroupMemberFullInfo, error) {
-	resp, err := g.Client.GetGroupMemberCache(ctx, &group.GetGroupMemberCacheReq{
-		GroupID:       groupID,
-		GroupMemberID: groupMemberID,
-	})
-	if err != nil {
-		return nil, err
-	}
-	return resp.Member, nil
-}
-
-func (g *GroupRpcClient) DismissGroup(ctx context.Context, groupID string) error {
-	_, err := g.Client.DismissGroup(ctx, &group.DismissGroupReq{
-		GroupID:      groupID,
-		DeleteMember: true,
-	})
-	return err
-}
-
-func (g *GroupRpcClient) NotificationUserInfoUpdate(ctx context.Context, userID string) error {
-	_, err := g.Client.NotificationUserInfoUpdate(ctx, &group.NotificationUserInfoUpdateReq{
-		UserID: userID,
-	})
-	return err
-}
diff --git a/pkg/rpcclient/init.go b/pkg/rpcclient/init.go
new file mode 100644
index 0000000000..3d3f68aef8
--- /dev/null
+++ b/pkg/rpcclient/init.go
@@ -0,0 +1,60 @@
+package rpcclient
+
+import (
+	"context"
+
+	"github.com/openimsdk/open-im-server/v3/pkg/common/config"
+	pbauth "github.com/openimsdk/protocol/auth"
+	pbconversation "github.com/openimsdk/protocol/conversation"
+	pbgroup "github.com/openimsdk/protocol/group"
+	pbmsg "github.com/openimsdk/protocol/msg"
+	pbmsggateway "github.com/openimsdk/protocol/msggateway"
+	pbpush "github.com/openimsdk/protocol/push"
+	pbrelation "github.com/openimsdk/protocol/relation"
+	pbthird "github.com/openimsdk/protocol/third"
+	pbuser "github.com/openimsdk/protocol/user"
+	"github.com/openimsdk/tools/discovery"
+	"github.com/openimsdk/tools/system/program"
+	"google.golang.org/grpc"
+)
+
+func InitRpcCaller(discov discovery.SvcDiscoveryRegistry, service config.RpcService) error {
+	initConn := func(discov discovery.SvcDiscoveryRegistry, name string, initFunc func(conn *grpc.ClientConn)) error {
+		conn, err := discov.GetConn(context.Background(), name)
+		if err != nil {
+			program.ExitWithError(err)
+			return err
+		}
+		initFunc(conn)
+		return nil
+	}
+	if err := initConn(discov, service.Auth, pbauth.InitAuth); err != nil {
+		return err
+	}
+	if err := initConn(discov, service.Conversation, pbconversation.InitConversation); err != nil {
+		return err
+	}
+	if err := initConn(discov, service.Group, pbgroup.InitGroup); err != nil {
+		return err
+	}
+	if err := initConn(discov, service.Msg, pbmsg.InitMsg); err != nil {
+		return err
+	}
+	if err := initConn(discov, service.MessageGateway, pbmsggateway.InitMsgGateway); err != nil {
+		return err
+	}
+	if err := initConn(discov, service.Push, pbpush.InitPushMsgService); err != nil {
+		return err
+	}
+	if err := initConn(discov, service.Friend, pbrelation.InitFriend); err != nil {
+		return err
+	}
+	if err := initConn(discov, service.Third, pbthird.InitThird); err != nil {
+		return err
+	}
+	if err := initConn(discov, service.User, pbuser.InitUser); err != nil {
+		return err
+	}
+
+	return nil
+}
diff --git a/pkg/rpcclient/msg.go b/pkg/rpcclient/msg.go
index 8313937cdb..ca9b8fc681 100644
--- a/pkg/rpcclient/msg.go
+++ b/pkg/rpcclient/msg.go
@@ -19,17 +19,14 @@ import (
 	"encoding/json"
 	"time"
 
-	"google.golang.org/grpc"
 	"google.golang.org/protobuf/proto"
 
 	"github.com/openimsdk/open-im-server/v3/pkg/common/config"
 	"github.com/openimsdk/protocol/constant"
 	"github.com/openimsdk/protocol/msg"
 	"github.com/openimsdk/protocol/sdkws"
-	"github.com/openimsdk/tools/discovery"
 	"github.com/openimsdk/tools/log"
 	"github.com/openimsdk/tools/mq/memamq"
-	"github.com/openimsdk/tools/system/program"
 	"github.com/openimsdk/tools/utils/idutil"
 	"github.com/openimsdk/tools/utils/jsonutil"
 	"github.com/openimsdk/tools/utils/timeutil"
@@ -129,126 +126,6 @@ func newSessionTypeConf() map[int32]int32 {
 	}
 }
 
-type Message struct {
-	conn   grpc.ClientConnInterface
-	Client msg.MsgClient
-	discov discovery.SvcDiscoveryRegistry
-}
-
-func NewMessage(discov discovery.SvcDiscoveryRegistry, rpcRegisterName string) *Message {
-	conn, err := discov.GetConn(context.Background(), rpcRegisterName)
-	if err != nil {
-		program.ExitWithError(err)
-	}
-	client := msg.NewMsgClient(conn)
-	return &Message{discov: discov, conn: conn, Client: client}
-}
-
-type MessageRpcClient Message
-
-func NewMessageRpcClient(discov discovery.SvcDiscoveryRegistry, rpcRegisterName string) MessageRpcClient {
-	return MessageRpcClient(*NewMessage(discov, rpcRegisterName))
-}
-
-// SendMsg sends a message through the gRPC client and returns the response.
-// It wraps any encountered error for better error handling and context understanding.
-func (m *MessageRpcClient) SendMsg(ctx context.Context, req *msg.SendMsgReq) (*msg.SendMsgResp, error) {
-	resp, err := m.Client.SendMsg(ctx, req)
-	if err != nil {
-		return nil, err
-	}
-	return resp, nil
-}
-
-// SetUserConversationsMinSeq set min seq
-func (m *MessageRpcClient) SetUserConversationsMinSeq(ctx context.Context, req *msg.SetUserConversationsMinSeqReq) (*msg.SetUserConversationsMinSeqResp, error) {
-	resp, err := m.Client.SetUserConversationsMinSeq(ctx, req)
-	if err != nil {
-		return nil, err
-	}
-	return resp, nil
-}
-
-// GetMaxSeq retrieves the maximum sequence number from the gRPC client.
-// Errors during the gRPC call are wrapped to provide additional context.
-func (m *MessageRpcClient) GetMaxSeq(ctx context.Context, req *sdkws.GetMaxSeqReq) (*sdkws.GetMaxSeqResp, error) {
-	resp, err := m.Client.GetMaxSeq(ctx, req)
-	if err != nil {
-		return nil, err
-	}
-	return resp, nil
-}
-
-func (m *MessageRpcClient) GetMaxSeqs(ctx context.Context, conversationIDs []string) (map[string]int64, error) {
-	log.ZDebug(ctx, "GetMaxSeqs", "conversationIDs", conversationIDs)
-	resp, err := m.Client.GetMaxSeqs(ctx, &msg.GetMaxSeqsReq{
-		ConversationIDs: conversationIDs,
-	})
-	if err != nil {
-		return nil, err
-	}
-	return resp.MaxSeqs, err
-}
-
-func (m *MessageRpcClient) GetHasReadSeqs(ctx context.Context, userID string, conversationIDs []string) (map[string]int64, error) {
-	resp, err := m.Client.GetHasReadSeqs(ctx, &msg.GetHasReadSeqsReq{
-		UserID:          userID,
-		ConversationIDs: conversationIDs,
-	})
-	if err != nil {
-		return nil, err
-	}
-	return resp.MaxSeqs, err
-}
-
-func (m *MessageRpcClient) GetMsgByConversationIDs(ctx context.Context, docIDs []string, seqs map[string]int64) (map[string]*sdkws.MsgData, error) {
-	resp, err := m.Client.GetMsgByConversationIDs(ctx, &msg.GetMsgByConversationIDsReq{
-		ConversationIDs: docIDs,
-		MaxSeqs:         seqs,
-	})
-	if err != nil {
-		return nil, err
-	}
-	return resp.MsgDatas, err
-}
-
-// PullMessageBySeqList retrieves messages by their sequence numbers using the gRPC client.
-// It directly forwards the request to the gRPC client and returns the response along with any error encountered.
-func (m *MessageRpcClient) PullMessageBySeqList(ctx context.Context, req *sdkws.PullMessageBySeqsReq) (*sdkws.PullMessageBySeqsResp, error) {
-	resp, err := m.Client.PullMessageBySeqs(ctx, req)
-	if err != nil {
-		// Wrap the error to provide more context if the gRPC call fails.
-		return nil, err
-	}
-	return resp, nil
-}
-
-func (m *MessageRpcClient) GetConversationsHasReadAndMaxSeq(ctx context.Context, req *msg.GetConversationsHasReadAndMaxSeqReq) (*msg.GetConversationsHasReadAndMaxSeqResp, error) {
-	resp, err := m.Client.GetConversationsHasReadAndMaxSeq(ctx, req)
-	if err != nil {
-		// Wrap the error to provide more context if the gRPC call fails.
-		return nil, err
-	}
-	return resp, nil
-}
-
-func (m *MessageRpcClient) GetSeqMessage(ctx context.Context, req *msg.GetSeqMessageReq) (*msg.GetSeqMessageResp, error) {
-	return m.Client.GetSeqMessage(ctx, req)
-}
-
-func (m *MessageRpcClient) GetConversationMaxSeq(ctx context.Context, conversationID string) (int64, error) {
-	resp, err := m.Client.GetConversationMaxSeq(ctx, &msg.GetConversationMaxSeqReq{ConversationID: conversationID})
-	if err != nil {
-		return 0, err
-	}
-	return resp.MaxSeq, nil
-}
-
-func (m *MessageRpcClient) DestructMsgs(ctx context.Context, ts int64) error {
-	_, err := m.Client.DestructMsgs(ctx, &msg.DestructMsgsReq{Timestamp: ts})
-	return err
-}
-
 type NotificationSender struct {
 	contentTypeConf map[int32]config.NotificationConfig
 	sessionTypeConf map[int32]int32
@@ -271,15 +148,17 @@ func WithLocalSendMsg(sendMsg func(ctx context.Context, req *msg.SendMsgReq) (*m
 	}
 }
 
-func WithRpcClient(msgRpcClient *MessageRpcClient) NotificationSenderOptions {
+func WithRpcClient() NotificationSenderOptions {
 	return func(s *NotificationSender) {
-		s.sendMsg = msgRpcClient.SendMsg
+		s.sendMsg = func(ctx context.Context, req *msg.SendMsgReq) (*msg.SendMsgResp, error) {
+			return msg.SendMsgCaller.Invoke(ctx, req)
+		}
 	}
 }
 
-func WithUserRpcClient(userRpcClient *UserRpcClient) NotificationSenderOptions {
+func WithUserRpcClient() NotificationSenderOptions {
 	return func(s *NotificationSender) {
-		s.getUserInfo = userRpcClient.GetUserInfo
+		s.getUserInfo = GetUserInfo
 	}
 }
 
diff --git a/pkg/rpcclient/push.go b/pkg/rpcclient/push.go
deleted file mode 100644
index c549e454a7..0000000000
--- a/pkg/rpcclient/push.go
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright © 2023 OpenIM. All rights reserved.
-//
-// 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.
-
-package rpcclient
-
-import (
-	"context"
-
-	"github.com/openimsdk/protocol/push"
-	"github.com/openimsdk/tools/discovery"
-	"github.com/openimsdk/tools/system/program"
-	"google.golang.org/grpc"
-)
-
-type Push struct {
-	conn   grpc.ClientConnInterface
-	Client push.PushMsgServiceClient
-	discov discovery.SvcDiscoveryRegistry
-}
-
-func NewPush(discov discovery.SvcDiscoveryRegistry, rpcRegisterName string) *Push {
-	conn, err := discov.GetConn(context.Background(), rpcRegisterName)
-	if err != nil {
-		program.ExitWithError(err)
-	}
-	return &Push{
-		discov: discov,
-		conn:   conn,
-		Client: push.NewPushMsgServiceClient(conn),
-	}
-}
-
-type PushRpcClient Push
-
-func NewPushRpcClient(discov discovery.SvcDiscoveryRegistry, rpcRegisterName string) PushRpcClient {
-	return PushRpcClient(*NewPush(discov, rpcRegisterName))
-}
-
-func (p *PushRpcClient) DelUserPushToken(ctx context.Context, req *push.DelUserPushTokenReq) (*push.DelUserPushTokenResp, error) {
-	return p.Client.DelUserPushToken(ctx, req)
-}
diff --git a/pkg/rpcclient/third.go b/pkg/rpcclient/third.go
deleted file mode 100644
index 7cdc60d52f..0000000000
--- a/pkg/rpcclient/third.go
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright © 2023 OpenIM. All rights reserved.
-//
-// 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.
-
-package rpcclient
-
-import (
-	"context"
-
-	"github.com/openimsdk/protocol/third"
-	"github.com/openimsdk/tools/discovery"
-	"github.com/openimsdk/tools/system/program"
-	"google.golang.org/grpc"
-)
-
-type Third struct {
-	conn       grpc.ClientConnInterface
-	Client     third.ThirdClient
-	discov     discovery.SvcDiscoveryRegistry
-	GrafanaUrl string
-}
-
-func NewThird(discov discovery.SvcDiscoveryRegistry, rpcRegisterName, grafanaUrl string) *Third {
-	conn, err := discov.GetConn(context.Background(), rpcRegisterName)
-	if err != nil {
-		program.ExitWithError(err)
-	}
-	client := third.NewThirdClient(conn)
-	if err != nil {
-		program.ExitWithError(err)
-	}
-	return &Third{discov: discov, Client: client, conn: conn, GrafanaUrl: grafanaUrl}
-}
-func (t *Third) DeleteOutdatedData(ctx context.Context, expires int64) error {
-	_, err := t.Client.DeleteOutdatedData(ctx, &third.DeleteOutdatedDataReq{ExpireTime: expires})
-	return err
-}
diff --git a/pkg/rpcclient/user.go b/pkg/rpcclient/user.go
index bdc1a2e012..463dd9a390 100644
--- a/pkg/rpcclient/user.go
+++ b/pkg/rpcclient/user.go
@@ -18,60 +18,18 @@ import (
 	"context"
 	"strings"
 
-	"github.com/openimsdk/open-im-server/v3/pkg/authverify"
 	"github.com/openimsdk/open-im-server/v3/pkg/common/servererrs"
 	"github.com/openimsdk/protocol/sdkws"
 	"github.com/openimsdk/protocol/user"
-	"github.com/openimsdk/tools/discovery"
-	"github.com/openimsdk/tools/system/program"
 	"github.com/openimsdk/tools/utils/datautil"
-	"google.golang.org/grpc"
 )
 
-// User represents a structure holding connection details for the User RPC client.
-type User struct {
-	conn                  grpc.ClientConnInterface
-	Client                user.UserClient
-	Discov                discovery.SvcDiscoveryRegistry
-	MessageGateWayRpcName string
-	imAdminUserID         []string
-}
-
-// NewUser initializes and returns a User instance based on the provided service discovery registry.
-func NewUser(discov discovery.SvcDiscoveryRegistry, rpcRegisterName, messageGateWayRpcName string,
-	imAdminUserID []string) *User {
-	conn, err := discov.GetConn(context.Background(), rpcRegisterName)
-	if err != nil {
-		program.ExitWithError(err)
-	}
-	client := user.NewUserClient(conn)
-	return &User{Discov: discov, Client: client,
-		conn:                  conn,
-		MessageGateWayRpcName: messageGateWayRpcName,
-		imAdminUserID:         imAdminUserID}
-}
-
-// UserRpcClient represents the structure for a User RPC client.
-type UserRpcClient User
-
-// NewUserRpcClientByUser initializes a UserRpcClient based on the provided User instance.
-func NewUserRpcClientByUser(user *User) *UserRpcClient {
-	rpc := UserRpcClient(*user)
-	return &rpc
-}
-
-// NewUserRpcClient initializes a UserRpcClient based on the provided service discovery registry.
-func NewUserRpcClient(client discovery.SvcDiscoveryRegistry, rpcRegisterName string,
-	imAdminUserID []string) UserRpcClient {
-	return UserRpcClient(*NewUser(client, rpcRegisterName, "", imAdminUserID))
-}
-
 // GetUsersInfo retrieves information for multiple users based on their user IDs.
-func (u *UserRpcClient) GetUsersInfo(ctx context.Context, userIDs []string) ([]*sdkws.UserInfo, error) {
+func GetUsersInfo(ctx context.Context, userIDs []string) ([]*sdkws.UserInfo, error) {
 	if len(userIDs) == 0 {
 		return []*sdkws.UserInfo{}, nil
 	}
-	resp, err := u.Client.GetDesignateUsers(ctx, &user.GetDesignateUsersReq{
+	resp, err := user.GetDesignateUsersCaller.Invoke(ctx, &user.GetDesignateUsersReq{
 		UserIDs: userIDs,
 	})
 	if err != nil {
@@ -86,8 +44,8 @@ func (u *UserRpcClient) GetUsersInfo(ctx context.Context, userIDs []string) ([]*
 }
 
 // GetUserInfo retrieves information for a single user based on the provided user ID.
-func (u *UserRpcClient) GetUserInfo(ctx context.Context, userID string) (*sdkws.UserInfo, error) {
-	users, err := u.GetUsersInfo(ctx, []string{userID})
+func GetUserInfo(ctx context.Context, userID string) (*sdkws.UserInfo, error) {
+	users, err := GetUsersInfo(ctx, []string{userID})
 	if err != nil {
 		return nil, err
 	}
@@ -95,8 +53,8 @@ func (u *UserRpcClient) GetUserInfo(ctx context.Context, userID string) (*sdkws.
 }
 
 // GetUsersInfoMap retrieves a map of user information indexed by their user IDs.
-func (u *UserRpcClient) GetUsersInfoMap(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error) {
-	users, err := u.GetUsersInfo(ctx, userIDs)
+func GetUsersInfoMap(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error) {
+	users, err := GetUsersInfo(ctx, userIDs)
 	if err != nil {
 		return nil, err
 	}
@@ -106,11 +64,11 @@ func (u *UserRpcClient) GetUsersInfoMap(ctx context.Context, userIDs []string) (
 }
 
 // GetPublicUserInfos retrieves public information for multiple users based on their user IDs.
-func (u *UserRpcClient) GetPublicUserInfos(
+func GetPublicUserInfos(
 	ctx context.Context,
 	userIDs []string,
 ) ([]*sdkws.PublicUserInfo, error) {
-	users, err := u.GetUsersInfo(ctx, userIDs)
+	users, err := GetUsersInfo(ctx, userIDs)
 	if err != nil {
 		return nil, err
 	}
@@ -126,8 +84,8 @@ func (u *UserRpcClient) GetPublicUserInfos(
 }
 
 // GetPublicUserInfo retrieves public information for a single user based on the provided user ID.
-func (u *UserRpcClient) GetPublicUserInfo(ctx context.Context, userID string) (*sdkws.PublicUserInfo, error) {
-	users, err := u.GetPublicUserInfos(ctx, []string{userID})
+func GetPublicUserInfo(ctx context.Context, userID string) (*sdkws.PublicUserInfo, error) {
+	users, err := GetPublicUserInfos(ctx, []string{userID})
 	if err != nil {
 		return nil, err
 	}
@@ -136,11 +94,11 @@ func (u *UserRpcClient) GetPublicUserInfo(ctx context.Context, userID string) (*
 }
 
 // GetPublicUserInfoMap retrieves a map of public user information indexed by their user IDs.
-func (u *UserRpcClient) GetPublicUserInfoMap(
+func GetPublicUserInfoMap(
 	ctx context.Context,
 	userIDs []string,
 ) (map[string]*sdkws.PublicUserInfo, error) {
-	users, err := u.GetPublicUserInfos(ctx, userIDs)
+	users, err := GetPublicUserInfos(ctx, userIDs)
 	if err != nil {
 		return nil, err
 	}
@@ -149,83 +107,3 @@ func (u *UserRpcClient) GetPublicUserInfoMap(
 		return e.UserID
 	}), nil
 }
-
-// GetUserGlobalMsgRecvOpt retrieves the global message receive option for a user based on the provided user ID.
-func (u *UserRpcClient) GetUserGlobalMsgRecvOpt(ctx context.Context, userID string) (int32, error) {
-	resp, err := u.Client.GetGlobalRecvMessageOpt(ctx, &user.GetGlobalRecvMessageOptReq{
-		UserID: userID,
-	})
-	if err != nil {
-		return 0, err
-	}
-	return resp.GlobalRecvMsgOpt, nil
-}
-
-// Access verifies the access rights for the provided user ID.
-func (u *UserRpcClient) Access(ctx context.Context, ownerUserID string) error {
-	_, err := u.GetUserInfo(ctx, ownerUserID)
-	if err != nil {
-		return err
-	}
-	return authverify.CheckAccessV3(ctx, ownerUserID, u.imAdminUserID)
-}
-
-// GetAllUserID retrieves all user IDs with pagination options.
-func (u *UserRpcClient) GetAllUserID(ctx context.Context, pageNumber, showNumber int32) (*user.GetAllUserIDResp, error) {
-	resp, err := u.Client.GetAllUserID(ctx, &user.GetAllUserIDReq{Pagination: &sdkws.RequestPagination{PageNumber: pageNumber, ShowNumber: showNumber}})
-	if err != nil {
-		return nil, err
-	}
-	return resp, nil
-}
-
-// GetAllUserIDs retrieves all user IDs with pagination options.
-func (u *UserRpcClient) GetAllUserIDs(ctx context.Context, pageNumber, showNumber int32) ([]string, error) {
-	resp, err := u.Client.GetAllUserID(ctx, &user.GetAllUserIDReq{Pagination: &sdkws.RequestPagination{PageNumber: pageNumber, ShowNumber: showNumber}})
-	if err != nil {
-		return nil, err
-	}
-	return resp.UserIDs, nil
-}
-
-// SetUserStatus sets the status for a user based on the provided user ID, status, and platform ID.
-func (u *UserRpcClient) SetUserStatus(ctx context.Context, userID string, status int32, platformID int) error {
-	_, err := u.Client.SetUserStatus(ctx, &user.SetUserStatusReq{
-		UserID: userID,
-		Status: status, PlatformID: int32(platformID),
-	})
-	return err
-}
-
-func (u *UserRpcClient) GetNotificationByID(ctx context.Context, userID string) error {
-	_, err := u.Client.GetNotificationAccount(ctx, &user.GetNotificationAccountReq{
-		UserID: userID,
-	})
-	return err
-}
-
-func (u *UserRpcClient) GetUsersOnlinePlatform(ctx context.Context, userIDs []string) ([]*user.OnlineStatus, error) {
-	if len(userIDs) == 0 {
-		return nil, nil
-	}
-	resp, err := u.Client.GetUserStatus(ctx, &user.GetUserStatusReq{UserIDs: userIDs, UserID: u.imAdminUserID[0]})
-	if err != nil {
-		return nil, err
-	}
-	return resp.StatusList, nil
-}
-
-func (u *UserRpcClient) GetUserOnlinePlatform(ctx context.Context, userID string) ([]int32, error) {
-	resp, err := u.GetUsersOnlinePlatform(ctx, []string{userID})
-	if err != nil {
-		return nil, err
-	}
-	if len(resp) == 0 {
-		return nil, nil
-	}
-	return resp[0].PlatformIDs, nil
-}
-
-func (u *UserRpcClient) GetAllOnlineUsers(ctx context.Context, cursor uint64) (*user.GetAllOnlineUsersResp, error) {
-	return u.Client.GetAllOnlineUsers(ctx, &user.GetAllOnlineUsersReq{Cursor: cursor})
-}