-
Notifications
You must be signed in to change notification settings - Fork 1
Return map from rule ID to MCPServerConfig in Result.MCPServers() #201
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- 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 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>
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. |
|
@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>
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:
SkillFrontMatter uses |
- 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>
There was a problem hiding this 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
| ext := filepath.Ext(baseName) | ||
| return strings.TrimSuffix(baseName, ext) |
Copilot
AI
Jan 16, 2026
There was a problem hiding this comment.
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").
| 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 |
| { | ||
| 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'") | ||
| } | ||
| }, | ||
| }, |
Copilot
AI
Jan 16, 2026
There was a problem hiding this comment.
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.
| 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 != "" { |
Copilot
AI
Jan 16, 2026
There was a problem hiding this comment.
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.
| if server.Command != "" || server.URL != "" { | |
| if (server.Command != "" || server.URL != "") && rule.FrontMatter.ID != "" { |
| { | ||
| 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'") | ||
| } | ||
| }, | ||
| }, |
Copilot
AI
Jan 16, 2026
There was a problem hiding this comment.
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.
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 returnsmap[string]mcp.MCPServerConfigIDfieldAuto-generated IDs: When loading files, if the
IDfield is not present in frontmatter, it is automatically set to the filename (without extension)generateIDFromPath()ensures consistent implementationTests: 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:
After:
Breaking change: Callers must update to iterate over map instead of slice.
Original prompt
💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.