Skip to content

gateway: normalize profile config for template eval (flat keys, schema, nesting)#462

Open
DavRodSwede wants to merge 1 commit into
docker:mainfrom
DavRodSwede:feat/gateway-config-for-eval
Open

gateway: normalize profile config for template eval (flat keys, schema, nesting)#462
DavRodSwede wants to merge 1 commit into
docker:mainfrom
DavRodSwede:feat/gateway-config-for-eval

Conversation

@DavRodSwede
Copy link
Copy Markdown

Problem

Environment and command templates for MCP servers (from OCI/catalog metadata) often use flat placeholders such as {{API_TOKEN}}. With the current Configuration.Find behavior, the map passed to pkg/eval only exposes profile fields under a single top-level key (the canonical server name). Flat placeholders then resolve empty, and docker run may miss expected -e values.

Some stored configs use a JSON-schema-like shape (type / properties); those values are not visible at the top level of the eval map either.

Even when flat keys and properties are handled, real profile JSON may still store:

  • a nested object under the server name, e.g. { "my-server": { "TOKEN": "x" } }, or
  • a single key named like my-server.TOKEN.

Templates that use dig("server.KEY", config) (and flat {{TOKEN}}) need a consistent eval map; without normalisation, one style works and the other does not.

Why

The eval map shape assumed one access pattern ({{serverName.key}}), but profile JSON and template authors commonly assume root-level keys for secrets and settings. Different tools and CLI flows persist config in different shapes; the gateway should normalise once at eval time instead of pushing complexity to every template or user edit.

What we want

  • Flat {{KEY}} works when the profile stores KEY at the per-server level.
  • Dotted-style templates that need {{canonicalName.key}} keep working.
  • Schema-shaped blobs expose properties.* as flat keys for eval.
  • Nested { serverName: { K: V } } promotes K to the top level (without losing the nested map where templates expect it).
  • Keys of the form canonical.K also populate top-level K when missing.

How

  • Add configForEval(serverName) to build the map passed to eval.
  • Merge flat keys at the top of that map and keep map[canonicalName] = perServerConfig for dotted lookups.
  • Add flattenProfileConfigForEval to unwrap properties when the config looks like a JSON-schema object.
  • Find uses Config: c.configForEval(serverName) instead of wrapping only c.config[canonical].
  • promoteNestedServerConfig — if per[canonical] or per[serverName] is a map, merge its entries to the top level.
  • aliasPrefixedConfigKeys — for prefix canonical., copy canonical.SUFFIX to SUFFIX when SUFFIX is not already set.
  • Call both from configForEval after flattenProfileConfigForEval.

Testing

go test ./pkg/gateway/...

Local validation: go test -short ./... in a Linux environment with isolated HOME (full suite may require the Docker MCP CLI plugin).

…a, nesting)

Build the map passed to pkg/eval so catalog/OCI env and command templates can use
flat {{KEY}} placeholders as well as dotted / dig() paths.

- Add configForEval(serverName) and use it from Find() for ServerConfig.Config.
- Merge per-server flat keys at the root of the eval map; keep the nested map
  under the canonical server name for {{server.key}} and dig("server.KEY", cfg).
- flattenProfileConfigForEval unwraps JSON-schema-shaped objects (properties).
- promoteNestedServerConfig lifts { serverName: { K: V } } entries to the top.
- aliasPrefixedConfigKeys copies canonical.SUFFIX to SUFFIX when absent.

Validated with: go test -short ./...

Made-with: Cursor
@DavRodSwede DavRodSwede requested a review from a team as a code owner April 1, 2026 16:40
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.

1 participant