Skip to content

Conversation

@BrandonShar
Copy link

@BrandonShar BrandonShar commented Oct 28, 2025

Description

As part of supporting OpenAI's Apps SDK, the underlying MCP python sdk added support for meta in tool call payloads in v1.19.0.

This PR modifies the ToolResult object to additionally support the meta field. It makes the same change to CachedToolResult to support the caching middleware and the local CallToolResult dataclass in the client.

It also adds some additional testing for ToolResult and CachedToolResult

Contributors Checklist

  • My change helps close Support for OpenAI Apps SDK #2014
  • I have followed the repository's development workflow
  • I have tested my changes manually and by adding relevant tests
  • I have performed all required documentation updates

Review Checklist

  • I have self-reviewed my changes
  • My Pull Request is ready for review

Summary by CodeRabbit

  • New Features

    • Tools can now return optional metadata alongside content and structured data; clients receive metadata when provided.
    • Added an example demonstrating metadata in tool results.
  • Documentation

    • Docs updated to describe metadata inclusion in tool results and behavior notes.
  • Tests

    • Added and updated tests to verify metadata round-trips and various content/structured/meta combinations.
  • Chores

    • Raised minimum MCP dependency requirement.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 28, 2025

Walkthrough

FastMCP now carries optional metadata on tool results: ToolResult.meta is introduced and propagated through to_mcp_result, the client call path, and the server caching middleware; docs and an example echo tool were updated and tests adjusted accordingly.

Changes

