Skip to content

MCP Gateway: Add upstream OIDC authentication to schema, spec, and compiler#23611

Merged
pelikhan merged 3 commits intomainfrom
copilot/add-upstream-authentication-oidc
Mar 31, 2026
Merged

MCP Gateway: Add upstream OIDC authentication to schema, spec, and compiler#23611
pelikhan merged 3 commits intomainfrom
copilot/add-upstream-authentication-oidc

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 31, 2026

The MCP Gateway supports GitHub Actions OIDC token injection for HTTP servers, but the schema rejected the auth field and the compiler had no support for it. This adds end-to-end support: schema validation, compiler codegen, spec documentation, and runtime validation.

Schema (mcp-gateway-config.schema.json)

  • Adds auth to httpServerConfig.properties (not stdioServerConfig)
  • auth.type: required, enum ["github-oidc"]
  • auth.audience: optional URI, defaults to server url if omitted

Compiler (pkg/workflow/mcp_config_custom.go + pkg/types/mcp.go)

  • MCPAuthConfig struct added to BaseMCPServerConfig (shared by parser and workflow packages)
  • getMCPConfig parses auth from map[string]any in the HTTP branch
  • auth rendered in JSON property order after headers, with nil guard
  • "auth" added to knownProperties so unknown-field validation doesn't reject it

Validation (pkg/workflow/mcp_config_validation.go)

  • "auth" added to knownToolFields so HTTP server configs with auth don't trigger the unknown-property error
  • Stdio servers with auth are rejected with a clear error message
  • HTTP auth.type is validated: required, non-empty string, and must be "github-oidc"

Documentation (docs/.../mcp-gateway.md)

  • New row in §4.1.2 server config fields table
  • New §7.6 covering OIDC behavior, caching semantics, header interaction, env vars, and validation rules

Tests

  • TestGetMCPConfigWithAuth: round-trip parsing of auth for HTTP servers (type+audience, type-only, absent)
  • TestRenderSharedMCPConfig_WithAuth: JSON rendering with/without auth, property order (type → url → headers → auth → tools)
  • New cases in TestValidateMCPConfigs: valid http auth, stdio rejection, missing auth.type, unsupported type, empty type
  • New cases in TestMCPServerConfigToMap: auth included when set, omitted when nil

Example frontmatter:

tools:
  mcp-servers:
    my-server:
      type: http
      url: "https://my-server.example.com/mcp"
      auth:
        type: github-oidc
        audience: "https://my-server.example.com"

Generated config:

"my-server": {
  "type": "http",
  "url": "https://my-server.example.com/mcp",
  "auth": {
    "type": "github-oidc",
    "audience": "https://my-server.example.com"
  }
}

… and compiler

- Add MCPAuthConfig struct and Auth field to BaseMCPServerConfig in pkg/types/mcp.go
- Implement GetAny method on MapToolConfig in pkg/workflow/mcp_config_types.go
- Update mcpServerConfigToMap to include auth field in pkg/workflow/tools_types.go
- Add auth field parsing and JSON rendering in pkg/workflow/mcp_config_custom.go
- Add auth property to httpServerConfig in both schema files
- Add auth row to Section 4.1.2 and new Section 7.6 in mcp-gateway.md

Closes #23566

Agent-Logs-Url: https://github.com/github/gh-aw/sessions/fe03ae40-ff9a-43ab-b882-da184a4adbcd

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Add upstream authentication (OIDC) to spec and schema MCP Gateway: Add upstream OIDC authentication to schema, spec, and compiler Mar 31, 2026
Copilot AI requested a review from pelikhan March 31, 2026 00:59
@pelikhan pelikhan marked this pull request as ready for review March 31, 2026 01:08
Copilot AI review requested due to automatic review settings March 31, 2026 01:08
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds end-to-end support for configuring upstream GitHub Actions OIDC authentication (auth) on HTTP MCP servers across schema validation, workflow compiler codegen, and reference documentation.

