{"id":"16fcd9f9-3cb6-49ac-b893-7195d2169470","slug":"nian-workspace","kind":"mcp","name":"nian-workspace","summary":"","owner":"QuocDuong16","repoUrl":"https://github.com/QuocDuong16/nian-workspace","license":"MIT","licenseTier":"permissive","trust":"community","stars":1,"match":null,"fewStars":true,"format":"mcp","createdAt":"2026-08-27T04:48:01.000Z","addedAt":"2026-10-21T21:47:04.846Z","logoUrl":"https://avatars.githubusercontent.com/u/88141204?v=4","linkOnly":false,"collection":null,"skillPath":null,"categories":["utilities"],"tags":[],"runtime":"binary","local":true,"cloudCapable":false,"cloudCapability":"unknown","cloudReadyOnPlatform":false,"needsApiKey":false,"reviewed":false,"syncedAt":"2026-10-26T09:16:23.262Z","sample":false,"url":"https://conduits.dev/tools/nian-workspace","language":"Rust","transports":["stdio"],"install":{},"requirements":{"env":[],"upstreamMayCharge":false},"tools":null,"readme":"# nian-workspace\n\nA secure local workspace bridge for web-hosted AI clients using MCP.\n\n`nian-workspace` lets a remote AI client — such as ChatGPT — work with local coding projects through the Model Context Protocol, without exposing an unauthenticated public filesystem or shell service. One process serves either a single workspace directory or a fixed set of operator-configured workspaces, providing file inspection, search, edits, controlled command execution, and Git access, always scoped to the configured directories.\n\n> **What it is not:** `nian-workspace` is not an AI agent.\n> The MCP client is the agent. `nian-workspace` is the controlled local\n> workspace capability layer it operates through.\n\n```text\nChatGPT / MCP client\n        |\n        | MCP\n        v\n Secure MCP Tunnel\n        |\n        v\n  nian-workspace\n        |\n        v\n local coding workspaces\n```\n\n## Quick start\n\n1. Install `nian-workspace` — a prebuilt binary from the [GitHub Releases page](https://github.com/QuocDuong16/nian-workspace/releases) needs no Rust toolchain (see [Install](#install)).\n\n2. Describe the workspaces to serve in a TOML registry file, e.g. `workspaces.toml`:\n\n   ```toml\n   version = 1\n\n   [workspaces.nian-workspace]\n   root = \"/home/user/Workspace/nian-workspace\"\n   write = true\n   exec = true\n\n   [workspaces.nian-vision]\n   root = \"/home/user/Workspace/nian-vision\"\n   write = true\n   ```\n\n3. Run the server (stdio is the default MCP transport):\n\n   ```bash\n   nian-workspace --workspace-config /home/user/workspaces.toml\n   ```\n\n4. Connect it to ChatGPT through Secure MCP Tunnel — see [Secure MCP Tunnel](#secure-mcp-tunnel).\n\nOnce connected, the client calls `list_workspaces` to discover the configured IDs (`nian-workspace`, `nian-vision`) and passes one as the `workspace` argument of every other tool.\n\nPrefer one workspace per process? Skip the TOML file and run `nian-workspace /path/to/project` (read-only by default; see [Basic usage](#basic-usage)).\n\n## Install\n\nPrebuilt, checksummed native archives are published on the [GitHub Releases page](https://github.com/QuocDuong16/nian-workspace/releases). No Rust toolchain is required to run them.\n\n| Platform | Archive |\n|---|---|\n| Linux x86_64 | `nian-workspace-vX.Y.Z-x86_64-unknown-linux-gnu.tar.gz` |\n| Linux arm64 | `nian-workspace-vX.Y.Z-aarch64-unknown-linux-gnu.tar.gz` |\n| Windows x86_64 (MSVC) | `nian-workspace-vX.Y.Z-x86_64-pc-windows-msvc.zip` |\n| macOS x86_64 | `nian-workspace-vX.Y.Z-x86_64-apple-darwin.tar.gz` |\n| macOS arm64 | `nian-workspace-vX.Y.Z-aarch64-apple-darwin.tar.gz` |\n\nEach archive contains the binary plus `README.md`, `LICENSE`, and `RELEASE_NOTES.md`. A `SHA256SUMS` file covering all archives is attached to the release for verification. Tagged releases are built and tested natively on each platform — see [docs/release.md](docs/release.md).\n\n### Build from source\n\nBuilding from source requires Rust 1.99.0 or newer. The exact development toolchain is pinned in [`mise.toml`](mise.toml), [`mise.lock`](mise.lock), and [`rust-toolchain.toml`](rust-toolchain.toml).\n\n```bash\ngit clone https://github.com/QuocDuong16/nian-workspace.git\ncd nian-workspace\nmise trust\nmise install --locked rust\n\n# Install into Cargo's binary directory (normally ~/.cargo/bin).\ncargo install --path . --locked\n\n# Or build an optimized binary without installing it.\ncargo build --release --locked\n# Linux/macOS: target/release/nian-workspace\n# Windows:     target/release/nian-workspace.exe\n```\n\n## Basic usage\n\n```\nnian-workspace [WORKSPACE] [OPTIONS]\n```\n\nWithout a positional workspace root, the current directory is served. The server starts **read-only**; every capability beyond reading must be enabled explicitly and is never promoted silently at runtime.\n\n| Flag | Effect |\n|---|---|\n| `--write` | Allow file edits through `apply_patch` |\n| `--exec` | Allow direct process execution (`run_command`) |\n| `--allow-shell` | Allow shell-mode execution — the system shell interprets the whole command line; requires `--exec` |\n| `--workspace-config <PATH>` | Serve a registry of named workspaces instead of one — see [Registry mode](#registry-mode) |\n| `--transport <stdio\\|http>` | MCP transport (default: `stdio`) |\n| `--host <HOST>` / `--port <PORT>` | HTTP bind address — loopback only (default `127.0.0.1:8787`) |\n| `--log-level <LEVEL>` | `error`, `warn`, `info`, `debug` (or set `RUST_LOG`) |\n\nPermission progression:\n\n```bash\nnian-workspace .                               # read-only\nnian-workspace . --write                       # + apply_patch\nnian-workspace . --write --exec                # + run_command (no shell)\nnian-workspace . --write --exec --allow-shell  # + shell syntax (cmd.exe / /bin/sh)\n```\n\nIn registry mode the CLI permission flags are not used at all — each workspace's permissions come from the configuration file.\n\n## Registry mode\n\n`--workspace-config <PATH>` loads a versioned TOML registry of named workspaces. One process serves all of them; each MCP request selects one workspace by its logical ID.\n\n```toml\nversion = 1\n\n[workspaces.nian-workspace]\nroot = \"/home/user/Workspace/nian-workspace\"\nwrite = true\nexec = true\nallow_shell = false\n\n[workspaces.nian-vision]\nroot = \"/home/user/Workspace/nian-vision\"\nwrite = true\nexec = true\nallow_shell = false\n```\n\nThe operational rules:\n\n- **Roots must be absolute** and must exist and be directories.\n- **Workspace IDs are logical names** — lowercase, 1–64 characters (`[a-z0-9][a-z0-9._-]{0,63}`). They are never filesystem paths.\n- **Roots are fixed at startup** — the registry is immutable while the process runs; there is no runtime add/remove/reload and no workspace switching.\n- **Overlapping or nested roots are rejected** at startup — including the same directory registered twice under different spellings — so a broader writable workspace cannot bypass a narrower read-only one.\n- **Permissions are per workspace**: read access is implicit; `write`, `exec`, and `allow_shell` default to `false`.\n- **`allow_shell = true` requires `exec = true`**.\n- `--workspace-config` is mutually exclusive with a positional `WORKSPACE` and with `--write`/`--exec`/`--allow-shell`.\n\nThe full configuration reference — ID grammar and quoting, validation rules, and a single-vs-registry comparison — is in [docs/configuration.md](docs/configuration.md).\n\n## Secure MCP Tunnel\n\nThis is the primary ChatGPT integration. ChatGPT connects to remote MCP servers rather than spawning local processes; Secure MCP Tunnel bridges a local `nian-workspace` stdio process to ChatGPT without exposing an unauthenticated HTTP listener to the public internet.\n\n**Supported baseline: `tunnel-client` v0.0.14 or newer.**\n\n1. Create (or reuse) a Secure MCP Tunnel and assign it to the ChatGPT workspace that will use the connector; otherwise it may not appear in the tunnel picker.\n2. Create a **Restricted Runtime API Key** for `tunnel-client` with only **Tunnels: Read** and **Tunnels: Use**. Do not use an Admin API key for the daemon.\n3. Export the key and tunnel ID, initialize a profile, and run it (registry-mode example):\n\n   ```bash\n   export CONTROL_PLANE_API_KEY='sk-...'\n   export CONTROL_PLANE_TUNNEL_ID='tunnel_...'\n\n   tunnel-client init \\\n     --sample sample_mcp_stdio_local \\\n     --profile nian-workspace \\\n     --tunnel-id \"$CONTROL_PLANE_TUNNEL_ID\" \\\n     --mcp-command \"/home/user/.local/bin/nian-workspace --workspace-config /home/user/workspaces.toml\"\n\n   tunnel-client doctor --profile nian-workspace --explain\n   tunnel-client run --profile nian-workspace\n   ```\n\n4. In ChatGPT, configure the custom MCP app/connector:\n\n   ```text\n   Settings\n     → Connectors / custom MCP app\n     → Connection: Tunnel\n     → select the tunnel / tunnel ID\n     → Authentication: None\n   ```\n\nNotes:\n\n- `CONTROL_PLANE_API_KEY` authenticates `tunnel-client` to the tunnel control plane. It is **not** MCP authentication for `nian-workspace` itself, which implements no OAuth or bearer-token MCP authentication.\n- **Single workspace instead of a registry:** point `--mcp-command` at one workspace root with its flags — `--mcp-command \"/path/to/nian-workspace /path/to/my-project --write --exec\"` — and keep the rest of the setup identical. To work on several projects this way, create several profiles with the same tunnel ID and run them one at a time.\n- **Only one backend should actively own a given tunnel at a time.** Stop the currently running profile before starting another profile that reuses the same tunnel — a profile switch changes which `nian-workspace` process is reachable.\n- If tool calls fail, first confirm the `nian-workspace` backend is healthy (`tunnel-client doctor --profile <name>`, process still running) and inspect the `tunnel-client` and `nian-workspace` logs for diagnostics.\n\n### Local MCP clients (stdio)\n\nAny MCP-compatible local client can use `nian-workspace` as a direct stdio backend. This is supported, but the primary design target is the Secure MCP Tunnel path above.\n\n```json\n{\n  \"mcpServers\": {\n    \"nian-workspace\": {\n      \"command\": \"/usr/local/bin/nian-workspace\",\n      \"args\": [\"/absolute/path/to/project\", \"--write\", \"--exec\"]\n    }\n  }\n}\n```\n\nUse an absolute binary path if the client does not inherit your shell `PATH`. Logs go to stderr while the protocol runs on stdout, so redirecting stderr will not corrupt a session.\n\n### Streamable HTTP\n\nFor clients that can reach the machine over a trusted local path, run the built-in loopback-only HTTP transport:\n\n```bash\nnian-workspace . --write --exec --transport http --host 127.0.0.1 --port 8787\n```\n\nThe MCP endpoint is then served at `http://127.0.0.1:8787/mcp`. Non-loopback binds are refused and there is no built-in authentication — for remote access, put a secure tunnel or another authenticated TLS layer in front of `127.0.0.1`.\n\n## Tools\n\nThe tool surface is mode-specific: single-workspace mode exposes exactly the eight tools below with the v0.1 schemas, while registry mode exposes those eight **plus `list_workspaces`** — every tool except `list_workspaces` then takes a required logical `workspace` argument.\n\n| Tool | Purpose | Permission |\n|---|---|---|\n| `workspace_info` | Workspace metadata: permissions, Git branch | read (implicit) |\n| `list_files` | Bounded directory listing | read (implicit) |\n| `read_file` | Line-numbered text read | read (implicit) |\n| `search` | Regex or literal text search | read (implicit) |\n| `git_status` | Working-tree status | read (implicit) |\n| `git_diff` | Unstaged or staged diff | read (implicit) |\n| `apply_patch` | Apply a unified diff | `write` |\n| `run_command` | Run a program directly (`shell = true` for shell syntax) | `exec` (shell mode also needs `allow_shell`) |\n| `list_workspaces` | *(registry mode only)* Configured IDs and their permissions | read (implicit) |\n\nThe complete reference — argument schemas, output shapes, registry selectors, and bounded-output behavior — is in [docs/tools.md](docs/tools.md).\n\n## Security\n\n**`nian-workspace` is not an OS sandbox.** Read this before enabling `--write`, `--exec`, or `--allow-shell`.\n\n- **Filesystem tools are restricted to the configured roots.** `list_files`, `read_file`, `search`, `apply_patch`, `run_command`'s working directory, and `git_diff` path filters reject `../` traversal, absolute paths outside the root, and symlinks that resolve outside it.\n- **Command execution runs real local processes** with your OS user's full permissions. A spawned command can access files outside the workspace, use the network, and spawn descendants. Enable `exec`/`write`/`shell` only for MCP clients you trust.\n- **`allow_shell` is a separate, stronger capability** because the shell (`/bin/sh` on Unix, `cmd.exe` on Windows) interprets the entire command line, enabling chaining, redirection, and expansion. It requires `exec`.\n- **HTTP mode is loopback-only.** Non-loopback bind addresses are rejected at startup: there is no authentication layer, so anything that can reach the port can use the enabled tools against your filesystem.\n- **Outputs are bounded** (~256 KiB per channel by default) with truncation metadata, so large logs and dumps cannot flood model context.\n\nNo security guarantees beyond these mechanisms are made. The full security model — filesystem boundary internals, the command-execution threat model, and Git hardening — is in [docs/security.md](docs/security.md).\n\n## Documentation\n\n| Document | Contents |\n|---|---|\n| [docs/configuration.md](docs/configuration.md) | Registry format, workspace IDs, root validation, permissions, single vs registry mode |\n| [docs/tools.md](docs/tools.md) | Complete MCP tool reference: schemas, outputs, provenance |\n| [docs/security.md](docs/security.md) | Filesystem boundary model, command-execution threat model, hardening details |\n| [docs/architecture.md](docs/architecture.md) | Bridge-not-agent design, server modes, transports, design invariants |\n| [docs/development.md](docs/development.md) | Local development, Rust toolchain, CI |\n| [docs/release.md](docs/release.md) | Release pipeline, platforms, artifacts |\n| [RELEASE_NOTES.md](RELEASE_NOTES.md) | Release history |\n\n## Development\n\nLocal quality gates:\n\n```bash\ncargo fmt --all --check\ncargo clippy --all-targets --all-features -- -D warnings\ncargo test\ncargo build --release\n```\n\nDevelopment changes are validated by CI, and tagged releases are built and tested natively for all supported platforms — see [docs/development.md](docs/development.md) and [docs/release.md](docs/release.md).\n\n## License\n\nMIT. See [LICENSE](LICENSE).\n"}