Cohort / File(s) Change Summary
Core tool & client
src/fastmcp/tools/tool.py, src/fastmcp/client/client.py
Add optional `meta: dict[str, Any]
Server middleware (caching)
src/fastmcp/server/middleware/caching.py
CachableToolResult gains a meta field; wrap/unwrap updated to preserve meta during cache round-trips.
Documentation & example
docs/servers/tools.mdx, examples/tool_result_echo.py
Docs updated to include meta semantics in ToolResult; new example examples/tool_result_echo.py demonstrates returning content, structured_content, and meta.
Tests
tests/server/middleware/test_caching.py, tests/server/test_server_interactions.py, tests/tools/test_tool.py
Add/modify tests to assert meta is preserved in caching and call results; adjust snapshots to include meta; add TestToolResultCasting tests (appears duplicated in diff).
Project config
pyproject.toml
Bump mcp dependency minimum from >=1.17.0 to >=1.19.0 (upper bound unchanged).

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant FastMCP as FastMCP Server
    participant Tool
    participant Cache as Caching Middleware
    participant CallResult as CallToolResult

    Client->>FastMCP: call_tool(tool_name, args)
    FastMCP->>Tool: invoke tool(...)
    Tool->>Tool: produce ToolResult(content, structured_content, meta)
    Tool->>FastMCP: ToolResult.to_mcp_result()
    note right of FastMCP #efefef: when meta present → returns CallToolResult
    FastMCP->>Cache: wrap CallToolResult (preserve meta)
    Cache-->>FastMCP: cached CachableToolResult.unwrap() → CallToolResult (meta preserved)
    FastMCP->>Client: return CallToolResult(content, structured_content, data, meta)
Loading

Poem

🐰 A little meta hops into view,
Content echoed, structured too,
Through tools, cache, and client call,
It travels steady — not so small.
The Echo Server answers all!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Title Check ✅ Passed The pull request title "Add meta support to ToolResult" is clear, concise, and directly reflects the main objective of the changeset. The title accurately summarizes the primary modification—adding a meta field to ToolResult and related components (CachedToolResult and CallToolResult) across the codebase. The title is specific enough to convey the essential change without being overly verbose, and it aligns well with the actual file modifications and the stated PR objectives.
Linked Issues Check ✅ Passed The changes comprehensively implement the coding requirements for issue #2014. The PR adds meta support to ToolResult (src/fastmcp/tools/tool.py), extends it to CachedToolResult for middleware compatibility (src/fastmcp/server/middleware/caching.py), and updates the client's CallToolResult (src/fastmcp/client/client.py). Additionally, the MCP dependency is updated to v1.19.0 to access the meta field support added upstream, documentation is updated to reflect the new capability, and tests validate the functionality. These changes directly enable OpenAI Apps SDK compatibility by supporting the meta field in tool call payloads.
Out of Scope Changes Check ✅ Passed All file modifications in the pull request are directly related to implementing meta support for ToolResult and associated components. The changes include: updates to ToolResult, CachedToolResult, and CallToolResult to add the meta field; dependency version bump to access upstream meta support; documentation and example updates to reflect the feature; and test additions for the new functionality. No unrelated modifications or cleanup tasks outside the scope of adding meta support are present.
Description Check ✅ Passed The pull request description is well-structured and complete, addressing all required sections from the template. It provides clear context about the upstream MCP SDK v1.19.0 changes that added meta support for OpenAI's Apps SDK, explains the specific modifications to ToolResult, CachedToolResult, and CallToolResult, and documents the addition of tests and documentation updates. All items in both the Contributors Checklist and Review Checklist are marked as complete with checkmarks, fulfilling the template requirements.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Comment @coderabbitai help to get the list of available commands and usage tips.

@marvin-context-protocol marvin-context-protocol bot added the enhancement Improvement to existing functionality. For issues and smaller PR improvements. label Oct 28, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs/servers/tools.mdx (1)

621-631: Example not runnable: missing TextContent import.

Add the import so users can copy/paste.

Apply:

 from fastmcp.tools.tool import ToolResult
+from mcp.types import TextContent
📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4ea896c and 7949879.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (9)
  • docs/servers/tools.mdx (2 hunks)
  • examples/tool_result_echo.py (1 hunks)
  • pyproject.toml (1 hunks)
  • src/fastmcp/client/client.py (2 hunks)
  • src/fastmcp/server/middleware/caching.py (1 hunks)
  • src/fastmcp/tools/tool.py (3 hunks)
  • tests/server/middleware/test_caching.py (2 hunks)
  • tests/server/test_server_interactions.py (1 hunks)
  • tests/tools/test_tool.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
src/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Use Python ≥ 3.10 and provide full type annotations for library code

Files:

  • src/fastmcp/client/client.py
  • src/fastmcp/server/middleware/caching.py
  • src/fastmcp/tools/tool.py
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Never use bare except; always catch specific exception types

Files:

  • src/fastmcp/client/client.py
  • tests/server/middleware/test_caching.py
  • src/fastmcp/server/middleware/caching.py
  • tests/tools/test_tool.py
  • src/fastmcp/tools/tool.py
  • examples/tool_result_echo.py
  • tests/server/test_server_interactions.py
docs/**/*.mdx

📄 CodeRabbit inference engine (docs/.cursor/rules/mintlify.mdc)

docs/**/*.mdx: Use clear, direct language appropriate for technical audiences
Write instructions and procedures in second person ("you")
Use active voice over passive voice
Use present tense for current states and future tense for outcomes
Maintain consistent terminology across the documentation
Keep sentences concise while preserving necessary context
Use parallel structure in lists, headings, and procedures
Lead with the most important information (inverted pyramid)
Use progressive disclosure: basic concepts before advanced ones
Break complex procedures into numbered steps
Include prerequisites and context before instructions
Provide expected outcomes for each major step
End sections with next steps or related information
Use descriptive, keyword-rich headings for navigation and SEO
Focus on user goals and outcomes rather than system features
Anticipate common questions and address them proactively
Include troubleshooting for likely failure points
Offer multiple pathways when appropriate (beginner vs advanced) and provide an opinionated recommended path
Use for supplementary information that supports the main content
Use for expert advice, shortcuts, or best practices
Use for critical cautions, breaking changes, or destructive actions
Use for neutral background or contextual information
Use to confirm success or completion
Provide single code examples using fenced code blocks with language (and filename when relevant)
Use to present the same concept in multiple languages
For API docs, use to show requests
For API docs, use to show responses
Use and to document procedures and sequential instructions
Use and for platform-specific or alternative approaches
Use / for supplementary content that might interrupt flow
In API docs, use for parameters (path, body, query, header) with type and required/default as appropria...

Files:

  • docs/servers/tools.mdx
docs/**/*.{md,mdx}

📄 CodeRabbit inference engine (AGENTS.md)

docs/**/*.{md,mdx}: Documentation code examples should be explained before the code and be fully runnable, including imports
Use clear headers with logical H2/H3 hierarchy to form navigation
Write user-focused content that motivates the why before the how
Prefer prose for important information over code comments in docs

Files:

  • docs/servers/tools.mdx
**/*.{md,mdx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{md,mdx}: Be brief and to the point in written materials; avoid regurgitating obvious code details
Avoid defensive constructions like "This isn't X" or "Not just X, but Y"; state what it is directly

Files:

  • docs/servers/tools.mdx
tests/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

tests/**/*.py: Tests must be atomic, self-contained, and cover a single functionality
Use pytest parameterization for multiple examples of the same functionality
Use separate tests for distinct pieces of functionality
Always put imports at the top of test files; do not import inside test bodies
Do not add @pytest.mark.asyncio; asyncio_mode = "auto" is set globally
Prefer in-memory transport for tests; use HTTP transport only when explicitly testing networking
For slow/long-running tests, mark them as integration or optimize (default timeout is 5s)
In tests, use # type: ignore[attr-defined] for MCP results instead of type assertions

Files:

  • tests/server/middleware/test_caching.py
  • tests/tools/test_tool.py
  • tests/server/test_server_interactions.py
🧬 Code graph analysis (7)
src/fastmcp/client/client.py (1)
src/fastmcp/contrib/bulk_tool_caller/bulk_tool_caller.py (2)
  • CallToolRequestResult (25-48)
  • from_call_tool_result (37-48)
tests/server/middleware/test_caching.py (2)
src/fastmcp/server/middleware/caching.py (5)
  • CachableToolResult (63-81)
  • wrap (52-53)
  • wrap (69-74)
  • unwrap (56-60)
  • unwrap (76-81)
src/fastmcp/tools/tool.py (1)
  • ToolResult (66-112)
src/fastmcp/server/middleware/caching.py (1)
src/fastmcp/tools/tool.py (1)
  • ToolResult (66-112)
tests/tools/test_tool.py (3)
src/fastmcp/client/client.py (1)
  • call_tool (865-934)
src/fastmcp/tools/tool.py (1)
  • ToolResult (66-112)
src/fastmcp/tools/tool_manager.py (1)
  • call_tool (153-172)
src/fastmcp/tools/tool.py (3)
src/fastmcp/client/client.py (1)
  • CallToolResult (946-951)
src/fastmcp/contrib/mcp_mixin/mcp_mixin.py (1)
  • mcp_tool (25-52)
src/fastmcp/contrib/bulk_tool_caller/bulk_tool_caller.py (1)
  • CallToolRequestResult (25-48)
examples/tool_result_echo.py (1)
src/fastmcp/tools/tool.py (1)
  • ToolResult (66-112)
tests/server/test_server_interactions.py (2)
tests/contrib/test_mcp_mixin.py (2)
  • test_tool_with_title_and_meta (257-279)
  • MyToolWithMeta (263-269)
tests/server/test_server.py (1)
  • test_tool_decorator_with_meta (434-448)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Run tests with lowest-direct dependencies
  • GitHub Check: Run tests: Python 3.10 on windows-latest
🔇 Additional comments (11)
src/fastmcp/server/middleware/caching.py (2)

66-75: Meta preserved in cache wrapper. LGTM.


78-81: Unwrap returns ToolResult with meta. LGTM.

tests/server/middleware/test_caching.py (2)

26-30: New import for CachableToolResult — OK.


511-523: Round‑trip test for meta/content/structured_content — OK.

tests/server/test_server_interactions.py (1)

1182-1183: Snapshot updated to include meta=None — OK.

Keeps equality stable after dataclass change.

src/fastmcp/client/client.py (1)

931-931: Code change verified—no issues found.

The script confirms that result.meta is available in the installed MCP SDK's CallToolResult model. The code correctly accesses the field without errors. The original review's approval stands.

pyproject.toml (1)

10-10: Constraint is correctly configured in pyproject.toml and uv.lock, but runtime mcp 1.16.0 violates the ≥1.19.0 floor.

What's correct:

  • pyproject.toml pins mcp>=1.19.0,<2.0.0 (line 10)
  • uv.lock resolves to mcp 1.19.0
  • CI matrix includes run_tests_lowest_direct job that enforces floor version (Python 3.10 via uv sync --resolution lowest-direct)
  • Both ubuntu-latest and windows-latest tested

Critical gap:
Runtime resolved to mcp 1.16.0, which violates the constraint and risks CallToolResult.meta attribute mismatches. Verify that:

  • Deployment environments use uv.lock or respect pyproject.toml constraints
  • No cached/stale environments are bypassing the floor version
  • All dependency resolution (pip, poetry, uv) respects the ≥1.19.0 constraint
examples/tool_result_echo.py (1)

1-21: LGTM! Clear demonstration of the new meta field.

This example effectively demonstrates the new meta support in ToolResult. The usage of all three fields (content, structured_content, and meta) clearly illustrates the intended API for users.

src/fastmcp/tools/tool.py (3)

19-19: LGTM! Necessary import for meta support.

The CallToolResult import from mcp.types is required for returning tool results with metadata, aligning with the MCP SDK v1.19.0 changes.


67-79: LGTM! Proper parameter addition and storage.

The meta parameter is correctly added with appropriate type annotations (dict[str, Any] | None) and default value (None), ensuring backwards compatibility. The storage on self.meta is straightforward and correctly typed.


99-112: LGTM! Correct implementation of meta support.

The to_mcp_result method correctly handles the new meta field:

  • When meta is present, returns a CallToolResult with all three fields, using the correct MCP SDK conventions (structuredContent in camelCase, _meta with underscore prefix)
  • Falls back to existing behavior when meta is None
  • Return type annotation properly reflects the new CallToolResult option

The logic correctly prioritizes meta handling and maintains backwards compatibility.

Comment on lines +635 to +637
- You control exactly what content, structured data, and metadata is sent
- Output schemas are optional - structured content can be provided without a schema
- Clients receive both traditional content blocks and structured data
- Clients receive traditional content blocks, structured data, and metadata
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Clarify meta constraints and size guidance.

Add a brief warning: JSON-serializable only; keep small to avoid bloating responses/cache.

Apply:

 - Clients receive traditional content blocks, structured data, and metadata
+ - Clients receive traditional content blocks, structured data, and metadata
+
+<Warning>
+Keep `meta` JSON‑serializable and small (a few KB). Large metadata increases latency and may be skipped by caches.
+</Warning>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- You control exactly what content, structured data, and metadata is sent
- Output schemas are optional - structured content can be provided without a schema
- Clients receive both traditional content blocks and structured data
- Clients receive traditional content blocks, structured data, and metadata
- You control exactly what content, structured data, and metadata is sent
- Output schemas are optional - structured content can be provided without a schema
- Clients receive traditional content blocks, structured data, and metadata
<Warning>
Keep `meta` JSON‑serializable and small (a few KB). Large metadata increases latency and may be skipped by caches.
</Warning>
🤖 Prompt for AI Agents
In docs/servers/tools.mdx around lines 635 to 637, add a concise warning
clarifying that metadata must be JSON-serializable and should be kept small to
avoid bloating responses and caches; update the three bullet points by appending
or inserting a short parenthetical note such as “(JSON-serializable only; keep
small to avoid bloating responses/cache)” so readers know the constraint and
size guidance.

class CallToolResult:
content: list[mcp.types.ContentBlock]
structured_content: dict[str, Any] | None
meta: dict[str, Any] | None
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Dataclass extended with meta — update downstream extenders.

Classes extending/deriving from CallToolResult should propagate structured_content and meta. Example fix for bulk caller:

 class CallToolRequestResult(CallToolResult):
@@
     def from_call_tool_result(
         cls, result: CallToolResult, tool: str, arguments: dict[str, Any]
     ) -> "CallToolRequestResult":
         return cls(
             tool=tool,
             arguments=arguments,
-            isError=result.isError,
-            content=result.content,
+            isError=result.is_error,
+            content=result.content,
+            structured_content=result.structured_content,
+            meta=result.meta,
         )

Search for similar helpers to update:


🏁 Script executed:

#!/bin/bash
rg -nP 'from_call_tool_result|class\s+CallToolResult|result\.(structuredContent|meta)\b' -C2

Length of output: 5210


🏁 Script executed:

#!/bin/bash
# View the implementation of from_call_tool_result
cat src/fastmcp/contrib/bulk_tool_caller/bulk_tool_caller.py | head -60

Length of output: 1693


🏁 Script executed:

#!/bin/bash
# View the CallToolResult dataclass definition
sed -n '945,960p' src/fastmcp/client/client.py

Length of output: 200


Update CallToolRequestResult.from_call_tool_result() to propagate all fields.

The method currently attempts to access result.isError (which doesn't exist) and fails to propagate structured_content and meta. Fix:

 @classmethod
 def from_call_tool_result(
     cls, result: CallToolResult, tool: str, arguments: dict[str, Any]
 ) -> "CallToolRequestResult":
     """
     Create a CallToolRequestResult from a CallToolResult.
     """
     return cls(
         tool=tool,
         arguments=arguments,
-        isError=result.isError,
+        is_error=result.is_error,
         content=result.content,
+        structured_content=result.structured_content,
+        meta=result.meta,
     )

Location: src/fastmcp/contrib/bulk_tool_caller/bulk_tool_caller.py lines 37–48

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/fastmcp/client/client.py around line 949, update
CallToolRequestResult.from_call_tool_result to stop referencing the non-existent
result.isError and instead propagate the actual fields from the incoming result:
use result.error (or set is_error = bool(result.error)) for error state, and
copy result.structured_content and result.meta into the returned
CallToolRequestResult object so all fields are preserved.

Comment on lines +1408 to +1470
class TestToolResultCasting:
@pytest.fixture
async def client(self):
from fastmcp import FastMCP
from fastmcp.client import Client

mcp = FastMCP()

@mcp.tool
def test_tool(
unstructured: str | None = None,
structured: dict[str, Any] | None = None,
meta: dict[str, Any] | None = None,
):
return ToolResult(
content=unstructured,
structured_content=structured,
meta=meta,
)

async with Client(mcp) as client:
yield client

async def test_only_unstructured_content(self, client):
result = await client.call_tool("test_tool", {"unstructured": "test data"})

assert result.content[0].type == "text"
assert result.content[0].text == "test data"
assert result.structured_content is None
assert result.meta is None

async def test_neither_unstructured_or_structured_content(self, client):
from fastmcp.exceptions import ToolError

with pytest.raises(ToolError):
await client.call_tool("test_tool", {})

async def test_structured_and_unstructured_content(self, client):
result = await client.call_tool(
"test_tool",
{"unstructured": "test data", "structured": {"data_type": "test"}},
)

assert result.content[0].type == "text"
assert result.content[0].text == "test data"
assert result.structured_content == {"data_type": "test"}
assert result.meta is None

async def test_structured_unstructured_and_meta_content(self, client):
result = await client.call_tool(
"test_tool",
{
"unstructured": "test data",
"structured": {"data_type": "test"},
"meta": {"some": "metadata"},
},
)

assert result.content[0].type == "text"
assert result.content[0].text == "test data"
assert result.structured_content == {"data_type": "test"}
assert result.meta == {"some": "metadata"}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Move fixture imports to top of file (tests guideline).

Avoid imports inside tests/fixtures.

Apply:

-from fastmcp import FastMCP
-from fastmcp.client import Client
+from fastmcp import FastMCP
+from fastmcp.client import Client

at the file top, then remove the same lines from the client fixture.

Ensure no duplicate TestToolResultCasting classes exist:


🏁 Script executed:

#!/bin/bash
rg -n "class\s+TestToolResultCasting\b" -C1 tests

Length of output: 139




🏁 Script executed:

#!/bin/bash
# Check top 30 lines for imports
head -30 tests/tools/test_tool.py | grep -n "from fastmcp import\|from fastmcp.client import"

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check the fixture to confirm imports still exist inside it
sed -n '1409,1430p' tests/tools/test_tool.py

Length of output: 576



---

🏁 Script executed:

```shell
#!/bin/bash
# Check the actual imports at the top of the test file
head -50 tests/tools/test_tool.py

