mirror of
https://github.com/cheikh2shift/godex.git
synced 2026-10-19 01:29:53 -05:00
Remove path restrictions for node, bash, python commands; add MCP.md and reference in README
This commit is contained in:
1 parent
bb494274ad
commit
953723dbc7
3 files changed
+164
-77
No files matched your search
@@ -0,0 +1,161 @@
|
||||
# MCP Integration Guide
|
||||
|
||||
GoDex supports integrating with external MCP (Model Context Protocol) servers to extend its capabilities. This document explains how to configure external MCP servers.
|
||||
|
||||
## Configuration
|
||||
|
||||
External MCP servers are configured in your `config.yaml` file under the `mcp` section.
|
||||
|
||||
### MCPServer Structure
|
||||
|
||||
Each MCP server is defined with the following properties:
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `name` | string | A friendly name for the server |
|
||||
| `command` | string | The command to run the MCP server executable |
|
||||
| `args` | []string | Optional command-line arguments |
|
||||
| `env` | []string | Optional environment variables |
|
||||
| `transport` | string | Transport type (e.g., `stdio`, `sse`) |
|
||||
| `allowed_paths` | []string | Paths the server is allowed to access |
|
||||
|
||||
### Example Configuration
|
||||
|
||||
```yaml
|
||||
mcp:
|
||||
servers:
|
||||
# Example: A custom filesystem server
|
||||
filesystem:
|
||||
command: "npx"
|
||||
args: ["-y", "@modelcontextprotocol/server-filesystem", "/Users/myuser/docs"]
|
||||
transport: "stdio"
|
||||
allowed_paths:
|
||||
- "/Users/myuser/docs"
|
||||
- "/Users/myuser/shared"
|
||||
|
||||
# Example: A GitHub MCP server
|
||||
github:
|
||||
command: "npx"
|
||||
args: ["-y", "@modelcontextprotocol/server-github"]
|
||||
transport: "stdio"
|
||||
env:
|
||||
- "GITHUB_PERSONAL_ACCESS_TOKEN=$GITHUB_TOKEN"
|
||||
```
|
||||
|
||||
## Built-in MCP Servers
|
||||
|
||||
GoDex includes several built-in MCP tools:
|
||||
|
||||
### Bash
|
||||
|
||||
Execute shell commands on your system.
|
||||
|
||||
```yaml
|
||||
mcp:
|
||||
servers:
|
||||
bash:
|
||||
command: "godex"
|
||||
args: ["mcp", "bash"]
|
||||
```
|
||||
|
||||
### Filesystem
|
||||
|
||||
Perform file operations (read, write, list, delete, search).
|
||||
|
||||
```yaml
|
||||
mcp:
|
||||
servers:
|
||||
filesystem:
|
||||
command: "godex"
|
||||
args: ["mcp", "filesystem"]
|
||||
allowed_paths:
|
||||
- "/home/user/projects"
|
||||
```
|
||||
|
||||
### Webscraper
|
||||
|
||||
Fetch URLs and extract content from web pages.
|
||||
|
||||
```yaml
|
||||
mcp:
|
||||
servers:
|
||||
webscraper:
|
||||
command: "godex"
|
||||
args: ["mcp", "webscraper"]
|
||||
```
|
||||
|
||||
## Using MCP Servers in Conversations
|
||||
|
||||
Once configured, you can use MCP servers in your conversations with GoDex. The AI agent will automatically discover and use available tools from your configured MCP servers.
|
||||
|
||||
For example:
|
||||
|
||||
```
|
||||
User: Can you read the contents of /home/user/projects/README.md?
|
||||
|
||||
GoDex: (uses filesystem MCP server to read the file)
|
||||
# Contents of README.md
|
||||
...
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
|
||||
You can reference environment variables in your MCP server configuration using `$VAR_NAME` syntax:
|
||||
|
||||
```yaml
|
||||
mcp:
|
||||
servers:
|
||||
myserver:
|
||||
command: "my-mcp-server"
|
||||
env:
|
||||
- "API_KEY=$MY_API_KEY"
|
||||
- "DATABASE_URL=$DB_URL"
|
||||
```
|
||||
|
||||
Make sure these environment variables are set before starting GoDex.
|
||||
|
||||
## Transport Types
|
||||
|
||||
### stdio
|
||||
|
||||
The default transport type. Communicates with the MCP server via standard input/output.
|
||||
|
||||
```yaml
|
||||
transport: "stdio"
|
||||
```
|
||||
|
||||
### SSE (Server-Sent Events)
|
||||
|
||||
For HTTP-based MCP servers.
|
||||
|
||||
```yaml
|
||||
transport: "sse"
|
||||
url: "http://localhost:8080/sse"
|
||||
```
|
||||
|
||||
## Security
|
||||
|
||||
- Only use MCP servers from trusted sources
|
||||
- Review the `allowed_paths` configuration to restrict filesystem access
|
||||
- Be cautious when passing sensitive data via environment variables
|
||||
- MCP servers run with the same permissions as the GoDex process
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Server fails to start
|
||||
|
||||
- Verify the command path is correct
|
||||
- Check that required dependencies are installed
|
||||
- Review the server logs for error messages
|
||||
|
||||
### Tools not available
|
||||
|
||||
- Ensure the MCP server started successfully
|
||||
- Check that the server configuration is valid YAML
|
||||
- Verify the transport type matches the server's requirements
|
||||
|
||||
### Permission denied errors
|
||||
|
||||
- Check that the paths in `allowed_paths` exist
|
||||
- Verify file/directory permissions
|
||||
- Ensure the MCP server process has necessary access rights
|
||||
@@ -141,6 +141,8 @@ GoDex includes built-in MCP servers:
|
||||
| `bash` | Run shell commands, Python, Node.js |
|
||||
| `webscraper` | Fetch URLs with JavaScript rendering, search HTML, extract links |
|
||||
|
||||
For detailed MCP configuration including external servers, see [MCP.md](MCP.md).
|
||||
|
||||
#### Adding Allowed Paths
|
||||
|
||||
By default, MCP servers only allow access to the current working directory. Add more allowed paths:
|
||||
|
||||
+1
-77
@@ -107,18 +107,9 @@ func (s *BashServer) isPathAllowed(path string) bool {
|
||||
}
|
||||
|
||||
var (
|
||||
cdRegex = regexp.MustCompile(`(?i)^cd\s+(\S+)`)
|
||||
pythonPathOp = regexp.MustCompile(`(?i)(?:os\.chdir|os\.mkdir|os\.makedirs|os\.rmdir|os\.remove|os\.rename|shutil\.move|shutil\.copy|open)\s*\(\s*['"]`)
|
||||
nodePathOp = regexp.MustCompile(`(?i)(?:process\.chdir|fs\.(?:mkdir|rmdir|unlink|rename|writeFile|readFile)|fs\.promises\.(?:mkdir|rmdir|unlink|rename|writeFile|readFile))\s*\(\s*['"]`)
|
||||
cdRegex = regexp.MustCompile(`(?i)^cd\s+(\S+)`)
|
||||
)
|
||||
|
||||
var pathCommands = []string{
|
||||
"cat", "ls", "rm", "rmdir", "mv", "cp", "touch", "chmod", "chown", "chgrp",
|
||||
"head", "tail", "less", "more", "grep", "rg", "find", "stat", "file",
|
||||
"mkdir", "tar", "zip", "unzip", "gzip", "gunzip", "xz", "diff", "cmp",
|
||||
"du", "df", "ln", "readlink", "realpath", "which", "whereis",
|
||||
}
|
||||
|
||||
func (s *BashServer) isCommandAllowed(command string) bool {
|
||||
trimmed := strings.TrimSpace(command)
|
||||
|
||||
@@ -132,65 +123,6 @@ func (s *BashServer) isCommandAllowed(command string) bool {
|
||||
}
|
||||
}
|
||||
|
||||
for _, cmd := range pathCommands {
|
||||
re := regexp.MustCompile(fmt.Sprintf(`(?i)^%s\s+(\S+)`, cmd))
|
||||
match := re.FindStringSubmatch(trimmed)
|
||||
if len(match) > 1 {
|
||||
targetPath := match[1]
|
||||
targetPath = strings.ReplaceAll(targetPath, "~", os.Getenv("HOME"))
|
||||
targetPath = filepath.Clean(targetPath)
|
||||
if !s.isPathAllowed(targetPath) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
reWithFlags := regexp.MustCompile(fmt.Sprintf(`(?i)^%s\s+-[a-zA-Z]+\s+(\S+)`, cmd))
|
||||
match = reWithFlags.FindStringSubmatch(trimmed)
|
||||
if len(match) > 1 {
|
||||
targetPath := match[1]
|
||||
targetPath = strings.ReplaceAll(targetPath, "~", os.Getenv("HOME"))
|
||||
targetPath = filepath.Clean(targetPath)
|
||||
if !s.isPathAllowed(targetPath) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *BashServer) isPythonCodeAllowed(code string) bool {
|
||||
indices := pythonPathOp.FindAllStringIndex(code, -1)
|
||||
for _, loc := range indices {
|
||||
quote := code[loc[1]]
|
||||
endIdx := loc[1] + 1
|
||||
for endIdx < len(code) && code[endIdx] != quote {
|
||||
endIdx++
|
||||
}
|
||||
path := code[loc[1]+1 : endIdx]
|
||||
path = strings.ReplaceAll(path, "~", os.Getenv("HOME"))
|
||||
path = filepath.Clean(path)
|
||||
if !s.isPathAllowed(path) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *BashServer) isNodeCodeAllowed(code string) bool {
|
||||
indices := nodePathOp.FindAllStringIndex(code, -1)
|
||||
for _, loc := range indices {
|
||||
quote := code[loc[1]]
|
||||
endIdx := loc[1] + 1
|
||||
for endIdx < len(code) && code[endIdx] != quote {
|
||||
endIdx++
|
||||
}
|
||||
path := code[loc[1]+1 : endIdx]
|
||||
path = strings.ReplaceAll(path, "~", os.Getenv("HOME"))
|
||||
path = filepath.Clean(path)
|
||||
if !s.isPathAllowed(path) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -360,10 +292,6 @@ func (s *BashServer) runPython(ctx context.Context, args map[string]interface{})
|
||||
return "", fmt.Errorf("code is required")
|
||||
}
|
||||
|
||||
if !s.isPythonCodeAllowed(code) {
|
||||
return "", fmt.Errorf("code not allowed: must operate within allowed paths: %s", strings.Join(s.allowedPaths, ", "))
|
||||
}
|
||||
|
||||
timeout := 30
|
||||
if t, ok := args["timeout"].(float64); ok {
|
||||
timeout = int(t)
|
||||
@@ -388,10 +316,6 @@ func (s *BashServer) runNode(ctx context.Context, args map[string]interface{}) (
|
||||
return "", fmt.Errorf("code is required")
|
||||
}
|
||||
|
||||
if !s.isNodeCodeAllowed(code) {
|
||||
return "", fmt.Errorf("code not allowed: must operate within allowed paths: %s", strings.Join(s.allowedPaths, ", "))
|
||||
}
|
||||
|
||||
timeout := 30
|
||||
if t, ok := args["timeout"].(float64); ok {
|
||||
timeout = int(t)
|
||||
|
||||
Reference in new issue
Block a user