Changes:

  • Extend MCP gateway JSON schemas (compiler + published docs) to allow httpServerConfig.auth with type: github-oidc and optional audience.
  • Add MCPAuthConfig to shared MCP server types and render/parse auth in the workflow compiler output.
  • Document the new auth field and expected OIDC behavior in the MCP gateway reference docs.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
pkg/workflow/tools_types.go Includes auth when converting MCPServerConfig to a backward-compat map representation.
pkg/workflow/schemas/mcp-gateway-config.schema.json Adds auth object schema under httpServerConfig.
pkg/workflow/mcp_config_types.go Adds GetAny accessor to support extracting non-stringly typed fields like auth.
pkg/workflow/mcp_config_custom.go Adds auth to JSON property ordering, rendering, and HTTP-branch parsing; updates known-properties allowlist.
pkg/types/mcp.go Adds Auth *MCPAuthConfig to BaseMCPServerConfig and defines MCPAuthConfig.
docs/src/content/docs/reference/mcp-gateway.md Documents auth field and new OIDC upstream authentication section.
docs/public/schemas/mcp-gateway-config.schema.json Updates published schema to match the compiler schema changes.
Comments suppressed due to low confidence (2)

pkg/workflow/mcp_config_custom.go:593

  • auth is added to the global knownProperties set, but there’s no subsequent validation to ensure it’s only used on HTTP MCP servers. As a result, a stdio server config that includes auth will pass the unknown-field check and then have auth silently ignored in the stdio branch, which contradicts the spec/docs (“stdio servers with auth MUST be rejected”). Consider adding an explicit check after inferring/reading result.Type that returns a validation error when auth is present and result.Type != "http".
	// Validate known properties - fail if unknown properties are found
	knownProperties := map[string]bool{
		"type":           true,
		"mode":           true, // Added for MCPServerConfig struct
		"command":        true,
		"container":      true,
		"version":        true,
		"args":           true,
		"entrypoint":     true,
		"entrypointArgs": true,
		"mounts":         true,
		"env":            true,
		"proxy-args":     true,
		"url":            true,
		"headers":        true,
		"auth":           true,
		"registry":       true,
		"allowed":        true,
		"toolsets":       true, // Added for MCPServerConfig struct
	}

pkg/workflow/mcp_config_custom.go:722

  • The HTTP auth parsing is currently permissive: it silently drops auth if type is missing/empty, accepts any type string (no enum check), and ignores unknown fields inside the auth object. This can lead to workflows compiling successfully but producing gateway configs that fail schema validation or behave unexpectedly. Recommend treating presence of auth as a strict validation surface: require auth to be an object, require non-empty auth.type and reject unsupported values (e.g., anything other than github-oidc), validate/parse audience if present, and error on unknown keys in the auth map.
		if authVal, hasAuth := config.GetAny("auth"); hasAuth {
			if authMap, ok := authVal.(map[string]any); ok {
				authConfig := &types.MCPAuthConfig{}
				if authType, ok := authMap["type"].(string); ok {
					authConfig.Type = authType
				}
				if audience, ok := authMap["audience"].(string); ok {
					authConfig.Audience = audience
				}
				if authConfig.Type != "" {
					result.Auth = authConfig
				}
			} else if authCfg, ok := authVal.(*types.MCPAuthConfig); ok {
				result.Auth = authCfg
			}
		}

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 100 to 106
// JSON format - include tools field for MCP gateway tool filtering (all engines)
// For HTTP MCP with secrets in headers, env passthrough is needed
if len(headerSecrets) > 0 {
propertyOrder = []string{"type", "url", "headers", "tools", "env"}
propertyOrder = []string{"type", "url", "headers", "auth", "tools", "env"}
} else {
propertyOrder = []string{"type", "url", "headers", "tools"}
propertyOrder = []string{"type", "url", "headers", "auth", "tools"}
}
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are existing unit tests covering getMCPConfig behavior, but no tests exercise the new auth handling (parsing, type restrictions, and rendering order). Adding focused tests would help prevent regressions: (1) auth is accepted and round-trips for HTTP servers, (2) auth on stdio is rejected, (3) missing/unsupported auth.type and unknown auth fields produce clear errors, and (4) JSON rendering includes auth in the intended property order after headers.

