@@ -14,6 +14,36 @@ import (
1414 "github.com/modelcontextprotocol/go-sdk/mcp"
1515)
1616
17+ // Input struct for the AddUser tool.
18+ type AddUserInput struct {
19+ Username string `json:"username" jsonschema:"the username of the new account"`
20+ BaseDir string `json:"base_dir,omitempty" jsonschema:"the base directory for the home directory of the new account"`
21+ Comment string `json:"comment,omitempty" jsonschema:"the GECOS field of the new account"`
22+ HomeDir string `json:"home_dir,omitempty" jsonschema:"the home directory of the new account"`
23+ ExpireDate string `json:"expire_date,omitempty" jsonschema:"the expiration date of the new account"`
24+ Inactive int `json:"inactive,omitempty" jsonschema:"the password inactivity period of the new account"`
25+ Gid string `json:"gid,omitempty" jsonschema:"the name or ID of the primary group of the new account"`
26+ Groups []string `json:"groups,omitempty" jsonschema:"the list of supplementary groups of the new account"`
27+ SkelDir string `json:"skel_dir,omitempty" jsonschema:"the alternative skeleton directory"`
28+ CreateHome bool `json:"create_home,omitempty" jsonschema:"create the user's home directory"`
29+ NoCreateHome bool `json:"no_create_home,omitempty" jsonschema:"do not create the user's home directory"`
30+ NoUserGroup bool `json:"no_user_group,omitempty" jsonschema:"do not create a group with the same name as the user"`
31+ NonUnique bool `json:"non_unique,omitempty" jsonschema:"allow to create users with duplicate (non-unique) UID"`
32+ Password string `json:"password,omitempty" jsonschema:"the encrypted password of the new account"`
33+ System bool `json:"system,omitempty" jsonschema:"create a system account"`
34+ Shell string `json:"shell,omitempty" jsonschema:"the login shell of the new account"`
35+ Uid int `json:"uid,omitempty" jsonschema:"the user ID of the new account"`
36+ UserGroup bool `json:"user_group,omitempty" jsonschema:"create a group with the same name as the user"`
37+ SelinuxUser string `json:"selinux_user,omitempty" jsonschema:"the specific SEUSER for the SELinux user mapping"`
38+ SelinuxRange string `json:"selinux_range,omitempty" jsonschema:"the specific MLS range for the SELinux user mapping"`
39+ }
40+
41+ // Output struct for the AddUser tool.
42+ type AddUserOutput struct {
43+ Success bool `json:"success" jsonschema:"whether the user was added successfully"`
44+ Message string `json:"message" jsonschema:"a message indicating the result of the operation"`
45+ }
46+
1747// User struct represents a single user account.
1848type User struct {
1949 Username string `json:"username"`
@@ -170,6 +200,78 @@ func getGroups() ([]Group, error) {
170200 return groups , nil
171201}
172202
203+ func AddUser (ctx context.Context , req * mcp.CallToolRequest , input AddUserInput ) (
204+ * mcp.CallToolResult , AddUserOutput , error ,
205+ ) {
206+ slog .Info ("AddUser tool called" )
207+ args := []string {}
208+ if input .BaseDir != "" {
209+ args = append (args , "-b" , input .BaseDir )
210+ }
211+ if input .Comment != "" {
212+ args = append (args , "-c" , input .Comment )
213+ }
214+ if input .HomeDir != "" {
215+ args = append (args , "-d" , input .HomeDir )
216+ }
217+ if input .ExpireDate != "" {
218+ args = append (args , "-e" , input .ExpireDate )
219+ }
220+ if input .Inactive != 0 {
221+ args = append (args , "-f" , strconv .Itoa (input .Inactive ))
222+ }
223+ if input .Gid != "" {
224+ args = append (args , "-g" , input .Gid )
225+ }
226+ if len (input .Groups ) > 0 {
227+ args = append (args , "-G" , strings .Join (input .Groups , "," ))
228+ }
229+ if input .SkelDir != "" {
230+ args = append (args , "-k" , input .SkelDir )
231+ }
232+ if input .CreateHome {
233+ args = append (args , "-m" )
234+ }
235+ if input .NoCreateHome {
236+ args = append (args , "-M" )
237+ }
238+ if input .NoUserGroup {
239+ args = append (args , "-N" )
240+ }
241+ if input .NonUnique {
242+ args = append (args , "-o" )
243+ }
244+ if input .Password != "" {
245+ args = append (args , "-p" , input .Password )
246+ }
247+ if input .System {
248+ args = append (args , "-r" )
249+ }
250+ if input .Shell != "" {
251+ args = append (args , "-s" , input .Shell )
252+ }
253+ if input .Uid != 0 {
254+ args = append (args , "-u" , strconv .Itoa (input .Uid ))
255+ }
256+ if input .UserGroup {
257+ args = append (args , "-U" )
258+ }
259+ if input .SelinuxUser != "" {
260+ args = append (args , "-Z" , input .SelinuxUser )
261+ }
262+ args = append (args , input .Username )
263+
264+ cmd := exec .Command ("useradd" , args ... )
265+ var out bytes.Buffer
266+ cmd .Stdout = & out
267+ cmd .Stderr = & out
268+ err := cmd .Run ()
269+ if err != nil {
270+ return nil , AddUserOutput {Success : false , Message : out .String ()}, err
271+ }
272+ return nil , AddUserOutput {Success : true , Message : out .String ()}, nil
273+ }
274+
173275func main () {
174276 listenAddr := flag .String ("http" , "" , "address for http transport, defaults to stdio" )
175277 flag .Parse ()
@@ -179,6 +281,10 @@ func main() {
179281 Name : "ListUsers" ,
180282 Description : "A tool to list the users on the system" ,
181283 }, ListUsers )
284+ mcp .AddTool (server , & mcp.Tool {
285+ Name : "AddUser" ,
286+ Description : "A tool to add a new user to the system" ,
287+ }, AddUser )
182288
183289 if * listenAddr == "" {
184290 // Run the server on the stdio transport.
0 commit comments