Dynamic Command Generation
Relevant source files
The following files were used as context for generating this wiki page:
Dynamic Command Generation is a core capability of the mcpcurl utility, allowing it to build a Command Line Interface (CLI) on-the-fly based on schemas retrieved from Model Context Protocol (MCP) servers. Instead of hard-coding support for specific GitHub operations, the system queries the server for its available tools and constructs a matching command hierarchy with built-in validation and documentation.
This mechanism ensures that the CLI remains in sync with the server's capabilities without requiring manual updates to the client code. It leverages JSON-RPC 2.0 for communication and uses the cobra library to manage the generated command tree.
Sources: cmd/mcpcurl/README.md:1-12, cmd/mcpcurl/main.go:120-145
Architecture and Flow
The generation process follows a discovery-based pattern where the client acts as a generic host for any toolset defined by the server.
Discovery and Initialization
When mcpcurl starts, it requires a --stdio-server-cmd flag. It executes this command to establish a connection via standard input/output streams. The client then sends a tools/list JSON-RPC request to fetch the server's tool definitions.
The diagram shows the sequence of events from initial user execution to the dynamic construction of the command tree.
Sources: cmd/mcpcurl/main.go:120-140, cmd/mcpcurl/README.md:130-135
Command Construction Logic
The function addCommandFromTool iterates through each tool provided in the schema response. It maps the JSON schema properties to CLI flags, determining types (string, number, boolean, etc.) and enforcing requirements.
- Mapping: Each tool name becomes a subcommand under the
toolscommand. - Validation: Enums, types, and required flags are enforced using
PreRunEhooks. - Viper Integration: Flags are bound to
viperfor environment variable support, using a prefix based on the tool name.
Sources: cmd/mcpcurl/main.go:155-215, cmd/mcpcurl/README.md:120-128
Data Structures
The dynamic generation relies on specific JSON structures to translate server capabilities into CLI elements.
Schema Models
The following table describes the primary data structures used to interpret the server's response:
| Structure | Purpose | Key Fields |
|---|---|---|
SchemaResponse | Top-level JSON-RPC result | Result, JSONRPC, ID |
Tool | Definition of a single capability | Name, Description, InputSchema |
InputSchema | Defines parameter requirements | Properties, Required, Type |
Property | Metadata for a single parameter | Type, Description, Enum, Items |
Sources: cmd/mcpcurl/main.go:23-65
Parameter Mapping and Validation
Dynamic commands support complex parameter types by mapping JSON schema types to Cobra's flag system.
Type Conversions
The system handles several data types specifically:
- Strings: Mapped to standard string flags. If an
Enumis present, aPreRunEvalidator ensures the input matches allowable values. - Arrays:
- For string arrays,
StringSliceflags are used. - For object arrays, a special
-jsonsuffix is appended to the flag name (e.g.,--files-json), requiring a JSON-encoded string.
- For string arrays,
- Booleans: Standard boolean flags that track if they were explicitly changed by the user.
Sources: cmd/mcpcurl/main.go:185-215, cmd/mcpcurl/main.go:235-265
Code Snippet: Dynamic Flag Creation
// cmd/mcpcurl/main.go:185-215
switch prop.Type {
case "string":
cmd.Flags().String(name, "", description)
if len(prop.Enum) > 0 {
cmd.PreRunE = func(cmd *cobra.Command, _ []string) error {
// Validation logic for enums
}
}
case "array":
if prop.Items != nil {
switch prop.Items.Type {
case "string":
cmd.Flags().StringSlice(name, []string{}, description)
case "object":
cmd.Flags().String(name+"-json", "", description+" (provide as JSON array)")
}
}
}
Sources: cmd/mcpcurl/main.go:185-215
Execution and Response Handling
Once a dynamic command is invoked, the arguments are collected into a map and transformed back into a tools/call JSON-RPC request.
- Argument Collection:
buildArgumentsMapextracts values from flags, handling the distinction between zero-values and unset optional parameters. - Request Dispatch: The request is piped to the server command's
stdin. - Response Formatting:
printResponsecaptures the server's output fromstdout. If the--prettyflag is set, it attempts to parse the text as JSON/JSONL and re-marshals it with indentation for readability.
Sources: cmd/mcpcurl/main.go:220-230, cmd/mcpcurl/main.go:305-330, cmd/mcpcurl/main.go:332-370
Documentation Generation
The project also uses dynamic toolsets to generate its own documentation. The generate-docs command uses a ToolsetGroup to iterate through all registered GitHub tools and create Markdown sections for the README.
- Tool Metadata: It extracts annotations like
TitleandReadOnlyHintto categorize tools. - Parameter Tables: It generates lists of parameters, noting their types and whether they are required or optional.
Sources: cmd/github-mcp-server/generate_docs.go:95-140, cmd/github-mcp-server/generate_docs.go:165-215
Summary
Dynamic Command Generation allows the GitHub MCP system to provide a scalable and maintainable CLI. By deriving the command structure directly from the server's schema, mcpcurl remains a thin, generic client capable of supporting any GitHub operation—from issue management to repository forking—without local code changes for new tools. This architecture prioritizes strict type validation and automated documentation, ensuring a consistent user experience across the varied GitHub API surface.