Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,9 @@ mcp proxy tool add_operation "Adds a and b" "a:int,b:int" ./examples/add.sh
# Register an inline command as an MCP tool
mcp proxy tool add_operation "Adds a and b" "a:int,b:int" -e 'echo "total is $a + $b = $(($a+$b))"'

# Register an inline command as an MCP tool with optional parameter
mcpt proxy tool add_operation "Adds a and b with optional result msg" "a:int,b:int,[msg:string]" -e 'echo "$msg$a + $b = $(($a+$b))"'

# Unregister a tool
mcp proxy tool --unregister add_operation

Expand Down
2 changes: 1 addition & 1 deletion cmd/mcptools/commands/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
var Version = "dev"

// getHomeDirectory returns the user's home directory
// Tries HOME first, then falls back to USERPROFILE for Windows
// Tries HOME first, then falls back to USERPROFILE for Windows.
func getHomeDirectory() string {
homeDir := os.Getenv("HOME")
if homeDir == "" {
Expand Down
51 changes: 43 additions & 8 deletions pkg/proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ import (

// Parameter represents a tool parameter with a name and type.
type Parameter struct {
Name string
Type string
Name string
Type string
Required bool
}

// Tool represents a proxy tool that executes a shell script or command.
Expand Down Expand Up @@ -157,6 +158,7 @@ func (s *Server) AddTool(name, description, paramStr, scriptPath string, command
}

// parseParameters parses a comma-separated parameter string in the format "name:type,name:type".
// If a parameter is wrapped in square brackets like [name:type], it's considered optional.
func parseParameters(paramStr string) ([]Parameter, error) {
if paramStr == "" {
return []Parameter{}, nil
Expand All @@ -166,6 +168,17 @@ func parseParameters(paramStr string) ([]Parameter, error) {
parameters := make([]Parameter, 0, len(params))

for _, param := range params {
param = strings.TrimSpace(param)
required := true

// Check if parameter is optional (wrapped in square brackets)
if strings.HasPrefix(param, "[") && strings.HasSuffix(param, "]") {
// Remove the brackets
param = strings.TrimPrefix(param, "[")
param = strings.TrimSuffix(param, "]")
required = false
}

parts := strings.Split(strings.TrimSpace(param), ":")
if len(parts) != 2 {
return nil, fmt.Errorf("invalid parameter format: %s, expected name:type", param)
Expand All @@ -189,8 +202,9 @@ func parseParameters(paramStr string) ([]Parameter, error) {
}

parameters = append(parameters, Parameter{
Name: name,
Type: normalizedType,
Name: name,
Type: normalizedType,
Required: required,
})
}

Expand Down Expand Up @@ -286,7 +300,11 @@ func (s *Server) GetToolSchema(toolName string) (map[string]interface{}, error)
}

properties[param.Name] = paramSchema
required = append(required, param.Name)

// Only add the parameter to required list if it's marked as required
if param.Required {
required = append(required, param.Name)
}
}

schema := map[string]interface{}{
Expand Down Expand Up @@ -435,7 +453,11 @@ func (s *Server) handleToolsList() map[string]interface{} {
}

properties[param.Name] = paramSchema
required = append(required, param.Name)

// Only add to required list if the parameter is required
if param.Required {
required = append(required, param.Name)
}
}

schema := map[string]interface{}{
Expand Down Expand Up @@ -471,7 +493,7 @@ func (s *Server) handleToolCall(params map[string]interface{}) (map[string]inter
return nil, fmt.Errorf("'name' parameter must be a string")
}

_, exists := s.tools[name]
tool, exists := s.tools[name]
if !exists {
return nil, fmt.Errorf("tool not found: %s", name)
}
Expand All @@ -487,6 +509,15 @@ func (s *Server) handleToolCall(params map[string]interface{}) (map[string]inter
return nil, fmt.Errorf("'arguments' parameter must be an object")
}

// Check for required parameters
for _, param := range tool.Parameters {
if param.Required {
if _, exists := arguments[param.Name]; !exists {
return nil, fmt.Errorf("missing required parameter: %s", param.Name)
}
}
}

// Log the input parameters
s.logJSON("Tool input", arguments)

Expand Down Expand Up @@ -587,7 +618,11 @@ func RunProxyServer(toolConfigs map[string]map[string]string) error {
if i > 0 {
paramStr += ", "
}
paramStr += param.Name + ":" + param.Type
if param.Required {
paramStr += param.Name + ":" + param.Type
} else {
paramStr += "[" + param.Name + ":" + param.Type + "]"
}
}
if paramStr != "" {
fmt.Fprintf(os.Stderr, " Parameters: %s\n", paramStr)
Expand Down