Install
$ agentstack add mcp-gabrielmaialva33-winx-code-agent Open-source listing β not yet scanned by AgentStack. Follow the source repository for install instructions.
Security review
β Flagged1 finding(s); flagged for manual review. Β· v0.1.0 How review works β
- β’ Prompt-injection patterns
- β’ Secret / credential exfiltration
- β’ Dangerous shell & filesystem operations
- β’ Untrusted network calls
- β’ Known-malicious package signatures
- high Pipes remote content directly into a shell (remote code execution).
What it can access
- β Network access Used
- β Filesystem access No
- β Shell / process execution No
- β Environment & secrets No
- β Dynamic code execution No
From automated source analysis of v0.1.0. βUsedβ means the capability is present in the source β more access means more to trust, not that itβs unsafe.
About
β¨ Winx - MCP Server for Shell & Coding Agents β¨
π¦ Native Rust implementation inspired by WCGW, built for local code-agent workflows
A local MCP server you can hand to a coding agent and stop worrying about the shell.
Winx is the MCP server I wanted while running Claude, Codex, and friends against real repos: one process that handles the shell, file IO, and PTY-backed interactive sessions, written in Rust so it doesn't fight you on stdio.
It started as a Rust port of WCGW but isn't a Python wrapper. Everything runs on a real PTY (via portable-pty), cd actually sticks, Ctrl+C actually interrupts, and background shells survive long-running TUIs without leaking output buffers into your token budget.
What you get
- A stateful bash session per thread with proper PTY semantics - foreground, background, status checks, text input,
Enter/Ctrl-C/Ctrl-D, raw ASCII. Multiline scripts and top-level command shorthand both work; NUL bytes are rejected before they reach the shell.
- Workspaces with three modes:
wcgw(full access),architect(read-only),code_writer(allowlist of commands and
write globs). The command allowlist is parsed with tree-sitter, so it checks every command on the line - pipelines, &&/||/;, command substitution, subshells - not just the first word, and can't be bypassed with ls && curl β¦ | sh or ls $(rm β¦).
- A resilient PTY: a shell that won't return to a prompt (even after Ctrl-C) is auto-reset at the same cwd/mode, child
processes are reaped on drop, and prompt detection is robust to a custom PS1. Opt into zsh with WINX_SHELL=zsh.
- File reads with WCGW-style line ranges (
file.rs:10-40,file.rs:10-,file.rs:-40). Active files are tracked
and prioritized in the repository context across calls.
- File writes and SEARCH/REPLACE edits that survive ambiguous matches, indentation drift, and the usual unicode
quote-mismatches from LLMs. Writes are blocked when the file hasn't been read or the cached content is stale, the success message shows a compact diff of what changed, and recent edits are reversible with UndoEdit. MultiFileEdit applies a change across several files all-or-nothing (validated in memory first, so a failure on the last file leaves the earlier ones untouched).
- Tree-sitter code navigation via
CodeMap: a token-budgeted symbol map of a file or the whole repo, or a
definition/reference lookup for a symbol name - the semantic view that plain grep can't give you, across 11 languages.
ContextSavefor handing a task summary plus its files to the next session - including workspace context, active
files, git status/diff, and terminal sharing for proper resumption. Resuming reopens the saved project root and token-caps the restored memory so it never overflows the context window.
ReadImageso multimodal clients can pull screenshots, mockups, error PNGs, etc.- Clean, token-aware shell output: cursor/ANSI noise from interactive programs (REPLs, progress
bars) is rendered away through a terminal emulator, and mechanical repetition is collapsed losslessly (line [winx: ΓN]) so build/install logs don't blow your context budget. Toggle the collapsing with WINX_NO_COMPRESS. When output still overflows the cap, the dropped head is streamed to a scratch file under .winx/scratch/ the agent can re-read, instead of being lost.
- Secret redaction on by default: provider API keys, JWTs, PEM private-key blocks and
user:pass@URLs
are scrubbed from all tool output and saved memory before they reach the model (disable with WINX_NO_REDACT=1). An opt-in Landlock sandbox (WINX_SANDBOX=1, Linux) adds a kernel-enforced second layer that confines writes to the workspace and hides the home directory.
- Two transports: stdio for local clients, plus an optional token-gated Streamable HTTP server
(winx serve --http) for remote MCP clients like ChatGPT - see [Remote access](#remote-access-chatgpt--other-remote-mcp-clients).
MCP Tools
| Tool | What it does | |-------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Initialize | Boots the workspace, picks the mode, hands you a thread_id. Call this first or everything else errors out. With no workspace path it spins up a scratch playground; resuming a task (task_id_to_resume) reopens its saved project root. | | BashCommand | Runs commands, polls long-running ones, sends Enter/Ctrl-C, drives TUIs. Supports is_background, status_check, send_text, send_specials, send_ascii, allow_multi, plus screen (a stable point-in-time frame of an interactive TUI with the cursor position; pass diff:true for only the lines that changed since your last look) and wait_for_turn (block until the TUI is ready for input, via per-app or configurable recognizers). When a foreground command finishes, the status line reports its real exit code (parsed from the prompt marker), so failures surface without grepping stderr. | | ReadFiles | One or many files, with line numbers. Append :10-40 to a path for a range. When the token budget is hit it tells you the exact line + file:N-M syntax to resume from instead of silently dropping the tail. | | FileWriteOrEdit | Full overwrites or SEARCH/REPLACE blocks (with optional @start-end line anchors to pin a repeated block). Validates file read coverage and freshness before writing, reports any fuzzy tolerances it had to apply, then runs a tree-sitter syntax check (18+ languages) and points at the offending line with a snippet. The success message includes a compact diff of what changed. | | MultiFileEdit | Edits several files all-or-nothing: every file's edit is validated and computed in memory first, and only if all succeed is anything written - so a SEARCH that fails to match in the last file leaves the earlier ones untouched. For a single file use FileWriteOrEdit. | | UndoEdit | Reverts a file to its content before the last FileWriteOrEdit/MultiFileEdit this session (per-file, last ~10 edits kept in memory). Refused if the file changed on disk since your edit; a brand-new file's creation isn't undoable. | | ContextSave | Dumps task description + file globs into a single text file with workspace context, active files, and git status/diff for clean handoff and task resumption. | | ReadImage | Returns a native MCP image content block (not base64 as text), so multimodal models actually see the image. Confined to the workspace (like ReadFiles) and size-capped. | | CodeMap | Tree-sitter code navigation, in one tool with two operations. outline: a symbol map (functions, types, methods, ...) - a file returns its definitions, a directory (or empty) a relevance-ranked, token-budgeted repo symbol map, in 11 languages. references: where a name is defined and used (called) across the repo, counting only real identifier occurrences (never inside strings/comments, unlike grep), definitions first. For plain-text/regex search and file discovery, just use rg/fd/grep via BashCommand. |
Search/Replace editing
Standard block syntax:
>>>>>> REPLACE
Things the matcher forgives so you don't have to babysit the model:
- atomic: ambiguous or missing matches abort without touching the file
- adjusts replacement indentation when the LLM gets the leading whitespace wrong
- strips
ReadFilesline numbers if they leak into a SEARCH block - normalizes the usual "smart quote" / em-dash / ellipsis substitutions
- uses neighboring blocks to disambiguate when the same snippet appears twice
- single-line substring edits work - you don't need the whole line in SEARCH
- retries once with
\"unescaped when the model over-escapes quotes in SEARCH - refuses edits that only matched after too much fuzzy fixup, and rejects blocks
that match in too many places - so you re-read instead of corrupting the file
- anchor a block to a line number to pin one of several identical snippets -
` Claude Code (CLI)
One-liner via the CLI (stdio is the default transport):
claude mcp add winx -- winx-code-agent
Or drop a .mcp.json in your project root:
{
"mcpServers": {
"winx": {
"command": "winx-code-agent",
"env": { "RUST_LOG": "winx_code_agent=info" }
}
}
}
Claude Desktop
Add to your config file (~/Library/Application Support/Claude/claude_desktop_config.json on macOS, %APPDATA%\Claude\claude_desktop_config.json on Windows):
{
"mcpServers": {
"winx": {
"command": "winx-code-agent",
"env": { "RUST_LOG": "winx_code_agent=info" }
}
}
}
Restart Claude Desktop after saving.
Codex (OpenAI CLI)
One-liner:
codex mcp add winx -- winx-code-agent
Or edit ~/.codex/config.toml:
[mcp_servers.winx]
command = "winx-code-agent"
env = { RUST_LOG = "winx_code_agent=info" }
Cursor
Add to ~/.cursor/mcp.json (or .cursor/mcp.json for project-local):
{
"mcpServers": {
"winx": {
"command": "winx-code-agent",
"env": { "RUST_LOG": "winx_code_agent=info" }
}
}
}
VS Code (Copilot Chat / MCP)
Add to .vscode/mcp.json:
{
"servers": {
"winx": {
"type": "stdio",
"command": "winx-code-agent"
}
}
}
Zed
Add to your Zed settings (~/.config/zed/settings.json):
{
"context_servers": {
"winx": {
"source": "custom",
"command": "winx-code-agent",
"args": [],
"env": { "RUST_LOG": "winx_code_agent=info" }
}
}
}
Windsurf
Add to ~/.codeium/windsurf/mcp_config.json:
{
"mcpServers": {
"winx": {
"command": "winx-code-agent",
"env": { "RUST_LOG": "winx_code_agent=info" }
}
}
}
OpenCode
Add to opencode.json:
{
"mcp": {
"winx": {
"type": "local",
"command": ["winx-code-agent"],
"enabled": true,
"environment": { "RUST_LOG": "winx_code_agent=info" }
}
}
}
Gemini CLI
Add to ~/.gemini/settings.json:
{
"mcpServers": {
"winx": {
"command": "winx-code-agent",
"args": [],
"env": { "RUST_LOG": "winx_code_agent=info" }
}
}
}
agy (Google Antigravity CLI)
agy is Google's new Gemini-powered CLI (Go binary, usually at ~/.local/bin/agy). No mcp add subcommand yet - it reads MCP servers from JSON.
Edit ~/.gemini/config/mcp_config.json (also ~/.gemini/antigravity/mcp_config.json if you run the Antigravity IDE alongside):
{
"mcpServers": {
"winx": {
"command": "winx-code-agent",
"env": { "RUST_LOG": "winx_code_agent=info" }
}
}
}
If winx-code-agent is not on the agy process $PATH, swap command for the absolute path (~/.cargo/bin/winx-code-agent after cargo install winx-code-agent).
Continue.dev
Add to your ~/.continue/config.yaml:
mcpServers:
- name: winx
command: winx-code-agent
env:
RUST_LOG: winx_code_agent=info
Kiro
Add to ~/.kiro/settings/mcp.json:
{
"mcpServers": {
"winx": {
"command": "winx-code-agent",
"env": { "RUST_LOG": "winx_code_agent=info" }
}
}
}
Warp
Settings β MCP Servers β Add MCP Server:
{
"winx": {
"command": "winx-code-agent",
"env": { "RUST_LOG": "winx_code_agent=info" }
}
}
Roo Code
Add to your Roo Code MCP config:
{
"mcpServers": {
"winx": {
"type": "stdio",
"command": "winx-code-agent"
}
}
}
Other clients (generic stdio)
Any client that speaks stdio MCP works with this shape:
{
"mcpServers": {
"winx": {
"command": "winx-code-agent",
"args": [],
"env": { "RUST_LOG": "winx_code_agent=info" }
}
}
}
If your client launches Winx with an empty $PATH, swap command for the absolute path ( ~/.cargo/bin/winx-code-agent).
Build from source
For unreleased changes or a custom build:
git clone https://github.com/gabrielmaialva33/winx-code-agent.git
cd winx-code-agent
cargo install --path .
Or run it without installing:
cargo run --release
Check it's wired up
List MCP tools in your client. You should see nine entries: Initialize, BashCommand, ReadFiles, FileWriteOrEdit, MultiFileEdit, UndoEdit, ContextSave, ReadImage, CodeMap. The first call always has to be Initialize; Winx tracks workspace + mode per thread.
Remote access (ChatGPT & other remote MCP clients)
By default Winx speaks MCP over stdio - the local transport every desktop client (Claude Desktop, Cursor, VS Code) uses. For clients that live in the cloud and can't reach your machine over stdio - like ChatGPT's developer-mode custom connectors - Winx can also serve MCP over Streamable HTTP:
winx serve --http --bind 127.0.0.1:8000 --token "$(openssl rand -hex 24)"
The MCP protocol is served at /mcp. Every request must carry the token in the Authorization: Bearer header (header-only - a ?token= query parameter would leak the secret into proxy/tunnel access logs and browser history). Without a token the server refuses to start - serving a shell over the network without auth is remote code execution waiting to happen. The endpoint also caps request bodies (64 MB) and times out stuck requests (120 s).
| Flag | Purpose | |------------------|-------------------------------------------------------------------------------------------------| | --http | Serve over Streamable HTTP instead of stdio. | | --bind | Listen address. Defaults to 127.0.0.1:8000. Keep it on loopback. | | --token | Shared secret required on every request. Falls back to the WINX_HTTP_TOKEN env var. | | --allowed-host | Extra Host authority to accept (your tunnel hostname). Repeatable. Loopback is always allowed. |
Remote clients run in the cloud, so the endpoint has to be reachable over HTTPS - put a tunnel in front of the loopback listener and allow its hostname through the built-in DNS-rebinding guard:
# 1. tunnel first, to learn the public hostname
cloudflared tunnel --url http://localhost:8000
# -> https://.trycloudflare.com
# 2. start Winx, allowing that host
winx serve --http --bind 127.0.0.1:8000 \
--token "$(openssl rand -hex 24)" \
--allowed-host .trycloudflare.com
In ChatGPT (Settings β Apps β Advanced β Developer mode), add a connector with:
- URL:
https://.trycloudflare.com/mcp - Authentication: bearer / API-key token set to ``, so the connector sends it as
Authorization: Bearer (the token is no longer accepted in the URL)
Remote clients are effectively stateless - they don't reuse the MCP session between tool calls - so the HTTP transport shares one shell session across all requests: the shell Initialize creates stays alive for the lifetime of the server, and later BashCommand calls find it. Reuse the same thread_id across calls.
> [!WARNING] > The HTTP transport puts arbitrary shell and file access on the network. Anyone with the token (and URL) gets a shell > on your machine as your user - and not just inside the workspace, since BashCommand in wcgw mode isn't > path-restricted. Bind to loopback, keep it behind an authenticat
β¦
Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source β we do not rehost the code.
- Author: gabrielmaialva33
- Source: gabrielmaialva33/winx-code-agent
- License: MIT
- Homepage: https://crates.io/crates/winx-code-agent
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet β be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.