Length of output: 1545


Move fixture imports to file top per guideline.

The imports from fastmcp import FastMCP and from fastmcp.client import Client are inside the client fixture (lines 1410–1411) and should be at the file top. Add them to the import block at the beginning of tests/tools/test_tool.py, then remove them from the fixture.

🤖 Prompt for AI Agents
In tests/tools/test_tool.py around lines 1408 to 1470, the imports "from fastmcp
import FastMCP" and "from fastmcp.client import Client" are currently inside the
async client fixture; move those two import statements to the top import block
of the file (alongside other imports) and remove them from inside the fixture so
the fixture uses the top-level imports instead.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7949879 and d291499.

📒 Files selected for processing (1)
  • examples/tool_result_echo.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Never use bare except; always catch specific exception types

Files:

  • examples/tool_result_echo.py
🧬 Code graph analysis (1)
examples/tool_result_echo.py (2)
src/fastmcp/server/server.py (1)
  • FastMCP (148-2693)
src/fastmcp/tools/tool.py (1)
  • ToolResult (66-112)
🔇 Additional comments (1)
examples/tool_result_echo.py (1)

1-8: LGTM!

The imports are appropriate for demonstrating the new meta feature in ToolResult.

Comment on lines +18 to +22
@mcp.tool
def echo(text: str) -> ToolResult:
return ToolResult(
content=text, structured_content=EchoData(data=text), meta={"some": "metadata"}
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider adding documentation to enhance the example's educational value.

While the implementation correctly demonstrates the new meta feature, adding documentation would help users understand when and why to use it:

  1. Add a docstring to the echo function explaining what the tool does and the purpose of the meta field
  2. Consider using a more realistic example for the meta content (e.g., {"timestamp": "...", "source": "..."}) to illustrate typical use cases
  3. Add a if __name__ == "__main__": block showing how to run the server, if that's the convention for examples in this project

Example enhancement:

 @mcp.tool
 def echo(text: str) -> ToolResult:
+    """
+    Echo the input text back to the caller.
+    
+    Demonstrates ToolResult with content, structured_content, and meta fields.
+    The meta field can carry additional metadata about the tool execution
+    (e.g., timestamps, tracing info, etc.) for Apps SDK integration.
+    """
     return ToolResult(
-        content=text, structured_content=EchoData(data=text), meta={"some": "metadata"}
+        content=text,
+        structured_content=EchoData(data=text),
+        meta={"source": "echo_tool", "version": "1.0"}
     )

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

Labels

enhancement Improvement to existing functionality. For issues and smaller PR improvements.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support for OpenAI Apps SDK

1 participant