Skip to content

fix: forward _meta to MCP tool calls and fix model_dump alias seriali…#1918

Merged
Unshure merged 2 commits into
strands-agents:mainfrom
mananpatel320:fix-mcp-meta-forwarding-3
Apr 6, 2026
Merged

fix: forward _meta to MCP tool calls and fix model_dump alias seriali…#1918
Unshure merged 2 commits into
strands-agents:mainfrom
mananpatel320:fix-mcp-meta-forwarding-3

Conversation

@mananpatel320

Copy link
Copy Markdown
Contributor

Description

MCPClient doesn't forward the _meta field to ClientSession.call_tool(), so custom metadata per the MCP
spec
never reaches the
server. Separately, the OpenTelemetry instrumentation in mcp_instrumentation.py uses model_dump()
instead of model_dump(by_alias=True), which serializes the Pydantic field as "meta" (Python name)
rather than "_meta" (wire name). This causes setdefault("_meta", {}) to create a new empty dict instead
of reusing the existing one, corrupting the outgoing payload.

This PR adds a meta parameter to call_tool_sync, call_tool_async, and _create_call_tool_coroutine that
gets forwarded to ClientSession.call_tool(meta=...), and fixes the instrumentation to use
model_dump(by_alias=True).

Resolves: #1916

Public API Changes

call_tool_sync and call_tool_async now accept an optional meta keyword argument:

python

Before: no way to pass _meta

result = mcp_client.call_tool_sync(
tool_use_id="id", name="my_tool", arguments={"key": "value"}
)

After: meta forwarded to the MCP server

result = mcp_client.call_tool_sync(
tool_use_id="id", name="my_tool", arguments={"key": "value"},
meta={"com.example/request_id": "abc-123"}
)

The meta parameter defaults to None, so this is fully backward compatible.

Related Issues

#1916

Type of Change

Bug fix

Testing

  • Updated existing unit test assertions to match the new meta=None kwarg in call_tool calls

  • Updated mock model_dump signatures to accept by_alias kwarg

  • Added unit tests for meta forwarding in both sync and async paths

  • Added unit test verifying instrumentation preserves existing _meta values

  • Added integration tests for call_tool_sync/call_tool_async with meta

  • Added integration test verifying instrumentation correctly sets _meta on outgoing requests

  • I ran hatch run prepare

Checklist

  • I have read the CONTRIBUTING document
  • I have added any necessary tests that prove my fix is effective or my feature works
  • I have updated the documentation accordingly
  • I have added an appropriate example to the documentation to outline the feature, or no new docs
    are needed
  • My changes generate no new warnings
  • Any dependent changes have been merged and published

@github-actions

Copy link
Copy Markdown
Contributor

Review Summary

Assessment: Approve

This PR correctly addresses both issues described in #1916: forwarding the meta parameter to MCP tool calls and fixing the model_dump(by_alias=True) serialization issue in instrumentation.

Review Notes
  • Implementation Quality: Changes are clean, well-documented with Google-style docstrings, and follow existing codebase patterns
  • Testing: Comprehensive unit tests and integration tests cover both sync and async paths, including meta preservation
  • Backward Compatibility: The meta=None default ensures existing code continues to work without modification
  • Minor Gap: The task-augmented execution path (experimental) does not forward meta - flagged as inline comment

Nice work on a thorough fix with good test coverage! 🎉

Comment thread tests/strands/tools/mcp/test_mcp_instrumentation.py Outdated
Comment thread tests_integ/mcp/test_mcp_client.py Outdated
Comment thread tests_integ/mcp/test_mcp_client.py
Unshure added a commit to Unshure/sdk-python that referenced this pull request Mar 20, 2026
- Add echo_meta tool to echo_server.py that returns _meta from request
  context, so integration tests can verify metadata reaches the server
- Update integration tests to use echo_meta and assert the server
  received the metadata, removing the spy-based approach
- Update unit test to verify the key name is '_meta' (alias) in the
  reconstructed params dict instead of checking inject positional args
@Unshure Unshure force-pushed the fix-mcp-meta-forwarding-3 branch from f46caa8 to 132ea33 Compare March 31, 2026 20:00
Unshure added a commit to mananpatel320/sdk-python that referenced this pull request Mar 31, 2026
- Add echo_meta tool to echo_server.py that returns _meta from request
  context, so integration tests can verify metadata reaches the server
