From f1e14de10d124369ab2a879e01bb141d9506fd29 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 6 Apr 2026 11:44:15 +0000 Subject: [PATCH] Update opentelemetry headers to support name=value string format (v1.12.0) Agent-Logs-Url: https://github.com/github/gh-aw/sessions/b7329771-15bb-4d8d-a62a-3c8e0315d0e4 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .../schemas/mcp-gateway-config.schema.json | 21 +++-- .../src/content/docs/reference/mcp-gateway.md | 81 +++++++++++++++++-- .../schemas/mcp-gateway-config.schema.json | 21 +++-- 3 files changed, 106 insertions(+), 17 deletions(-) diff --git a/docs/public/schemas/mcp-gateway-config.schema.json b/docs/public/schemas/mcp-gateway-config.schema.json index 65aea1d0995..3581a6cd572 100644 --- a/docs/public/schemas/mcp-gateway-config.schema.json +++ b/docs/public/schemas/mcp-gateway-config.schema.json @@ -298,12 +298,21 @@ "minLength": 1 }, "headers": { - "type": "object", - "description": "Additional HTTP headers sent with every OTLP export request (e.g., for authentication). Values may contain variable expressions using '${VARIABLE_NAME}' syntax.", - "additionalProperties": { - "type": "string" - }, - "default": {} + "description": "Additional HTTP headers sent with every OTLP export request (e.g., for authentication). Accepts either an object mapping header names to values, or a multi-line string where each line uses 'name=value' syntax (splitting on the first '=' character). Values may contain variable expressions using '${VARIABLE_NAME}' syntax.", + "oneOf": [ + { + "type": "object", + "description": "Object form: keys are header names, values are header values.", + "additionalProperties": { + "type": "string" + } + }, + { + "type": "string", + "description": "String form: each line is 'name=value'. Lines not containing '=' are ignored. Leading and trailing whitespace on names and values is trimmed.", + "minLength": 1 + } + ] }, "traceId": { "type": "string", diff --git a/docs/src/content/docs/reference/mcp-gateway.md b/docs/src/content/docs/reference/mcp-gateway.md index 555323e8eb1..2b4c438997b 100644 --- a/docs/src/content/docs/reference/mcp-gateway.md +++ b/docs/src/content/docs/reference/mcp-gateway.md @@ -7,7 +7,7 @@ sidebar: # MCP Gateway Specification -**Version**: 1.11.0 +**Version**: 1.12.0 **Status**: Draft Specification **Latest Version**: [mcp-gateway](/gh-aw/reference/mcp-gateway/) **JSON Schema**: [mcp-gateway-config.schema.json](/gh-aw/schemas/mcp-gateway-config.schema.json) @@ -458,12 +458,12 @@ The optional `opentelemetry` object in the gateway configuration enables the gat | Field | Type | Required | Description | |-------|------|----------|-------------| | `endpoint` | string | Yes (when `opentelemetry` is present) | OTLP/HTTP endpoint URL for the OpenTelemetry collector (e.g., `https://collector.example.com:4318/v1/traces`). MUST use HTTPS. Supports variable expressions. | -| `headers` | object | No | Additional HTTP headers sent with every export request to the collector endpoint. Commonly used for authentication (e.g., `Authorization: "Bearer ${OTEL_TOKEN}"`). Values MAY contain variable expressions. | +| `headers` | object \| string | No | Additional HTTP headers sent with every export request to the collector endpoint. Commonly used for authentication (e.g., `Authorization: "Bearer ${OTEL_TOKEN}"`). Accepts either an **object** mapping header names to string values, or a **multi-line string** where each line uses `name=value` syntax. Values MAY contain variable expressions. See Section 4.1.3.6.1 for details. | | `traceId` | string | No | Parent trace ID for context propagation. When set, the gateway attaches all emitted spans as children of this trace, enabling correlation with an existing distributed trace. MUST be a 32-character lowercase hex string (128-bit W3C trace ID format). Supports variable expressions. | | `spanId` | string | No | Parent span ID for context propagation. When set together with `traceId`, the gateway sets this span as the direct parent of its root span. MUST be a 16-character lowercase hex string (64-bit W3C span ID format). Ignored when `traceId` is not set. Supports variable expressions. | | `serviceName` | string | No | Logical service name reported in the `service.name` resource attribute of all emitted spans. Identifies the gateway in the tracing backend. Defaults to `"mcp-gateway"` when not specified. | -**Configuration Example**: +**Configuration Example (object form)**: ```json { @@ -484,6 +484,23 @@ The optional `opentelemetry` object in the gateway configuration enables the gat } ``` +**Configuration Example (string form)**: + +```json +{ + "gateway": { + "port": 8080, + "domain": "localhost", + "apiKey": "${MCP_GATEWAY_API_KEY}", + "opentelemetry": { + "endpoint": "https://collector.example.com:4318/v1/traces", + "headers": "Authorization=Bearer ${OTEL_TOKEN}\nX-Custom-Header=value", + "serviceName": "my-mcp-gateway" + } + } +} +``` + **Tracing Behavior**: When `opentelemetry` is configured, the gateway MUST: @@ -513,8 +530,48 @@ The gateway MUST NOT fail to start if the OpenTelemetry collector endpoint is un - `spanId`, when provided, MUST be a 16-character lowercase hex string - `spanId` SHOULD only be set when `traceId` is also set; if `spanId` is provided without `traceId` the gateway SHOULD log a warning and ignore `spanId` - Export failures MUST NOT propagate errors to MCP clients +- When `headers` is provided as a string, the gateway MUST parse it as described in Section 4.1.3.6.1 + +**Compliance Test**: T-OTEL-001 through T-OTEL-012 (Section 10.1.10) + +##### 4.1.3.6.1 Headers String Format -**Compliance Test**: T-OTEL-001 through T-OTEL-009 (Section 10.1.10) +The `headers` field in the `opentelemetry` configuration MAY be specified as a multi-line string using HTTP header-like `name=value` syntax as an alternative to the object form. + +**Parsing Rules**: + +The implementation MUST apply the following rules when parsing a `headers` string: + +1. Split the string into lines using newline (`\n`) and/or carriage-return-newline (`\r\n`) as line separators +2. For each line, locate the first `=` character; the text before it is the header name and the text after it is the header value +3. Trim leading and trailing ASCII whitespace from both the header name and the header value +4. Lines that do not contain an `=` character MUST be ignored +5. Lines where the trimmed header name is empty MUST be ignored +6. Variable expressions (`${VARIABLE_NAME}`) in values MUST be expanded in the same manner as object-form values + +**Examples**: + +The following string form: + +``` +Authorization=Bearer ${OTEL_TOKEN} +X-Custom-Header=value +``` + +is semantically equivalent to the object form: + +```json +{ + "Authorization": "Bearer ${OTEL_TOKEN}", + "X-Custom-Header": "value" +} +``` + +**Notes**: + +- Header names are case-sensitive in the string form; implementations SHOULD preserve the casing as provided +- Values may contain additional `=` characters; only the first `=` on each line acts as the name/value separator +- Duplicate header names within a single string: the last occurrence MUST take precedence #### 4.1.3a Top-Level Configuration Fields @@ -1456,11 +1513,13 @@ A conforming implementation MUST pass the following test categories: - **T-OTEL-003**: Reject `opentelemetry` configuration with missing `endpoint` field - **T-OTEL-004**: Reject `opentelemetry` configuration with a non-HTTPS endpoint - **T-OTEL-005**: Span emitted for each MCP tool invocation with required attributes (`mcp.server`, `mcp.method`, `mcp.tool`, `http.status_code`) -- **T-OTEL-006**: Configured `headers` are sent with every OTLP export request +- **T-OTEL-006**: Configured `headers` (object form) are sent with every OTLP export request - **T-OTEL-007**: W3C `traceparent` context propagated when both `traceId` and `spanId` are configured - **T-OTEL-008**: Gateway generates random `spanId` in `traceparent` when only `traceId` is provided - **T-OTEL-009**: Export failure does not affect MCP request processing or gateway availability - **T-OTEL-010**: `serviceName` is reflected in `service.name` resource attribute of emitted spans +- **T-OTEL-011**: Configured `headers` (string form) are correctly parsed and sent with every OTLP export request +- **T-OTEL-012**: Lines without `=` in string-form `headers` are ignored; lines with empty trimmed name are ignored; duplicate header names use the last occurrence ### 10.2 Compliance Checklist @@ -1817,6 +1876,18 @@ Content-Type: application/json ## Change Log +### Version 1.12.0 (Draft) + +- **Changed**: `headers` field in `opentelemetry` configuration now accepts two forms (Section 4.1.3.6) + - **Object form** (existing): keys are header names, values are header values — fully backward-compatible + - **String form** (new): a multi-line string where each line uses `name=value` syntax, providing a concise alternative for simple header lists +- **Added**: Section 4.1.3.6.1 — Headers String Format + - Parsing rules for `name=value` lines: split on first `=`, trim whitespace, skip lines without `=` or with empty name, last occurrence wins for duplicate names + - Equivalence example showing string form vs object form + - Notes on case sensitivity and duplicate name handling +- **Added**: Compliance tests T-OTEL-011 and T-OTEL-012 for string-form header parsing +- **Updated**: JSON Schema `opentelemetryConfig.headers` changed from a plain `object` type to `oneOf [object, string]` + ### Version 1.11.0 (Draft) - **Added**: `opentelemetry` field to gateway configuration (Section 4.1.3, 4.1.3.6) diff --git a/pkg/workflow/schemas/mcp-gateway-config.schema.json b/pkg/workflow/schemas/mcp-gateway-config.schema.json index 96cf225cfec..6f7351f10a9 100644 --- a/pkg/workflow/schemas/mcp-gateway-config.schema.json +++ b/pkg/workflow/schemas/mcp-gateway-config.schema.json @@ -267,12 +267,21 @@ "minLength": 1 }, "headers": { - "type": "object", - "description": "Additional HTTP headers sent with every OTLP export request (e.g., for authentication). Values may contain variable expressions using '${VARIABLE_NAME}' syntax.", - "additionalProperties": { - "type": "string" - }, - "default": {} + "description": "Additional HTTP headers sent with every OTLP export request (e.g., for authentication). Accepts either an object mapping header names to values, or a multi-line string where each line uses 'name=value' syntax (splitting on the first '=' character). Values may contain variable expressions using '${VARIABLE_NAME}' syntax.", + "oneOf": [ + { + "type": "object", + "description": "Object form: keys are header names, values are header values.", + "additionalProperties": { + "type": "string" + } + }, + { + "type": "string", + "description": "String form: each line is 'name=value'. Lines not containing '=' are ignored. Leading and trailing whitespace on names and values is trimmed.", + "minLength": 1 + } + ] }, "traceId": { "type": "string",