HTTP Header Propagation¶
When running HolmesGPT as a server, HTTP headers from incoming requests can be forwarded to toolsets when they make outgoing API calls. This is useful for passing per-request authentication tokens, tenant identifiers, or other contextual headers through to backend services.
Header propagation is supported across all toolset types: MCP servers, HTTP connectors, custom (YAML) toolsets, and built-in Python toolsets.
Note
Header propagation is only available when running Holmes as a server (Helm deployment). It does not apply when using the CLI directly.
How It Works¶
- A client sends an HTTP request to the Holmes server (e.g.,
/api/investigate) - Holmes extracts non-sensitive headers from the request (blocking
Authorization,Cookie, andSet-Cookieby default) - The extracted headers are available as
request_contextduring tool execution - Toolsets that opt in render those templates using the request context and forward the resulting values to their tools at invocation time. Toolsets without the config key are unaffected.
Configuration¶
The config key is placed inside the config section of each toolset and accepts a dictionary of names mapped to Jinja2 template strings:
extra_headers-- for MCP servers, HTTP connectors, and Python toolsets (values become HTTP headers)- For custom (YAML) toolsets,
request_contextandenvare available directly in Jinja2 command/script templates — no extra config key needed
Templates can reference:
{{ request_context.headers['Header-Name'] }}-- a header from the incoming HTTP request (case-insensitive lookup){{ env.ENV_VAR }}-- an environment variable- Plain strings -- static values that don't need rendering
Toolset Examples¶
MCP Servers¶
Add to ~/.holmes/config.yaml:
Add to your Holmes Helm values:
Add to your generated_values.yaml:
See MCP Servers -- Dynamic Headers for the full MCP configuration reference.
HTTP Connectors¶
Add to ~/.holmes/config.yaml:
Add to your Holmes Helm values:
The rendered headers are merged into every outgoing request after the endpoint's own authentication headers, so they can override defaults when needed.
See HTTP Connectors for the full HTTP connector configuration reference.
Custom (YAML) Toolsets¶
YAML tool commands and scripts are Jinja2 templates. The variables request_context and env are available directly — no extra config key needed. Use request_context.headers['Header-Name'] to access incoming request headers and env.VAR_NAME to access environment variables.
See Custom Toolsets for the full YAML toolset reference.
Built-in Python Toolsets¶
Each built-in Python toolset decides individually whether to support extra_headers. Not all toolsets support it — only those whose request method renders extra_headers via render_header_templates() and merges the result into outgoing HTTP calls.
The following example shows how ServiceNow Tables, one toolset that supports header propagation, is configured:
Add to ~/.holmes/config.yaml:
Add to your Holmes Helm values:
additionalEnvVars:
- name: SERVICENOW_API_KEY
valueFrom:
secretKeyRef:
name: servicenow-credentials
key: api-key
toolsets:
servicenow/tables:
config:
extra_headers:
X-Correlation-Id: "{{ request_context.headers['X-Correlation-Id'] }}"
api_key: "{{ env.SERVICENOW_API_KEY }}"
api_url: "https://instance.service-now.com"
Add to your generated_values.yaml:
holmes:
additionalEnvVars:
- name: SERVICENOW_API_KEY
valueFrom:
secretKeyRef:
name: servicenow-credentials
key: api-key
toolsets:
servicenow/tables:
config:
extra_headers:
X-Correlation-Id: "{{ request_context.headers['X-Correlation-Id'] }}"
api_key: "{{ env.SERVICENOW_API_KEY }}"
api_url: "https://instance.service-now.com"
For a reference implementation showing how to add extra_headers support to a Python toolset, see servicenow_tables.py.
Sending Headers to Holmes¶
Include your custom headers alongside the normal request:
curl -X POST http://holmes-server/api/investigate \
-H "Content-Type: application/json" \
-H "X-Auth-Token: your-token-here" \
-H "X-Tenant-Id: tenant-42" \
-d '{"question": "Check system status"}'
Blocked Headers¶
By default, the following headers are not forwarded from the incoming request to the request_context:
AuthorizationCookieSet-Cookie
You can override this list with the HOLMES_PASSTHROUGH_BLOCKED_HEADERS environment variable (comma-separated, case-insensitive):
# Block only Authorization (allow cookies through)
export HOLMES_PASSTHROUGH_BLOCKED_HEADERS="authorization"
# Block additional headers
export HOLMES_PASSTHROUGH_BLOCKED_HEADERS="authorization,cookie,set-cookie,x-internal-only"
Precedence¶
When multiple header sources exist, later layers override earlier ones:
- Toolset's own authentication headers (e.g., API key, bearer token)
- LLM-provided headers (HTTP connector only, via the
headerstool parameter) extra_headers(rendered templates from theconfigsection)