# spring-nacos-mcp [中文文档](README.zh-CN.md) **A project-aware, read-only Nacos MCP server for Spring Cloud repositories.** Point it at your Spring Cloud repo. It reads your own `application-*` / `bootstrap-*` files, discovers every environment (dev / test / pre / prod / ...), and gives your AI assistant read-only Nacos tools across **all** of them — no host, port, namespace or token to configure. ```text You: "Is sso.server.productCode consistent between dev and test?" Claude: → nacos_search_config(env=dev, keyword=sso.server.productCode) → nacos_diff_config(env_a=dev, env_b=test, data_id=sso.properties) "Yes — the value is identical in both environments (`PC-1001`). One related key differs though: sso.server.url points to dev-sso.corp.com in dev and test-sso.corp.com in test." ``` ## Why not the official `nacos-mcp-server`? The official [nacos-group/nacos-mcp-server](https://github.com/nacos-group/nacos-mcp-server) connects to **one cluster** that you configure by hand (`--host`, `--port`, `--access_token`). That's the right tool for operating a Nacos cluster. This project answers a different question: *"what does **my project's** config look like across environments?"* | | official nacos-mcp-server | spring-nacos-mcp | |---|---|---| | Setup | manual host/port/token per cluster | **zero-config**: parsed from your repo | | Environments | one per server instance | all profiles, `env` param on every tool | | Cross-env diff | not possible (single cluster) | built-in `nacos_diff_config` | | Spring awareness | none | shared-configs, file-extension, app config | | Write operations | planned | **never** (read-only by design) | ## Quickstart ### The easy way: let your AI agent install it Paste this into Cursor / Claude Code / Codex / Trae: > Install the MCP server from https://github.com/kestiny18/spring-nacos-mcp > into this project and verify it works. The repo ships an [llms-install.md](llms-install.md) with exact steps per client, so the agent can do the whole thing — download, config, verification — by itself. ### Manual, option A: copy one file (no PyPI, no dependencies) The whole server is a single, zero-dependency, standard-library-only Python file. Drop it into your repo: ```bash curl -sfL -o tools/nacos_mcp.py https://raw.githubusercontent.com/kestiny18/spring-nacos-mcp/main/src/spring_nacos_mcp/server.py ``` ```jsonc // .cursor/mcp.json or .mcp.json (Claude Code), at the repo root { "mcpServers": { "spring-nacos-mcp": { "command": "python", "args": ["tools/nacos_mcp.py"] } } } ``` Works on intranet machines too — copy the file over however you like. ### Manual, option B: uv / pip straight from git ```jsonc { "mcpServers": { "spring-nacos-mcp": { "command": "uvx", "args": ["--from", "git+https://github.com/kestiny18/spring-nacos-mcp", "spring-nacos-mcp"] } } } ``` Or `pip install git+https://github.com/kestiny18/spring-nacos-mcp` and use the `spring-nacos-mcp` command. The server auto-detects the repo root from its working directory (your editor's workspace). For clients that don't launch servers in the workspace (e.g. Claude Desktop), pin it: `"args": [..., "--repo", "/path/to/repo"]`. ### Verify your setup ```bash python tools/nacos_mcp.py --check # or: spring-nacos-mcp --check ``` Prints every discovered environment, where it came from, and whether the Nacos server is reachable. Exit codes: `0` all reachable · `1` nothing discovered · `2` discovered but some unreachable (usually VPN/network, not setup). ## Tools | Tool | What it does | |---|---| | `nacos_list_envs` | List discovered environments with address/namespace/groups | | `nacos_get_config` | Read one config's raw content by dataId | | `nacos_get_app_config` | App config + the shared/extension configs your project declares | | `nacos_list_configs` | List dataIds in a namespace (optional fuzzy filter) | | `nacos_search_config` | Full-text search across all config contents | | `nacos_diff_config` | **Key-level diff of one config between two environments** | | `nacos_list_services` | List services in the discovery registry | | `nacos_list_instances` | List online instances (IP/port/health) of a service | ## How discovery works 1. Find the repo root (`.git`, `pom.xml`, `build.gradle`, `mvnw`, `gradlew`, ...). 2. Scan every `*/src/main/resources/` for `application[-].{yml,yaml,properties}` and `bootstrap[-].{yml,yaml,properties}`. Multi-document YAML with `spring.config.activate.on-profile` (or legacy `spring.profiles`) is supported. 3. For each profile, merge sources in priority order: `bootstrap-` → `application-` → base `bootstrap` → base `application`. 4. Extract `spring.cloud.nacos.*`: server-addr, namespace, username/password, config group (also from `spring.config.import: nacos:...?group=X`), discovery group, `file-extension`, `shared-configs` / `extension-configs` / legacy `shared-dataids`. Relaxed binding (`server-addr` / `serverAddr` / `server_addr`) is handled. 5. `${...}` placeholders are resolved from environment variables (`${nacos.addr}` also tries `NACOS_ADDR`); `${name:default}` uses the default. Environments with unresolved placeholders are skipped with a clear log line. ### Overrides Environment variables (highest precedence), `` is the upper-cased profile name: ```bash NACOS_DEV_SERVER_ADDR / NACOS_DEV_NAMESPACE / NACOS_DEV_USERNAME / NACOS_DEV_PASSWORD / NACOS_DEV_GROUP / NACOS_DEV_CONTEXT_PATH NACOS_USERNAME / NACOS_PASSWORD # global fallback credentials ``` Or a `.spring-nacos-mcp.yml` at the repo root — patch discovered environments or define ones that aren't in the repo at all: ```yaml envs: staging: server-addr: nacos-staging.corp.com:8848 namespace: ns-staging username: readonly password: ${STAGING_NACOS_PASSWORD} # resolved from env var ``` ## Security notes - **Read-only by construction**: the only endpoints ever called are config/service GET queries and the login endpoint. There is no code path that writes to Nacos. - **Config content reaches the LLM.** If your configs contain secrets, enable masking: `SPRING_NACOS_MCP_MASK=1` masks values whose keys contain `password/secret/token/credential/...`, or provide your own list: `SPRING_NACOS_MCP_MASK=password,apikey`. Masking is off by default. - Prefer a read-only Nacos account (via `NACOS_USERNAME` / `NACOS_PASSWORD`) over credentials committed in config files. ## Compatibility - Python ≥ 3.9, zero runtime dependencies. - Nacos 1.x / 2.x via the v1 OpenAPI; auth via `/v1/auth/login` with automatic fallback to `/v3/auth/user/login` (Nacos 3.x). `https://` server addresses and comma-separated cluster address lists are supported. - Nacos 3.x keeps v1 OpenAPI compatibility in current releases; if your deployment disables it, please open an issue — a v3 API backend is on the roadmap. ## Limitations - The built-in YAML parser covers the subset used by Spring config files (nested maps, lists, multi-document). Anchors and flow collections are ignored. - Placeholders that come from Maven profile filtering (`@...@`) are not resolved; use the override file for those repos. ## License [Apache-2.0](LICENSE)