Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Jan 16, 2026

The current MCPServers() method returns a slice, making it impossible to identify which MCP server configuration belongs to which rule.

Changes

  • API change: Result.MCPServers() now returns map[string]mcp.MCPServerConfig

    • Map key is the rule's ID field
    • All types with ID fields (Rules, Tasks, Commands) automatically set ID to the filename (without extension) if not explicitly provided in frontmatter
    • Empty configs still filtered (no command and no URL)
  • Auto-generated IDs: When loading files, if the ID field is not present in frontmatter, it is automatically set to the filename (without extension)

    • RuleFrontMatter: ID auto-set from filename
    • TaskFrontMatter: ID auto-set from filename
    • CommandFrontMatter: ID auto-set from filename
    • Helper function generateIDFromPath() ensures consistent implementation
  • Tests: Added comprehensive coverage for ID-based and auto-generated keys, including integration tests for both rules and tasks

  • Docs: Updated README example and API reference

Usage

Before:

mcpServers := result.MCPServers()
for i, config := range mcpServers {
    fmt.Printf("MCP Server %d: %s\n", i, config.Command)
}

After:

mcpServers := result.MCPServers()
for id, config := range mcpServers {
    fmt.Printf("MCP Server %s: %s\n", id, config.Command)
}

Breaking change: Callers must update to iterate over map instead of slice.

Original prompt

It seems we cannot find out the name of the MCPServer returned in the Result.. Change th result to a map from ID. to the MCPConfig.


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

- Modified Result.MCPServers() to return map[string]mcp.MCPServerConfig
- Use rule ID as map key, with fallback to "rule-<index>" for rules without IDs
- Updated all tests to verify map-based behavior
- Updated documentation to reflect new API

Co-authored-by: alexec <1142830+alexec@users.noreply.github.com>
Copilot AI changed the title [WIP] Update result structure to map from ID to MCPConfig Return map from rule ID to MCPServerConfig in Result.MCPServers() Jan 16, 2026
Copilot AI requested a review from alexec January 16, 2026 18:56
@alexec
Copy link
Contributor

alexec commented Jan 16, 2026

@copilot Remind me, is ID automatically set? If so, what is it set to? It should be the file's base name without extension.

- Modified rule loading to auto-set ID from filename (without extension)
- Simplified MCPServers() since ID is now always set
- Updated tests to reflect auto-generated IDs
- Added integration test to verify ID auto-generation behavior

Co-authored-by: alexec <1142830+alexec@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Jan 16, 2026

@copilot Remind me, is ID automatically set? If so, what is it set to? It should be the file's base name without extension.

The ID was not automatically set before. I've updated the code to automatically set the ID to the file's base name (without extension) when loading rules if it's not explicitly provided in the frontmatter. See commit 4e76fdf.

@alexec
Copy link
Contributor

alexec commented Jan 16, 2026

@copilot Can you please double check for code related to IDL

- Added ID auto-setting for TaskFrontMatter and CommandFrontMatter
- Ensures consistent behavior: all types with ID field get auto-set from filename
- Added tests to verify task ID auto-setting (both explicit and implicit)

Co-authored-by: alexec <1142830+alexec@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Jan 16, 2026

@copilot Can you please double check for code related to IDL

I've double-checked all code related to ID. The following types have ID fields and now all auto-set ID from filename (without extension) when not explicitly provided:

  • RuleFrontMatter: ✅ (commit 4e76fdf)
  • TaskFrontMatter: ✅ (commit 0572a0c)
  • CommandFrontMatter: ✅ (commit 0572a0c)

SkillFrontMatter uses Name field (required) instead of ID, so no change needed there.

- Created generateIDFromPath() helper to reduce code duplication
- Updated all three locations (tasks, commands, rules) to use helper
- Improves maintainability and consistency

