-
Notifications
You must be signed in to change notification settings - Fork 313
feat: support metadata in Python SDK #134
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Co-authored-by: idosal <[email protected]>
Deploying mcp-ui with
|
| Latest commit: |
b3d50a1
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://b9ab52d7.mcp-ui.pages.dev |
| Branch Preview URL: | https://copilot-fix-preferred-frame.mcp-ui.pages.dev |
Co-authored-by: idosal <[email protected]>
Co-authored-by: idosal <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR adds comprehensive metadata support to the Python SDK, enabling UI resources to include metadata like preferred-frame-size and initial-render-data. The implementation matches the TypeScript SDK's approach by automatically prefixing UI-specific metadata with mcpui.dev/ui- while allowing custom metadata to be provided alongside without prefixing.
Key changes:
- Added
uiMetadataandmetadataoptional fields toCreateUIResourceOptions - Implemented metadata processing with automatic UI prefix application
- Added 11 comprehensive test cases covering all metadata scenarios
Reviewed Changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
types.py |
Added UI metadata constants, keys, and optional metadata fields to CreateUIResourceOptions |
core.py |
Implemented _get_additional_resource_props() helper for metadata processing and integration |
test_metadata.py |
Added comprehensive test suite with 11 test cases for all metadata scenarios |
__init__.py |
Exported UIMetadataKey class for external use |
README.md |
Added extensive documentation section with metadata usage examples |
python_server_demo.py |
Updated example to demonstrate metadata usage with UIMetadataKey |
python-server-demo/README.md |
Added metadata documentation and usage examples |
| "encoding": "text" | ||
| "encoding": "text", | ||
| "uiMetadata": { | ||
| UIMetadataKey.PREFERRED_FRAME_SIZE: ["800px", "600px"] # CSS dimension strings (can be px, %, vh, etc.) |
Copilot
AI
Oct 25, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using UIMetadataKey.PREFERRED_FRAME_SIZE as a dictionary key follows Python best practices, but the comment suggests this can accept CSS unit strings while the constant is defined as a plain string 'preferred-frame-size'. Consider documenting the expected value types (e.g., list of strings or list of numbers) in the UIMetadataKey class docstring to clarify the API contract.
|
|
||
|
|
||
| class UIMetadataKey: | ||
| """Keys for UI metadata.""" |
Copilot
AI
Oct 25, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The UIMetadataKey class lacks documentation about the expected value types for each metadata key. For example, PREFERRED_FRAME_SIZE should clarify whether it expects a list of integers (pixels) or strings (CSS units), and INITIAL_RENDER_DATA should specify that it expects a dictionary. This would improve API usability and prevent type confusion.
| """Keys for UI metadata.""" | |
| """ | |
| Keys for UI metadata. | |
| - PREFERRED_FRAME_SIZE: expects a list of two integers [width, height] in pixels, e.g. [800, 600]. | |
| - INITIAL_RENDER_DATA: expects a dictionary containing initial render data for the UI component. | |
| """ |
| }, | ||
| "encoding": "text", | ||
| "uiMetadata": { | ||
| "preferred-frame-size": [800, 600] # width, height in pixels or css units |
Copilot
AI
Oct 25, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment indicates 'pixels or css units' but the example shows numeric values without units. This creates ambiguity about whether clients should pass [800, 600] (integers) or ['800px', '600px'] (strings). Consider providing examples for both cases or clarifying which format is preferred and how they differ in behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1 issue found across 7 files
Prompt for AI agents (all 1 issues)
Understand the root cause of the following 1 issues and fix them.
<file name="examples/python-server-demo/README.md">
<violation number="1" location="examples/python-server-demo/README.md:76">
The example sets `preferred-frame-size` to string numbers ("1200", "800"), but UI clients expect either numeric pixels or CSS values with units. Update the example to use integers or unit-suffixed strings so the metadata actually applies.</violation>
</file>
React with 👍 or 👎 to teach cubic. Mention @cubic-dev-ai to give feedback, ask questions, or re-run the review.
| }, | ||
| "encoding": "text", | ||
| "uiMetadata": { | ||
| "preferred-frame-size": ["1200", "800"], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The example sets preferred-frame-size to string numbers ("1200", "800"), but UI clients expect either numeric pixels or CSS values with units. Update the example to use integers or unit-suffixed strings so the metadata actually applies.
Prompt for AI agents
Address the following comment on examples/python-server-demo/README.md at line 76:
<comment>The example sets `preferred-frame-size` to string numbers ("1200", "800"), but UI clients expect either numeric pixels or CSS values with units. Update the example to use integers or unit-suffixed strings so the metadata actually applies.</comment>
<file context>
@@ -50,6 +52,38 @@ Each tool returns an MCP resource that can be rendered by MCP UI clients:
+ },
+ "encoding": "text",
+ "uiMetadata": {
+ "preferred-frame-size": ["1200", "800"],
+ },
+ # Optional: custom metadata (not prefixed)
</file context>
| "preferred-frame-size": ["1200", "800"], | |
| "preferred-frame-size": [1200, 800], |
# 1.0.0 (2025-11-04) ### Bug Fixes * add a bridge to pass messages in and out of the proxy ([#38](#38)) ([30ccac0](30ccac0)) * bump client version ([75c9236](75c9236)) * **client:** specify iframe ([fd0b70a](fd0b70a)) * **client:** styling ([6ff9b68](6ff9b68)) * dependencies ([887f61f](887f61f)) * Enable bidirectional message relay in rawhtml proxy mode ([#138](#138)) ([f0bdefb](f0bdefb)) * ensure Apps SDK adapter is bundled properly and initialized wth config ([#137](#137)) ([4f7c25c](4f7c25c)) * export RemoteDomResource ([2b86f2d](2b86f2d)) * export ResourceRenderer and HtmlResource ([2b841a5](2b841a5)) * exports ([3a93a16](3a93a16)) * fix file extension reference in package.json ([927989c](927989c)) * iframe handle ([#15](#15)) ([66bd4fd](66bd4fd)) * lint ([4487820](4487820)) * lint ([d0a91f9](d0a91f9)) * minor typo ([a0bee9c](a0bee9c)) * move react dependencies to be peer dependencies ([#91](#91)) ([f672f3e](f672f3e)), closes [#90](#90) * package config ([8dc1e53](8dc1e53)) * packaging ([9e6babd](9e6babd)) * pass ref explicitly using iframeProps ([#33](#33)) ([d01b5d1](d01b5d1)) * publish ([0943e7a](0943e7a)) * ref passing to UIResourceRenderer ([#32](#32)) ([d28c23f](d28c23f)) * remove shared dependency ([e66e8f4](e66e8f4)) * rename components and methods to fit new scope ([#22](#22)) ([6bab1fe](6bab1fe)) * rename delivery -> encoding and flavor -> framework ([#36](#36)) ([9a509ed](9a509ed)) * Ruby comment ([b22dc2e](b22dc2e)) * support react-router ([21ffb95](21ffb95)) * text and blob support in RemoteDOM resources ([ec68eb9](ec68eb9)) * trigger release ([aaca831](aaca831)) * typescript ci publish ([e7c0ebf](e7c0ebf)) * typescript types to be compatible with MCP SDK ([#10](#10)) ([74365d7](74365d7)) * update deps ([4091ef4](4091ef4)) * update isUIResource to use EmbeddedResource type ([#122](#122)) ([5a65a0b](5a65a0b)), closes [#117](#117) * use targetOrigin in the proxy message relay ([#40](#40)) ([b3fb54e](b3fb54e)) * validate URL ([b7c994d](b7c994d)) * wc dist overwrite ([#63](#63)) ([9e46c56](9e46c56)) ### Documentation * bump ([#4](#4)) ([ad4d163](ad4d163)) ### Features * add convenience function isUIResource to client SDK ([#86](#86)) ([607c6ad](607c6ad)) * add embeddedResourceProps for annotations ([#99](#99)) ([b96ec44](b96ec44)) * add proxy option to externalUrl ([#37](#37)) ([7b95cd0](7b95cd0)) * add remote-dom content type ([#18](#18)) ([5dacf37](5dacf37)) * add Ruby server SDK ([#31](#31)) ([5ffcde4](5ffcde4)) * add sandbox permissions instead of an override ([#83](#83)) ([b1068e9](b1068e9)) * add ui-request-render-data message type ([#111](#111)) ([26135ce](26135ce)) * add UIResourceRenderer Web Component ([#58](#58)) ([ec8f299](ec8f299)) * auto resize with the autoResizeIframe prop ([#56](#56)) ([76c867a](76c867a)) * change onGenericMcpAction to optional onUiAction ([1913b59](1913b59)) * **client:** allow setting supportedContentTypes for HtmlResource ([#17](#17)) ([e009ef1](e009ef1)) * consolidate ui:// and ui-app:// ([#8](#8)) ([2e08035](2e08035)) * pass iframe props down ([#14](#14)) ([112539d](112539d)) * refactor UTFtoB64 (bump server version) ([#95](#95)) ([2d5e16b](2d5e16b)) * send render data to the iframe ([#51](#51)) ([d38cfc7](d38cfc7)) * separate html and remote-dom props ([#24](#24)) ([a7f0529](a7f0529)) * support adapters ([#127](#127)) ([d4bd152](d4bd152)) * support generic messages response ([#35](#35)) ([10b407b](10b407b)) * support metadata in Python SDK ([#134](#134)) ([9bc3c64](9bc3c64)) * support passing resource metadata ([#87](#87)) ([f1c1c9b](f1c1c9b)) * support proxy for rawHtml ([#132](#132)) ([1bbeb09](1bbeb09)) * support ui action result types ([#6](#6)) ([899d152](899d152)) * switch to ResourceRenderer ([#21](#21)) ([6fe3166](6fe3166)) ### BREAKING CHANGES * The existing naming is ambiguous. Renaming delivery to encoding and flavor to framework should clarify the intent. * exported names have changed * removed deprecated client API * (previous one didn't take due to semantic-release misalignment)
…r/v5.14.0) (2025-11-29) ### Features * support metadata in Python SDK ([#134](#134)) ([9bc3c64](9bc3c64))
Problem
The Python SDK was missing support for the
uiMetadatafield when creating UI resources, causing metadata likepreferred-frame-sizeto be ignored and resulting inmeta: nullin the output. This prevented users from specifying important UI hints such as preferred dimensions or initial render data.Solution
Implemented full metadata support in the Python SDK to match the TypeScript implementation:
uiMetadataandmetadataoptional fields toCreateUIResourceOptionsmcpui.dev/ui-for client recognition_metafield for MCP protocol complianceUsage
Changes
uiMetadataandmetadatafields, metadata constants_get_additional_resource_props()helper for metadata processingTesting
Compatibility
Fixes #[issue_number]
Original prompt
Fixes #133
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.