Token导航 LogoToken导航TokenDH.com
MCP Useradd logo
开发工具stdio官方级别未说明来源级核验

MCP Useradd

MCP Server

@modelcontextprotocol/inspector

MCP服务器是大型语言模型(LLM)与应用程序之间的中间件,通过JSON封装调用,适用于开发者构建用户管理工具。

工具数

0

提示词数

0

GitHub Stars

2

资源数

0
开发工具Go用户管理

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

作者 / 组织

mslacken

提供方

mslacken

最后核验

2026/5/17 20:23

运行时

Node.js

快速接入

先看主来源和安装命令,再打开仓库或文档;下面只保留这个条目的关键接入事实。

命令预览

npx @modelcontextprotocol/inspector http://localhost:8666 --transport http

详细介绍

如何创建MCP服务器

本指南适用于想要构建MCP服务器的开发人员。它描述了如何实现用于列出和添加用户的MCP。

什么是MCP服务器?

MCP服务器是一个位于大型语言模型(LLM)和应用程序之间的包装器,以JSON形式包装从LLM到应用程序的调用。 您可能会想通过以下方式包装应用程序的现有API fastapi和fastmcp,但如所述 基本无害,这是个坏主意。

其主要原因是LLM基于“下载”的互联网进行文本完成,并且可以专注于不超过约100页文本的主题。很难用聊天填满这些页面,你可能从未遇到过这个限制。这也意味着你需要一个用户故事或任务来填充这本书,包括所有可能的失败和死胡同。在我们的示例中,我们将 add a user "tux" to the system.

这本虚构的书的第一页已经被 *系统提示* 以及MCP工具及其参数的描述。此描述由工具的作者提供,因此您在编写工具描述时可以非常具有描述性。多写几行文字不会有什么坏处。

每个工具调用都有一个JSON覆盖,因此您还需要避免太多的工具调用。尽量减少工具的数量,并将类似的操作组合到一个工具中。例如,如果你有一个工具与 系统守护进程,您将只有一个工具来组合启用、禁用、启动和重新启动服务,而不是每个操作都有一个工具。

对于工具输出,不要犹豫,尽可能多地组合信息。一个好的工具的输出不应该只返回组ID(GID),还应该返回组名。

这里的警告是,您很容易用太多的信息使LLM过饱和,例如返回 find /这将完全填满LLM对话的想象书。在这种情况下,修剪信息并为工具提供参数,如过滤输出。

这归结为以下几点:

  • 为这些工具编写一个用户故事。
  • 为工具及其参数提供详尽的描述。
  • 将工具精简为合理的操作,并毫不犹豫地添加许多参数。
  • 一个工具调用可以有多个API调用。
  • 避免过载:LLM不能忽略输出,因此您有责任修剪信息。

还有我一路上学到的以下加分:

  • 避免a verbose 参数;法学硕士将始终使用它。
\[!注意\]永远记住: “背景为王”

构建示例MCP服务器

用户故事

首先,我们必须提出一个用户故事。我们必须决定用户应该能够使用该工具做什么。

我们的用户故事很简单:“我想在系统中添加一个用户。”

第一步

我们将在这个项目中使用Go,并从这个简单的样板代码开始,它添加了工具“Foo”:

package main

import (
	"context"
	"flag"
	"log/slog"
	"net/http"

	"github.com/modelcontextprotocol/go-sdk/mcp"
)

// Input struct for the Foo tool.
type FooInput struct {
	Message string `json:"message,omitempty" jsonschema:"a message for the Foo tool"`
}

// Output struct for the Foo tool.
type FooOutput struct {
	Response string `json:"response" jsonschema:"the response from the Foo tool"`
}

// Foo function implements the Foo tool.
func Foo(ctx context.Context, req *mcp.CallToolRequest, input FooInput) (
	*mcp.CallToolResult, FooOutput, error,
) {
	slog.Info("Foo tool called", "message", input.Message)
	return nil, FooOutput{Response: "Foo received your message: " + input.Message}, nil
}

