Metadata-Version: 2.4
Name: exoscale-mcp-advisor
Version: 0.2.0
Summary: Read-only Exoscale advisor MCP server — docs search plus list-only live catalogue queries, structurally incapable of mutation.
Project-URL: Homepage, https://github.com/ralle-lang/exoscale-mcp-advisor
Project-URL: Repository, https://github.com/ralle-lang/exoscale-mcp-advisor
Project-URL: Issues, https://github.com/ralle-lang/exoscale-mcp-advisor/issues
Project-URL: Changelog, https://github.com/ralle-lang/exoscale-mcp-advisor/blob/main/CHANGELOG.md
Author: Raphael Lang
License: MIT
License-File: LICENSE
Keywords: advisor,ai,cloud,exoscale,mcp,read-only
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: System Administrators
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Systems Administration
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: exoscale-connector>=0.3.0
Requires-Dist: mcp<2,>=1.2
Provides-Extra: dev
Requires-Dist: build>=1.0; extra == 'dev'
Requires-Dist: coverage>=7.0; extra == 'dev'
Requires-Dist: mypy>=1.8; extra == 'dev'
Requires-Dist: pytest>=7.4; extra == 'dev'
Requires-Dist: ruff>=0.4; extra == 'dev'
Requires-Dist: twine>=5.0; extra == 'dev'
Description-Content-Type: text/markdown

# exoscale-mcp-advisor