Co-authored-by: alexec <1142830+alexec@users.noreply.github.com>
@alexec alexec marked this pull request as ready for review January 16, 2026 20:08
Copilot AI review requested due to automatic review settings January 16, 2026 20:08
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR modifies the Result.MCPServers() method to return a map from rule ID to MCP server configuration, instead of a slice. This change enables callers to identify which MCP server configuration belongs to which rule, addressing the limitation where MCP servers were previously unidentifiable.

Changes:

  • Changed MCPServers() return type from slice to map keyed by rule ID
  • Added automatic ID generation from filename (without extension) for Rules, Tasks, and Commands when not explicitly set in frontmatter
  • Introduced helper function generateIDFromPath() for consistent ID extraction from file paths

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
pkg/codingcontext/result.go Modified MCPServers() to return map[string]mcp.MCPServerConfig instead of slice, using rule.FrontMatter.ID as key
pkg/codingcontext/context.go Added generateIDFromPath() helper and auto-ID setting logic for rules, tasks, and commands
pkg/codingcontext/result_test.go Updated all test cases to use map-based assertions instead of slice indices, added new test cases for ID scenarios
pkg/codingcontext/context_test.go Added integration tests validating auto-generated and explicit IDs for tasks and rules
pkg/codingcontext/README.md Updated example code and API documentation to reflect map-based return type
Comments suppressed due to low confidence (1)

pkg/codingcontext/result.go:37

  • The MCPServers method silently overwrites duplicate IDs when multiple rules have the same ID. This can happen if two rule files in different directories have the same filename, or if multiple rules explicitly specify the same ID in their frontmatter. Consider either detecting and logging/warning about duplicate IDs, or using a composite key (e.g., file path + ID) to ensure uniqueness, or returning an error when duplicates are detected.
