Windows Console MCP
Provides a Bilibili download capability under tools/bilibili-download, including a bridge and bundled yt-dlp fallback for downloading videos.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Windows Console MCPList devices and run 'systeminfo' on remote-worker"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Windows Console MCP
Self-hosted multi-device Windows MCP controller for ChatGPT.
One controller owns the public OAuth/Funnel endpoint. Local and remote workers expose Desktop Commander through the controller with an explicit deviceId on every routed worker tool call.
Architecture
ChatGPT
|
| OAuth + MCP
v
Tailscale Funnel /rdc/mcp
|
v
Controller
|- OAuth sidecar 127.0.0.1:18008
|- MCP router 127.0.0.1:18009
|- Local worker hub 127.0.0.1:18101
|- local worker deviceId=local-pc
`- Remote worker hub <Tailscale IPv4>:18100
`- remote workers deviceId=remote-worker, ...The public /rdc/mcp endpoint uses the MCP SDK StreamableHTTPServerTransport, matching CCM's standard initialize/session lifecycle.
Related MCP server: JARVIS-MCP
Controller setup
npm install
powershell.exe -NoProfile -ExecutionPolicy Bypass -File .\scripts\rdc-enable-oauth.ps1 `
-PublicBaseUrl https://your-machine.your-tailnet.ts.net
powershell.exe -NoProfile -ExecutionPolicy Bypass -File .\scripts\install-rdc-autostart.ps1Runtime configuration is intentionally local-only:
config/rdc.env
config/devices.json
config/worker-*.env
.state/
logs/config/devices.json.example shows the registry format. Local workers use a local token. Remote workers are bound to their registered Tailscale IPv4 and are accepted only on the controller's Tailscale-bound TCP listener.
Remote workers
Remote workers do not run OAuth or Funnel. They connect directly to the Controller's Tailscale-bound worker hub.
Windows remote workers can run natively with Node.js 20+ or in the existing Docker deployment. The native deployment uses the same worker/agent.mjs runtime as the Controller host, wrapped by a dedicated per-device Scheduled Task and supervisor; no worker protocol fork is involved.
See worker/README.md for native install/status/uninstall and Docker deployment details.
Tool routing
The router adds list_devices and requires deviceId on every Desktop Commander worker tool. Example targets are local-pc and remote-worker. After resolving the target worker, the router removes its own deviceId routing argument, applies configured path mappings, and forwards the remaining business arguments directly to Desktop Commander.
WCM has two local approval modes:
timed(default): every ordinary routed worker-tool call is frozen independently and returnsapproval_required=truewith a fresh opaqueapproval_id. An unbound frozen action is valid for 15 minutes. Callingrequest_approvalbinds that ID to an approval card and starts a separate 3-day (72-hour) card-validity window. Its optionalduration_secondscontrols only that ID's post-approval full-WCM grant; omitting it requests 21600 seconds (6 hours). Approve starts the grant at approval time and dispatches only that ID's frozen owner action once. Deny dispatches nothing. Different IDs never block, replace, or supersede one another, so multiple approved IDs may remain active concurrently with independent expiry times.off: routed tools execute directly without approval cards.
duration_seconds is accepted only by request_approval, not by ordinary worker tools or the app-only resolver. Valid values are whole seconds from 60 through 604800 (7 days). It is independent of card validity: a 60-second grant request still has the normal 3-day card window, and the 60-second grant starts only after approval. Once a card is bound, its duration cannot be changed and its hidden nonce is never reissued.
Approved IDs are reused through the Router-local call_with_approval tool:
call_with_approvalacceptsapproval_id,deviceId,tool_name, and the target tool's normal businessarguments.It accepts only a currently active, unexpired grant for that exact ID. Pending, denied, expired, revoked, superseded, or unknown IDs cannot borrow another grant.
It can target any registered device and any real Desktop Commander worker tool because the approved grant is full-WCM access.
It cannot recursively call Router-local tools such as
request_approval,resolve_pending_action,approval_status,list_devices, or itself.Existing Desktop Commander tool schemas and worker protocol are unchanged; approval reuse is entirely a Router-layer wrapper.
Calling an ordinary WCM worker tool directly in timed mode always requests another fresh independent approval, even while other IDs are active. approval_status(approval_id) performs a point lookup for an ID already known to the caller. list_devices exposes only aggregate pending/grant counts and nearest expiry information; it deliberately does not enumerate raw approval IDs because an approved ID is a bearer capability.
Request state and grant state are independent. For example, after approval the frozen owner action can be consumed, approved_retryable, or execution_unknown while that same ID's timed grant remains active. Expired, denied, revoked, and policy-invalidated records are retained for six hours as terminal tombstones (bounded to 1000 terminal records per store) so late callbacks and status lookups return concrete state instead of immediately collapsing to unknown.
The local mode/revoke helper is:
.\scripts\set-wcm-approval-mode.ps1 -Mode Timed
.\scripts\set-wcm-approval-mode.ps1 -Mode Off
.\scripts\set-wcm-approval-mode.ps1 -RevokeAll
.\scripts\set-wcm-approval-mode.ps1 -Status-RevokeAll increments the local policy revision; the Router sees that revision change on the next gate/status check and supersedes all in-memory pending requests and revokes all active approval-id grants.
The ChatGPT-facing approval surface follows the currently working CCM wire contract: approval tools and the approval resource are ordinary MCP tools/resources without a separate UI capability negotiation layer. request_approval carries ui.resourceUri, ui/resourceUri, openai/outputTemplate, and openai/widgetAccessible; resolve_pending_action is app-only and widget-accessible. The only public MCP endpoint is the canonical /rdc/mcp.
The approval View is one static String.raw HTML document intentionally kept structurally aligned with CCM's current working approval View. It uses the same classic inline-script layout, ui/initialize / ui/notifications/initialized lifecycle, tool-result notifications, tools/call, ui/update-model-context, and ChatGPT window.openai globals (toolResponseMetadata, toolOutput, openai:set_globals, intrinsic-height notification, and follow-up continuation). The resource path is fixed at ui://wcm/approval-v1.html, matching CCM's fixed-URI pattern while keeping the WCM namespace distinct.
The router also advertises bundled specialized capabilities in MCP discovery, list_devices, and start_process descriptions so an LLM can discover them without pretending that each helper is a standalone MCP action. The current catalog contains two capabilities: Bilibili download under tools/bilibili-download (including its bridge and bundled yt-dlp.exe fallback) and Quark transfer under tools/quark-transfer. Their READMEs remain the source of truth for invocation details and authentication requirements.
Checks
Coding agents: read
AGENTS.mdbefore running tests on a live WCM host.
npm test
powershell.exe -NoProfile -ExecutionPolicy Bypass -File .\scripts\rdc-status.ps1npm test is self-contained with respect to test data/config, but do not launch it through the same live WCM connection that is controlling this checkout: doing so can interrupt that worker/gateway transport and cause temporary HTTP 502s. Run it from an independent local terminal instead. It validates the CCM-aligned static approval View, checks the frozen approval state machine and routing contracts, and covers OAuth state pruning/caps, worker heartbeat expiry, and reconnect isolation.
To exercise an already configured live controller and sidecar, run:
npm run test:live
npm run test:sdkThe live suite covers the canonical SDK Streamable HTTP endpoint, OAuth registration/PKCE/token refresh, the ChatGPT approval surface, timed/off routing behavior, device routing, the local approval UI resource, and session handling. It uses the configured OAuth deployment and can register test clients and exercise a real frozen approval flow on the target worker, so it is intentionally separate from the default CI test.
The public endpoint is configured by RDC_RESOURCE. With a Tailscale Funnel hostname it typically looks like:
https://your-machine.your-tailnet.ts.net/rdc/mcpRDC_ISSUER and RDC_RESOURCE are deployment-specific and are never hard-coded by the sidecar.
ChatGPT rebuild handoff rule
When the ChatGPT WCM registration needs to be rebuilt, provide the current public MCP resource from RDC_RESOURCE and the following absolute-path PowerShell command so the user can print the current WCM key and URL locally:
$wcmKey = (Get-Content -LiteralPath 'C:\Users\Songjx\Documents\ChatGPT\windows-console-mcp\.state\rdc-approval-secret.txt' -Raw).Trim()
$wcmUrl = ((Get-Content -LiteralPath 'C:\Users\Songjx\Documents\ChatGPT\windows-console-mcp\config\rdc.env' | Where-Object { $_ -match '^RDC_RESOURCE=' } | Select-Object -First 1) -replace '^RDC_RESOURCE=', '').Trim().Trim('"')
Write-Output ("WCM key: " + $wcmKey)
Write-Output ("WCM URL: " + $wcmUrl)Troubleshooting
When a live WCM deployment behaves differently from the checked-out code, debug the runtime path before changing client configuration. The most common failure modes are stale processes, worker connection churn, or a tool-discovery request that never completed.
Code on disk is not proof that the live process reloaded it. Compare the running router/worker PIDs and start times with the change you expect to be live. Then query the live SDK endpoint with
initialize,tools/list, or the relevant tool call instead of inferring state from the checkout alone. After a restart, confirm that the PID changed and thatlist_devicesworks again.A
tools/listtimeout can look like stale schema or client caching. Inspect MCP BEGIN/END log pairs, session IDs, and elapsed time. If initialize succeeds buttools/listis missing an END record, is cancelled, or takes tens of seconds, fix that transport/runtime failure first. Once healthy,tools/listshould normally complete quickly and consistently.Only one active worker should own a given
deviceId. Duplicate or orphaned workers using the same ID can repeatedly replace each other's connection, causing reconnect loops and invalidating in-flight RPCs. Check worker-hub logs for frequentWorker connectedmessages and inspect process parentage. Keep the supervisor-owned worker and terminate stale/manual copies rather than starting another copy on top of them.Large tool results are capped at the router boundary.
tools/callresults larger than 512 KiB are replaced with a compact error before they reach the MCP client (WC_MAX_TOOL_RESULT_BYTEScan override the limit). Large images are previewed at a 64 KiB raw budget, andread_multiple_filesadvertises a four-image batch limit to avoid cumulative media payload spikes.Connection replacement should fail pending RPCs promptly. A
Worker connection replacedorWorker disconnectederror is preferable to waiting for the full RPC timeout. Retry after the worker stabilizes; do not treat a long timeout as evidence that the requested tool is unsupported.Debug the deployment layer by layer. Test the public OAuth sidecar, local MCP router, worker hub, and worker separately. A healthy local router does not prove the public sidecar is forwarding successfully, and a healthy OAuth flow does not prove tool discovery succeeded. Use the per-layer ports from the architecture diagram and correlate requests with the logs.
Short transport failures are expected while restarting the process that carries the current tool call. Killing or restarting the live router can make the triggering call end with HTTP 502 or
network_errorbecause its own transport disappeared. Wait for the supervisor to respawn the service, then verify a new PID and a successfullist_devices/discovery call. Do not classify this as a WCM safety refusal.Only the exact
Error: Command not allowedmarker is a WCM command-blocklist refusal. Schema errors, quoting mistakes, command-not-found errors, non-zero exits, HTTP failures,network_error, and transient 502s should be debugged as ordinary runtime/transport failures.Do not treat a single network/site failure as proof that WCM or a device is unavailable.
Network is unreachable, DNS failures, timeouts, connection resets, HTTP 403/404, and target-site verification/challenges can be transient or site-specific. Checklist_devices, retry transient requests 2-3 times when appropriate, and usecurlor another source when useful. Only conclude that WCM/device connectivity is unavailable when the device is reported offline or repeated harmless local WCM checks fail.For slow network operations, separate process start from result collection. Start the command with a short initial wait so the MCP call can return a PID/session, then use
read_process_outputto collect the result. This is more robust for operations such as remote pushes or downloads than keeping one MCP request open for the entire network operation.Avoid manual parallel launches on a supervised controller. Prefer the repository's supervisor/restart scripts. Manual router or worker instances are useful only on isolated test ports and must be cleaned up afterward. Before running disruptive tests, read
AGENTS.mdand avoid using the same live WCM transport that the test may restart.Verify client-visible schema, not just tool count or tool names. When testing discovery changes, inspect the actual
tools/listdescriptions, server instructions, resources, and tool metadata received by the SDK client. A normal tool count only proves the list was structurally available; it does not prove updated descriptions or instructions were loaded.Keep unrelated worktree changes out of operational fixes. Check
git status, stage only the intended files, rungit diff --cached --check, then commit and push. A live checkout often contains local experiments or runtime-only edits that should not be bundled into an unrelated repair.
Security
WCM can execute commands and access files on registered devices. Expose only the OAuth-protected sidecar through your HTTPS ingress; keep the router and worker hubs private to localhost/Tailscale. Remote worker admission relies on the registered Tailscale source IP, so treat your tailnet and config/devices.json as part of the trust boundary.
The owner action is frozen server-side before the card is shown. The one-time approval nonce is delivered only in the tool result _meta, compared timing-safely, bound to the Host session when available, and never accepted as a replacement for the frozen action. Unbound action validity, bound-card validity, and post-approval grant duration are separate clocks. Pending approvals, retained terminal approval/grant state, and active grants are memory-only and are cleared by Router restart.
An approved approval_id is bearer authorization for its remaining lifetime, so Router status and routine audit logs do not enumerate raw active IDs. Approval audit records use a one-way SHA-256 fingerprint prefix for correlation instead. Timed WCM access skips only the Router approval gate; it does not bypass OAuth, device admission, registered-device routing, path mapping, Desktop Commander business validation, or Desktop Commander safety rules.
Secrets, OAuth state, worker-local configuration, runtime logs, and node_modules are excluded from Git. Never commit the generated config/rdc.env, config/approval-policy.json, config/devices.json, config/worker-*.env, or .state/ contents.
License
This repository is licensed under the MIT License. Third-party dependencies retain their own licenses and copyright notices.
This server cannot be deployed
Maintenance
Related MCP Connectors
Zero-setup MCP gateway securely connecting AI to your tools with authentication and workflows
Remote streamable-HTTP MCP server running on a single Cloudflare Worker. Your assistant gets live Airbnb, Amazon, Booking.com, Google Flights, Maps and Reddit data, social search on X, Instagram and TikTok, the Meta Ad Library, and image/video generation without any keys. Connect your own accounts to let it send WhatsApp or Telegram messages, work an IMAP inbox, manage Meta Ads campaigns and publish to X and LinkedIn. OAuth 2.1 with PKCE; stored credentials are AES-256-GCM encrypted.
Multi-tenant Telegram gateway for AI agents — HTTP+stdio, 8 tools, MTProto User API
The Remote MCP server acts as a standardized bridge between LLM applications (like Claude, ChatGPT, and Cursor) and external services, enabling AI agents to access external tools and resources. Its primary capability is providing a centralized search tool to discover other MCP servers and their respective tools. Unlike local implementations, it runs remotely with OAuth authentication and permission controls for security.
Related MCP Servers
- FlicenseNot gradedqualityBmaintenanceEnables ChatGPT to securely control a single authorized Windows worker through an MCP endpoint, handling job scheduling, approval, and execution with outbound-only connectivity.-
- AlicenseNot gradedqualityBmaintenanceProvides a Windows-first local AI-agent gateway with configurable tools for files, Git, processes, Windows automation, WSL, browser control, durable agent runs, memory, verification, and intelligent routing, while exposing a secure MCP endpoint for ChatGPT Web and a local web UI.10 npmMIT
- AlicenseNot gradedqualityAmaintenanceEnables ChatGPT to work with explicitly registered projects on a Windows device through a secure, self-hosted bridge.MIT
- AlicenseNot gradedqualityAmaintenanceEnables self-hosted remote control of your own computers from Claude and ChatGPT, allowing file management, terminal access, and process control on paired machines via an outbound WebSocket relay you host.3 npmISC