Files
mattermost-mcp-server/operation/user/user.go
T
Karti Tripathi a4e51f6412 feat: initial release with 48 Mattermost MCP tools
- 27 base tools: channels, messaging, users, reactions, files, DMs
- Team management: invite/remove users, get stats, list members
- Slash commands: execute /remind, /poll, etc.
- Webhook management: incoming and outgoing webhooks
- System tools: server config, logs, bulk status updates
- Channel admin: create, invite, leave, delete channels
- Read-only mode for safe exploration
- Dual token support (bot + PAT) for enhanced security
- Apache 2.0 licensed
2026-04-15 21:15:26 -07:00

130 lines
3.3 KiB
Go

package user
import (
"context"
"fmt"
"github.com/karti-ai/mattermost-mcp-server/pkg/log"
"github.com/karti-ai/mattermost-mcp-server/pkg/mattermost"
"github.com/karti-ai/mattermost-mcp-server/pkg/params"
"github.com/karti-ai/mattermost-mcp-server/pkg/to"
"github.com/karti-ai/mattermost-mcp-server/pkg/tool"
"github.com/mark3labs/mcp-go/mcp"
"github.com/mark3labs/mcp-go/server"
"github.com/mattermost/mattermost-server/v6/model"
)
var Tool = tool.New()
const (
SearchUsersToolName = "mattermost_search_users"
GetUserToolName = "mattermost_get_user"
)
var (
SearchUsersTool = mcp.NewTool(
SearchUsersToolName,
mcp.WithDescription("Search users by term"),
mcp.WithString("term", mcp.Required(), mcp.Description("Search term (username, email, name)")),
mcp.WithString("team_id", mcp.Description("Limit to team (optional)")),
mcp.WithNumber("limit", mcp.Description("Max results (default 30)")),
)
GetUserTool = mcp.NewTool(
GetUserToolName,
mcp.WithDescription("Get a specific user by ID or username"),
mcp.WithString("user_id", mcp.Description("User ID to look up (optional if username provided)")),
mcp.WithString("username", mcp.Description("Username to look up (optional if user_id provided)")),
)
)
func init() {
registerTools()
}
func registerTools() {
tools := []server.ServerTool{
{Tool: SearchUsersTool, Handler: SearchUsersFn},
{Tool: GetUserTool, Handler: GetUserFn},
}
for _, t := range tools {
Tool.RegisterRead(t)
}
}
func SearchUsersFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("[User] Called SearchUsersFn")
args := req.GetArguments()
term, err := params.GetString(args, "term")
if err != nil {
return to.Error(fmt.Errorf("[term] %v", err)), nil
}
teamID := params.GetOptionalString(args, "team_id", "")
limit := params.GetOptionalInt(args, "limit", 30)
client := mattermost.GetGlobalClient()
if client == nil {
return to.Error(fmt.Errorf("[internal] client not initialized")), nil
}
search := &model.UserSearch{
Term: term,
Limit: int(limit),
}
if teamID != "" {
search.TeamId = teamID
}
users, err := client.SearchUsers(ctx, search)
if err != nil {
return to.Error(fmt.Errorf("[users] failed to search users: %v", err)), nil
}
results := make([]map[string]interface{}, 0, len(users))
for _, u := range users {
results = append(results, SlimUser(u))
}
return to.Result(map[string]interface{}{
"users": results,
"count": len(results),
}), nil
}
func GetUserFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("[User] Called GetUserFn")
args := req.GetArguments()
userID := params.GetOptionalString(args, "user_id", "")
username := params.GetOptionalString(args, "username", "")
if userID == "" && username == "" {
return to.Error(fmt.Errorf("[user] either user_id or username must be provided")), nil
}
client := mattermost.GetGlobalClient()
if client == nil {
return to.Error(fmt.Errorf("[internal] client not initialized")), nil
}
var user *model.User
var err error
if userID != "" {
user, err = client.GetUser(ctx, userID)
} else {
user, err = client.GetUserByUsername(ctx, username)
}
if err != nil {
return to.Error(fmt.Errorf("[user] failed to get user: %v", err)), nil
}
return to.Result(SlimUser(user)), nil
}