Skip to content

Conversation

alexanderreiff
Copy link

@alexanderreiff alexanderreiff commented Oct 13, 2025

This PR allows resources to directly return TextResourceContents or BlobResourceContents instead of having it cast automatically by the lowlevel server.

Inspired by #1459, but for resources.

Motivation and Context

OpenAI's Apps SDK uses the _meta field of a read resource result representing a "widget" to configure Content Security Policy and other behaviors.

This use of _meta is supported by the protocol, but isn't implemented in the SDK.

In order to maximize discoverability and future change-abililty, I added the ability to directly return the two ResourceContents classes, which already supports the _meta field, rather than add additional tuple fields.

How Has This Been Tested?

Test suite additions and example snippets are provided. Running the example shows _meta in the response.

npx @modelcontextprotocol/inspector uv run examples/snippets/servers/resource_contents_direct.py
image image

Breaking Changes

N/A

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

N/A

alexanderreiff and others added 9 commits October 13, 2025 14:33
…d_resource handlers

Updated the low-level server's read_resource decorator to accept TextResourceContents
and BlobResourceContents objects directly, in addition to the existing ReadResourceContents.
This provides more flexibility for resource handlers to construct and return properly
typed ResourceContents objects with full control over all properties.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
…ctly

Updated FastMCP server and resource base classes to support returning
TextResourceContents and BlobResourceContents objects directly from
resource handlers, matching the low-level server functionality.

- Updated Resource.read() abstract method to accept ResourceContents types
- Modified FunctionResource to handle ResourceContents in wrapped functions
- Updated FastMCP server read_resource to pass through ResourceContents
- Updated Context.read_resource to match new return types

This provides FastMCP users with more control over resource properties
and maintains consistency with the low-level server API.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
…tionality

Added test coverage for the new feature allowing resources to return
TextResourceContents and BlobResourceContents objects directly:

Low-level server tests (test_read_resource_direct.py):
- Test direct TextResourceContents return
- Test direct BlobResourceContents return
- Test mixed direct and wrapped content
- Test multiple ResourceContents objects

FastMCP tests (test_resource_contents_direct.py):
- Test custom resources returning ResourceContents
- Test function resources returning ResourceContents
- Test resource templates with ResourceContents
- Test mixed traditional and direct resources

All tests verify proper handling and pass-through of ResourceContents
objects without wrapping them in ReadResourceContents.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Added example snippets demonstrating the main benefit of returning
ResourceContents objects directly - the ability to include metadata
via the _meta field:

- FastMCP example: Shows various metadata use cases including timestamps,
  versions, authorship, image metadata, and query execution details
- Low-level server example: Demonstrates metadata for documents, images,
  multi-part content, and code snippets

The examples emphasize that metadata is the key advantage of this feature,
allowing servers to provide rich contextual information about resources
that helps clients better understand and work with the content.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Updated imports in base.py and types.py to add ResourceContents types
to the existing mcp.types import rather than using a separate import
statement. This follows the existing pattern and keeps imports cleaner.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Corrected the examples to use the proper _meta field name as specified
in the MCP protocol, rather than the constructor parameter name 'meta'.
This ensures the metadata appears correctly when viewed in MCP Inspector.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Move ReadResourceContents import to top of file in lowlevel example
- Use union syntax (X | Y) instead of tuple in isinstance call
- Fix line length issue by breaking long function signature
- Add proper type annotations for consistency

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Fixed type narrowing issues in test files that were accessing attributes
on union types without proper isinstance checks. The FastMCP read_resource
method returns ReadResourceContents | TextResourceContents | BlobResourceContents,
requiring explicit type checking before accessing type-specific attributes.

Changes:
- Added proper type narrowing with isinstance() checks in all affected tests
- Fixed incorrect Resource base class usage in test files
- Corrected AnyUrl constructor usage in resource creation
- Updated lowlevel example to avoid delegation conflicts

All tests pass and pyright reports 0 errors.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Fixed datetime.UTC usage which is only available in Python 3.11+.
Replaced with datetime.timezone.utc for broader Python version compatibility.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
@alexanderreiff alexanderreiff marked this pull request as ready for review October 13, 2025 23:57
@alexanderreiff
Copy link
Author

@felixweinberger here is one more related to META Improvements milestone, for resources.

Similar to #1459 for tool call results.

@felixweinberger felixweinberger added this to the META Improvements milestone Oct 14, 2025
@felixweinberger felixweinberger added the needs maintainer action Potentially serious issue - needs proactive fix and maintainer attention label Oct 14, 2025
@BrandonShar
Copy link

I think this could be implemented the same way as #1463 by just exposing the meta field in the resource decorator instead of altering the return type.

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

Labels

needs maintainer action Potentially serious issue - needs proactive fix and maintainer attention

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants