update for resources-bug-fix#884
Conversation
Reviewer's GuideAdds a serialization wrapper so resource handlers returning Pydantic models or dicts are converted to JSON strings for FastMCP v3, and wires Unity editor advanced deployment events to refresh the displayed version and trigger update checks after deploy/restore operations. Sequence diagram for FastMCP resource serialization wrappersequenceDiagram
participant Client
participant FastMCP
participant ResourceFunction as Resource_function
participant SerializeWrapper as _serialize_pydantic_wrapper
Client->>FastMCP: HTTP request to resource URI
FastMCP->>SerializeWrapper: Invoke wrapped resource handler
SerializeWrapper->>ResourceFunction: Call original resource function
ResourceFunction-->>SerializeWrapper: MCPResponse(BaseModel) or dict or str
alt Result is BaseModel
SerializeWrapper->>SerializeWrapper: result.model_dump_json()
SerializeWrapper-->>FastMCP: JSON string
else Result is dict
SerializeWrapper->>SerializeWrapper: json.dumps(result)
SerializeWrapper-->>FastMCP: JSON string
else Result is already str/bytes/ResourceResult
SerializeWrapper-->>FastMCP: result
end
FastMCP-->>Client: Resource response (JSON string or allowed type)
Sequence diagram for Unity advanced deployment and version refreshsequenceDiagram
actor User
participant McpAdvancedSection
participant MCPForUnityEditorWindow
User->>McpAdvancedSection: Click Deploy or Restore
McpAdvancedSection->>McpAdvancedSection: Perform deployment or restore
McpAdvancedSection->>User: Show dialog Deployment Complete or Restore Complete
McpAdvancedSection->>McpAdvancedSection: OnPackageDeployed?.Invoke()
McpAdvancedSection-->>MCPForUnityEditorWindow: OnPackageDeployed event
MCPForUnityEditorWindow->>MCPForUnityEditorWindow: UpdateVersionLabel()
MCPForUnityEditorWindow->>MCPForUnityEditorWindow: QueueUpdateCheck()
Class diagram for resource registration and Unity advanced deployment eventsclassDiagram
class ResourcesModule {
+register_all_resources(mcp, project_scoped_tools)
+_serialize_pydantic(func)
}
class FastMCP {
+resource(uri, name, description, handler)
}
class BaseModel {
+model_dump_json()
}
ResourcesModule ..> FastMCP : uses
ResourcesModule ..> BaseModel : checks_instance_of
class MCPForUnityEditorWindow {
+CreateGUI()
-UpdateVersionLabel()
-QueueUpdateCheck()
}
class McpAdvancedSection {
+event OnPackageDeployed
+Root
-OnDeployClicked()
-OnRestoreBackupClicked()
}
class ConnectionSection {
+VerifyBridgeConnectionAsync()
+SetHealthStatusUpdateCallback(callback)
}
MCPForUnityEditorWindow o-- McpAdvancedSection : contains
MCPForUnityEditorWindow o-- ConnectionSection : contains
McpAdvancedSection ..> MCPForUnityEditorWindow : OnPackageDeployed event
ConnectionSection ..> McpAdvancedSection : health_status_callback
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
Caution Review failedPull request was closed or merged during review 📝 WalkthroughWalkthroughThe pull request introduces an event-driven update mechanism in the MCPForUnity editor window and adds a serialization wrapper for Pydantic model handling in the server resource services. A new Changes
Sequence Diagram(s)sequenceDiagram
participant McpAdv as McpAdvancedSection
participant Event as OnPackageDeployed Event
participant Window as MCPForUnityEditorWindow
participant UI as Version Label & Update Check
McpAdv->>Event: Raise OnPackageDeployed
Event->>Window: Notify subscribers
Window->>UI: Update version label
Window->>UI: Queue update check
sequenceDiagram
participant Client as Resource Function
participant Wrapper as _serialize_pydantic
participant Model as Pydantic BaseModel
participant JSON as JSON Serializer
participant FastMCP as FastMCP 3.x
Client->>Wrapper: Call with result
alt Result is BaseModel
Wrapper->>Model: Detect BaseModel type
Model->>JSON: model_dump_json()
JSON->>Wrapper: JSON string
else Result is dict
Wrapper->>JSON: json.dumps()
JSON->>Wrapper: JSON string
else Other
Wrapper->>Wrapper: Return as-is
end
Wrapper->>FastMCP: Pass serialized result
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Hey - I've found 1 issue, and left some high level feedback:
- The
_serialize_pydanticwrapper only handles a singleBaseModelordict; if any existing resources return lists or nested structures of Pydantic models, you may want to extend this helper to recursively serialize common container types (e.g., list/tuple/dict of models) to avoid subtle runtime issues. - By placing
_serialize_pydanticas the outermost wrapper beforelog_executionandtelemetry_resource, those middle layers now see only JSON strings rather than structured models; consider whether these wrappers should instead operate on the originalBaseModel(e.g., for richer logging/metrics) and apply serialization only at the final FastMCP boundary.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The `_serialize_pydantic` wrapper only handles a single `BaseModel` or `dict`; if any existing resources return lists or nested structures of Pydantic models, you may want to extend this helper to recursively serialize common container types (e.g., list/tuple/dict of models) to avoid subtle runtime issues.
- By placing `_serialize_pydantic` as the outermost wrapper before `log_execution` and `telemetry_resource`, those middle layers now see only JSON strings rather than structured models; consider whether these wrappers should instead operate on the original `BaseModel` (e.g., for richer logging/metrics) and apply serialization only at the final FastMCP boundary.
## Individual Comments
### Comment 1
<location path="MCPForUnity/Editor/Windows/Components/Advanced/McpAdvancedSection.cs" line_range="47-50" />
<code_context>
public event Action OnGitUrlChanged;
public event Action OnHttpServerCommandUpdateRequested;
public event Action OnTestConnectionRequested;
+ public event Action OnPackageDeployed;
public VisualElement Root { get; private set; }
</code_context>
<issue_to_address>
**suggestion:** Event name may be misleading since it also fires on restore.
Since this event is raised for both deploy and restore, the name doesn’t reflect its full behavior. Consider renaming it to something more generic (e.g., `OnPackageChanged`) or adding distinct events for deploy and restore so subscribers can clearly distinguish the operation.
Suggested implementation:
```csharp
public event Action OnGitUrlChanged;
public event Action OnHttpServerCommandUpdateRequested;
public event Action OnTestConnectionRequested;
/// <summary>
/// Raised whenever the package deployment state changes (deploy or restore).
/// </summary>
public event Action OnPackageChanged;
/// <summary>
/// Raised specifically after a successful package deployment.
/// </summary>
public event Action OnPackageDeployed;
/// <summary>
/// Raised specifically after a successful package restore.
/// </summary>
public event Action OnPackageRestored;
```
```csharp
else
{
EditorUtility.DisplayDialog(
"Deployment Complete",
result.Message + (string.IsNullOrEmpty(result.BackupPath) ? string.Empty : $"\nBackup: {result.BackupPath}"),
"OK");
// Notify listeners of a successful deployment and a package state change.
OnPackageDeployed?.Invoke();
OnPackageChanged?.Invoke();
}
```
To fully implement the intent of your review comment, you should also:
1. Locate the code path that performs a **restore** operation in `McpAdvancedSection` (or related classes in this editor window) and:
- Replace any existing `OnPackageDeployed?.Invoke()` call that is used for restore with:
- `OnPackageRestored?.Invoke();`
- `OnPackageChanged?.Invoke();`
2. Update any external subscribers:
- If any code currently relies on `OnPackageDeployed` to be fired for restore, adjust those subscribers to:
- Listen to `OnPackageChanged` when they don’t care which operation occurred, **or**
- Listen to `OnPackageDeployed` and/or `OnPackageRestored` when they need to distinguish between deploy and restore.
This will ensure the event naming is no longer misleading while giving callers explicit hooks for both operations.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| public event Action OnPackageDeployed; | ||
|
|
||
| public VisualElement Root { get; private set; } | ||
|
|
There was a problem hiding this comment.
suggestion: Event name may be misleading since it also fires on restore.
Since this event is raised for both deploy and restore, the name doesn’t reflect its full behavior. Consider renaming it to something more generic (e.g., OnPackageChanged) or adding distinct events for deploy and restore so subscribers can clearly distinguish the operation.
Suggested implementation:
public event Action OnGitUrlChanged;
public event Action OnHttpServerCommandUpdateRequested;
public event Action OnTestConnectionRequested;
/// <summary>
/// Raised whenever the package deployment state changes (deploy or restore).
/// </summary>
public event Action OnPackageChanged;
/// <summary>
/// Raised specifically after a successful package deployment.
/// </summary>
public event Action OnPackageDeployed;
/// <summary>
/// Raised specifically after a successful package restore.
/// </summary>
public event Action OnPackageRestored; else
{
EditorUtility.DisplayDialog(
"Deployment Complete",
result.Message + (string.IsNullOrEmpty(result.BackupPath) ? string.Empty : $"\nBackup: {result.BackupPath}"),
"OK");
// Notify listeners of a successful deployment and a package state change.
OnPackageDeployed?.Invoke();
OnPackageChanged?.Invoke();
}To fully implement the intent of your review comment, you should also:
- Locate the code path that performs a restore operation in
McpAdvancedSection(or related classes in this editor window) and:- Replace any existing
OnPackageDeployed?.Invoke()call that is used for restore with:OnPackageRestored?.Invoke();OnPackageChanged?.Invoke();
- Replace any existing
- Update any external subscribers:
- If any code currently relies on
OnPackageDeployedto be fired for restore, adjust those subscribers to:- Listen to
OnPackageChangedwhen they don’t care which operation occurred, or - Listen to
OnPackageDeployedand/orOnPackageRestoredwhen they need to distinguish between deploy and restore.
This will ensure the event naming is no longer misleading while giving callers explicit hooks for both operations.
- Listen to
- If any code currently relies on
There was a problem hiding this comment.
Pull request overview
This PR fixes a bug introduced when upgrading to FastMCP v3, which stopped accepting Pydantic BaseModel instances as resource return values. It wraps all resource handler functions with a _serialize_pydantic decorator that converts BaseModel and dict returns to JSON strings. Additionally, the Unity editor GUI is updated to refresh the version label and trigger an update check after successful advanced deployment or backup restore operations.
Changes:
- Added
_serialize_pydanticwrapper in the resource registration pipeline to serialize Pydantic/dict responses to JSON strings for FastMCP v3 compatibility - Added
OnPackageDeployedevent toMcpAdvancedSectionand raised it after both successful deploy and backup restore actions - Wired the event in
MCPForUnityEditorWindowto callUpdateVersionLabel()andQueueUpdateCheck()after package changes
Reviewed changes
Copilot reviewed 3 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
Server/src/services/resources/__init__.py |
Adds _serialize_pydantic decorator and applies it as the innermost wrapper before log_execution and telemetry_resource in resource registration |
MCPForUnity/Editor/Windows/MCPForUnityEditorWindow.cs |
Subscribes to the new OnPackageDeployed event to refresh version info after package changes |
MCPForUnity/Editor/Windows/Components/Advanced/McpAdvancedSection.cs |
Adds OnPackageDeployed event and raises it on successful deploy and restore operations |
Server/uv.lock |
Version bump from 9.4.8 to 9.5.1, consistent with pyproject.toml |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
| if isinstance(result, BaseModel): | ||
| return result.model_dump_json() | ||
| if isinstance(result, dict): | ||
| import json |
There was a problem hiding this comment.
The import json statement is placed inside the hot path of the wrapper function, within the isinstance(result, dict) branch. While Python caches module imports in sys.modules so re-importing is cheap, it still incurs a dictionary lookup on every call that returns a dict. The json module should be moved to the top-level imports alongside the other standard library imports (e.g., next to import functools) for consistency with the rest of the codebase and to avoid any per-call overhead.
| else | ||
| { | ||
| EditorUtility.DisplayDialog("Restore Complete", result.Message, "OK"); | ||
| OnPackageDeployed?.Invoke(); |
There was a problem hiding this comment.
The OnPackageDeployed event is fired from OnRestoreBackupClicked when a backup restore succeeds. While the behavior (refreshing version info) is correct and intentional, the event name OnPackageDeployed is semantically misleading for a restore operation - restoring is not deploying. Consider renaming the event to something more general like OnPackageInstallationChanged to accurately describe both deploy and restore scenarios.
Fix the resources bug that emerged when updating FastMCP to V3. It does not accept Pydantic BaseModel anyway so it is now wrapped in JSON format. GUI updates that update the version number when using advanced deployment are also included.
Summary by Sourcery
Wrap MCP resource handlers to serialize Pydantic and dict responses for FastMCP v3 compatibility and update the Unity editor UI to refresh version info after advanced deployments.
Bug Fixes:
Enhancements:
Summary by CodeRabbit
New Features
Bug Fixes