Skip to content

Add custom engine MCP configuration fields for flexible format generation#1497

Closed
Copilot wants to merge 8 commits intomainfrom
copilot/update-mcp-config-format
Closed

Add custom engine MCP configuration fields for flexible format generation#1497
Copilot wants to merge 8 commits intomainfrom
copilot/update-mcp-config-format

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Oct 10, 2025

Problem

The simonw-LLM shared workflow was copying the MCP configuration file directly to ~/.llm-tools-mcp/mcp.json, but the llm-tools-mcp extension expects a different configuration format than what gh-aw generates.

gh-aw generates (mcpServers object format):

{
  "mcpServers": {
    "github": {
      "command": "docker",
      "args": ["run", "-i", "--rm", "ghcr.io/github/github-mcp-server:v0.18.0"],
      "env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "..." }
    }
  }
}

llm-tools-mcp expects (servers array format):

{
  "servers": [
    {
      "name": "github",
      "transport": "stdio",
      "command": ["docker", "run", "-i", "--rm", "ghcr.io/github/github-mcp-server:v0.18.0"],
      "env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "..." }
    }
  ]
}

Solution

Added three optional configuration fields to the custom engine that control MCP configuration generation:

  1. mcp-config-file: Path to the MCP configuration file (custom engine only). Overrides the default path (/tmp/gh-aw/mcp-config/mcp-servers.json).

  2. mcp-servers-field: Field name for the MCP servers in the configuration file (custom engine only). Common values: "mcpServers" (default), "servers". The field value is directly used in the generated configuration structure.

  3. mcp-servers-shape: Shape of the MCP servers in the configuration file (custom engine only). Enum values: "array" | "map" (default: "map"). Provides a semantic alternative to mcp-servers-field.

The custom engine now generates MCP configurations in either format based on these fields, eliminating the need for post-processing transformation scripts. Both mcp-servers-field and mcp-servers-shape are supported, with mcp-servers-field taking precedence if both are specified.

Implementation Details

Schema Changes:

  • Added new fields to main_workflow_schema.json and included_file_schema.json
  • Updated EngineConfig struct with MCPConfigFile, MCPServersField, and MCPServersShape fields
  • Added extraction logic for all three fields

Custom Engine Updates:

  • Modified RenderMCPConfig to support both mcpServers object format and servers array format
  • Supports both mcp-servers-field (direct field name) and mcp-servers-shape (semantic enum)
  • The mcp-servers-field value is directly interpolated into the JSON structure using the mcpServersField variable
  • mcp-servers-shape is converted to the appropriate field name: "array""servers", "map""mcpServers"
  • Added array format rendering functions for all MCP server types (GitHub, Playwright, safe-outputs, web-fetch, custom)
  • Updated path handling to use custom config file path from engine configuration
  • Default behavior uses "mcpServers" field (backward compatible)

simonw-llm Workflow:

  • Configured to use new fields:
    engine:
      id: custom
      mcp-config-file: ~/.llm-tools-mcp/mcp.json
      mcp-servers-field: servers
  • Removed Python transformation script (no longer needed)
  • MCP config is now generated directly in the llm-tools-mcp extension format

Configuration Options

Users can choose any of these approaches:

Option 1: Use mcp-servers-field (direct field name)

engine:
  id: custom
  mcp-servers-field: servers  # or "mcpServers", or any custom name

Option 2: Use mcp-servers-shape (semantic enum)

engine:
  id: custom
  mcp-servers-shape: array  # or "map"

Option 3: Use both (field takes precedence)

engine:
  id: custom
  mcp-servers-field: customName
  mcp-servers-shape: array  # This is ignored when field is specified

MCP Server Configuration Formats

  • mcp-servers-field: "servers" or mcp-servers-shape: "array": Generates {"servers": [{"name": "...", "transport": "stdio", "command": [...]}]} - suitable for extensions like llm-tools-mcp
  • mcp-servers-field: "mcpServers" or mcp-servers-shape: "map" (default): Generates {"mcpServers": {"server-name": {"command": "...", "args": [...]}}} - standard gh-aw format
  • The field name can be any string value and will be used directly in the JSON structure

Changes

  • pkg/parser/schemas/main_workflow_schema.json: Added mcp-config-file, mcp-servers-field, and mcp-servers-shape to engine_config schema
  • pkg/parser/schemas/included_file_schema.json: Added same fields for imported workflows
  • pkg/workflow/engine.go: Updated EngineConfig struct and extraction logic for all three fields
  • pkg/workflow/custom_engine.go: Added support for both MCP config formats with array format rendering functions, supports both field and shape configuration with proper precedence
  • .github/workflows/shared/simonw-llm.md: Configured to use new engine fields, removed transformation script
  • .github/workflows/shared/simonw-llm.lock.yml: Recompiled with new configuration
  • .github/workflows/issue-triage-llm.lock.yml: Recompiled with new configuration

Testing