func main() {
	listenAddr := flag.String("http", "", "address for http transport, defaults to stdio")
	flag.Parse()

	server := mcp.NewServer(&mcp.Implementation{Name: "useradd", Version: "v0.0.1"}, nil)
	mcp.AddTool(server, &mcp.Tool{
		Name:        "Foo",
		Description: "A simple Foo tool",
	}, Foo)

	if *listenAddr == "" {
		// Run the server on the stdio transport.
		if err := server.Run(context.Background(), &mcp.StdioTransport{}); err != nil {
			slog.Error("Server failed", "error", err)
		}
	} else {
		// Create a streamable HTTP handler.
		handler := mcp.NewStreamableHTTPHandler(func(*http.Request) *mcp.Server {
			return server
		}, nil)

		// Run the server on the HTTP transport.
		slog.Info("Server listening", "address", *listenAddr)
		if err := http.ListenAndServe(*listenAddr, handler); err != nil {
			slog.Error("Server failed", "error", err)
		}
	}
}

要运行服务器,我们首先必须用以下命令初始化Go依赖关系:

  go mod init github.com/mslacken/mcp-useradd
  go mod tidy

现在可以使用以下命令运行服务器:

  go run main.go -http localhost:8666

我们可以通过以下方式在附加终端中运行基于JavaScript的浏览器:

  npx @modelcontextprotocol/inspector http://localhost:8666 --transport http

在调用输入为“Baar”的“Foo”工具后,我们看到了以下屏幕。

Tool Foo was called input "Baar" response is {"response": "Foo received your message: Baar"}

让我们分解一下我们的Go代码。之后 imports,我们马上有两个 structs 管理我们工具的输入和输出。Go有一个内置的数据结构序列化器。关键字 json:"message,omitempty" 告诉序列化库使用“message”作为变量的名称。更重要的是第二个选项“omitempty”,它将此标记为可选输入参数;如果为空,则变量将不在输出中。“jsonschema”参数描述了此参数的作用以及预期的输入。虽然参数的类型是从结构中推断出来的,但描述至关重要。该工具的方法通过构造输出结构并返回它来返回消息。 方法本身被添加到MCP服务器实例中,还需要有一个名称和描述。工具的描述也非常重要 LLM了解工具正在做什么的方法。

将工具具体化

本节的完整代码可以在git commit中找到 简单用户列表

因为我们不想在这个早期阶段改变系统,整个项目需要一个工具来获取系统的实际用户。那么,让我们添加工具 get_users. 为了简单起见,我们只使用 getent passwd 完成这项任务。 可以执行此操作的函数如下

// User struct represents a single user account.
type User struct {
	Username string `json:"username"`
	Password string `json:"password"`
	UID      int    `json:"uid"`
	GID      int    `json:"gid"`
	Comment  string `json:"comment"`
	Home     string `json:"home"`
	Shell    string `json:"shell"`
}
func ListUsers(ctx context.Context, req *mcp.CallToolRequest, _ ListUsersInput) (
	*mcp.CallToolResult, ListUsersOutput, error,
) {
	slog.Info("ListUsers tool called")
	cmd := exec.Command("getent", "passwd")
	var out bytes.Buffer
	cmd.Stdout = &out
	err := cmd.Run()
	if err != nil {
		return nil, ListUsersOutput{}, err
	}
	var users []User
	scanner := bufio.NewScanner(&out)
	for scanner.Scan() {
		line := scanner.Text()
		parts := strings.Split(line, ":")
		if len(parts) != 7 {
			continue
		}
		uid, _ := strconv.Atoi(parts[2])
		gid, _ := strconv.Atoi(parts[3])
		users = append(users, User{
			Username: parts[0],
			Password: parts[1],
			UID:      uid,
			GID:      gid,
			Comment:  parts[4],
			Home:     parts[5],
			Shell:    parts[6],
		})
	}
	return nil, ListUsersOutput{Users: users}, nil
}

当您检查此方法时,您会看到输出只是用户及其属性的列表(称为go中的slice)。

虽然这看起来是正确的,但这种方法缺少了一些重要的东西

  • 用户类型,是系统还是用户,是人类的用户帐户
  • 其中组是用户部分

问这类问题,然后提供信息是 最重要的 在编写MCP工具时。LLM不知道此信息,但在添加用户时可能会定义输入参数。

与此相反,这种工具的真正实现只会将所有gid\ 0 { groups, err := getUserGroups(username) if err == nil { users[0].Groups = groups } } return users, nil }


