Skip to content

Commit e388f80

Browse files
Copilotalexec
andcommitted
Change MCPServers() to return map from rule ID to MCPServerConfig
- 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>
1 parent f77bbb9 commit e388f80

3 files changed

Lines changed: 113 additions & 26 deletions

File tree

pkg/codingcontext/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,8 @@ func main() {
116116

117117
// Access MCP server configurations
118118
mcpServers := result.MCPServers()
119-
for i, config := range mcpServers {
120-
fmt.Printf("MCP Server %d: %s\n", i, config.Command)
119+
for id, config := range mcpServers {
120+
fmt.Printf("MCP Server %s: %s\n", id, config.Command)
121121
}
122122
}
123123
```
@@ -139,7 +139,7 @@ Result holds the assembled context from running a task:
139139
- `Agent Agent` - The agent used (from task frontmatter or option)
140140

141141
**Methods:**
142-
- `MCPServers() []MCPServerConfig` - Returns all MCP server configurations from rules as a slice
142+
- `MCPServers() map[string]MCPServerConfig` - Returns all MCP server configurations from rules as a map from rule ID to configuration
143143

144144
#### `Markdown[T]`
145145

pkg/codingcontext/result.go

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package codingcontext
22

33
import (
4+
"fmt"
5+
46
"github.com/kitproj/coding-context-cli/pkg/codingcontext/markdown"
57
"github.com/kitproj/coding-context-cli/pkg/codingcontext/mcp"
68
"github.com/kitproj/coding-context-cli/pkg/codingcontext/skills"
@@ -16,19 +18,25 @@ type Result struct {
1618
Prompt string // Combined prompt: all rules and task content
1719
}
1820

19-
// MCPServers returns all MCP server configurations from rules.
21+
// MCPServers returns all MCP server configurations from rules as a map.
2022
// Each rule can specify one MCP server configuration.
21-
// Returns a slice of all configured MCP servers from rules only.
23+
// Returns a map from rule ID to MCP server configuration.
2224
// Empty/zero-value MCP server configurations are filtered out.
23-
func (r *Result) MCPServers() []mcp.MCPServerConfig {
24-
var servers []mcp.MCPServerConfig
25+
// Rules without an ID field are included with a generated key "rule-<index>".
26+
func (r *Result) MCPServers() map[string]mcp.MCPServerConfig {
27+
servers := make(map[string]mcp.MCPServerConfig)
2528

2629
// Add server from each rule, filtering out empty configs
27-
for _, rule := range r.Rules {
30+
for i, rule := range r.Rules {
2831
server := rule.FrontMatter.MCPServer
2932
// Skip empty MCP server configs (no command and no URL means empty)
3033
if server.Command != "" || server.URL != "" {
31-
servers = append(servers, server)
34+
// Use the rule's ID as the key, or generate one if not present
35+
key := rule.FrontMatter.ID
36+
if key == "" {
37+
key = fmt.Sprintf("rule-%d", i)
38+
}
39+
servers[key] = server
3240
}
3341
}
3442

pkg/codingcontext/result_test.go

Lines changed: 96 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ func TestResult_MCPServers(t *testing.T) {
7272
tests := []struct {
7373
name string
7474
result Result
75-
want []mcp.MCPServerConfig
75+
want map[string]mcp.MCPServerConfig
7676
}{
7777
{
7878
name: "no MCP servers",
@@ -82,19 +82,21 @@ func TestResult_MCPServers(t *testing.T) {
8282
FrontMatter: markdown.TaskFrontMatter{},
8383
},
8484
},
85-
want: []mcp.MCPServerConfig{},
85+
want: map[string]mcp.MCPServerConfig{},
8686
},
8787
{
88-
name: "MCP servers from rules only",
88+
name: "MCP servers from rules with IDs",
8989
result: Result{
9090
Rules: []markdown.Markdown[markdown.RuleFrontMatter]{
9191
{
9292
FrontMatter: markdown.RuleFrontMatter{
93+
ID: "jira-server",
9394
MCPServer: mcp.MCPServerConfig{Type: mcp.TransportTypeStdio, Command: "jira"},
9495
},
9596
},
9697
{
9798
FrontMatter: markdown.RuleFrontMatter{
99+
ID: "api-server",
98100
MCPServer: mcp.MCPServerConfig{Type: mcp.TransportTypeHTTP, URL: "https://api.example.com"},
99101
},
100102
},
@@ -103,9 +105,33 @@ func TestResult_MCPServers(t *testing.T) {
103105
FrontMatter: markdown.TaskFrontMatter{},
104106
},
105107
},
106-
want: []mcp.MCPServerConfig{
107-
{Type: mcp.TransportTypeStdio, Command: "jira"},
108-
{Type: mcp.TransportTypeHTTP, URL: "https://api.example.com"},
108+
want: map[string]mcp.MCPServerConfig{
109+
"jira-server": {Type: mcp.TransportTypeStdio, Command: "jira"},
110+
"api-server": {Type: mcp.TransportTypeHTTP, URL: "https://api.example.com"},
111+
},
112+
},
113+
{
114+
name: "MCP servers from rules without IDs",
115+
result: Result{
116+
Rules: []markdown.Markdown[markdown.RuleFrontMatter]{
117+
{
118+
FrontMatter: markdown.RuleFrontMatter{
119+
MCPServer: mcp.MCPServerConfig{Type: mcp.TransportTypeStdio, Command: "server1"},
120+
},
121+
},
122+
{
123+
FrontMatter: markdown.RuleFrontMatter{
124+
MCPServer: mcp.MCPServerConfig{Type: mcp.TransportTypeStdio, Command: "server2"},
125+
},
126+
},
127+
},
128+
Task: markdown.Markdown[markdown.TaskFrontMatter]{
129+
FrontMatter: markdown.TaskFrontMatter{},
130+
},
131+
},
132+
want: map[string]mcp.MCPServerConfig{
133+
"rule-0": {Type: mcp.TransportTypeStdio, Command: "server1"},
134+
"rule-1": {Type: mcp.TransportTypeStdio, Command: "server2"},
109135
},
110136
},
111137
{
@@ -114,25 +140,29 @@ func TestResult_MCPServers(t *testing.T) {
114140
Rules: []markdown.Markdown[markdown.RuleFrontMatter]{
115141
{
116142
FrontMatter: markdown.RuleFrontMatter{
143+
ID: "server1-id",
117144
MCPServer: mcp.MCPServerConfig{Type: mcp.TransportTypeStdio, Command: "server1"},
118145
},
119146
},
120147
{
121148
FrontMatter: markdown.RuleFrontMatter{
149+
ID: "server2-id",
122150
MCPServer: mcp.MCPServerConfig{Type: mcp.TransportTypeStdio, Command: "server2"},
123151
},
124152
},
125153
{
126-
FrontMatter: markdown.RuleFrontMatter{},
154+
FrontMatter: markdown.RuleFrontMatter{
155+
ID: "empty-rule",
156+
},
127157
},
128158
},
129159
Task: markdown.Markdown[markdown.TaskFrontMatter]{
130160
FrontMatter: markdown.TaskFrontMatter{},
131161
},
132162
},
133-
want: []mcp.MCPServerConfig{
134-
{Type: mcp.TransportTypeStdio, Command: "server1"},
135-
{Type: mcp.TransportTypeStdio, Command: "server2"},
163+
want: map[string]mcp.MCPServerConfig{
164+
"server1-id": {Type: mcp.TransportTypeStdio, Command: "server1"},
165+
"server2-id": {Type: mcp.TransportTypeStdio, Command: "server2"},
136166
// Empty rule MCP server is filtered out
137167
},
138168
},
@@ -141,17 +171,51 @@ func TestResult_MCPServers(t *testing.T) {
141171
result: Result{
142172
Rules: []markdown.Markdown[markdown.RuleFrontMatter]{
143173
{
144-
FrontMatter: markdown.RuleFrontMatter{},
174+
FrontMatter: markdown.RuleFrontMatter{
175+
ID: "no-server-rule",
176+
},
145177
},
146178
},
147179
Task: markdown.Markdown[markdown.TaskFrontMatter]{
148180
FrontMatter: markdown.TaskFrontMatter{},
149181
},
150182
},
151-
want: []mcp.MCPServerConfig{
183+
want: map[string]mcp.MCPServerConfig{
152184
// Empty rule MCP server is filtered out
153185
},
154186
},
187+
{
188+
name: "mixed rules with and without IDs",
189+
result: Result{
190+
Rules: []markdown.Markdown[markdown.RuleFrontMatter]{
191+
{
192+
FrontMatter: markdown.RuleFrontMatter{
193+
ID: "explicit-id",
194+
MCPServer: mcp.MCPServerConfig{Type: mcp.TransportTypeStdio, Command: "server1"},
195+
},
196+
},
197+
{
198+
FrontMatter: markdown.RuleFrontMatter{
199+
MCPServer: mcp.MCPServerConfig{Type: mcp.TransportTypeStdio, Command: "server2"},
200+
},
201+
},
202+
{
203+
FrontMatter: markdown.RuleFrontMatter{
204+
ID: "another-id",
205+
MCPServer: mcp.MCPServerConfig{Type: mcp.TransportTypeHTTP, URL: "https://example.com"},
206+
},
207+
},
208+
},
209+
Task: markdown.Markdown[markdown.TaskFrontMatter]{
210+
FrontMatter: markdown.TaskFrontMatter{},
211+
},
212+
},
213+
want: map[string]mcp.MCPServerConfig{
214+
"explicit-id": {Type: mcp.TransportTypeStdio, Command: "server1"},
215+
"rule-1": {Type: mcp.TransportTypeStdio, Command: "server2"},
216+
"another-id": {Type: mcp.TransportTypeHTTP, URL: "https://example.com"},
217+
},
218+
},
155219
}
156220

157221
for _, tt := range tests {
@@ -160,22 +224,37 @@ func TestResult_MCPServers(t *testing.T) {
160224

161225
if len(got) != len(tt.want) {
162226
t.Errorf("MCPServers() returned %d servers, want %d", len(got), len(tt.want))
227+
t.Logf("Got keys: %v", mapKeys(got))
228+
t.Logf("Want keys: %v", mapKeys(tt.want))
163229
return
164230
}
165231

166-
for i, wantServer := range tt.want {
167-
gotServer := got[i]
232+
for key, wantServer := range tt.want {
233+
gotServer, ok := got[key]
234+
if !ok {
235+
t.Errorf("MCPServers() missing key %q", key)
236+
continue
237+
}
168238

169239
if gotServer.Type != wantServer.Type {
170-
t.Errorf("MCPServers()[%d].Type = %v, want %v", i, gotServer.Type, wantServer.Type)
240+
t.Errorf("MCPServers()[%q].Type = %v, want %v", key, gotServer.Type, wantServer.Type)
171241
}
172242
if gotServer.Command != wantServer.Command {
173-
t.Errorf("MCPServers()[%d].Command = %q, want %q", i, gotServer.Command, wantServer.Command)
243+
t.Errorf("MCPServers()[%q].Command = %q, want %q", key, gotServer.Command, wantServer.Command)
174244
}
175245
if gotServer.URL != wantServer.URL {
176-
t.Errorf("MCPServers()[%d].URL = %q, want %q", i, gotServer.URL, wantServer.URL)
246+
t.Errorf("MCPServers()[%q].URL = %q, want %q", key, gotServer.URL, wantServer.URL)
177247
}
178248
}
179249
})
180250
}
181251
}
252+
253+
// Helper function to get map keys for debugging
254+
func mapKeys(m map[string]mcp.MCPServerConfig) []string {
255+
keys := make([]string, 0, len(m))
256+
for k := range m {
257+
keys = append(keys, k)
258+
}
259+
return keys
260+
}

0 commit comments

Comments
 (0)