Bundle MCP gateway config schema in binary via go:embed#2933
Conversation
…rk fetch Agent-Logs-Url: https://github.com/github/gh-aw-mcpg/sessions/e18d275d-1cfe-4125-8dd3-b0a394ea8a68 Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
…dedSchemaID constant Agent-Logs-Url: https://github.com/github/gh-aw-mcpg/sessions/e18d275d-1cfe-4125-8dd3-b0a394ea8a68 Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
Move //go:embed directive to immediately before the var declaration, after the doc comment block, as required by gofmt. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR removes the MCP Gateway’s runtime dependency on fetching its JSON Schema over the network by bundling the schema into the binary with go:embed, while keeping remote fetch behavior for validating custom server schemas.
Changes:
- Embedded the MCP gateway config JSON Schema at build time and switched schema compilation to use embedded bytes (no runtime HTTP fetch).
- Refactored schema transformation logic into a pure
fixSchemaByteshelper and reused it from both embedded and remote fetch paths. - Updated tests to exercise schema-fix behavior directly from bytes rather than via HTTP test servers.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| internal/config/validation_schema.go | Embeds the schema and refactors schema fix/fetch/compile flow to remove runtime network dependency. |
| internal/config/validation_schema_test.go | Updates schema configuration test to validate embedded schema presence and compilation. |
| internal/config/schema/mcp-gateway-config.schema.json | Adds the bundled MCP Gateway configuration schema JSON file to the repo. |
| internal/config/fetch_and_fix_schema_test.go | Simplifies transformation tests to call fixSchemaBytes directly. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| func fixSchemaBytes(schemaBytes []byte) ([]byte, error) { | ||
| fixStart := time.Now() | ||
| var schema map[string]interface{} | ||
| if err := json.Unmarshal(schemaBytes, &schema); err != nil { |
There was a problem hiding this comment.
fixSchemaBytes currently removes the type: "string" constraint from definitions.customServerConfig.properties.type (and only adds a not enum). That makes schema validation accept non-string values (e.g., numbers/objects) as a valid custom server type and drops the type-name format constraints, weakening config validation and producing less helpful downstream unmarshal errors. Suggest keeping type: "string" and replacing only the negative-lookahead portion with a Draft-7-safe equivalent (e.g., preserve the allowed-name pattern and add a not enum for reserved types).
| } | ||
| logSchema.Printf("Schema fixes applied in %v", time.Since(fixStart)) | ||
|
|
||
| logSchema.Printf("Total schema fetch and fix completed in %v", time.Since(startTime)) | ||
| return fixedBytes, nil |
There was a problem hiding this comment.
fixSchemaBytes unconditionally injects/overwrites several properties (e.g., trustedBots, guard-policies) in the schema map. Now that the bundled schema version already includes some of these fields, this risks clobbering upstream definitions/descriptions and leaves the inline comment about the field being absent in older released schemas stale. Consider only injecting these properties if they are missing (and refresh/remove the version-specific comment) to avoid silently diverging from the embedded schema source-of-truth.
| "port": 8080, | ||
| "domain": "localhost", | ||
| "startupTimeout": 60, | ||
| "toolTimeout": 120 |
There was a problem hiding this comment.
The second entry in the examples array has gateway missing the required apiKey field (gatewayConfig.required includes apiKey). Examples should be valid instances of the schema to avoid confusing users and downstream tooling; add an apiKey to this example (or adjust required fields if apiKey is intentionally optional).
| "toolTimeout": 120 | |
| "toolTimeout": 120, | |
| "apiKey": "gateway-secret-token" |
The gateway schema was fetched at runtime from a pinned GitHub raw URL, causing startup failures in network-restricted environments and introducing a hard dependency on external availability.
Changes
Embed schema at build time: Added
internal/config/schema/mcp-gateway-config.schema.json(v0.64.4) and a//go:embeddirective with aembeddedSchemaBytesvariable.getOrCompileSchema()now uses the embedded bytes directly — no network request.Extract transformation logic: Split
fetchAndFixSchemainto two functions:fixSchemaBytes([]byte) ([]byte, error)— pure JSON transformation (negative-lookahead fix, registry/guard-policies injection)fetchAndFixSchema(url string) ([]byte, error)— HTTP fetch +fixSchemaBytes, retained for custom server schema validationRemove
schemaURLpackage var: The hardcoded GitHub URL is no longer needed for the main schema path. Update instructions are in the comment onembeddedSchemaBytes.Simplify tests:
fetch_and_fix_schema_test.gotests now callfixSchemaBytesdirectly with marshaled JSON instead of spinning up HTTP mock servers.Warning
Firewall rules blocked me from connecting to one or more addresses (expand for details)
I tried to connect to the following addresses, but was blocked by firewall rules:
example.com/tmp/go-build1174324405/b340/launcher.test /tmp/go-build1174324405/b340/launcher.test -test.testlogfile=/tmp/go-build1174324405/b340/testlog.txt -test.paniconexit0 -test.timeout=10m0s /tmp/go-build1174324405/b240/vet.cfg se 8413017/b047/vet.cfg ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet --gdwarf-5 --64 -o ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet(dns block)invalid-host-that-does-not-exist-12345.com/tmp/go-build31076197/b001/config.test /tmp/go-build31076197/b001/config.test -test.testlogfile=/tmp/go-build31076197/b001/testlog.txt -test.paniconexit0 -test.timeout=10m0s -test.run=TestFetchAndFixSchema -test.v=true --local .13/x64/as user.email(dns block)/tmp/go-build2540153460/b001/config.test /tmp/go-build2540153460/b001/config.test -test.testlogfile=/tmp/go-build2540153460/b001/testlog.txt -test.paniconexit0 -test.timeout=10m0s -test.v=true 64/src/runtime/cgo 64/src/log/internal/internal.go ache/go/1.25.8/x64/pkg/tool/linu-o gpg.program(dns block)/tmp/go-build3088080346/b001/config.test /tmp/go-build3088080346/b001/config.test -test.testlogfile=/tmp/go-build3088080346/b001/testlog.txt -test.paniconexit0 -test.timeout=10m0s go_.�� 8958092/b096/_pkg_.a(dns block)nonexistent.local/tmp/go-build1174324405/b340/launcher.test /tmp/go-build1174324405/b340/launcher.test -test.testlogfile=/tmp/go-build1174324405/b340/testlog.txt -test.paniconexit0 -test.timeout=10m0s /tmp/go-build1174324405/b240/vet.cfg se 8413017/b047/vet.cfg ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet --gdwarf-5 --64 -o ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet(dns block)slow.example.com/tmp/go-build1174324405/b340/launcher.test /tmp/go-build1174324405/b340/launcher.test -test.testlogfile=/tmp/go-build1174324405/b340/testlog.txt -test.paniconexit0 -test.timeout=10m0s /tmp/go-build1174324405/b240/vet.cfg se 8413017/b047/vet.cfg ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet --gdwarf-5 --64 -o ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet(dns block)this-host-does-not-exist-12345.com/tmp/go-build1174324405/b349/mcp.test /tmp/go-build1174324405/b349/mcp.test -test.testlogfile=/tmp/go-build1174324405/b349/testlog.txt -test.paniconexit0 -test.timeout=10m0s /tmp/go-build1174324405/b256/vet.cfg se 8413017/b038/vet.cfg ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet (compatibility issue with Go 1.25.0). Continuing with other checks..."; \ elif command -v golan vendor/golang.or-unsafeptr=false -lang=go1.25 ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet(dns block)If you need me to access, download, or install something from one of these locations, you can either: