Commit 3906216
authored
Refactor URL derivation and helper ownership across envutil/config/mcp (#3968)
The codebase had duplicated GitHub API URL resolution logic with
divergent behavior between proxy and unified server paths, plus helper
placement that blurred package boundaries. This refactor consolidates
URL derivation, separates config expansion from validation, and moves
MCP result construction to the MCP layer.
- **GitHub API URL derivation is now single-source (`envutil`)**
- Added `envutil.DeriveGitHubAPIURL(defaultURL string)` and internal
server-URL derivation logic.
- `server/unified` now derives from `GITHUB_API_URL` **or**
`GITHUB_SERVER_URL` (instead of only `GITHUB_API_URL`), aligning
behavior with proxy mode.
- Removed duplicate derivation functions from `internal/proxy/proxy.go`.
- Updated call sites:
- `internal/cmd/proxy.go` → `envutil.DeriveGitHubAPIURL("")`
- `internal/server/unified.go` →
`envutil.DeriveGitHubAPIURL("https://api.github.com")`
- **Config variable expansion extracted from validation**
- Moved expansion concerns from `internal/config/validation.go` to new
`internal/config/expand.go`:
- `expandVariablesCore`, `expandVariables`, `ExpandRawJSONVariables`,
`expandEnvVariables`, `expandTracingVariables`, `varExprPattern`
- `validation.go` now remains focused on validation rules and flow.
- **MCP error `CallToolResult` helper moved to `mcp` package**
- Added `mcp.NewErrorCallToolResult(err)` in
`internal/mcp/tool_result.go`.
- Replaced server-local helper usage in `internal/server/unified.go` and
`internal/server/tool_registry.go`.
- Updated corresponding tests to use the new helper location.
```go
// unified/server path now uses centralized derivation logic
apiURL := envutil.DeriveGitHubAPIURL("https://api.github.com")
// shared MCP-layer error result helper
return mcp.NewErrorCallToolResult(err)
```
> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build1057253636/b514/launcher.test
/tmp/go-build1057253636/b514/launcher.test
-test.testlogfile=/tmp/go-build1057253636/b514/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build1057253636/b467/vet.cfg apic.go decode.go x_amd64/vet -p
roundrobin lcache/go/1.25.8-bool x_amd64/vet -p g_.a 1227851/b288/
x_amd64/vet -I /tmp/go-build278-atomic` (dns block)
> - Triggering command: `/tmp/go-build900982912/b514/launcher.test
/tmp/go-build900982912/b514/launcher.test
-test.testlogfile=/tmp/go-build900982912/b514/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -d -lang=go1.25
64/pkg/tool/linu./internal/config b2799acda4848aff53b399dfb07b4159
/tmp/go-build278bash 0a4 64/pkg/tool/linu--noprofile ctl star��
r/runc-log.json
64/pkg/tool/linu/var/run/docker/runtime-runc/mob--log-format .13/x64/git
auHmSssMaaom2Ek4bash -goversion r/6j32koixnhwjnj--noprofile
/usr/bin/runc.original` (dns block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build1057253636/b496/config.test
/tmp/go-build1057253636/b496/config.test
-test.testlogfile=/tmp/go-build1057253636/b496/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build1057253636/b387/vet.cfg @v1.1.3/cpu/cpu.-errorsas
1227851/b151/ x_amd64/vet --gdwarf-5 ternal/engine/in-unsafeptr=false
lcache/go/1.25.8-unreachable=false x_amd64/vet 1227�� 8RQNG6Nox -I
x_amd64/vet --gdwarf-5 --64 -o x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build2556833836/b492/config.test
/tmp/go-build2556833836/b492/config.test
-test.testlogfile=/tmp/go-build2556833836/b492/testlog.txt
-test.paniconexit0 -test.timeout=10m0s /usr��
7253636/b560/tty--log-format ntime.v2.task/mojson 7253636/b560/impdelete
ntime.v2.task/mobash 062439bb528087fb/usr/bin/runc
UNDLE=/etc/ssl/c--root uKbOHgHoxAqgN/t5/var/run/docker/runtime-runc/moby
k/_t��
tr7/ca-certifica/run/containerd/io.containerd.runtime.v2.task/moby/d15ea4acb1ef69f4d1e1e6e2b19b0bash
test:latest bash .cfg olang.org/protob--norc x_amd64/vet
95d45854b162103b` (dns block)
> - Triggering command: `/tmp/go-build76351485/b001/config.test
/tmp/go-build76351485/b001/config.test
-test.testlogfile=/tmp/go-build76351485/b001/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -m
2e5d631e9ae2084a/run/containerd/io.containerd.runtime.v2.task/moby/b6f36c5d7e9d4--size-limit
y ctl b04263944d57c5b7git d94d1b364afb75b8show 5d0/log.json ctl dock��
ion.go y ash
ntime.v2.task/mo/opt/hostedtoolcache/CodeQL/2.25.1/x64/codeql/tools/linux64/REDACTED-linux
0b5929f8b23b298f/opt/hostedtoolcache/CodeQL/2.25.1/x64/codeql/go/tools/autobuild.sh
e-handler 2a9e172d1927c35b435/log.json` (dns block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build1057253636/b514/launcher.test
/tmp/go-build1057253636/b514/launcher.test
-test.testlogfile=/tmp/go-build1057253636/b514/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build1057253636/b467/vet.cfg apic.go decode.go x_amd64/vet -p
roundrobin lcache/go/1.25.8-bool x_amd64/vet -p g_.a 1227851/b288/
x_amd64/vet -I /tmp/go-build278-atomic` (dns block)
> - Triggering command: `/tmp/go-build900982912/b514/launcher.test
/tmp/go-build900982912/b514/launcher.test
-test.testlogfile=/tmp/go-build900982912/b514/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -d -lang=go1.25
64/pkg/tool/linu./internal/config b2799acda4848aff53b399dfb07b4159
/tmp/go-build278bash 0a4 64/pkg/tool/linu--noprofile ctl star��
r/runc-log.json
64/pkg/tool/linu/var/run/docker/runtime-runc/mob--log-format .13/x64/git
auHmSssMaaom2Ek4bash -goversion r/6j32koixnhwjnj--noprofile
/usr/bin/runc.original` (dns block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build1057253636/b514/launcher.test
/tmp/go-build1057253636/b514/launcher.test
-test.testlogfile=/tmp/go-build1057253636/b514/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build1057253636/b467/vet.cfg apic.go decode.go x_amd64/vet -p
roundrobin lcache/go/1.25.8-bool x_amd64/vet -p g_.a 1227851/b288/
x_amd64/vet -I /tmp/go-build278-atomic` (dns block)
> - Triggering command: `/tmp/go-build900982912/b514/launcher.test
/tmp/go-build900982912/b514/launcher.test
-test.testlogfile=/tmp/go-build900982912/b514/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -d -lang=go1.25
64/pkg/tool/linu./internal/config b2799acda4848aff53b399dfb07b4159
/tmp/go-build278bash 0a4 64/pkg/tool/linu--noprofile ctl star��
r/runc-log.json
64/pkg/tool/linu/var/run/docker/runtime-runc/mob--log-format .13/x64/git
auHmSssMaaom2Ek4bash -goversion r/6j32koixnhwjnj--noprofile
/usr/bin/runc.original` (dns block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build1057253636/b523/mcp.test
/tmp/go-build1057253636/b523/mcp.test
-test.testlogfile=/tmp/go-build1057253636/b523/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -I .cfg
olang.org/grpc@v1.80.0/balancer_wrapper.go x_amd64/vet ute.go
mentation.go -o x_amd64/vet .cfg�� J5E4/LjHfXKvhsjfAdZsIJ5E4 -I
x_amd64/vet -I 1227851/b468/ -imultiarch x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build2556833836/b489/mcp.test
/tmp/go-build2556833836/b489/mcp.test
-test.testlogfile=/tmp/go-build2556833836/b489/testlog.txt
-test.paniconexit0 -test.timeout=10m0s` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>13 files changed
Lines changed: 358 additions & 545 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
189 | 189 | | |
190 | 190 | | |
191 | 191 | | |
192 | | - | |
| 192 | + | |
193 | 193 | | |
194 | 194 | | |
195 | 195 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
16 | 16 | | |
17 | 17 | | |
18 | 18 | | |
19 | | - | |
20 | | - | |
21 | | - | |
22 | 19 | | |
23 | 20 | | |
24 | 21 | | |
| |||
45 | 42 | | |
46 | 43 | | |
47 | 44 | | |
48 | | - | |
49 | | - | |
50 | | - | |
51 | | - | |
52 | | - | |
53 | | - | |
54 | | - | |
55 | | - | |
56 | | - | |
57 | | - | |
58 | | - | |
59 | | - | |
60 | | - | |
61 | | - | |
62 | | - | |
63 | | - | |
64 | | - | |
65 | | - | |
66 | | - | |
67 | | - | |
68 | | - | |
69 | | - | |
70 | | - | |
71 | | - | |
72 | | - | |
73 | | - | |
74 | | - | |
75 | | - | |
76 | | - | |
77 | | - | |
78 | | - | |
79 | | - | |
80 | | - | |
81 | | - | |
82 | | - | |
83 | | - | |
84 | | - | |
85 | | - | |
86 | | - | |
87 | | - | |
88 | | - | |
89 | | - | |
90 | | - | |
91 | | - | |
92 | | - | |
93 | | - | |
94 | | - | |
95 | | - | |
96 | | - | |
97 | | - | |
98 | | - | |
99 | | - | |
100 | | - | |
101 | | - | |
102 | | - | |
103 | | - | |
104 | | - | |
105 | | - | |
106 | | - | |
107 | | - | |
108 | | - | |
109 | | - | |
110 | | - | |
111 | | - | |
112 | | - | |
113 | | - | |
114 | | - | |
115 | | - | |
116 | | - | |
117 | | - | |
118 | | - | |
119 | | - | |
120 | | - | |
121 | | - | |
122 | | - | |
123 | | - | |
124 | | - | |
125 | | - | |
126 | | - | |
127 | | - | |
128 | | - | |
129 | | - | |
130 | | - | |
131 | | - | |
132 | | - | |
133 | | - | |
134 | | - | |
135 | | - | |
136 | | - | |
137 | | - | |
138 | | - | |
139 | | - | |
140 | | - | |
141 | | - | |
142 | | - | |
143 | | - | |
144 | | - | |
145 | | - | |
146 | | - | |
147 | | - | |
148 | | - | |
149 | | - | |
150 | | - | |
151 | | - | |
152 | | - | |
153 | | - | |
154 | | - | |
155 | | - | |
156 | | - | |
157 | | - | |
158 | | - | |
159 | | - | |
160 | | - | |
161 | | - | |
162 | | - | |
163 | | - | |
164 | 45 | | |
165 | 46 | | |
166 | 47 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | 3 | | |
| 4 | + | |
| 5 | + | |
4 | 6 | | |
5 | 7 | | |
6 | 8 | | |
| |||
9 | 11 | | |
10 | 12 | | |
11 | 13 | | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
12 | 17 | | |
13 | 18 | | |
14 | 19 | | |
| |||
49 | 54 | | |
50 | 55 | | |
51 | 56 | | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
0 commit comments