This issue also appears in the following locations of the same file:

  • line 574
  • line 707

Copilot uses AI. Check for mistakes.
Comment on lines 133 to +142
// Add HTTP-specific fields
if config.URL != "" {
result["url"] = config.URL
}
if len(config.Headers) > 0 {
result["headers"] = config.Headers
}
if config.Auth != nil {
result["auth"] = config.Auth
}
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mcpServerConfigToMap now includes the new auth field, but the existing unit tests for this helper don’t cover it. Please add/extend a test case to assert that when config.Auth is set, the resulting map includes an auth entry with the expected serialized shape (and that it’s omitted when nil).

Copilot uses AI. Check for mistakes.
@github-actions
Copy link
Copy Markdown
Contributor

Hey @Copilot 👋 — great work adding end-to-end OIDC authentication support to the MCP Gateway! The schema, compiler, and documentation changes all hang together nicely and the PR description is thorough. One thing is missing before this is ready:

Add tests — the project has extensive MCP test coverage (mcp_config_compilation_test.go, mcp_http_headers_test.go, mcp_config_validation_test.go, mcp_gateway_config_test.go, and many others), but the PR includes no test changes. The new auth parsing in getMCPConfig and its JSON rendering in renderSharedMCPConfig both need coverage. There are also two gaps flagged by Copilot's own review that tests would surface:

  • auth on stdio servers is silently ignored instead of being rejected with a validation error (contradicts the spec in §7.6.3).
  • auth.type is not validated against the "github-oidc" enum — unknown types compile without error and produce an invalid gateway config.

If you'd like a hand, you can assign this prompt to your coding agent:

Add tests for the new MCP Gateway upstream OIDC auth feature in pkg/workflow/.
Follow the patterns in mcp_http_headers_test.go and mcp_config_compilation_test.go.

Cover the following scenarios:

1. Happy path – HTTP server with auth.type "github-oidc" and explicit audience:
   - Frontmatter parses correctly into MCPAuthConfig{Type:"github-oidc", Audience:"(example.com/redacted)"}
   - renderSharedMCPConfig emits valid JSON with "auth":{"type":"github-oidc","audience":"(example.com/redacted)"}

2. Happy path – HTTP server with auth.type "github-oidc" and no audience:
   - Rendered JSON omits the audience key entirely

3. Validation error – auth present on a stdio server:
   - getMCPConfig (or the validation layer) returns an error; the workflow does NOT compile
   - This requires adding a server-type check after getMCPConfig returns when result.Type != "http" and result.Auth != nil

4. Validation error – unsupported auth.type (e.g. "custom-oidc"):
   - getMCPConfig returns a descriptive error listing supported types
   - This requires adding an enum check in the HTTP branch of getMCPConfig

5. Validation error – auth is not an object (e.g. a string scalar):
   - getMCPConfig returns an error rather than silently ignoring the field

All tests should use table-driven style consistent with mcp_config_compilation_test.go.

Generated by Contribution Check ·

@pelikhan
Copy link
Copy Markdown
Collaborator

@copilot review comments

- Add auth field validation in mcp_config_validation.go:
  - Add 'auth' to knownToolFields (prevents spurious unknown-property errors)
  - HTTP servers: validate auth.type is present, non-empty, and 'github-oidc'
  - Stdio servers: reject auth with a clear error message
- Add TestGetMCPConfigWithAuth: round-trip parsing of auth for HTTP servers
- Add auth cases to TestValidateMCPConfigs: valid, stdio-rejection, missing type, unsupported type, empty type
- Add auth cases to TestMCPServerConfigToMap: set and nil auth
- Add TestRenderSharedMCPConfig_WithAuth: JSON rendering with/without auth, property order