- Update integration tests to use echo_meta and assert the server
  received the metadata, removing the spy-based approach
- Update unit test to verify the key name is '_meta' (alias) in the
  reconstructed params dict instead of checking inject positional args
@github-actions github-actions Bot added size/m and removed size/m labels Mar 31, 2026
@Unshure Unshure temporarily deployed to manual-approval March 31, 2026 20:00 — with GitHub Actions Inactive
@codecov

codecov Bot commented Mar 31, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Unshure added a commit to mananpatel320/sdk-python that referenced this pull request Mar 31, 2026
- Add echo_meta tool to echo_server.py that returns _meta from request
  context, so integration tests can verify metadata reaches the server
- Update integration tests to use echo_meta and assert the server
  received the metadata, removing the spy-based approach
- Update unit test to verify the key name is '_meta' (alias) in the
  reconstructed params dict instead of checking inject positional args
@Unshure Unshure force-pushed the fix-mcp-meta-forwarding-3 branch from 132ea33 to 709a924 Compare March 31, 2026 21:26
@github-actions github-actions Bot removed the size/m label Mar 31, 2026
Unshure added a commit to mananpatel320/sdk-python that referenced this pull request Apr 1, 2026
@Unshure Unshure force-pushed the fix-mcp-meta-forwarding-3 branch from 709a924 to 99f5d8b Compare April 1, 2026 14:59
@github-actions github-actions Bot added size/m and removed size/m labels Apr 1, 2026
@Unshure Unshure force-pushed the fix-mcp-meta-forwarding-3 branch from 99f5d8b to 3fb6359 Compare April 1, 2026 15:25
@github-actions github-actions Bot added size/m and removed size/m labels Apr 1, 2026
@Unshure Unshure temporarily deployed to manual-approval April 1, 2026 15:26 — with GitHub Actions Inactive
@Unshure Unshure enabled auto-merge (squash) April 1, 2026 17:51
@mkmeral

mkmeral commented Apr 3, 2026

Copy link
Copy Markdown
Contributor

/strands review

@github-actions

github-actions Bot commented Apr 3, 2026

Copy link
Copy Markdown
Contributor

Re-Review Summary

Assessment: Approve ✅

I've reviewed the new commit (3fb6359 - "fix: address review feedback on PR #1918").

Changes in Latest Commit

The instrumentation code was improved to properly handle None values:

# Before (setdefault doesn't handle explicit None)
meta = params_dict.setdefault("_meta", {})

# After (properly handles None values)
meta = params_dict.get("_meta") if params_dict.get("_meta") is not None else {}
params_dict["_meta"] = meta

This is an improvement because setdefault only uses the default when the key is missing, but the new code also handles the case where _meta exists but is explicitly None.

Verification Summary
Component Status
mcp_client.py meta parameter added and forwarded
mcp_instrumentation.py by_alias=True + None handling
Unit tests ✅ Comprehensive coverage
Integration tests echo_meta verifies end-to-end
Codecov ✅ 100% coverage on modified lines

The PR is ready to merge.

Comment thread src/strands/tools/mcp/mcp_client.py
@Unshure Unshure merged commit 1682a0c into strands-agents:main Apr 6, 2026
20 of 21 checks passed
agent-of-mkmeral added a commit to agent-of-mkmeral/sdk-python that referenced this pull request Apr 6, 2026
MCPClient's _create_call_tool_coroutine didn't forward the meta parameter
to _call_tool_as_task_and_poll_async when using task-augmented execution.
This meant that custom _meta per the MCP spec never reached the server for
tools using the task execution path, even though it worked correctly for
direct call_tool calls.

Changes:
- Pass meta from _create_call_tool_coroutine to _call_tool_as_task_and_poll_async
- Add meta parameter to _call_tool_as_task_and_poll_async signature
- Forward meta to session.experimental.call_tool_as_task()
- Add tests for meta forwarding in sync, async, and None meta paths

Follow-up from strands-agents#1918 per @mkmeral's review comment.
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.

[BUG] Strands MCPClient does not forward _meta to MCP tool calls + instrumentation corrupts _meta

4 participants