siyuan-note/siyuan · error
command is required for stdio server
Error message
command is required for stdio server
What it means
connectStdio launches the MCP server as a local subprocess via exec.Command, so the configured Command field must be a non-empty executable path or name. This guard fires before any process is spawned when server.Command is the empty string. Without a command there is no stdio peer to speak MCP over.
Solutions
- Set the Command field to the MCP server executable (absolute path recommended)
- If the executable is invoked via npx/uvx, set Command to that launcher (e.g. "npx") and put the package in Args
- Re-add the stdio server via the settings UI, filling in the command field
- Validate the config entry before saving: type=stdio requires a non-empty command
Example fix
// before
{"name": "filesystem", "type": "stdio", "command": "", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]}
// after
{"name": "filesystem", "type": "stdio", "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]} Defensive patterns
Strategy: validation
Validate before calling
if server.Type == "stdio" && strings.TrimSpace(server.Command) == "" {
return fmt.Errorf("stdio server [%s] needs a command", server.Name)
} Type guard
null
Try / catch
if err := connectStdio(ctx, client, server); err != nil {
if strings.Contains(err.Error(), "command is required") {
return fmt.Errorf("configure command for stdio server %q", server.Name)
}
return err
} Prevention
- Make the command field required in the add-server UI when type is stdio
- Always fill both command and args together; test the command line in a shell first
- Validate config entries at load time and disable invalid servers with a visible warning
When it happens
Trigger: connectServer dispatches a server with Type "stdio" whose conf.MCPServer.Command is "" — e.g. the entry was created with a type but no command, or the command field was cleared.
Common situations: Adding a stdio server in config and forgetting to fill in the executable, a config migration or UI edit clearing the command field, or copying a template entry with an empty command placeholder.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- configuration is not initialized
- connect
- each key requires name and type
- environment
- must define light and dark themes
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/ab0427c15d43f989.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/mcp/client/mcp.go:450
logging.LogInfof("mcp: server [%s] tool list changed, reconnecting", server.Name)
go reconnectMCPServer(server.ID)
},
})
switch server.Type {
case "stdio":
session, cmd, err := connectStdio(ctx, c, server)
return session, cmd, nil, err
case "http":
return connectHTTP(ctx, c, server, interactive)
default:
return nil, nil, nil, fmt.Errorf("unsupported server type: %s", server.Type)
}
}
func connectStdio(ctx context.Context, client *mcp.Client, server conf.MCPServer) (*mcp.ClientSession, *exec.Cmd, error) {
if server.Command == "" {
return nil, nil, fmt.Errorf("command is required for stdio server")
}
cmd := exec.Command(server.Command, server.Args...)
// stdio 环境变量插值不受密钥 AllowedHosts 约束:目标是本地子进程而非网络主机,管理员在 Env 中
// 引用 {{secrets.NAME}} 本身就是对该服务器的显式授权,与直接写入明文属于同一信任级别。
cmdEnv, err := buildStdioEnvironment(server, os.LookupEnv, func(value string) string {
if model.Conf == nil {
return value
}
return conf.ResolveSecretsVars(model.Conf.Secrets, model.Conf.Variables, value)
}, runtime.GOOS)
if err != nil {
return nil, nil, fmt.Errorf("environment: %w", err)
}
cmd.Env = cmdEnv
stdin, err := cmd.StdinPipe()
if err != nil {
return nil, nil, fmt.Errorf("stdin pipe: %w", err)View on GitHub (pinned to 9f775e8a12)