Content
<div align="center">
<img src="./assets/hero.svg" alt="mcps-manager" width="820"/>
<h1>mcps-manager</h1>
<p><b>Centralize MCP configurations from 6 AI coding tools into one unified management system</b></p>
<p><i>One central UMS repo · six host adapters · lossless format conversion</i></p>
<p>
<a href="LICENSE"><img src="https://img.shields.io/github/license/tinymindkin/mcps-manager?style=flat-square&color=blue" alt="license"/></a>
<img src="https://img.shields.io/badge/platform-macOS-000000?style=flat-square&logo=apple" alt="macOS"/>
<img src="https://img.shields.io/badge/tauri-2-24C8DB?style=flat-square&logo=tauri&logoColor=white" alt="tauri 2"/>
<img src="https://img.shields.io/badge/rust-1.97+-B7410E?style=flat-square&logo=rust&logoColor=white" alt="rust"/>
<img src="https://img.shields.io/badge/frontend-vanilla_JS-F7DF1E?style=flat-square&logo=javascript&logoColor=black" alt="vanilla JS"/>
<img src="https://img.shields.io/badge/PRs-welcome-brightgreen?style=flat-square" alt="PRs welcome"/>
<a href="https://github.com/tinymindkin/mcps-manager/stargazers"><img src="https://img.shields.io/github/stars/tinymindkin/mcps-manager?style=flat-square&color=yellow" alt="stars"/></a>
</p>
<p>
<a href="#-why">Why</a> ·
<a href="#-core-features">Features</a> ·
<a href="#-quick-start">Install</a> ·
<a href="#-supported-hosts">Hosts</a> ·
<a href="#-architecture">Architecture</a> ·
<a href="#-roadmap">Roadmap</a> ·
<a href="#-contributing-a-new-host">Contributing</a>
</p>
</div>
---
## 🤔 Why
Are you using more than one of **Claude Code / Codex / Cursor / Gemini / OpenCode / Qwen / Kimi**? If so, you've likely encountered the following issues:
- Having to manually configure the same MCP across **six different tools**;
- Configuration files scattered across **six different directories** in **three different formats** — Claude uses JSON, Codex uses **TOML**, and OpenCode uses a different JSON format with `command` and `args` combined into an array;
- Field names differ across tools: `mcpServers` vs `mcp`, `env` vs `environment`;
- Manually converting MCP configurations between tools is tedious and error-prone;
- Copying configurations between tools can lead to security issues, such as [exposed Anthropic API Keys on GitHub](https://github.com/search?q=claude_desktop_config&type=code).
**mcps-manager** solves these problems by providing a centralized UMS repository and six host adapters:
- Maintain a single configuration in `~/.mcps-manager/` and automatically convert formats and preserve host-specific fields when pushing to any host.
---
## ✨ Core Features
| | |
|---|---|
| 🎯 **Focused on MCPs** | Only manages MCPs, not Skills, Plugins, Hooks, Memory, or Rules. Depth over breadth. |
| 🔄 **Bidirectional format conversion** | Central UMS ⇄ 6 native host formats, automatically and losslessly. |
| 🛡 **Preserves host file integrity** | 89KB `.claude.json` or 356-line `.codex/config.toml` files remain unchanged, with all non-MCP fields preserved. |
| 💾 **Host-specific fields preserved** | Codex's `[mcp_servers.foo.tools.<tool>] approval_mode` is preserved in UMS `hostExtras.codex` and restored when pushing back to the same host. |
| 🔒 **Secure writing** | Backups to `~/.mcps-manager/backups/<timestamp>/` + atomic `tmp → fsync → rename` + pre-write round-trip parsing. |
| 🧩 **Decoupled architecture** | Each host has its own file, with hardcoded paths, formats, and schema concentrated in top-level constants. Adding a new host requires only 3 files. |
| ⚡ **Lightweight** | Tauri 2, ~10MB packaged. Frontend has zero npm dependencies, using pure HTML/CSS/JS. |
| 🧪 **Tested** | 4 integration tests ensure that non-MCP fields remain unchanged. |
---
## 📸 Interface Preview
<div align="center">
<i>Three panes: hosts on the left, servers in the middle, and UMS details + Push panel on the right</i>
<br/><br/>
<sub>(Screenshot to be updated after v0.3 release; run <code>cargo tauri dev</code> to see it in action)</sub>
</div>
---
## 📦 Quick Start
### Dependencies
- macOS 12+ (Apple Silicon verified; Intel not tested)
- Rust 1.97+ (will be installed by the following command)
- Node **not required** — frontend has zero dependencies
### One-time setup
```bash
# Install Rust (to ~/.cargo, can be uninstalled with rustup self uninstall)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable
source "$HOME/.cargo/env"
# Install Tauri CLI
cargo install tauri-cli --version '^2.0' --locked
```
### Run it
```bash
git clone git@github.com:tinymindkin/mcps-manager.git
cd mcps-manager/src-tauri
cargo tauri dev
```
First compilation takes ~3–5 minutes; subsequent hot reloads are instantaneous. Frontend code is in `dist/`, and can be refreshed with `⌘R` in the window (no need to restart the backend).
### Directory structure (after first launch)
```
~/.mcps-manager/
├── servers/ # One UMS JSON file per MCP (git-friendly)
│ ├── filesystem.json
│ ├── notion.json
│ └── ...
├── backups/ # Automatic backups before writing to host files
│ └── 2026-07-22T14-30-00/
│ └── codex__config.toml
└── profiles/ # (v0.4) Scene packaging
```
---
## 🛠 Supported Hosts
| Host | Config Path | Format | MCP Root Key | Special Fields |
|---|---|---|---|---|
| **Claude Code** | `~/.claude.json` | JSON | `mcpServers` | — |
| **Codex** | `~/.codex/config.toml` | **TOML** | `mcp_servers` | `[mcp_servers.<x>.tools.<tool>] approval_mode` nested table; inline env |
| **Gemini CLI** | `~/.gemini/settings.json` | JSONC (with `//` comments) | `mcpServers` | — |
| **OpenCode** | `~/.config/opencode/opencode.json` | JSON | `mcp` | `command` is an array; env key is `environment`; each entry must have `type: "local"` |
| **Qwen Code** | `~/.qwen/settings.json` | JSON | `mcpServers` | — |
| **Kimi CLI** | `~/.kimi-code/mcp.json` | JSON | `mcpServers` | Optional `transport: "stdio" \| "sse" \| "http"` |
> **Not supported**: Cursor, Windsurf, Copilot, Roo Code, TRAE, etc. Want to add one? [Open an issue](../../issues) or submit a PR — see [Contributing a new host](#-contributing-a-new-host).
---
## 🏗 Architecture
<div align="center">
<img src="./assets/architecture.svg" alt="architecture" width="900"/>
</div>
Four layers, from top to bottom:
1. **UI Layer**: Tauri 2 window + pure HTML/CSS/JS three panes.
2. **Application Commands**: `list_hosts` / `import_from_host` / `export_to_host` / `write_repo_server` tauri commands.
3. **Domain**: UMS schema, Repo (`~/.mcps-manager/servers/*.json`), `HostAdapter` trait, Registry. **Host-agnostic**.
4. **Adapter Layer**: Each host has its own file, with hardcoded constants concentrated at the top; shared JSON/TOML helpers are extracted into `adapters/mod.rs` and `adapters/toml_common.rs`.
Complete design is in [DESIGN.md](./DESIGN.md).
---
## 🔄 Format Conversion (Example)
<div align="center">
<img src="./assets/formats.svg" alt="format conversion" width="900"/>
</div>
Real-world translation details:
- **Codex TOML** uses [`toml_edit`](https://crates.io/crates/toml_edit) — preserves original file comments, key order, and empty lines, rather than "deserialize and serialize" which can mess up formatting.
- **Gemini's JSONC** uses `json5` fallback parsing to handle `// commented-out servers`.
- **OpenCode** automatically merges `command + args` into an array, renames the env key to `environment`, and adds `type: "local"`.
- **Kimi's `transport` field** is intelligently preserved: `stdio` is not emitted (implicitly omitted), while `sse` / `http` are written out — matching Kimi's official documentation style.
---
## 🛡 Three Safeguards for Host File Security
Before writing to any host configuration file, `mcps-manager` performs:
1. **MCP subtree isolation**: only touches the `mcpServers` / `mcp_servers` / `mcp` subtree; all other top-level keys, comments, and formatting are preserved.
2. **Backup**: entire original file is copied to `~/.mcps-manager/backups/<ISO timestamp>/`.
3. **Atomic write + round-trip validation**: `.tmp → fsync → rename`; pre-write parsing to ensure the written content can be successfully parsed.
Four integration tests in `src-tauri/tests/roundtrip.rs` ensure these invariants:
```
running 4 tests
test claude_json_shape_preserves_other_keys ... ok
test codex_toml_preserves_other_sections_and_writes_subtable ... ok
test kimi_json_shape_handles_stdio_sse_and_explicit_transport ... ok
test opencode_shape_uses_command_array_and_environment_and_type ... ok
```
---
## 🗺 Roadmap
- [x] **v0.1** — Read-only import: 6 host adapters, UMS repo, three-pane UI
- [x] **v0.2** — Bidirectional: `export_to_host` + format conversion + backup + atomic write
- [x] **v0.2.4** — Kimi JSON + optional `transport` field support
- [ ] **v0.3** — Diff view, UMS editor (currently can only delete and recreate)
- [ ] **v0.4** — Profile: package MCPs into scenes
- [ ] **v0.5** — CLI (`mcps-manager export --host codex ...`) + Keychain secret
- [ ] **v0.6** — Project-level configuration (Claude's `.mcp.json`, OpenCode's project `opencode.json`)
- [ ] **v1.0** — Apple-notarized `.dmg`, Cursor / Windsurf / Copilot adapter
---
## 🤝 Contributing a New Host
Theoretically, adding a new host requires only 3 files and ~50 lines of code:
```rust
// 1. src-tauri/src/adapters/cursor.rs
use super::{parse_json_servers, read_json_lenient, write_json_host,
HostAdapter, JsonAdapterShape, WriteReport};
use crate::ums::UmsServer;
use anyhow::Result;
use std::path::PathBuf;
pub struct CursorAdapter;
const SHAPE: JsonAdapterShape = JsonAdapterShape {
root_key: "mcpServers",
env_key: "env",
command_is_array: false,
emit_type_field: false,
transport_key: None,
known_fields: &["command", "args", "env", "url", "headers", "type"],
};
impl HostAdapter for CursorAdapter {
fn id(&self) -> &'static str { "cursor" }
fn display_name(&self) -> &'static str { "Cursor" }
fn primary_path(&self) -> PathBuf {
dirs::home_dir().unwrap().join(".cursor/mcp.json")
}
fn format_label(&self) -> &'static str { "JSON (mcpServers)" }
fn list_servers(&self) -> Result<Vec<UmsServer>> {
let path = self.primary_path();
if !path.exists() { return Ok(vec![]); }
let root = read_json_lenient(&path)?;
let Some(map) = root.get(SHAPE.root_key).and_then(|v| v.as_object())
else { return Ok(vec![]); };
Ok(parse_json_servers(map, &SHAPE, self.id()))
}
fn write_servers(&self, upserts: &[UmsServer]) -> Result<WriteReport> {
write_json_host(&self.primary_path(), &SHAPE, self.id(), upserts)
}
}
```
Then:
```rust
// 2. src-tauri/src/adapters/mod.rs
pub mod cursor; // + one line
// ...
Arc::new(cursor::CursorAdapter), // + one line in Registry::default_set()
```
```rust
// 3. src-tauri/tests/roundtrip.rs — add a test to ensure the host's shape remains unchanged
```
The UI will automatically include the new host. **No hardcoded frontend**.
## ❓ FAQ
<details>
<summary><b>How does it differ from HarnessKit/skills-manager?</b></summary>
- **HarnessKit**(@赛博Ditto): Skills + MCP + Plugin + Hook + CLI + memory + rules all-in-one, 7 agents. "Trying to manage everything".
- **[skills-manager](https://github.com/xingkongliang/skills-manager)**(xingkongliang): Focuses on Skills, with MCP as a bonus.
- **mcps-manager**(this project): **Only does MCP, with six tools and three formats**. Narrow and deep. For skill management, see the first two projects; for MCP only, use this one.
</details>
<details>
<summary><b>Why choose Tauri over Electron?</b></summary>
- Size: Tauri ~10MB, Electron 150MB+. Users of such small tools are sensitive to size.
- Rust core can be reused for future CLI (v0.5 milestone).
- Codex's TOML requires `toml_edit`, which preserves comments and key order, and there's no equivalent in the Node ecosystem.
</details>
<details>
<summary><b>Windows/Linux support?</b></summary>
The code itself is cross-platform (Rust + Tauri). Path constants currently assume macOS (`~/.claude.json` etc.); Windows requires override. **PRs for Windows/Linux default paths are welcome**.
</details>
<details>
<summary><b>Safety: Will my API Key be uploaded?</b></summary>
- Completely local tool, no network requests (except those from your own MCP server at runtime).
- Secrets are stored in plaintext (v0.5 will use Keychain). **Do not** push `~/.mcps-manager/servers/*.json` to public git repositories.
- Before writing to the host file, a backup is made; you can restore from `~/.mcps-manager/backups/` at any time.
</details>
<details>
<summary><b>macOS Gatekeeper blocks the app, what to do?</b></summary>
No Apple notarization before `v1.0`. Gatekeeper blocking is normal:
- Open **System Settings → Privacy & Security**
- Find the mcps-manager prompt and click **Still Open**
(If you're concerned, you can run `cargo tauri dev` from the source code yourself — the first principle is always "code reviewed".)
</details>
---
## 🙏 Acknowledgements
Inspiration from:
- **HarnessKit**(@赛博Ditto) — Skills/MCP/Plugin/Hook all-in-one idea
- **[xingkongliang/skills-manager](https://github.com/xingkongliang/skills-manager)** — Central Skills library + multi-tool distribution
- **[toml_edit](https://crates.io/crates/toml_edit)** — Enables preserving comments in Codex TOML
## 📝 License
[MIT](./LICENSE) © 2026 tinymindkin
---
<div align="center">
<sub><b>If it helps you, give it a ⭐ to let me know.</b></sub><br/>
<sub><a href="../../issues">Issues</a> · <a href="../../pulls">Pull Requests</a> · <a href="./DESIGN.md">Design Doc</a></sub>
</div>
MCP Config
Below is the configuration for this MCP Server. You can copy it directly to Cursor or other MCP clients.
mcp.json
Connection Info
You Might Also Like
No recommendations available