func (r *Result) MCPServers() map[string]mcp.MCPServerConfig {
	servers := make(map[string]mcp.MCPServerConfig)

	// Add server from each rule, filtering out empty configs
	for _, rule := range r.Rules {
		server := rule.FrontMatter.MCPServer
		// Skip empty MCP server configs (no command and no URL means empty)
		if server.Command != "" || server.URL != "" {
			servers[rule.FrontMatter.ID] = server
		}
	}

	return servers

Comment on lines +63 to +64
ext := filepath.Ext(baseName)
return strings.TrimSuffix(baseName, ext)
Copy link

Copilot AI Jan 16, 2026

Choose a reason for hiding this comment

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

The generateIDFromPath function does not handle edge cases such as files without extensions or multiple extensions. For example, "file.tar.gz" would result in ID "file.tar" instead of "file". Consider using filepath.Base followed by removing all extensions, or documenting this behavior if it's intentional. Also consider handling empty filenames or paths with only an extension (e.g., ".gitignore").

Suggested change
ext := filepath.Ext(baseName)
return strings.TrimSuffix(baseName, ext)
if baseName == "" || baseName == "." {
return ""
}
name := baseName
for {
ext := filepath.Ext(name)
if ext == "" {
break
}
// If the entire name is just an extension (e.g., ".gitignore"),
// avoid returning an empty string and instead strip the leading dot.
if len(name) == len(ext) {
return strings.TrimPrefix(name, ".")
}
name = strings.TrimSuffix(name, ext)
}
return name

Copilot uses AI. Check for mistakes.
Comment on lines +728 to +767
{
name: "rule IDs automatically set from filename",
setup: func(t *testing.T, dir string) {
createTask(t, dir, "id-task", "", "Task")
createRule(t, dir, ".agents/rules/my-rule.md", "", "Rule without ID in frontmatter")
createRule(t, dir, ".agents/rules/another-rule.md", "id: explicit-id", "Rule with explicit ID")
},
taskName: "id-task",
wantErr: false,
check: func(t *testing.T, result *Result) {
if len(result.Rules) != 2 {
t.Fatalf("expected 2 rules, got %d", len(result.Rules))
}

// Check that one rule has auto-generated ID from filename
foundMyRule := false
foundAnotherRule := false
for _, rule := range result.Rules {
if rule.FrontMatter.ID == "my-rule" {
foundMyRule = true
if !strings.Contains(rule.Content, "Rule without ID") {
t.Error("my-rule should contain 'Rule without ID'")
}
}
if rule.FrontMatter.ID == "explicit-id" {
foundAnotherRule = true
if !strings.Contains(rule.Content, "Rule with explicit ID") {
t.Error("explicit-id should contain 'Rule with explicit ID'")
}
}
}

if !foundMyRule {
t.Error("expected to find rule with auto-generated ID 'my-rule'")
}
if !foundAnotherRule {
t.Error("expected to find rule with explicit ID 'explicit-id'")
}
},
},
Copy link

Copilot AI Jan 16, 2026

Choose a reason for hiding this comment

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

Missing test coverage for duplicate IDs scenario. Consider adding a test case that verifies behavior when two rules have the same ID (either from same filenames in different directories, or explicit duplicate IDs in frontmatter). This should validate whether duplicates are detected, logged, or result in silent data loss.

Copilot uses AI. Check for mistakes.
for _, rule := range r.Rules {
server := rule.FrontMatter.MCPServer
// Skip empty MCP server configs (no command and no URL means empty)
if server.Command != "" || server.URL != "" {
Copy link

Copilot AI Jan 16, 2026

Choose a reason for hiding this comment

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

If a rule has an empty ID (neither auto-generated nor explicitly set), it will be used as a map key with an empty string. This could cause multiple rules with empty IDs to overwrite each other. Consider adding validation to ensure IDs are non-empty before inserting into the map, or add a test case to validate behavior with empty IDs.

Suggested change
if server.Command != "" || server.URL != "" {
if (server.Command != "" || server.URL != "") && rule.FrontMatter.ID != "" {

Copilot uses AI. Check for mistakes.
Comment on lines +728 to +767
{
name: "rule IDs automatically set from filename",
setup: func(t *testing.T, dir string) {
createTask(t, dir, "id-task", "", "Task")
createRule(t, dir, ".agents/rules/my-rule.md", "", "Rule without ID in frontmatter")
createRule(t, dir, ".agents/rules/another-rule.md", "id: explicit-id", "Rule with explicit ID")
},
taskName: "id-task",
wantErr: false,
check: func(t *testing.T, result *Result) {
if len(result.Rules) != 2 {
t.Fatalf("expected 2 rules, got %d", len(result.Rules))
}

// Check that one rule has auto-generated ID from filename
foundMyRule := false
foundAnotherRule := false
for _, rule := range result.Rules {
if rule.FrontMatter.ID == "my-rule" {
foundMyRule = true
if !strings.Contains(rule.Content, "Rule without ID") {
t.Error("my-rule should contain 'Rule without ID'")
}
}
if rule.FrontMatter.ID == "explicit-id" {
foundAnotherRule = true
if !strings.Contains(rule.Content, "Rule with explicit ID") {
t.Error("explicit-id should contain 'Rule with explicit ID'")
}
}
}

if !foundMyRule {
t.Error("expected to find rule with auto-generated ID 'my-rule'")
}
if !foundAnotherRule {
t.Error("expected to find rule with explicit ID 'explicit-id'")
}
},
},
Copy link

Copilot AI Jan 16, 2026

Choose a reason for hiding this comment

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

Missing integration test coverage for the MCPServers functionality. Consider adding an integration test that creates rule files with MCP server configurations, runs the context, and validates that MCPServers returns the correct map with the expected IDs and configurations. This would validate the full flow from file loading through ID generation to the MCPServers method.

Copilot uses AI. Check for mistakes.
@alexec alexec merged commit f1bb4a0 into main Jan 16, 2026
6 of 7 checks passed
@alexec alexec deleted the copilot/change-result-to-map branch January 16, 2026 22:18
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