-
Notifications
You must be signed in to change notification settings - Fork 371
spec(mcp-gateway): allow opentelemetry headers as name=value string (v1.12.0) #24869
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -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 | ||||||||||||||
|
Comment on lines
+572
to
+574
|
||||||||||||||
| - 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 | |
| - Header names are case-insensitive for comparison, duplicate detection, and merging, consistent with HTTP field-name semantics; implementations SHOULD preserve the casing as provided when emitting requests or retaining source fidelity | |
| - Values may contain additional `=` characters; only the first `=` on each line acts as the name/value separator | |
| - Duplicate header names within a single string are determined case-insensitively; the last occurrence MUST take precedence |
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -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.", | ||||||||
|
||||||||
| "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.", | |
| "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.", | |
| "default": {}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
opentelemetry.headersschema change removed the previousdefault: {}annotation. If the published schema is consumed by generators/docs that use defaults, consider adding"default": {}at theheadersproperty level to preserve prior behavior and match other object properties in the schema.