Agent-Logs-Url: https://github.com/github/gh-aw/sessions/aab4c252-327f-4964-b814-cd5bb33643f1

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 31, 2026

@copilot review comments

Added tests and validation in commit f28f999:

Tests added:

  • TestGetMCPConfigWithAuth — round-trips auth (type + audience, type only, absent)
  • TestRenderSharedMCPConfig_WithAuth — JSON rendering with/without auth, verifies property order type → url → headers → auth → tools
  • TestValidateMCPConfigs — 6 new cases: valid http auth, stdio auth rejection, missing auth.type, unsupported type, empty type string
  • TestMCPServerConfigToMap — set and nil auth

Validation added (mcp_config_validation.go):

  • auth added to knownToolFields so it doesn't trigger the unknown-property error for valid HTTP configs
  • Stdio servers with auth are now rejected with a clear error message
  • HTTP auth.type is validated: required, non-empty string, must be "github-oidc"

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:

  • https://api.github.com/graphql
    • Triggering command: /usr/bin/gh /usr/bin/gh api graphql -f query=query($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } -f owner=github -f name=gh-aw (http block)
  • https://api.github.com/repos/actions/ai-inference/git/ref/tags/v1
    • Triggering command: /usr/bin/gh gh api /repos/actions/ai-inference/git/ref/tags/v1 --jq .object.sha npx prettier --write &#39;**/*.cjs&#39; &#39;**/*.ts&#39; &#39;**/*.json&#39; --ignore-path ../../../.pr**/*.json -tests /home/REDACTED/go/bin/sh (http block)
  • https://api.github.com/repos/actions/checkout/git/ref/tags/v3
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v3 --jq .object.sha .js&#39; --ignore-path .prettierignore --log-level=e!../../../pkg/workflow/js/**/*.json 5580402/b165/vet.cfg tions/setup/js/node_modules/.bin/node (http block)
  • https://api.github.com/repos/actions/checkout/git/ref/tags/v5
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha ath ../../../.pr**/*.json (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha &#34;prettier&#34; --write &#39;../../../**/*.json&#39; &#39;!../../../pkg/workflow/js/**/*.json&#39; --ignore-path ../.git (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha --show-toplevel 64/pkg/tool/linux_amd64/vet /usr/bin/git get .cfg 64/pkg/tool/linu--show-toplevel git rev-�� --show-toplevel 64/pkg/tool/linux_amd64/vet n-dir/node get .cfg 64/pkg/tool/linu--show-toplevel git (http block)
  • https://api.github.com/repos/actions/checkout/git/ref/tags/v6
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha -unreachable=false /tmp/go-build2665580402/b073/vet.cfg on rkflow/js/**/*.jgit (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha te &#39;../../../**/*.json&#39; &#39;!../../../pkg/workflow/js/**/*.json&#39; --ignore-path ../../../.prettieriggit -buildtags /opt/hostedtoolcache/go/1.25.0/x64/pkg/tool/linux_amd64/link -errorsas -ifaceassert -nilfunc /opt/hostedtoolcache/go/1.25.0/x64/pkg/tool/linux_amd64/link -o /tmp/go-build2665580402/b001/workflow.test -importcfg /home/REDACTED/node_modules/.bin/node -s -w -buildmode=exe node (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha --show-toplevel x_amd64/vet /usr/bin/git (http block)
  • https://api.github.com/repos/actions/github-script/git/ref/tags/v8
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha rite &#39;../../../**/*.json&#39; &#39;!../../../pkg/workflow/js/**/*.json&#39; --ignore-path /tmp/go-build2665580402/b228/vet.cfg /opt/hostedtoolcache/go/1.25.0/x64/pkg/tool/linux_amd64/vet (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha te &#39;../../../**/*.json&#39; &#39;!../../../pkg/workflow/js/**/*.json&#39; --ignore-path ../../../.prettieriggit k/gh-aw/gh-aw/pkg/workflow/import_schema_test.go /opt/hostedtoolcache/go/1.25.0/x64/pkg/tool/linux_amd64/vet (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha te &#39;../../../**/*.json&#39; &#39;!../../../pkg/workflow/js/**/*.json&#39; --ignore-path ../../../.prettieriggit /tmp/go-build2665580402/b264/vet.cfg /tmp/go-build2665580402/b001/workflow.test (http block)
  • https://api.github.com/repos/actions/setup-go/git/ref/tags/v4
    • Triggering command: /usr/bin/gh gh api /repos/actions/setup-go/git/ref/tags/v4 --jq .object.sha -bool -buildtags on rkflow/js/**/*.jgit -ifaceassert erignore /opt/hostedtoolcache/go/1.25.0/x64/pkg/tool/linux_amd64/vet -ato�� -bool -buildtags /home/REDACTED/work/gh-aw/gh-aw/actions/setup/node_modules/.bin/node -errorsas -ifaceassert -nilfunc node (http block)
  • https://api.github.com/repos/actions/setup-node/git/ref/tags/v4
    • Triggering command: /usr/bin/gh gh api /repos/actions/setup-node/git/ref/tags/v4 --jq .object.sha -bool -buildtags on rkflow/js/**/*.jgit -ifaceassert erignore /opt/hostedtoolcache/go/1.25.0/x64/pkg/tool/linux_amd64/vet -ato�� -bool -buildtags /home/REDACTED/work/gh-aw/gh-aw/actions/setup/js/node_modules/.bin/node -errorsas -ifaceassert -nilfunc node (http block)
  • https://api.github.com/repos/actions/upload-artifact/git/ref/tags/v4
    • Triggering command: /usr/bin/gh gh api /repos/actions/upload-artifact/git/ref/tags/v4 --jq .object.sha --local credential.helper de_modules/.bin/sh (http block)
  • https://api.github.com/repos/github/gh-aw-actions/git/ref/tags/v0.1.2
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw-actions/git/ref/tags/v0.1.2 --jq .object.sha -unreachable=false /tmp/go-build2665580402/b236/vet.cfg on rkflow/js/**/*.jgit (http block)
  • https://api.github.com/repos/github/gh-aw-actions/git/ref/tags/v1.0.0
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw-actions/git/ref/tags/v1.0.0 --jq .object.sha --local user.email ache/go/1.25.0/x64/pkg/tool/linux_amd64/vet (http block)
  • https://api.github.com/repos/github/gh-aw-actions/git/ref/tags/v1.2.3
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw-actions/git/ref/tags/v1.2.3 --jq .object.sha --local .cfg ache/go/1.25.0/x64/pkg/tool/linux_amd64/vet (http block)
  • https://api.github.com/repos/github/gh-aw/git/ref/tags/v0.47.4
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v0.47.4 --jq .object.sha --show-toplevel (http block)
  • https://api.github.com/repos/github/gh-aw/git/ref/tags/v1.0.0
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v1.0.0 --jq .object.sha ignore-path ../../../.prettierignore (http block)
  • https://api.github.com/repos/nonexistent/action/git/ref/tags/v999.999.999
    • Triggering command: /usr/bin/gh gh api /repos/nonexistent/action/git/ref/tags/v999.999.999 --jq .object.sha ignore-path ../../../.prettierignore (http block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI requested a review from pelikhan March 31, 2026 01:52
@pelikhan pelikhan merged commit 09d4ede into main Mar 31, 2026
83 of 84 checks passed
@pelikhan pelikhan deleted the copilot/add-upstream-authentication-oidc branch March 31, 2026 02:04
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.

MCP Gateway: Add upstream authentication (OIDC) to spec and schema

3 participants