Skip to content

Python: Propagate user-supplied _meta from function_invocation_kwargs to MCP …#5159

Open
Serjbory wants to merge 4 commits intomicrosoft:mainfrom
Serjbory:feature/mcp-meta-support
Open

Python: Propagate user-supplied _meta from function_invocation_kwargs to MCP …#5159
Serjbory wants to merge 4 commits intomicrosoft:mainfrom
Serjbory:feature/mcp-meta-support

Conversation

@Serjbory
Copy link
Copy Markdown

@Serjbory Serjbory commented Apr 8, 2026

…call_tool requests (#5158)

Motivation and Context

MCP servers can accept a _meta field alongside tool arguments in call_tool requests, enabling clients to pass request-level metadata such as correlation IDs, user locale, session info, and other context that servers may use for debugging, distributed tracing, or request-specific behavior.

Both OpenAI Agents SDK (PR #2375) and LangChain MCP Adapters (PR #468) have recently added _meta support, making this an expected capability across MCP client frameworks.

Description

Propagate user-supplied _meta from function_invocation_kwargs to MCP call_tool requests. The change is minimal (~4 lines in MCPTool.call_tool()):

  1. Extract _meta from incoming **kwargs via kwargs.pop("_meta", None) before filtering
  2. Add "_meta" to the existing filtered-kwargs exclusion set so it never leaks into tool arguments
  3. Pass the extracted dict to _inject_otel_into_mcp_meta(user_meta) instead of _inject_otel_into_mcp_meta() — user keys take precedence, OTel keys fill in non-conflicting slots

This uses the established function_invocation_kwargs mechanism — the same per-request injection pattern already used across 6+ samples for API keys, user IDs, and session metadata:

response = await agent.run(
    "Search for Python repos",
    function_invocation_kwargs={
        "_meta": {
            "correlation_id": "req-456",
            "session_id": "abc-123",
            "locale": "fr-FR",
        },
    },
)

No new public types, parameters, or constructor changes. Fully backward compatible — when _meta is not provided, behavior is identical to before.

Files changed:

  • python/packages/core/agent_framework/_mcp.py — extract and forward _meta in call_tool()
  • python/packages/core/tests/core/test_mcp.py — 9 new tests covering all edge cases

Test coverage:

  • _meta forwarded as protocol-level meta, excluded from tool arguments
  • User meta merged with OTel trace context; user keys win on conflicts
  • Backward compatibility when _meta is absent
  • Caller's dict not mutated by OTel injection
  • Empty _meta={} treated as no user meta
  • End-to-end flow through FunctionTool wrapper (as created by load_tools())
  • MCPStreamableHTTPTool override forwards _meta to super().call_tool()
  • Combined with header_provider without interference

Contribution Checklist

  • The code builds clean without any errors or warnings
  • The PR follows the Contribution Guidelines
  • All unit tests pass, and I have added new tests where possible
  • Is this a breaking change? If yes, add "[BREAKING]" prefix to the title of the PR.

@moonbox3 moonbox3 added the python label Apr 8, 2026
@github-actions github-actions bot changed the title Propagate user-supplied _meta from function_invocation_kwargs to MCP … Python: Propagate user-supplied _meta from function_invocation_kwargs to MCP … Apr 8, 2026
@moonbox3
Copy link
Copy Markdown
Contributor

moonbox3 commented Apr 8, 2026

Python Test Coverage

Python Test Coverage Report •
FileStmtsMissCoverMissing
packages/core/agent_framework
   _mcp.py6123095%153, 294, 354–355, 484, 546, 559, 561–564, 583–584, 597–600, 602–603, 607, 670–672, 1031, 1151, 1203–1204, 1207, 1225, 1678
TOTAL27035318588% 

Python Unit Test Overview

Tests Skipped Failures Errors Time
5398 20 💤 0 ❌ 0 🔥 1m 27s ⏱️

@Serjbory
Copy link
Copy Markdown
Author

hello @moonbox3 , @vincentkoc . Could you please review this PR and run @copilot review if possible (in order to resolve his remarks if needed)?

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

Propagates user-supplied MCP request metadata (_meta) provided via function_invocation_kwargs through to MCP tools/call requests, while keeping framework/runtime kwargs out of tool arguments and maintaining existing OpenTelemetry meta injection behavior.

Changes:

  • Update MCPTool.call_tool() to extract _meta from **kwargs, prevent it from leaking into tool arguments, and merge it with OTel-injected metadata.
  • Add unit tests validating _meta forwarding, merge/precedence behavior, non-mutation of caller dictionaries, and behavior through MCPStreamableHTTPTool/FunctionTool flows.

Reviewed changes

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

File Description
python/packages/core/agent_framework/_mcp.py Extracts and forwards user _meta as MCP request metadata and merges it with OTel context while filtering reserved kwargs from tool arguments.
python/packages/core/tests/core/test_mcp.py Adds tests covering _meta propagation, merge semantics, precedence, and integration via wrapper/HTTP tool paths.

…urate and use agnostic-propagator in tests
@Serjbory
Copy link
Copy Markdown
Author

thanks @eavanvalkenburg ! All comments were resolved

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants