SteamWorkshopAgent is a local stdio MCP server for publishing RimWorld mod releases to Steam Workshop from an already-prepared GitHub release. Its preferred backend uses the Steam desktop client's authenticated RimWorld session and never handles a Steam password or Steam Guard code.
The server is aimed at the local mod-development workflow: build the mod in Release mode, stage the generated mod folder, and upload the Workshop update through the authenticated desktop Steam session without opening RimWorld's mod UI.
- README.md: user-facing overview and quick start
- AGENTS.md: local MCP redeploy convention for this workspace
- Architecture Enhancements: hybrid Steamworks, RimWorld companion, SteamCMD, and Workshop read-back architecture
- Inspect RimWorld mod metadata from a source repository or an already-deployed mod folder using
About/About.xml, optionalAbout/PublishedFileId.txt,LoadFolders.xml, and optionalDirectory.Build.props. - Use the fixed RimWorld Steam app id
294100and the mod Workshop id fromAbout/PublishedFileId.txtwhen present. - Create the initial private Steam Workshop item for a new local mod from either a source repository or an already-built mod folder, and write the returned id to
About/PublishedFileId.txt. - Read GitHub release notes through
gh release view. - Generate a dry-run Workshop release plan before uploading.
- Publish content through a detached Steamworks helper using the logged-on Steam desktop session.
- Fall back before submission to a minimal headless RimWorld plus RimBridge companion when Steam does not authenticate the standalone helper.
- Keep SteamCMD
+workshop_build_itemas an explicit emergency backend. - Submit RimWorld Workshop category tags such as
Modand1.6through the same local Steamworks UGC path RimWorld uses. - Preserve the existing Workshop page description unless
updateDescriptionis explicitly enabled. - Read the current main Workshop page title and description through Steam's public item details API.
- Update the main Workshop page description directly with a metadata-only SteamCMD VDF, without rebuilding mod content or changing tags.
- Override the Steam Workshop release changenote at publish time when you want a concise hand-written note instead of the GitHub release body.
- Submit a changenote update for an already-published Workshop item through local Steamworks.
- .NET 10 SDK to build from source
- GitHub CLI
ghfor reading release notes - A running, online, logged-on Steam desktop client
- RimWorld and RimBridgeServer for the in-game authenticated fallback
- SteamCMD only when explicitly using the emergency
steamcmdbackend - A RimWorld mod source repository with a Release build target that supports
RIMWORLD_MOD_DIRfor release publishing - For initial
new-moduploads, either a source repository or an already-built RimWorld mod folder withAbout/About.xml,About/Preview.png, and versionedAssembliescontent
Install SteamCMD on this Mac with:
brew install --cask steamcmdSteamWorkshopAgent does not store Steam passwords or Steam Guard codes. It passes only the Steam username to SteamCMD. Pass that username to the publish tool or set:
export STEAMCMD_USER=your_steam_usernameWhen running as an MCP server, the client process may not inherit your terminal environment. If steamUser is omitted and STEAMCMD_USER is missing from the MCP process environment, the agent also probes your configured shell startup files and reads only that username value.
Normal publishing does not use SteamCMD authentication. If the Steamworks and RimWorld fallback paths are unavailable and you deliberately select backend=steamcmd, authenticate SteamCMD in a real terminal:
steamcmd +login your_steam_username +quitEnter the password and Steam Guard token there. SteamCMD stores a reusable login token in Steam's config directory, not in this MCP server. On this Mac the relevant file is:
~/Library/Application Support/Steam/config/config.vdf
That token is used only by the explicit SteamCMD fallback. Never pass passwords or Steam Guard codes to SteamWorkshopAgent, MCP tools, or chat.
Routine updates preserve the Workshop item's existing category tags. The separate tag maintenance tool calls RimWorld's local Steamworks UGC path, using RimWorld app id 294100 and the native Steam API library bundled with the installed RimWorld app. It requires the desktop Steam client session to be logged on from Steamworks' point of view.
dotnet build SteamWorkshopAgent.slnx -c Release
dotnet test SteamWorkshopAgent.slnxThis workspace follows the same local MCP install pattern as the active gabs and decompiler servers: publish a stable native binary under ~/.codex/mcp-servers/<server-dir>/ and point Codex at that installed binary.
make installThe install target writes:
~/.codex/mcp-servers/steam-workshop-agent/SteamWorkshopAgent
Local redeploys should overwrite that binary in place. Do not point MCP config at repo-local build output.
Codex CLI:
[mcp_servers.steam-workshop-agent]
command = "/Users/you/.codex/mcp-servers/steam-workshop-agent/SteamWorkshopAgent"
args = ["server"]Generic MCP client:
{
"command": "/Users/you/.codex/mcp-servers/steam-workshop-agent/SteamWorkshopAgent",
"args": ["server"]
}Restart the MCP client after changing the installed binary or MCP configuration. Codex loads MCP servers at session startup.
SteamStatus
Checks whether SteamCMD is installed for emergency use, whether RimWorld is installed through Steam, whether RimWorld's native Steam API library is available for publishing, and where Steam Workshop logs are expected.
SteamSessionProbe
Starts a short-lived detached helper process, initializes RimWorld's native Steam API, and reports whether the Steam desktop session authenticated it as app 294100. It does not read or modify a Workshop item.
SteamUser.BLoggedOn=false means the desktop client has no live Steam-server connection; a visible Steam window alone is not proof that the session is usable. If the probe returns failureCode=desktop-session-offline and recoveryAction=restart-steam, fully quit and reopen Steam, wait for it to reconnect, and probe again before starting RimWorld or selecting a fallback. A common cause is SteamCMD logging into the same account and replacing the desktop session while leaving Steam's UI open.
RimWorldModInspect
Reads a RimWorld mod source repository or already-deployed mod folder and returns the metadata needed for Workshop publishing.
WorkshopReleasePlan
Creates a dry-run plan for a GitHub release tag. It reads the GitHub release body, resolves mod metadata, prepares SteamCMD VDF content, and reports validation issues before upload.
Steam changenotes are formatted from the mod metadata and GitHub release body by default:
v1.2.3
GitHub release body
GitHub release: https://github.com/owner/repo/releases/tag/v1.2.3.0
Pass changeNote to use custom Steam changenote text for the plan or publish. The agent still prefixes the version heading unless your text already starts with it.
Four-part mod versions with a trailing .0 are shortened for the Steam heading only.
WorkshopPublishRelease
Publishes a confirmed release to Steam Workshop. backend=auto and backend=standalone prepare an owner-verified, expiring request, fingerprint the exact staged content, and submit it through a detached Steamworks helper. If desktop Steam does not authenticate that helper, the returned result has fallbackAllowed=true and can be submitted once through the RimBridge companion running inside RimWorld. Existing tags are preserved.
backend=steamcmd is an explicit emergency path. It is never selected automatically and is the only release path that needs a SteamCMD username or cached SteamCMD credentials.
Do not pre-authenticate or probe SteamCMD before trying the desktop backend. A SteamCMD login to the same account can replace the desktop client's live session. After an explicitly selected SteamCMD fallback completes, probe desktop Steam again and restart it if the fallback displaced its session.
Source release builds always pass BuildBridgeTools=false so GitHub/Steam release artifacts contain only the main mod payload. Local validation builds can keep building companion BridgeTools by default.
WorkshopPublishDeployedRelease
Publishes an already-built deployed mod folder through the same prepared-request and backend policy. This path does not rebuild the mod and does not refresh Workshop tags. Use it when a separate Release build has already produced the exact deployed folder that should be uploaded.
WorkshopPublishPrepared
Submits a still-valid prepared request through the detached helper. The request must live under the agent's run directory and its content fingerprint must still match.
WorkshopVerifyAfterPublish
Reads Steam's public item details and verifies the prepared title and update timestamp. It never retries an upload. A callback timeout after submissionStarted=true is deliberately ambiguous and must be verified before any human retry.
WorkshopCreateNewMod
Creates a new Steam Workshop item for a local RimWorld mod through SteamCMD. The tool defaults to a dry run. With confirm=true, it builds source repositories into a temporary staging directory or uploads an already-built mod folder directly, creates a new private Workshop item by using publishedfileid 0, reads the id SteamCMD writes back into the VDF, submits the Mod tag plus supported RimWorld version tags such as 1.6 through Steamworks, and saves the id to About/PublishedFileId.txt.
Source new-mod builds use the same release-build convention and pass BuildBridgeTools=false.
WorkshopSetTags
Sets category tags on an existing RimWorld Workshop item. Pass either a numeric Workshop id or a source/deployed mod path with About/PublishedFileId.txt. If tags is omitted for a mod path, the tool uses Mod plus the supported RimWorld versions from About/About.xml.
WorkshopGetDescription
Reads the current main Steam Workshop item title and description. Pass either a numeric Workshop id or a local mod path with About/PublishedFileId.txt. The result includes the raw editable description text, character count, title, update timestamp, visibility, tags returned by Steam, and the public Workshop URL.
WorkshopUpdateDescription
Updates the main Steam Workshop item description field. Pass either a numeric Workshop id or a local mod path with About/PublishedFileId.txt, plus the complete new description text. This path writes a small VDF containing appid, publishedfileid, and description; it intentionally omits contentfolder, previewfile, and tags so the upload is metadata-only. Title and changenote are optional and omitted by default.
WorkshopSetChangeNote
Submits a changenote update for an existing RimWorld Workshop item. Pass either a numeric Workshop id or a source/deployed mod path with About/PublishedFileId.txt, plus the changenote text and confirm=true.
This submits a new Steamworks item update with the supplied changenote. It does not edit old historical changenote entries that Steam has already recorded.
The preferred publish path is intentionally conservative:
- Refuse to publish from a dirty git worktree.
- For release publishes, create a detached temporary Git worktree at the requested tag and build that source tree in Release mode into a temporary staging directory with
BuildBridgeTools=false. This keeps the caller's checkout clean even when the mod build rewrites tracked local deploy artifacts. - Validate the staged mod content and preview image.
- Write
plan.jsonplus owner-onlysteamworks-request.jsonunder~/Library/Application Support/SteamWorkshopAgent/runs/.... - Record the current Workshop creator id and a deterministic digest of every staged content path and byte.
- Start a detached helper session with
setsid(), verify app id and Steam account ownership, and apply title, optional description, preview, and content beforeSubmitItemUpdate. - Persist a no-fallback
submit-intentmarker before callingSubmitItemUpdate, then asubmittedmarker after receiving a valid API call handle. This survives helper crashes and terminal disconnects. - Allow a fallback only before the durable intent marker exists. Once submission may have started, a timeout or exception is ambiguous and automatic retry is forbidden.
- Persist
steamworks-result.jsonwith owner-only permissions and verify public Workshop state.
The release tag must exist locally so Git can create the detached worktree. If the agent reports that the tag cannot be resolved, run git fetch --tags in the mod repository and retry.
The publish tool defaults to dry-run behavior unless confirm is true.
The installed binary also has a thin CLI over the same services used by the MCP tools:
~/.codex/mcp-servers/steam-workshop-agent/SteamWorkshopAgent status
~/.codex/mcp-servers/steam-workshop-agent/SteamWorkshopAgent inspect /path/to/mod/repo-or-folder
~/.codex/mcp-servers/steam-workshop-agent/SteamWorkshopAgent plan /path/to/mod/repo v1.2.3
~/.codex/mcp-servers/steam-workshop-agent/SteamWorkshopAgent plan /path/to/mod/repo v1.2.3 --changenote "Simple public release note"
~/.codex/mcp-servers/steam-workshop-agent/SteamWorkshopAgent steam-session-probe
~/.codex/mcp-servers/steam-workshop-agent/SteamWorkshopAgent publish /path/to/mod/repo v1.2.3 --confirm --backend auto
~/.codex/mcp-servers/steam-workshop-agent/SteamWorkshopAgent publish /path/to/mod/repo v1.2.3 --confirm --backend steamcmd --steam-user your_steam_username --changenote "Simple public release note"
~/.codex/mcp-servers/steam-workshop-agent/SteamWorkshopAgent publish-deployed /path/to/mod/repo v1.2.3 /path/to/deployed/mod --confirm --backend auto
~/.codex/mcp-servers/steam-workshop-agent/SteamWorkshopAgent verify '/path/to/run/steamworks-request.json' --wait-seconds 90
~/.codex/mcp-servers/steam-workshop-agent/SteamWorkshopAgent new-mod /path/to/mod/repo-or-folder --confirm --steam-user your_steam_username
~/.codex/mcp-servers/steam-workshop-agent/SteamWorkshopAgent description-get /path/to/mod/repo-or-folder
~/.codex/mcp-servers/steam-workshop-agent/SteamWorkshopAgent description-get 928376710
~/.codex/mcp-servers/steam-workshop-agent/SteamWorkshopAgent description /path/to/mod/repo-or-folder description.txt --confirm --steam-user your_steam_username
~/.codex/mcp-servers/steam-workshop-agent/SteamWorkshopAgent description 928376710 description.txt --confirm --steam-user your_steam_username
~/.codex/mcp-servers/steam-workshop-agent/SteamWorkshopAgent set-tags /path/to/mod/repo-or-folder --confirm
~/.codex/mcp-servers/steam-workshop-agent/SteamWorkshopAgent set-tags 3727949765 Mod 1.6 --confirm
~/.codex/mcp-servers/steam-workshop-agent/SteamWorkshopAgent set-changenote 3727949765 --changenote "Simple public release note" --confirmThe agent focuses on initial item creation, release publishing, single-item description updates, and category tag updates. Bulk Workshop description edits can be driven by a manifest or shell loop around the metadata-only description command.
The new-mod path creates the initial item with private visibility by default. Pass --visibility public, friends, or unlisted only when that is intentional.
SteamCMD remains available only as the explicitly selected steamcmd backend. It is not an automatic fallback because doing so would reintroduce independent credentials and make duplicate-submission handling harder.
Existing Workshop updates preserve tags. Steamworks tag submission remains available as a separate maintenance tool and for first-time items, but release publishing does not refresh tags.
The tool only updates the Workshop description when updateDescription is explicitly true. By default it publishes the release changenote and leaves the long Workshop page description alone.