mirror of
https://github.com/cheikh2shift/godex.git
synced 2026-10-19 01:29:53 -05:00
Add built-in filesystem MCP server and enhance MCP command support
- Introduced a built-in filesystem implementation as a standalone MCP server accessible via stdio. - Updated MCP command to include 'serve' subcommand for managing the filesystem server. - Enhanced shell completion for MCP commands to include new options. - Added detailed documentation for the built-in filesystem MCP server.
This commit is contained in:
1 parent
576e2243cb
commit
a64e0ac7b5
6 files changed
+433
-5
No files matched your search
@@ -94,6 +94,16 @@ mcp_servers:
|
||||
|
||||
## External MCP Servers
|
||||
|
||||
## Built-in filesystem as an MCP server (stdio)
|
||||
|
||||
GoDex can run its built-in filesystem implementation as a standalone MCP server over stdio:
|
||||
|
||||
```bash
|
||||
godex mcp serve filesystem --allowed-path /home/user/project --allowed-path /tmp
|
||||
```
|
||||
|
||||
Details: [MCP_BUILTIN_FILESYSTEM_SERVER.md](MCP_BUILTIN_FILESYSTEM_SERVER.md)
|
||||
|
||||
### Chrome MCP Controller
|
||||
|
||||
Control Chrome tabs via a browser extension. Requires the [chrome-mcp](https://github.com/cheikh2shift/chrome-mcp) server and Chrome extension.
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
# Built-in filesystem MCP server (`godex mcp serve filesystem`)
|
||||
|
||||
GoDex contains a built-in filesystem tool implementation.
|
||||
|
||||
This page documents how to run that built-in filesystem as a **standalone MCP server over stdio**, so other AI agents/clients can connect to it.
|
||||
|
||||
## Run
|
||||
|
||||
```bash
|
||||
godex mcp serve filesystem
|
||||
```
|
||||
|
||||
## Permissions (roots + allowlist)
|
||||
|
||||
This server supports common MCP permission workflows used by other agents:
|
||||
|
||||
- **Client roots** (recommended): when the connected client supports MCP *roots*, GoDex will request the roots list and treat them as allowed paths.
|
||||
- **Explicit allowlist**: pass `--allowed-path` (repeatable) to add allowed paths up front.
|
||||
|
||||
Examples:
|
||||
|
||||
```bash
|
||||
# Explicit allowlist
|
||||
godex mcp serve filesystem --allowed-path /home/user/project --allowed-path /tmp
|
||||
|
||||
# Disable roots usage (only use explicit allowlist / cwd fallback)
|
||||
godex mcp serve filesystem --use-roots=false --allowed-path /tmp
|
||||
```
|
||||
|
||||
`--auto-confirm` (unsafe) will automatically expand allowed paths when a request hits a restricted path.
|
||||
|
||||
## Configure another agent/client
|
||||
|
||||
Any MCP client that can launch stdio servers can run:
|
||||
|
||||
```text
|
||||
command: godex
|
||||
args: ["mcp", "serve", "filesystem", "--allowed-path", "/path/to/workspace"]
|
||||
transport: stdio
|
||||
```
|
||||
|
||||
## Tools
|
||||
|
||||
The server exposes a subset of GoDex’s filesystem tools, including:
|
||||
|
||||
- `read_file`, `write_file`, `list_directory`
|
||||
- `create_directory`, `delete_file`
|
||||
- `search_files`, `search_in_file`, `search_directory_text`, `search_file_text`
|
||||
- `get_file_info`, `read_file_line_range`
|
||||
- `replace_first_in_file`, `replace_line_range`, `insert_at_line`
|
||||
- `list_allowed_paths`
|
||||
|
||||
## Add to OpenCode
|
||||
|
||||
### Via config file
|
||||
|
||||
In your `opencode.json` (project) or `~/.config/opencode/opencode.json` (global):
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"mcp": {
|
||||
"godex-filesystem": {
|
||||
"type": "local",
|
||||
"command": ["godex", "mcp", "serve", "filesystem", "--allowed-path", "/path/to/workspace"],
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then restart OpenCode.
|
||||
|
||||
### Via CLI
|
||||
|
||||
```bash
|
||||
npx @anthropic/anthropic-cli mcp add
|
||||
# Or if opencode has the same tool:
|
||||
opencode mcp add
|
||||
```
|
||||
|
||||
## Add to Claude Desktop
|
||||
|
||||
Edit `claude_desktop_config.json` (location varies by OS):
|
||||
- macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
||||
- Linux: `~/.config/Claude/claude_desktop_config.json`
|
||||
- Windows: `%APPDATA%\Claude\claude_desktop_config.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"godex-filesystem": {
|
||||
"command": "godex",
|
||||
"args": ["mcp", "serve", "filesystem", "--allowed-path", "/path/to/workspace"],
|
||||
"env": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Add to Claude Code
|
||||
|
||||
```bash
|
||||
claude mcp add godex-filesystem --transport stdio -- godex mcp serve filesystem --allowed-path /path/to/workspace
|
||||
```
|
||||
|
||||
Or via config in `.mcp.json` (project) or `~/.claude.json` (global):
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"mcp": {
|
||||
"godex-filesystem": {
|
||||
"command": ["godex", "mcp", "serve", "filesystem", "--allowed-path", "/path/to/workspace"],
|
||||
"env": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Add to Codex
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
codex mcp add godex-filesystem -- godex mcp serve filesystem --allowed-path /path/to/workspace
|
||||
```
|
||||
|
||||
Or edit `~/.codex/config.toml`:
|
||||
|
||||
```toml
|
||||
[mcp_servers.godex-filesystem]
|
||||
command = "godex"
|
||||
args = ["mcp", "serve", "filesystem", "--allowed-path", "/path/to/workspace"]
|
||||
```
|
||||
|
||||
For workspace-specific config, create `.codex/config.toml` in your project.
|
||||
|
||||
## Add to Cursor
|
||||
|
||||
Cursor doesn't have a CLI command for adding MCP servers. Edit `~/.cursor/mcp.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"godex-filesystem": {
|
||||
"command": "godex",
|
||||
"args": ["mcp", "serve", "filesystem", "--allowed-path", "/path/to/workspace"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Or add via Settings > Tools & MCP > Add > Enter custom server details.
|
||||
|
||||
## Add to VS Code
|
||||
|
||||
### Via Command Palette
|
||||
1. Press `Ctrl+Shift+P` (or `Cmd+Shift+P` on Mac)
|
||||
2. Search **MCP: Add Server**
|
||||
3. Select **Local** (stdio)
|
||||
4. Enter command: `godex mcp serve filesystem --allowed-path /path/to/workspace`
|
||||
|
||||
### Via CLI
|
||||
|
||||
```bash
|
||||
code --add-mcp '{"name":"godex-filesystem","command":"godex","args":["mcp","serve","filesystem","--allowed-path","/path/to/workspace"]}'
|
||||
```
|
||||
|
||||
### Via config file
|
||||
Edit `.vscode/mcp.json` (workspace) or run **MCP: Open User Configuration** to edit global config:
|
||||
|
||||
```json
|
||||
{
|
||||
"servers": {
|
||||
"godex-filesystem": {
|
||||
"command": "godex",
|
||||
"args": ["mcp", "serve", "filesystem", "--allowed-path", "/path/to/workspace"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -222,6 +222,8 @@ GoDex includes built-in MCP servers:
|
||||
|
||||
For detailed MCP configuration including external servers, see [MCP.md](MCP.md).
|
||||
|
||||
To expose the built-in filesystem MCP server to other agents/clients over stdio, see [MCP_BUILTIN_FILESYSTEM_SERVER.md](MCP_BUILTIN_FILESYSTEM_SERVER.md).
|
||||
|
||||
### Hive Network
|
||||
|
||||
GoDex supports a Hive network mode where multiple instances can delegate tasks to each other. See [HIVE.md](HIVE.md) for details.
|
||||
|
||||
@@ -583,7 +583,7 @@ complete -c godex -l debug -s d -f
|
||||
complete -c godex -l completion -x -a "bash zsh fish" -d "Generate shell completion"
|
||||
complete -c godex -l llama-server -s l -x -d "External llama.cpp server URL"
|
||||
complete -c godex -n "__fish_use_subcommand" -a "mcp" -d "Manage MCP servers"
|
||||
complete -c godex -n "__fish_seen_subcommand_from mcp" -a "add remove" -d "MCP subcommand"
|
||||
complete -c godex -n "__fish_seen_subcommand_from mcp" -a "add remove serve" -d "MCP subcommand"
|
||||
complete -c godex -n "__fish_seen_subcommand_from mcp; and __fish_seen_subcommand_from add" -l provider -x -a "(__godex_complete_providers)"
|
||||
complete -c godex -n "__fish_seen_subcommand_from mcp; and __fish_seen_subcommand_from add" -l name -x -a "filesystem bash webscraper"
|
||||
complete -c godex -n "__fish_seen_subcommand_from mcp; and __fish_seen_subcommand_from add" -l command -x
|
||||
@@ -594,8 +594,12 @@ complete -c godex -n "__fish_seen_subcommand_from mcp; and __fish_seen_subcomman
|
||||
complete -c godex -n "__fish_seen_subcommand_from mcp; and __fish_seen_subcommand_from add" -l allowed-url -x
|
||||
complete -c godex -n "__fish_seen_subcommand_from mcp; and __fish_seen_subcommand_from remove" -l provider -x -a "(__godex_complete_providers)"
|
||||
complete -c godex -n "__fish_seen_subcommand_from mcp; and __fish_seen_subcommand_from remove" -l name -x -a "(__godex_complete_mcp_servers)"
|
||||
complete -c godex -n "__fish_seen_subcommand_from mcp; and __fish_seen_subcommand_from serve" -a "filesystem" -d "Serve built-in MCP server"
|
||||
complete -c godex -n "__fish_seen_subcommand_from mcp; and __fish_seen_subcommand_from serve; and __fish_seen_subcommand_from filesystem" -l allowed-path -x -a "(__fish_complete_directories)"
|
||||
complete -c godex -n "__fish_seen_subcommand_from mcp; and __fish_seen_subcommand_from serve; and __fish_seen_subcommand_from filesystem" -l auto-confirm -f
|
||||
complete -c godex -n "__fish_seen_subcommand_from mcp; and __fish_seen_subcommand_from serve; and __fish_seen_subcommand_from filesystem" -l use-roots -x -a "true false"
|
||||
`, defaultConfigPath, defaultConfigPath, defaultConfigPath)
|
||||
}
|
||||
}
|
||||
|
||||
func printCompletionHelp() {
|
||||
fmt.Print(`Shell completion for godex
|
||||
|
||||
+6
-3
@@ -1323,6 +1323,7 @@ Flags:
|
||||
MCP subcommands:
|
||||
godex mcp add --provider <name> --name <server> [options]
|
||||
godex mcp remove --provider <name> --name <server>
|
||||
godex mcp serve filesystem [options]
|
||||
|
||||
MCP add options:
|
||||
--name MCP server name (filesystem, bash, webscraper, or external name)
|
||||
@@ -1347,7 +1348,7 @@ func (s *stringList) Set(value string) error {
|
||||
|
||||
func handleMCPSubcommand(args []string, configPath string) error {
|
||||
if len(args) == 0 {
|
||||
return fmt.Errorf("usage: godex mcp <add|remove> [options]")
|
||||
return fmt.Errorf("usage: godex mcp <add|remove|serve> [options]")
|
||||
}
|
||||
|
||||
isFilesystem := func(name string) bool {
|
||||
@@ -1444,8 +1445,10 @@ func handleMCPSubcommand(args []string, configPath string) error {
|
||||
if err := config.Save(configPath, cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("Added MCP server %q to provider %q\n", serverName, provider.Name)
|
||||
return nil
|
||||
fmt.Printf("Added MCP server %q to provider %q\n", serverName, provider.Name)
|
||||
return nil
|
||||
case "serve":
|
||||
return handleMCPServeSubcommand(args[1:])
|
||||
case "remove":
|
||||
fs := flag.NewFlagSet("mcp remove", flag.ContinueOnError)
|
||||
var providerName string
|
||||
|
||||
@@ -0,0 +1,228 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/cheikh2shift/godex/internal/mcp"
|
||||
mcplib "github.com/mark3labs/mcp-go/mcp"
|
||||
"github.com/mark3labs/mcp-go/server"
|
||||
)
|
||||
|
||||
func handleMCPServeSubcommand(args []string) error {
|
||||
if len(args) == 0 {
|
||||
return fmt.Errorf("usage: godex mcp serve filesystem [options]")
|
||||
}
|
||||
|
||||
switch strings.ToLower(strings.TrimSpace(args[0])) {
|
||||
case "filesystem", "files":
|
||||
fs := flag.NewFlagSet("mcp serve filesystem", flag.ContinueOnError)
|
||||
var allowedPaths stringList
|
||||
var autoConfirm bool
|
||||
var useRoots bool
|
||||
fs.Var(&allowedPaths, "allowed-path", "allowed path (repeatable); if omitted, falls back to client roots or cwd")
|
||||
fs.BoolVar(&autoConfirm, "auto-confirm", false, "auto-confirm restricted paths (unsafe)")
|
||||
fs.BoolVar(&useRoots, "use-roots", true, "use client-provided MCP roots as additional allowed paths")
|
||||
if err := fs.Parse(args[1:]); err != nil {
|
||||
return err
|
||||
}
|
||||
return serveFilesystemMCP([]string(allowedPaths), autoConfirm, useRoots)
|
||||
default:
|
||||
return fmt.Errorf("unknown server: %s (supported: filesystem)", args[0])
|
||||
}
|
||||
}
|
||||
|
||||
func serveFilesystemMCP(baseAllowedPaths []string, autoConfirm bool, useRoots bool) error {
|
||||
s := server.NewMCPServer(
|
||||
"godex-filesystem",
|
||||
version,
|
||||
server.WithToolCapabilities(true),
|
||||
server.WithRoots(),
|
||||
)
|
||||
|
||||
resolveAllowedPaths := func(ctx context.Context) []string {
|
||||
paths := append([]string{}, baseAllowedPaths...)
|
||||
if useRoots {
|
||||
if res, err := s.RequestRoots(ctx, mcplib.ListRootsRequest{}); err == nil {
|
||||
for _, r := range res.Roots {
|
||||
if strings.TrimSpace(r.URI) == "" {
|
||||
continue
|
||||
}
|
||||
// Roots are usually file:// URIs, but some clients may send plain paths.
|
||||
p := strings.TrimPrefix(r.URI, "file://")
|
||||
if strings.TrimSpace(p) == "" {
|
||||
continue
|
||||
}
|
||||
paths = append(paths, p)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(paths) == 0 {
|
||||
if wd, err := os.Getwd(); err == nil && strings.TrimSpace(wd) != "" {
|
||||
paths = []string{wd}
|
||||
}
|
||||
}
|
||||
return uniqueStrings(paths)
|
||||
}
|
||||
|
||||
addProxyTool := func(name string, description string, schema mcplib.ToolInputSchema) {
|
||||
s.AddTool(mcplib.Tool{
|
||||
Name: name,
|
||||
Description: description,
|
||||
InputSchema: schema,
|
||||
}, func(ctx context.Context, request mcplib.CallToolRequest) (*mcplib.CallToolResult, error) {
|
||||
allowed := resolveAllowedPaths(ctx)
|
||||
fs := mcp.NewFileSystemServer(allowed, autoConfirm)
|
||||
|
||||
args, _ := request.Params.Arguments.(map[string]any)
|
||||
argMap := make(map[string]interface{}, len(args))
|
||||
for k, v := range args {
|
||||
argMap[k] = v
|
||||
}
|
||||
|
||||
out, err := fs.CallTool(ctx, name, argMap)
|
||||
if err != nil {
|
||||
return mcplib.NewToolResultError(err.Error()), nil
|
||||
}
|
||||
return mcplib.NewToolResultText(out), nil
|
||||
})
|
||||
}
|
||||
|
||||
// Permissions helpers (works well with other agents' root/permission prompts).
|
||||
s.AddTool(mcplib.Tool{
|
||||
Name: "list_allowed_paths",
|
||||
Description: "List currently allowed filesystem paths (union of server flags and client-provided roots).",
|
||||
InputSchema: mcplib.ToolInputSchema{Type: "object", Properties: map[string]any{}},
|
||||
}, func(ctx context.Context, request mcplib.CallToolRequest) (*mcplib.CallToolResult, error) {
|
||||
paths := resolveAllowedPaths(ctx)
|
||||
return mcplib.NewToolResultText(strings.Join(paths, "\n")), nil
|
||||
})
|
||||
|
||||
// Core filesystem tools (proxy to internal built-in implementation).
|
||||
addProxyTool("read_file", "Read contents of a file.", mcplib.ToolInputSchema{
|
||||
Type: "object",
|
||||
Properties: map[string]any{
|
||||
"path": map[string]any{"type": "string", "description": "Absolute path to the file."},
|
||||
},
|
||||
Required: []string{"path"},
|
||||
})
|
||||
addProxyTool("write_file", "Write content to a file.", mcplib.ToolInputSchema{
|
||||
Type: "object",
|
||||
Properties: map[string]any{
|
||||
"path": map[string]any{"type": "string", "description": "Absolute path to the file."},
|
||||
"content": map[string]any{"type": "string", "description": "Content to write."},
|
||||
},
|
||||
Required: []string{"path", "content"},
|
||||
})
|
||||
addProxyTool("list_directory", "List files in a directory.", mcplib.ToolInputSchema{
|
||||
Type: "object",
|
||||
Properties: map[string]any{
|
||||
"path": map[string]any{"type": "string", "description": "Absolute path to directory."},
|
||||
},
|
||||
Required: []string{"path"},
|
||||
})
|
||||
addProxyTool("create_directory", "Create a new directory.", mcplib.ToolInputSchema{
|
||||
Type: "object",
|
||||
Properties: map[string]any{
|
||||
"path": map[string]any{"type": "string", "description": "Directory path to create."},
|
||||
},
|
||||
Required: []string{"path"},
|
||||
})
|
||||
addProxyTool("delete_file", "Delete a file or directory.", mcplib.ToolInputSchema{
|
||||
Type: "object",
|
||||
Properties: map[string]any{
|
||||
"path": map[string]any{"type": "string", "description": "File or directory path to delete."},
|
||||
},
|
||||
Required: []string{"path"},
|
||||
})
|
||||
addProxyTool("search_files", "Search for files matching a glob pattern.", mcplib.ToolInputSchema{
|
||||
Type: "object",
|
||||
Properties: map[string]any{
|
||||
"path": map[string]any{"type": "string", "description": "Directory to search."},
|
||||
"pattern": map[string]any{"type": "string", "description": "File pattern (e.g., *.go)."},
|
||||
},
|
||||
Required: []string{"path", "pattern"},
|
||||
})
|
||||
addProxyTool("get_file_info", "Get information about a file.", mcplib.ToolInputSchema{
|
||||
Type: "object",
|
||||
Properties: map[string]any{
|
||||
"path": map[string]any{"type": "string", "description": "File path."},
|
||||
},
|
||||
Required: []string{"path"},
|
||||
})
|
||||
addProxyTool("read_file_line_range", "Read a specific range of lines from a file.", mcplib.ToolInputSchema{
|
||||
Type: "object",
|
||||
Properties: map[string]any{
|
||||
"path": map[string]any{"type": "string", "description": "File path."},
|
||||
"start": map[string]any{"type": "number", "description": "Start line number (1-indexed)."},
|
||||
"end": map[string]any{"type": "number", "description": "End line number (inclusive)."},
|
||||
},
|
||||
Required: []string{"path", "start", "end"},
|
||||
})
|
||||
addProxyTool("replace_first_in_file", "Replace the first occurrence of a string in a file.", mcplib.ToolInputSchema{
|
||||
Type: "object",
|
||||
Properties: map[string]any{
|
||||
"path": map[string]any{"type": "string", "description": "File path."},
|
||||
"find": map[string]any{"type": "string", "description": "Text to find (plain string)."},
|
||||
"replace": map[string]any{"type": "string", "description": "Replacement text."},
|
||||
},
|
||||
Required: []string{"path", "find", "replace"},
|
||||
})
|
||||
addProxyTool("replace_line_range", "Replace a range of lines in a file.", mcplib.ToolInputSchema{
|
||||
Type: "object",
|
||||
Properties: map[string]any{
|
||||
"path": map[string]any{"type": "string", "description": "File path."},
|
||||
"start": map[string]any{"type": "number", "description": "Start line number (1-indexed)."},
|
||||
"end": map[string]any{"type": "number", "description": "End line number (inclusive)."},
|
||||
"new_content": map[string]any{"type": "string", "description": "New content to insert at the deleted location."},
|
||||
},
|
||||
Required: []string{"path", "start", "end", "new_content"},
|
||||
})
|
||||
addProxyTool("insert_at_line", "Insert content at a specific line number.", mcplib.ToolInputSchema{
|
||||
Type: "object",
|
||||
Properties: map[string]any{
|
||||
"path": map[string]any{"type": "string", "description": "File path."},
|
||||
"line": map[string]any{"type": "number", "description": "Line number to insert at (1-indexed, 0 = append at end)."},
|
||||
"content": map[string]any{"type": "string", "description": "Content to insert."},
|
||||
},
|
||||
Required: []string{"path", "line", "content"},
|
||||
})
|
||||
addProxyTool("search_file_text", "Search for text content within files in a directory.", mcplib.ToolInputSchema{
|
||||
Type: "object",
|
||||
Properties: map[string]any{
|
||||
"path": map[string]any{"type": "string", "description": "Directory to search."},
|
||||
"query": map[string]any{"type": "string", "description": "Text to search for."},
|
||||
"case_sensitive": map[string]any{"type": "boolean", "description": "Enable case-sensitive matching."},
|
||||
"use_regex": map[string]any{"type": "boolean", "description": "Treat query as a regular expression."},
|
||||
},
|
||||
Required: []string{"path", "query"},
|
||||
})
|
||||
addProxyTool("search_in_file", "Search for text within a specific file.", mcplib.ToolInputSchema{
|
||||
Type: "object",
|
||||
Properties: map[string]any{
|
||||
"path": map[string]any{"type": "string", "description": "File path."},
|
||||
"query": map[string]any{"type": "string", "description": "Text to search for (ignored if pattern provided)."},
|
||||
"pattern": map[string]any{"type": "string", "description": "Regex pattern (takes precedence)."},
|
||||
"case_sensitive": map[string]any{"type": "boolean", "description": "Enable case-sensitive matching."},
|
||||
"use_regex": map[string]any{"type": "boolean", "description": "Treat query as a regular expression."},
|
||||
},
|
||||
Required: []string{"path"},
|
||||
})
|
||||
addProxyTool("search_directory_text", "Search for text content within files in a directory.", mcplib.ToolInputSchema{
|
||||
Type: "object",
|
||||
Properties: map[string]any{
|
||||
"path": map[string]any{"type": "string", "description": "Directory to search."},
|
||||
"query": map[string]any{"type": "string", "description": "Text to search for (ignored if pattern is provided)."},
|
||||
"pattern": map[string]any{"type": "string", "description": "Regex pattern to search for (takes precedence over query)."},
|
||||
"case_sensitive": map[string]any{"type": "boolean", "description": "Enable case-sensitive matching."},
|
||||
},
|
||||
Required: []string{"path"},
|
||||
})
|
||||
|
||||
log.Printf("[MCP] Serving built-in filesystem MCP server over stdio (autoConfirm=%v, useRoots=%v, baseAllowedPaths=%v)", autoConfirm, useRoots, baseAllowedPaths)
|
||||
return server.ServeStdio(s)
|
||||
}
|
||||
Reference in new issue
Block a user