-
Notifications
You must be signed in to change notification settings - Fork 693
feat: Add beta server mode with PyPI pre-release support #640
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
- Add UseTestPyPI editor preference key - Add TestPyPI toggle to Advanced settings UI with tooltip - Configure uvx to use test.pypi.org when TestPyPI mode enabled - Skip version pinning in TestPyPI mode to get latest pre-release - Update ConfigJsonBuilder to handle TestPyPI index URL
TestPyPI has polluted packages (broken httpx, mcp, fastapi) that cause server startup failures. Switch to publishing beta versions directly to PyPI as pre-releases (e.g., 9.3.0b20260127). Key changes: - beta-release.yml: Publish to PyPI instead of TestPyPI, use beta suffix - Use --prerelease explicit with version specifier (>=0.0.0a0) to only get prereleases of our package, not broken dependency prereleases - Default "Use Beta Server" toggle to true on beta branch - Rename UI label from "Use TestPyPI" to "Use Beta Server" - Add UseTestPyPI to EditorPrefsWindow known prefs - Add search field and refresh button to EditorPrefsWindow Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Show "β" suffix on version badge when beta server mode is enabled - Badge updates dynamically when toggle changes - Add server version to startup log: "MCP for Unity Server v9.2.0 starting up" - Add version field to /health endpoint response Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Rename EditorPref key from UseTestPyPI to UseBetaServer for clarity - Rename all related variables and UXML element names - Increase bottom margin on EditorPrefs search bar to prevent clipping first entry Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Reviewer's GuideImplements a beta server mode that fetches PyPI pre-release server versions safely, wires it into the Unity editor advanced settings and version badge, updates uv/ConfigJson invocation logic, adds server version reporting in logs and /health, introduces a new UseBetaServer editor pref key, and improves the editor prefs window with a search bar. Sequence diagram for beta server mode startup and health checksequenceDiagram
actor User
participant UnityEditorWindow
participant McpAdvancedSection
participant EditorPrefs
participant ServerManagementService
participant ConfigJsonBuilder
participant UvCli
participant McpServer
participant HealthEndpoint
User->>McpAdvancedSection: Toggle useBetaServerToggle
McpAdvancedSection->>EditorPrefs: SetBool(UseBetaServer, value)
McpAdvancedSection->>UnityEditorWindow: OnBetaModeChanged(value)
UnityEditorWindow->>UnityEditorWindow: UpdateVersionLabel(useBetaServer)
User->>UnityEditorWindow: Start server
UnityEditorWindow->>ServerManagementService: TryGetLocalHttpServerCommandParts
alt useBetaServer is true
ServerManagementService->>EditorPrefs: GetBool(UseBetaServer, defaultTrue)
ServerManagementService->>ServerManagementService: Build fromArgs with --prerelease explicit
else useBetaServer is false
ServerManagementService->>EditorPrefs: GetBool(UseBetaServer, defaultTrue)
ServerManagementService->>ServerManagementService: Build fromArgs from fromUrl or empty
end
ServerManagementService->>UvCli: Invoke uvx with arguments
UvCli->>McpServer: Start MCP for Unity Server
McpServer->>McpServer: get_package_version
McpServer->>McpServer: Log startup with version
User->>HealthEndpoint: HTTP GET /health
HealthEndpoint->>McpServer: get_package_version
HealthEndpoint-->>User: JSON { status, timestamp, version, message }
Updated class diagram for editor beta mode and prefs searchclassDiagram
class EditorPrefKeys {
<<static>>
string WebSocketUrlOverride
string GitUrlOverride
string DevModeForceServerRefresh
string UseBetaServer
string ProjectScopedToolsLocalHttp
string PackageDeploySourcePath
}
class McpAdvancedSection {
- VisualElement Root
- Toggle debugLogsToggle
- Toggle devModeForceRefreshToggle
- Toggle useBetaServerToggle
- TextField deploySourcePath
+ event Action OnGitUrlChanged
+ event Action OnHttpServerCommandUpdateRequested
+ event Action OnTestConnectionRequested
+ event Action~bool~ OnBetaModeChanged
+ void CacheUIElements()
+ void InitializeUI()
+ void InitializeValues()
+ void RegisterCallbacks()
+ void UpdatePathOverrides()
}
class MCPForUnityEditorWindow {
- Label versionLabel
+ void CreateGUI()
- void SetupTabs()
- void RefreshAllData()
- void EnsureToolsLoaded()
- void UpdateVersionLabel(bool useBetaServer)
}
class EditorPrefsWindow {
- ScrollView scrollView
- VisualElement prefsContainer
- TextField searchField
- string searchFilter
- List~EditorPrefItem~ currentPrefs
+ void CreateGUI()
- void RefreshPrefs()
- EditorPrefItem CreateEditorPrefItem(string key)
}
class ConfigJsonBuilder {
+ static IList~string~ BuildUvxArgs(string fromUrl, string packageName)
}
class ServerManagementService {
- bool TryGetLocalHttpServerCommandParts(out string fileName, out string arguments)
}
McpAdvancedSection --> MCPForUnityEditorWindow : OnBetaModeChanged
McpAdvancedSection --> EditorPrefKeys : uses UseBetaServer
MCPForUnityEditorWindow --> EditorPrefKeys : uses UseBetaServer
EditorPrefsWindow --> EditorPrefKeys : uses UseBetaServer
ConfigJsonBuilder --> EditorPrefKeys : reads UseBetaServer
ServerManagementService --> EditorPrefKeys : reads UseBetaServer
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
Caution Review failedThe pull request is closed. 📝 WalkthroughWalkthroughAdds a prerelease/beta flow: CI now builds and publishes beta pre-releases to PyPI; Unity editor gains a "Use Beta Server" toggle persisted in EditorPrefs; package source argument construction is centralized for prerelease handling; server exposes a cached startup version in health and telemetry. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant UI as Advanced UI
participant Prefs as EditorPrefs
participant AssetUtil as AssetPathUtility
participant Builder as Config/ServerManagement
participant PkgMgr as uvx / Package Manager
participant Server as Server (startup / health)
User->>UI: Toggle "Use Beta Server"
UI->>Prefs: Set UseBetaServer
Prefs-->>UI: Persisted
UI->>UI: Fire OnBetaModeChanged
Builder->>Prefs: Read UseBetaServer
alt UseBetaServer = true
Builder->>AssetUtil: GetBetaServerFromArgsList()
AssetUtil-->>Builder: ["--prerelease","explicit","--from","mcpforunityserver>=0.0.0a0"]
else UseBetaServer = false
Builder->>AssetUtil: GetBetaServerFromArgsList()
AssetUtil-->>Builder: ["--from","https://..."] or []
end
Builder->>PkgMgr: Invoke uvx with constructed args
PkgMgr-->>Builder: Package resolved / installed
Note over Server: At startup
Server->>Server: compute and cache _server_version
Server-->>Builder: health/version uses _server_version
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~30 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey - I've left some high level feedback:
- The beta server flag handling is duplicated in both
ServerManagementService.TryGetLocalHttpServerCommandPartsandConfigJsonBuilder.BuildUvxArgs; consider centralizing construction of theuvxargument list so the prerelease logic stays consistent in one place. - The health endpoint now calls
get_package_version()on every request; if this is non-trivial I/O, you could cache the version during startup (e.g., inserver_lifespan) and reuse it in/healthresponses and logs. - The beta version generation in
beta-release.ymlassumes a simpleMAJOR.MINOR.PATCHnumericversioninpyproject.toml; if a pre-release or non-standard version string is ever used, theread -r MAJOR MINOR PATCHsplit may fail—adding a safety check or guard would make this more robust.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The beta server flag handling is duplicated in both `ServerManagementService.TryGetLocalHttpServerCommandParts` and `ConfigJsonBuilder.BuildUvxArgs`; consider centralizing construction of the `uvx` argument list so the prerelease logic stays consistent in one place.
- The health endpoint now calls `get_package_version()` on every request; if this is non-trivial I/O, you could cache the version during startup (e.g., in `server_lifespan`) and reuse it in `/health` responses and logs.
- The beta version generation in `beta-release.yml` assumes a simple `MAJOR.MINOR.PATCH` numeric `version` in `pyproject.toml`; if a pre-release or non-standard version string is ever used, the `read -r MAJOR MINOR PATCH` split may fail—adding a safety check or guard would make this more robust.Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
- Centralize beta server uvx args in AssetPathUtility.GetBetaServerFromArgs() to avoid duplication between HTTP and stdio transports - Cache server version at startup instead of calling get_package_version() on every /health request - Add robustness to beta version parsing in workflow: strip existing pre-release suffix and validate X.Y.Z format before parsing Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
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.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@MCPForUnity/Editor/Helpers/ConfigJsonBuilder.cs`:
- Around line 174-187: The current logic in ConfigJsonBuilder.cs uses
usePreRelease (EditorPrefKeys.UseBetaServer) to unconditionally add the
prerelease "--from mcpforunityserver>=0.0.0a0" source and thus ignores an
explicit fromUrl override; change the branch so an explicit fromUrl wins: first
check if fromUrl is non-empty and, if so, add args.Add("--from") followed by
that fromUrl (and still add any other flags you want), otherwise if fromUrl is
empty then --prerelease and the mcpforunityserver source are applied; update the
conditional around usePreRelease/fromUrl (references: usePreRelease, fromUrl,
args.Add("--prerelease"), args.Add("--from"), EditorPrefKeys.UseBetaServer)
accordingly.
🧹 Nitpick comments (1)
MCPForUnity/Editor/Windows/EditorPrefs/EditorPrefsWindow.cs (1)
169-205: UseIndexOf(..., OrdinalIgnoreCase)to avoid per-item allocations.The current filter lowercases both strings inside the loop. You can pre-trim the filter and use
IndexOfwithStringComparison.OrdinalIgnoreCasefor clarity and fewer allocations.♻️ Suggested refactor
- // Create items for existing prefs + var filter = searchFilter?.Trim(); + // Create items for existing prefs foreach (var key in allKeys) { // Skip Customer UUID but show everything else that's defined if (key != EditorPrefKeys.CustomerUuid) { // Apply search filter - if (!string.IsNullOrEmpty(searchFilter) && - !key.ToLowerInvariant().Contains(searchFilter.ToLowerInvariant())) + if (!string.IsNullOrEmpty(filter) && + key.IndexOf(filter, StringComparison.OrdinalIgnoreCase) < 0) { continue; }
| // Beta server mode: allow beta versions from PyPI | ||
| // Beta server versions are published to PyPI as beta versions (e.g., 9.3.0b20260127) | ||
| // Defaults to true on beta branch to ensure server schema matches C# client. | ||
| // Use --prerelease explicit with version specifier to only get prereleases of our package, | ||
| // not of dependencies (which can be broken on PyPI). | ||
| bool usePreRelease = EditorPrefs.GetBool(EditorPrefKeys.UseBetaServer, true); | ||
| if (usePreRelease) | ||
| { | ||
| args.Add("--prerelease"); | ||
| args.Add("explicit"); | ||
| args.Add("--from"); | ||
| args.Add("mcpforunityserver>=0.0.0a0"); | ||
| } | ||
| else if (!string.IsNullOrEmpty(fromUrl)) |
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.
Preserve explicit fromUrl overrides when beta mode is on.
With UseBetaServer=true, fromUrl is ignored, so local/server overrides (e.g., GitUrlOverride or local dev paths) won’t work on the beta branch where the toggle defaults to ON. This is a behavior regression for dev workflows. Consider letting an explicit fromUrl win and only using the prerelease path when no override is provided.
🐛 Proposed fix
- bool usePreRelease = EditorPrefs.GetBool(EditorPrefKeys.UseBetaServer, true);
- if (usePreRelease)
+ bool usePreRelease = EditorPrefs.GetBool(EditorPrefKeys.UseBetaServer, true);
+ if (!string.IsNullOrEmpty(fromUrl))
{
- args.Add("--prerelease");
- args.Add("explicit");
- args.Add("--from");
- args.Add("mcpforunityserver>=0.0.0a0");
+ args.Add("--from");
+ args.Add(fromUrl);
}
- else if (!string.IsNullOrEmpty(fromUrl))
+ else if (usePreRelease)
{
args.Add("--from");
- args.Add(fromUrl);
+ args.Add("mcpforunityserver>=0.0.0a0");
+ args.Add("--prerelease");
+ args.Add("explicit");
}🤖 Prompt for AI Agents
In `@MCPForUnity/Editor/Helpers/ConfigJsonBuilder.cs` around lines 174 - 187, The
current logic in ConfigJsonBuilder.cs uses usePreRelease
(EditorPrefKeys.UseBetaServer) to unconditionally add the prerelease "--from
mcpforunityserver>=0.0.0a0" source and thus ignores an explicit fromUrl
override; change the branch so an explicit fromUrl wins: first check if fromUrl
is non-empty and, if so, add args.Add("--from") followed by that fromUrl (and
still add any other flags you want), otherwise if fromUrl is empty then
--prerelease and the mcpforunityserver source are applied; update the
conditional around usePreRelease/fromUrl (references: usePreRelease, fromUrl,
args.Add("--prerelease"), args.Add("--from"), EditorPrefKeys.UseBetaServer)
accordingly.
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.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@MCPForUnity/Editor/Helpers/AssetPathUtility.cs`:
- Around line 253-271: GetBetaServerFromArgs currently returns the prerelease
"--from mcpforunityserver>=0.0.0a0" whenever EditorPrefKeys.UseBetaServer is
true, which bypasses any explicit override from GetMcpServerPackageSource;
change the logic in GetBetaServerFromArgs to first call
GetMcpServerPackageSource() and, if it returns a non-empty string (an explicit
override like GitUrlOverride/local path), return $"--from {fromUrl}"
immediately, otherwise fall back to the existing beta behavior that returns the
prerelease "--prerelease explicit --from mcpforunityserver>=0.0.0a0"; keep
references to EditorPrefKeys.UseBetaServer and the existing quoteFromPath
handling intact.
- Around line 277-300: GetBetaServerFromArgsList currently checks the
UseBetaServer preference before considering any GitUrlOverride; change its logic
to check GitUrlOverride first (same as GetBetaServerFromArgs) by calling the
override accessor (GitUrlOverride or the existing GetGitUrlOverride()) at the
top of GetBetaServerFromArgsList, and if that override is non-empty add "--from"
and the override to args and return immediately; otherwise proceed to the
existing UseBetaServer branch and fallback to GetMcpServerPackageSource() when
UseBetaServer is false. Ensure you reference GetBetaServerFromArgsList,
GitUrlOverride/GetGitUrlOverride, EditorPrefKeys.UseBetaServer, and
GetMcpServerPackageSource when making the change.
🧹 Nitpick comments (2)
Server/src/main.py (1)
136-139: Rename unusedserverarg to_serverto silence lintRuff flags the unused parameter; renaming makes intent explicit and keeps the signature compatible.
♻️ Suggested tweak
-async def server_lifespan(server: FastMCP) -> AsyncIterator[dict[str, Any]]: +async def server_lifespan(_server: FastMCP) -> AsyncIterator[dict[str, Any]]:MCPForUnity/Editor/Helpers/ConfigJsonBuilder.cs (1)
159-185: Remove unusedfromUrlparameter.The
fromUrlparameter is now unused since the centralized helperGetBetaServerFromArgsList()handles the source resolution internally. This dead parameter should be removed to avoid confusion.♻️ Proposed refactor
Update the method signature and call site:
-private static IList<string> BuildUvxArgs(string fromUrl, string packageName) +private static IList<string> BuildUvxArgs(string packageName)And at line 91:
-var toolArgs = BuildUvxArgs(fromUrl, packageName); +var toolArgs = BuildUvxArgs(packageName);
- GetBetaServerFromArgs/GetBetaServerFromArgsList now check for explicit GitUrlOverride before applying beta server mode, ensuring local dev paths and custom URLs are honored - EditorPrefsWindow search filter uses IndexOf with OrdinalIgnoreCase instead of ToLowerInvariant().Contains() for fewer allocations Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Summary
/healthendpointUseTestPyPItoUseBetaServerfor clarityThis supersedes PR #639.
Why PyPI pre-releases instead of TestPyPI
TestPyPI is polluted with broken/incompatible packages that cause server startup failures:
httpxversions missingTransportErrorclassmcp==0.8.0.dev0(ancient dev version)fastapi==1.0(broken package)Using
--prerelease allowwith TestPyPI or even regular PyPI pulls these broken dependency pre-releases.Solution: Publish beta versions directly to PyPI as pre-releases (e.g.,
9.3.0b20260127) and use--prerelease explicitwith a version specifier (mcpforunityserver>=0.0.0a0). This only allows pre-releases for our package, not dependencies.Test plan
/healthendpoint returns version field🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Chores
✏️ Tip: You can customize this high-level summary in your review settings.