尽管如此,我们仍然可以在这里添加许多东西作为参数,比如仅对非系统用户进行过滤,检查与用户交互的“pam.d”选项。..

### 添加用户

为了完整起见,我们现在添加了一个用于添加用户的工具,该工具由SUSE特定的 `useradd` 电话。
本节的完整代码可以在git commit中找到 [添加用户添加方法](https://github.com/mslacken/mcp-useradd/commit/81b67b9)
工具可以看起来像

// Input struct for the AddUser tool. type AddUserInput struct { Username string json:"username" jsonschema:"the username of the new account" BaseDir string json:"base_dir,omitempty" jsonschema:"the base directory for the home directory of the new account" Comment string json:"comment,omitempty" jsonschema:"the GECOS field of the new account" HomeDir string json:"home_dir,omitempty" jsonschema:"the home directory of the new account" ExpireDate string json:"expire_date,omitempty" jsonschema:"the expiration date of the new account" Inactive int json:"inactive,omitempty" jsonschema:"the password inactivity period of the new account" Gid string json:"gid,omitempty" jsonschema:"the name or ID of the primary group of the new account" Groups []string json:"groups,omitempty" jsonschema:"the list of supplementary groups of the new account" SkelDir string json:"skel_dir,omitempty" jsonschema:"the alternative skeleton directory" CreateHome bool json:"create_home,omitempty" jsonschema:"create the user's home directory" NoCreateHome bool json:"no_create_home,omitempty" jsonschema:"do not create the user's home directory" NoUserGroup bool json:"no_user_group,omitempty" jsonschema:"do not create a group with the same name as the user" NonUnique bool json:"non_unique,omitempty" jsonschema:"allow to create users with duplicate (non-unique) UID" Password string json:"password,omitempty" jsonschema:"the encrypted password of the new account" System bool json:"system,omitempty" jsonschema:"create a system account" Shell string json:"shell,omitempty" jsonschema:"the login shell of the new account" Uid int json:"uid,omitempty" jsonschema:"the user ID of the new account" UserGroup bool json:"user_group,omitempty" jsonschema:"create a group with the same name as the user" SelinuxUser string json:"selinux_user,omitempty" jsonschema:"the specific SEUSER for the SELinux user mapping" SelinuxRange string json:"selinux_range,omitempty" jsonschema:"the specific MLS range for the SELinux user mapping" } func AddUser(ctx context.Context, req *mcp.CallToolRequest, input AddUserInput) ( *mcp.CallToolResult, AddUserOutput, error, ) { slog.Info("AddUser tool called") args := []string{} if input.BaseDir != "" { args = append(args, "-b", input.BaseDir) } /* Cutted a lot of command line parameter settings */ if input.SelinuxUser != "" { args = append(args, "-Z", input.SelinuxUser) } args = append(args, input.Username)

cmd := exec.Command("useradd", args...) var out bytes.Buffer cmd.Stdout = &out cmd.Stderr = &out err := cmd.Run() if err != nil { return nil, AddUserOutput{Success: false, Message: out.String()}, err } return nil, AddUserOutput{Success: true, Message: out.String()}, nil }


对于真正的MCP服务器,该工具还可以知道标准的主位置,并在这些位置上提供与btrfs相关的选项,如果启用或未启用SELinux,则情况也是如此,然后只需添加这些选项。
但我认为现在很清楚MCP工具是如何崩溃的。

目录标签

目录标签

开发工具Go用户管理LLM中间件本地部署JSON封装开发者工具

接入字段

传输方式(transport,传输协议)

stdio

鉴权方式(authType,认证方式)

session

运行时(runtime,运行环境)

Node.js

来源包(packageName,安装包名)

@modelcontextprotocol/inspector

工具数量(toolCount,工具数)

0

资源数量(resourceCount,资源数)

0

提示词数量(promptCount,提示词数)

0

权限和风险

stdiosession部署方式未说明

接入前请确认传输方式、认证方式和部署位置,并根据实际工具能力限制访问范围。

安装前确认

不要直接授予不必要的文件、网络或账号权限;先核对安装命令和配置内容。

来源信息

继续浏览同类 MCP