✅ All 64 workflows compile successfully
✅ Unit tests pass
✅ Integration tests pass
✅ MCP configuration generated in correct extension format
✅ Default "mcpServers" format works correctly (backward compatible)
✅ "servers" format generates correct extension format for simonw-llm
mcp-servers-field works correctly (direct field name approach)
mcp-servers-shape: array generates {"servers": [...]}
mcp-servers-shape: map generates {"mcpServers": {...}}
✅ Precedence works correctly - field takes priority over shape

The custom engine now provides a flexible, declarative way to control MCP configuration generation without requiring post-processing scripts. Any workflow can specify the desired MCP config format using either the direct field name approach (mcp-servers-field) or the semantic enum approach (mcp-servers-shape), based on user preference.

Original prompt

Update simonw-LLM shared agentic workflow to rewrite the MCP config file to match the extension configuration format.

{
"servers": [
{
"name": "time_server",
"transport": "stdio",
"command": ["python", "time_server.py"],
"tools": ["get_time"]
}
]
}


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 2 commits October 10, 2025 22:35
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Update shared agentic workflow for MCP config file Add MCP config transformation for simonw-LLM extension format Oct 10, 2025
Copilot AI requested a review from pelikhan October 10, 2025 22:42
Copy link
Copy Markdown
Collaborator

@pelikhan pelikhan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot add two optional fields to the custom engine configuration:

  • mcp config file : path to the config file.json
  • mcp servers field: field name (mcpServers, servers, ...)

Update custom agentic engine to generate the MCP config file based on those fields

Use those fields to configure the way the MCP config file is generated for LLM

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Oct 10, 2025

@copilot add two optional fields to the custom engine configuration:

  • mcp config file : path to the config file.json...

Added the two optional fields to the custom engine configuration:

  • mcp-config-file: Path to the MCP config file (overrides default /tmp/gh-aw/mcp-config/mcp-servers.json)
  • mcp-servers-field: Field name for MCP servers in config file (mcpServers (default) or servers)

The custom engine now generates MCP config files based on these fields. Updated simonw-llm to use:

engine:
  id: custom
  mcp-config-file: ~/.llm-tools-mcp/mcp.json
  mcp-servers-field: servers

This generates the extension format directly without needing the Python transformation script.

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title Add MCP config transformation for simonw-LLM extension format Add custom engine MCP configuration fields for flexible format generation Oct 10, 2025
Copilot AI requested a review from pelikhan October 10, 2025 23:04
@pelikhan
Copy link
Copy Markdown
Collaborator

@copilot add a optional field to the custom engine "mcp-servers-shape: array" | "map", default is map.

The option determines how the servers are stored in config

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Oct 10, 2025

@copilot add a optional field to the custom engine "mcp-servers-shape: array" | "map", default is map.

The option determines how the servers are stored in config

Added mcp-servers-shape field with enum values "array" | "map" (default: "map").

The field determines the structure of the MCP configuration:

  • "array": Generates {"servers": [...]}
  • "map": Generates {"mcpServers": {...}}

Updated simonw-llm to use mcp-servers-shape: array.

if mcpServersShape == "array" {
// Extension format: { "servers": [ {...}, {...} ] }
yaml.WriteString(" {\n")
yaml.WriteString(" \"servers\": [\n")
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot use mcpServersField for "servers"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated to use mcpServersField variable with value "servers" on line 172.

// Default map format: { "mcpServers": { "name": {...}, ... } }
yaml.WriteString(" {\n")
yaml.WriteString(fmt.Sprintf(" \"%s\": {\n", mcpServersField))
yaml.WriteString(" \"mcpServers\": {\n")
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot use mcpServersField for "mcpServers"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated to use mcpServersField variable with value "mcpServers" on line 213.

"type": "string",
"description": "Path to the MCP configuration file (custom engine only). Overrides the default path (/tmp/gh-aw/mcp-config/mcp-servers.json)."
},
"mcp-servers-field": {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot keep mcp-servers-field

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kept mcp-servers-field in included_file_schema.json.

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI requested a review from pelikhan October 10, 2025 23:57
@pelikhan
Copy link
Copy Markdown
Collaborator

@copilot add ALSO support for mcp-servers-shape.

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Oct 11, 2025

@copilot add ALSO support for mcp-servers-shape.

Added support for both mcp-servers-field and mcp-servers-shape. Both fields work independently, with mcp-servers-field taking precedence if both are specified. Users can now choose either approach based on preference.

// mcp-servers-field takes precedence if both are provided
if workflowData.EngineConfig.MCPServersField != "" {
mcpServersField = workflowData.EngineConfig.MCPServersField
} else if workflowData.EngineConfig.MCPServersShape != "" {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot the shape is separate from the field name. DO NOT ASSOCIATE THEM.

@pelikhan pelikhan closed this Oct 11, 2025
@pelikhan pelikhan deleted the copilot/update-mcp-config-format branch October 11, 2025 00:46
Copilot AI requested a review from pelikhan October 11, 2025 00:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants