anthropics / anthropics/claude-agent-sdk-python

Feature Request: Expose MCP `_meta` field in ToolResultBlock for handler-only data

Đang mở
#407 0 bình luận 4 reaction 0 người được giao Xem trên GitHub
enhancement
Ngôn ngữ chính
Python
Star
8.1k
Fork
1.3k
Merge trung bình
2 ngày 31 phút
Pull request đã merge (30 ngày)
1

Mô tả

## The Ask

Provide a return path from MCP tools to event handlers that **does not enter model context**.

MCP's `_meta` field is designed for exactly this. Exposing it in `ToolResultBlock` would solve it.

## Problem

MCP tools often need to return two types of data:

| Data Type | Destination | Example |
|-----------|-------------|---------|
| **For model** | Model context | "Found 3 matching records" |
| **For UI/handlers** | Event handlers only | Record IDs, metadata, pagination cursors |

Currently, **everything in the tool return enters model context**. There's no way to say "this part is for handlers, not the model."

The only options today:

| Approach | Reaches Handlers | Enters Model Context |
|----------|------------------|----------------------|
| Put in `content` | ✓ | ✓ (unwanted) |
| Put in `_meta` | ✗ (stripped by SDK) | ✗ |
| Build custom callback | ✓ | ✗ |

To avoid polluting model context, we're forced to build out-of-band callback infrastructure for each tool that needs UI-only data.

## What We Have To Do Today

```python
# 1. Define a notifier class
class DataNotifier:
def __init__(self):
self._callback = None
def set_callback(self, cb):
self._callback = cb
def notify(self, data):
if self._callback:
self._callback(data)

# 2. Create module-level singleton
_notifier = DataNotifier()

# 3. Tool fires callback BEFORE return (before SDK processes)
async def my_tool(args):
result = do_work(args)
_notifier.notify(result["ui_data"]) # Side-channel to handler
return {"content": [{"type": "text", "text": "Done"}]}

# 4. Wire callback during app initialization
notifier.set_callback(handler.on_ui_data)

# 5. Handler receives via callback
def on_ui_data(self, data):
self.panel.update(data)
```

This pattern must be repeated for every tool that needs handler-only data.

## Why Not Just Use `content`?

We can put UI data in `content` and parse it in handlers. But:

1. **Token waste** - Model receives data it doesn't need
2. **Context pollution** - Model sees IDs, cursors, metadata meant for UI
3. **Semantic confusion** - Model may try to interpret UI-specific data structures

MCP designed `_meta` specifically for "hidden data for client applications only, not visible to the model."

## Proposed Solution

Expose `_meta` in `ToolResultBlock`:

```python
@dataclass
class ToolResultBlock:
tool_use_id: str
content: str | List[Dict[str, Any]] | None = None
is_error: bool | None = None
meta: Dict[str, Any] | None = None # NEW
```

Tools return:
```python
return {
"content": [{"type": "text", "text": "Recalled 3 observations"}],
"_meta": {"observation_ids": ["obs_1", "obs_2", "obs_3"]}
}
```

Handlers receive:
```python
def on_tool_complete(self, block: ToolResultBlock):
if block.meta:
self.highlight_items(block.meta["observation_ids"])
```

- **Model sees:** `"Recalled 3 observations"`
- **Handler gets:** `{"observation_ids": ["obs_1", "obs_2", "obs_3"]}`

## Use Cases

| Use Case | Model Sees | Handler Gets (via `_meta`) |
|----------|------------|----------------------------|
| Knowledge retrieval | "Found 3 relevant items" | Item IDs for UI highlighting |
| Search | "Results for 'query'" | Facets, pagination cursor, result IDs |
| File operations | "Uploaded file.txt" | Progress %, bytes transferred |
| Database query | Query results | Execution plan, timing stats |
| API calls | Response data | Rate limits, request ID, headers |

## Related

[anthropics/claude-code#9767](https://github.com/anthropics/claude-code/issues/9767) addresses MCP events/notifications not reaching the LLM for multi-turn state. This request is complementary - we need a channel that reaches event handlers but **bypasses** model context, for UI-only data that shouldn't consume tokens.

## Benefit

- Eliminates custom callback machinery for every UI-data use case
- Aligns SDK with MCP specification intent for `_meta`
- Natural pattern for synchronous tool calls
- Backwards compatible (new optional field)

Hướng dẫn đóng góp

Chưa lập chỉ mục được hướng dẫn đóng góp cho kho mã nguồn này

Đánh giá

Issue này chưa được đánh giá.

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.