A **read-only** [Model Context Protocol](https://modelcontextprotocol.io) server
that lets an MCP-capable agent learn about Exoscale: search the verified
connector documentation and run **list-only** live catalogue queries (zones,
instance types, templates). It is, by construction, incapable of mutating any
cloud resource.

> **Status: released.** Seven read-only tools, the stdio server, and the
> four-layer test suite (structural no-mutation, mocked-connector,
> protocol-level, gated live smoke) are in place and green; published to PyPI as
> [`exoscale-mcp-advisor`](https://pypi.org/project/exoscale-mcp-advisor/). The
> full design is in [`docs/mcp-advisor-design.md`](docs/mcp-advisor-design.md);
> release history is in [`CHANGELOG.md`](CHANGELOG.md).

It builds on [`exoscale-connector`](https://github.com/ralle-lang/exoscale-python-connector):
the knowledge it serves is read from that package's bundled reference, and the
live queries reuse the connector's read-only `list` clients. Nothing about
Exoscale is hardcoded or duplicated here.

---

## General description

The advisor targets the **learning** path, not the execution path. An agent can
ask "what instance types exist in `at-vie-1` right now?" and "how do I create a
security group with the connector?" — and get live data plus verified docs —
while the server remains structurally unable to create, change, or delete
anything. Infrastructure changes stay the human's job, performed with reviewed,
idempotent code.

Tool surface (see design §3):

| Tool | Credentials | Purpose |
|------|:-----------:|---------|
| `search_docs(query)` | — | Ranked sections from the connector's reference bundle. |
| `get_asset_page(asset_type)` | — | Full reference page for one asset type. |
| `list_asset_types()` | — | The asset-type index (slug + heading) for discovery. |
| `list_zones()` | ✔ | Live list of zones. |
| `list_instance_types(zone)` | ✔ | Live list of instance types (with derived `memory_gib`). |
| `list_templates(zone, visibility)` | ✔ | Live list of templates (with derived `size_gib`). |
| `list_dbaas_plans(zone=None)` | ✔ | Live managed-database (DBaaS) service types and plans. |

The three docs tools need no credentials; the four live tools read Exoscale API
credentials from the server's environment (see the User guide). No mutation
tools — ever, by design.

## User guide

The server runs with no clone or install step:

```bash
uvx exoscale-mcp-advisor
```

Or from a source checkout (for development):

```bash
pip install -e .
exoscale-mcp-advisor            # or: python -m exoscale_mcp_advisor
```

It speaks MCP over **stdio**, so it is configured like any other stdio MCP
server in your client. The four live catalogue tools require Exoscale API
credentials in the **server's launch environment** — never on the command line,
never read from a file by the app:

```
EXOSCALE_API_KEY=...
EXOSCALE_API_SECRET=...
EXOSCALE_ZONE=at-vie-1
```

Getting them into the server's environment, two common ways:

```bash
# 1) Pass them to the MCP client as it launches the server (Claude Code shown):
claude mcp add exoscale-advisor \
  -e EXOSCALE_API_KEY=... -e EXOSCALE_API_SECRET=... -e EXOSCALE_ZONE=at-vie-1 \
  -- uvx exoscale-mcp-advisor

# 2) Inject from a vault at launch, so no secret is typed or stored in config:
claude mcp add exoscale-advisor -- \
  infisical run --domain http://localhost:8080 -- uvx exoscale-mcp-advisor
```

Use a **least-privilege, read-only** API key (see the Admin guide). The three
docs tools (`search_docs`, `get_asset_page`, `list_asset_types`) need no
credentials; if the live tools run without credentials they return a clear,
actionable error while the docs tools keep working. The catalogue exposes **no
pricing** — use [Exoscale's calculator](https://www.exoscale.com/pricing/) for
cost estimates.

## Example use cases

What the advisor is for, from trivial to advanced. Every example is **read-only**:
the server produces explanations and reviewable code — it never provisions,
changes, or deletes anything (design D1). Each rung notes the tools it exercises
and whether credentials are needed.

1. **Docs lookup — no credentials.**
   *"Search the Exoscale docs for how to create a security group, then show me
   the full security-group reference page."*
   → `search_docs` + `get_asset_page` (discover slugs first with
   `list_asset_types`). Works with zero credentials.

2. **A single live query — credentials.**
   *"What instance types are available in `at-vie-1` right now?"* or *"List the
   public templates and their default login user."*
   → one live tool (`list_instance_types` / `list_templates`). `memory_gib` and
   `size_gib` come pre-derived, so no manual byte math.

3. **Live + docs synthesis — credentials.**
   *"Compare the instance types in `at-vie-1` and recommend the cheapest one
   suitable as an SKS worker, citing the sizing constraints."*
   → a live tool + `get_asset_page` + reasoning. The advisor cites the verified
   docs; it has no pricing data, so cost questions defer to Exoscale's
   calculator.

4. **Multi-asset design, read-only — credentials.**
   *"Design an HA web-app stack in `at-vie-1` (load balancer + web tier +
   managed database), cite the docs for each asset, and don't provision
   anything."*
   → many `get_asset_page` (+ `list_dbaas_plans`, `list_zones`) with trade-off
   reasoning. You get a design and citations, never a side effect.

5. **Reviewable code generation — credentials.**
   *"Generate an `exoscale-connector` script that provisions the stack above,
   with secrets side-loaded from the environment — but I'll run it."*
   → the **advisor, not operator** pattern: read-only advice plus a script
   *you* review and run. The server stays structurally unable to apply changes.

The jump from rung 1 to rung 5 is the whole point: a low-friction, credential-free
entry for learning, and an aspirational ceiling where the advisor designs and
writes the infrastructure code while a human keeps the keys and the final apply.

## Admin guide

**Least-privilege credentials (defense in depth).** Although the server can only
issue `list` calls, the API key it runs with should also be restricted to
read-only operations, so the key itself cannot mutate anything. Build the IAM
policy with the connector's own `iam_expr` / `IAMPolicy` helpers (default-deny,
then allow only `list`/`get` catalogue operations) — see the connector's IAM
policy cookbook and design §7.

**Credential injection.** Credentials come from the environment, injected at
startup by a vault CLI (e.g. `infisical run -- uvx exoscale-mcp-advisor` in
development; a production vault agent in production). The application never reads
secrets from files and is not coupled to any specific vault provider.

**Security model.** Read-only is enforced on two independent layers: the code
registers only read-only tools (a CI test fails the build if a mutation tool is
ever added), and the credentials are scoped to read-only operations. See
design §6–§7.

## Developer guide

**Setup**

```bash
python -m venv .venv && source .venv/bin/activate
pip install -e '.[dev]'
```

Requires **Python ≥3.10** (the `mcp` SDK floor).

**Checks**

```bash
ruff check src tests     # lint
mypy src                 # type-check
pytest tests/unit -q     # unit tests
```

The gated live smoke test (under `tests/integration`) talks to a real account
using only `list`, and is opt-in behind `EXOSCALE_RUN_LIVE_TESTS=1` — default-
skipped, and never run in CI. Run it with credentials injected from the
environment (never hardcoded):

```bash
EXOSCALE_RUN_LIVE_TESTS=1 \
  infisical run --domain http://localhost:8080 -- \
  pytest tests/integration -q
```

It is read-only, so safe to run against any account.

**Architecture & contribution.** Read
[`docs/mcp-advisor-design.md`](docs/mcp-advisor-design.md) first — it defines the
tool surface, the zero-duplication knowledge source, the read-only-by-
construction guarantee, and the four-layer test strategy. Conventional commits;
keep this README current with behavior changes in the same commit; no untested
code lands.

---

## License

[MIT](LICENSE) © 2026 Raphael Lang
