Skip to main content
Glama
Aethis-ai

aethis-mcp

Official
by Aethis-ai
README.md
<div align="center">

# aethis-mcp

MCP server for the Aethis decision engine. Compile legislation, policy, contracts, and regulation into deterministic logic — same input, same answer, every time, with a full audit trail.

[![npm version](https://img.shields.io/npm/v/aethis-mcp.svg)](https://www.npmjs.com/package/aethis-mcp)
[![Docs](https://img.shields.io/badge/docs-docs.aethis.ai-blue)](https://docs.aethis.ai)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)

[Install](#install) · [Skills](#skills) · [Quick start](#quick-start) · [Tools](#tools) · [Setup](#setup) · [Authoring](#authoring-private-beta) · [DSL](#dsl-capabilities) · [Troubleshooting](#troubleshooting)

</div>

---

## Install

> **Authoring is in private beta.** Decision tools (`aethis_decide`, `aethis_schema`, `aethis_explain`, `aethis_next_question`) are public — no key required. Authoring tools (rule generation, test refinement, publishing) require an invite. Request access at [aethis.ai/developer-access](https://aethis.ai/developer-access).

**Recommended — one command via [aethis-cli](https://github.com/Aethis-ai/aethis-cli):**

```bash
uv tool install aethis-cli
aethis mcp install --target all
```

Wires the server into claude-code, cursor, claude-desktop, or windsurf. Idempotent. Restart your editor to pick up the change. Re-run after `aethis account generate` rotates a key. Full options: `aethis mcp install --help`.

**Manual install:**

```bash
claude mcp add aethis -- npx -y aethis-mcp
```

For Cursor / Claude Desktop / Windsurf manual config, see [Setup](#setup).

> Onboarding an AI coding agent end-to-end? See [docs.aethis.ai/agents/onboarding](https://docs.aethis.ai/agents/onboarding) — install + verify + auth + workflow patterns in one page.

---

## Skills

After the MCP server is installed, add reusable agent workflows with [`aethis-skills`](https://github.com/Aethis-ai/aethis-skills):

```bash
npx skills add Aethis-ai/aethis-skills
```

The skills package provides workflows for policy-to-ruleset authoring, test/refine/publish loops, decisions with trace, and regression comparison. It calls the MCP tools in this package; it does not replace the MCP server.

---

## Quick start

```
aethis_decide({
  ruleset_id: "aethis/spacecraft-crew-certification",
  field_values: { "space.crew.species": "Vogon" },
  include_trace: true
})
```

```json
{
  "decision": "not_eligible",
  "fields_provided": 1,
  "fields_evaluated": 11,
  "trace": {
    "species_check": "FAIL — species is 'Vogon' (disqualifying, Section 3)"
  }
}
```

Public rulesets work without a key. Browse: `aethis_discover_rulesets({})` or [docs.aethis.ai](https://docs.aethis.ai).

Engine determinism + accuracy benchmarks: [Aethis-ai/confidently-wrong-benchmark](https://github.com/Aethis-ai/confidently-wrong-benchmark).

---

## Tools

35 tools across six groups.

| Group | Access | Tools |
|-------|--------|-------|
| **Decision** | public | `aethis_decide`, `aethis_schema`, `aethis_next_question`, `aethis_explain`, `aethis_explain_failure`, `aethis_graph` |
| **Discovery — public catalogue** | public | `aethis_discover_rulesets` |
| **Discovery — your tenant** | private beta | `aethis_list_projects`, `aethis_list_rulesets`, `aethis_list_rulebooks`, `aethis_rulebook_schema` |
| **Authoring — rulebooks** | private beta | `aethis_create_rulebook`, `aethis_update_rulebook` |
| **Authoring — sections & fields** | private beta | `aethis_discover_sections`, `aethis_refine_sections`, `aethis_validate_sections`, `aethis_set_field_spec`, `aethis_discover_fields`, `aethis_refine_fields`, `aethis_validate_fields` |
| **Authoring — generation** | private beta | `aethis_create_ruleset`, `aethis_set_tests`, `aethis_add_guidance`, `aethis_list_guidance`, `aethis_generate_and_test`, `aethis_generation_status`, `aethis_cancel_generation`, `aethis_refine`, `aethis_publish`, `aethis_add_domain_guidance`, `aethis_list_domain_guidance` |
| **Management** | private beta | `aethis_archive_project`, `aethis_archive_ruleset` |

`aethis_graph` is public for a public showcase ruleset (`ruleset_id`) and tenant-scoped for a rulebook (`rulebook_id`) — it returns the ruleset-map graph (`{nodes, edges, sections, stats}`, each node's `display.sentence`/`display.routes`/`display.expr`) plus a ready-to-render `mermaid` diagram string. Pass `include_graph_overlay: true` to `aethis_decide` to get that same graph back with a specific decision's per-criterion status (`satisfied`/`not_satisfied`/`pending`) stamped onto it (`graph_overlay` in the response) — a "you are here" map for those inputs.

`aethis_create_rulebook` / `aethis_update_rulebook` manage a Rulebook's identity (name/domain/slug/description) and `robot_hints` — beat-keyed natural-language guidance for the conversational agent. Active beats: `general_context`, `preamble`, `session_start`, `postamble`, `session_end`, `stuck`. Reserved (accepted, not yet acted on): `persona`, `conversational_style`, `section_transition`. Composition (bridging rulesets via `outcome_logic`) is a separate, larger surface not covered by these two tools yet.

### Workflows

**Evaluate eligibility (2 calls):**

```
aethis_schema(ruleset_id)          → fields needed
aethis_decide(ruleset_id, fields)  → eligible / not_eligible / undetermined
```

Pass `include_trace: true` for the per-criterion evaluation trail. Pass `include_explanation: true` for human-readable rule descriptions.

`aethis_decide` accepts either `ruleset_id` (single ruleset, may be public) or `rulebook_id` (composed multi-ruleset rulebook) — the two are mutually exclusive. Rulebook decide always requires an API key (`AETHIS_API_KEY`); anonymous callers get HTTP 401. `aethis_graph` follows the same `ruleset_id`/`rulebook_id` split for the underlying map.

**Conversational eligibility (next-question routing):**

```
aethis_next_question(ruleset_id, field_values)
```

Returns the most informative remaining question and the `optimal_path` of remaining questions. Call again after each answer; the engine recomputes from the updated state. Stops when a decision is reachable.

**Authoring** (private beta): see [Authoring](#authoring-private-beta).

### Prompts

| Prompt | Description |
|--------|-------------|
| `aethis-author` | Step-by-step TDD authoring workflow |
| `aethis-decide` | Decision workflow guide; accepts optional `ruleset_id` |

---

## Setup

Decision tools work with no key. For invited authoring access, run `aethis login`, then install with `aethis mcp install --target <client>`. The installer references a saved profile so the host configuration does not contain the API key.

### Claude Code

```bash
# Decision tools only
claude mcp add aethis -- npx -y aethis-mcp

# With authoring access
claude mcp add aethis -e AETHIS_PROFILE=default -e XDG_CONFIG_HOME=/absolute/path/to/config -- npx -y aethis-mcp
```

### Claude Desktop

Add to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):

```json
{
  "mcpServers": {
    "aethis": {
      "command": "npx",
      "args": ["-y", "aethis-mcp"]
    }
  }
}
```

For authoring, add `"env": { "AETHIS_PROFILE": "default", "XDG_CONFIG_HOME": "/absolute/path/to/config" }`. Use your saved profile name and the absolute directory containing `aethis/credentials` (normally your home directory’s `.config`).

### Cursor / Windsurf

Add to `~/.cursor/mcp.json` or `~/.codeium/windsurf/mcp_config.json` (same JSON shape).

### Keys

- `AETHIS_PROFILE` — non-secret saved profile name. It pins the account and endpoint used by this registration, even if the CLI’s `active_profile` later changes.
- `XDG_CONFIG_HOME` — absolute config directory containing `aethis/credentials`. Relative values and credentials symlinks escaping your home/config directory are refused; credential files must have no group/other permission bits (normally `0600`).
- `AETHIS_API_KEY` — optional deliberate process-environment override for the platform key. Prefer saved-profile references when installing; avoid putting raw keys in host config or command arguments. The host must securely supply the process environment; it may not inherit your shell environment.
- `AETHIS_ANTHROPIC_KEY_ENV` — the **name** of the env var holding the Anthropic key Aethis authoring tools may use (e.g. `AETHIS_ANTHROPIC_KEY`). The server never reads a provider key from the environment unless you set this. See [Passing your Anthropic key safely](#passing-your-anthropic-key-safely).
- Rotate via `aethis account generate` + `aethis account revoke <key_id>`. Mint one key per machine for surgical revocation.

### Credential precedence and restart behavior

MCP parses the CLI credentials file as YAML. `AETHIS_PROFILE` selects a named profile; otherwise the file’s `active_profile` (or `default`) selects it. The profile supplies both its API key and `base_url`, with `https://api.aethis.ai` as the default endpoint. With an explicit `AETHIS_PROFILE`, `AETHIS_API_KEY` and `AETHIS_BASE_URL` deliberately override their respective values. Without an explicit profile selector, `AETHIS_API_KEY` uses `AETHIS_BASE_URL` or the default endpoint, ignoring the implicitly active profile (including implicit anonymous). Missing or malformed explicitly selected profiles fail visibly, including when environment overrides are present. Explicit `AETHIS_PROFILE=anonymous` always stays unsigned. After anonymous setup, run `aethis login` and install again to reference the saved authoring profile, then restart the host.

A saved profile outranks old macOS Keychain entries. If no profile is configured and no explicit name is selected, MCP can use the legacy default keychain entry, then the older flat `credentials.yaml` file. Flat `api_key`/`base_url` files at `aethis/credentials` remain supported. A configured profile awaiting login stays unsigned instead of borrowing another stored key.

The server keeps its authenticated startup key and endpoint paired until restart. If it started without a key, an authenticated tool can pick up a later login for the same endpoint. A changed endpoint causes a visible refusal: restart the MCP host to load the new pair. Startup stderr reports only the credential source, never key values.

### Passing your Anthropic key safely

Authoring tools (`aethis_generate_and_test`, `aethis_refine`, `aethis_discover_fields`, `aethis_refine_fields`, `aethis_discover_sections`, `aethis_refine_sections`) need an Anthropic API key per call. Three accepted forms — listed in **preferred order**:

The server sends a provider key to Aethis **only when you configured one for Aethis**. It never picks up `ANTHROPIC_API_KEY` (or any other variable) from your environment on its own, and an env-var name supplied in a tool call by the host model is refused unless it is the one you configured. Only Anthropic keys (`sk-ant-…`) are accepted; anything else is refused locally and not sent.

1. **`AETHIS_ANTHROPIC_KEY_ENV`** (recommended). In the MCP server config, put the key in a dedicated env var and name that var in `AETHIS_ANTHROPIC_KEY_ENV`. Tools then use it automatically. The raw value never appears in the tool call payload, so it does not land in the MCP host's session transcript on disk.

   ```jsonc
   // claude_desktop_config.json
   {
     "mcpServers": {
       "aethis": {
         "command": "npx",
         "args": ["aethis-mcp"],
         "env": {
           "AETHIS_PROFILE": "default",
           "XDG_CONFIG_HOME": "/absolute/path/to/config",
           "AETHIS_ANTHROPIC_KEY_ENV": "AETHIS_ANTHROPIC_KEY",
           "AETHIS_ANTHROPIC_KEY": "sk-ant-..."   // never echoed back to the LLM
         }
       }
     }
   }
   ```

   ```
   aethis_generate_and_test({ project_id })   // uses the configured key
   ```

2. **`anthropic_key_keychain`** (macOS). A keychain reference — either `"account"` (service defaults to `aethis-anthropic-key`) or `"service:account"`. Store the key once with `security add-generic-password -U -s aethis-anthropic-key -a my-anthropic -w 'sk-ant-...'`, then call:

   ```
   aethis_generate_and_test({ project_id, anthropic_key_keychain: "my-anthropic" })
   ```

3. **`anthropic_key`** (deprecated). Pass the raw key as a tool argument. Accepted for backwards compatibility, but the raw value is written verbatim to the host's session transcript JSONL on disk. If a key was ever passed this way, rotate it before relying on the safer forms.

---

## Authoring (private beta)

> Authoring requires an invite. [Request access](https://aethis.ai/developer-access). Decision tools (above) are public.

Three-phase workflow. Phases 1–2 are for multi-section domains; skip them for single-section rules and go straight to Phase 3.

### Phase 1 — Section discovery

```
aethis_discover_sections({ domain, sources: [{ name, content }, ...] })
aethis_validate_sections({ domain, expected_sections, discovered_sections })
aethis_refine_sections({ domain, feedback, sources })
```

### Phase 2 — Field vocabulary

```
aethis_set_field_spec({
  project_id,
  expected_fields: [{ key, sort, enum_values?, notes?: [{ note_text, source?, metadata? }] }, ...]
})
aethis_discover_fields({ project_id })           // auto-validates against the spec if set
aethis_refine_fields({ project_id, feedback })
aethis_validate_fields({ project_id, expected_fields })
```

### Phase 3 — Generate, test, publish

```
aethis_create_ruleset({
  name, section_id, domain?, source_text,
  test_cases: [{ name, field_values, expected_outcome, expectations? }, ...],
  contract_version?: 1,
  expected_review_bindings?: { field_id: { token: true | false | null } }
})
aethis_generate_and_test({ project_id })
aethis_refine({ project_id, feedback })          // iterate until tests pass
aethis_publish({ project_id })                   // refuses if tests fail; returns ruleset_id on success
```

When a test carries `expectations`, set `contract_version: 1`. The optional
binding catalogue is generic authoring metadata: omit it when no binding
assertion is needed, or pass `{}` to assert that no review bindings exist.
The server must confirm the complete stored contract before generation begins.
`aethis_create_ruleset` creates a project; it does not append or replace tests
on an existing project. Use `aethis_set_tests` with the complete version-1
contract for a later replacement, then generate or refine that same project.
Legacy updates cannot discard stored assertions. Object keys named `__proto__`
are rejected in field-value and binding maps rather than silently discarded.

If generation polling times out, call `aethis_generation_status({ project_id })`
before retrying: use its `telemetry_availability`, server-authoritative
`worker_lifecycle`, and `retry_readiness`, and retry only when readiness is
`ready`. An old heartbeat alone is not proof that the worker died. Call
`aethis_cancel_generation({ project_id, job_id, confirm_job_id })` only after
showing the observed `job_id` and receiving explicit confirmation to abandon
that active run. It releases the project's job ownership, but worker shutdown
may be cooperative rather than immediate; inspect the returned detail. It is a
destructive, API-key-protected mutation. The response distinguishes a new
`cancelled` transition from the idempotent `already_cancelled` result.

### Guidance

Targeted hints without regenerating, plus cross-section principles for a domain:

```
aethis_add_guidance({ project_id, guidance_text, process_type })
aethis_list_guidance({ project_id })

aethis_add_domain_guidance({ domain, guidance_text, process_type, notes? })
aethis_list_domain_guidance({ domain })
```

`process_type` is `rule_generation` (default) or `field_extraction`.

### Diagnose a failing test

```
aethis_explain_failure({
  ruleset_id, field_values, expected_outcome, test_name
})
// Returns criterion statuses, the failing rule, and a targeted fix hint.
```

> [!IMPORTANT]
> **Tests are the publish gate.** `aethis_publish` refuses to publish a ruleset with a failing test. SMEs write the tests; the LLM generates the rules from source text + guidance; the platform refuses to ship rules that don't satisfy the tests. Better tests = faster convergence.

> [!IMPORTANT]
> Anthropic key required for authoring. Configure `AETHIS_ANTHROPIC_KEY_ENV` or use `anthropic_key_keychain` (macOS keychain ref) rather than the raw `anthropic_key` argument — see [Passing your Anthropic key safely](#passing-your-anthropic-key-safely). Used per-request, never stored server-side; the raw form, however, lands in the MCP host's session transcript on disk.

> [!IMPORTANT]
> DATE fields use integer ordinals (`date.toordinal()`), not ISO strings. `2025-04-13` = `739354`. Quick conversion: `python3 -c "from datetime import date; print(date(2025,4,13).toordinal())"`.

---

<details>
<summary><strong>DSL capabilities</strong></summary>

### Field types

| Type | Description |
|------|-------------|
| `Bool` | True / false |
| `Int` | Integer (counts, money as pence, percentages as integers) |
| `Enum` | Closed set of named values |
| `Date` | Integer ordinal — `date.toordinal()` |
| `Duration` | Integer days |
| `String` | Free text — prefer `Enum` for known sets |

### Operators

| Category | Operators |
|----------|-----------|
| Logic | `AND`, `OR`, `NOT`, `IMPLIES` |
| Comparison | `=`, `≠`, `<`, `≤`, `>`, `≥` |
| Membership | `IN [v1, v2, ...]` |
| Arithmetic | `+`, `−` for `Int`/`Date`; `*` for `Int` |
| Aggregation | `min(...)`, `max(...)` |

### Helpers

- `days_between(date_a, date_b)` → `Int`
- `years_between(date_a, date_b)` → `Int` — completed whole years between the two dates (leap-correct). Use this for age from a date-of-birth field; never derive age as `days_between(...) / 365`.
- `min(a, b, ...)`, `max(a, b, ...)` → `Int`
- Constant arithmetic folded at authoring time (`5 * 365` → `1825`)

### Not supported

- Division between runtime field values
- Weighted scoring or probabilistic outcomes
- Lists as field values (use pre-aggregated `Int` / `Bool`)
- More than 3 outcome tiers (`eligible` / `not_eligible` / `undetermined`)

</details>

---

## Troubleshooting

| Error | Cause | Fix |
|-------|-------|-----|
| `API key is required` | `AETHIS_API_KEY` not set (authoring) | Configure in MCP client settings, not shell profile |
| `X-Anthropic-Key header is required` | Missing Anthropic key | Set `AETHIS_ANTHROPIC_KEY_ENV` in the MCP server config (preferred), or pass `anthropic_key_keychain` / `anthropic_key` on the tool call. See [Passing your Anthropic key safely](#passing-your-anthropic-key-safely). |
| `Ruleset not found` (404) | Wrong ID or archived | `aethis_list_projects` → `aethis_list_rulesets` |
| `Rate limit exceeded` (429) | Daily limit | Client retries automatically. [eng@aethis.ai](mailto:eng@aethis.ai) for higher tier |
| `Cannot publish: tests failing` | Tests don't pass | `aethis_refine` until all tests pass |
| Generation timeout (504) | Server still generating (5–15 min normal) | Wait, then `aethis_list_rulesets({ project_id })` to check. Don't re-trigger |
| `Expected an integer for <field>, got str` | DATE field passed as ISO string | Use `date.toordinal()` integer |

---

## Related

- [aethis-cli](https://github.com/Aethis-ai/aethis-cli) — Python CLI; file-based authoring with YAML test cases
- [aethis-examples](https://github.com/Aethis-ai/aethis-examples) — runnable rulesets (spacecraft, construction-CAR, consumer credit) and benchmark scenarios
- [confidently-wrong-benchmark](https://github.com/Aethis-ai/confidently-wrong-benchmark) — paper, 225-scenario benchmark, LegalBench harness

## Development

```bash
git clone https://github.com/Aethis-ai/aethis-mcp.git
cd aethis-mcp && npm install && npm test && npm run build
```

## License

MIT

TDQS

A3.7/5.0

Scored across 35 tools

Disambiguation4/5

Most tools target distinct actions within the authoring/decision lifecycle, and descriptions often explicitly disambiguate similar-sounding pairs (e.g. discover_rulesets vs list_rulesets, schema vs rulebook_schema). However, with 35 tools there are several easily confused clusters: discover/refine/validate for sections and fields, add_guidance vs add_domain_guidance, and explain vs graph vs explain_failure.

Naming Consistency4/5

All tools use the same aethis_ snake_case prefix and are mostly verb_noun (e.g. create_ruleset, list_projects, archive_project). Minor deviations include noun-only or verb-only names like aethis_schema, aethis_graph, aethis_decide, and aethis_refine, but the overall convention is predictable.

Tool Count2/5

35 tools is heavy for the apparent domain, well above the 3–15 sweet spot. Many operations are split into discover/refine/validate triples, suggesting consolidation could reduce surface area without losing capability.

Completeness4/5

The surface covers a full authoring lifecycle: discovery, field/section validation, generation, testing, refinement, publishing, archiving, guidance, usage, and review. Minor gaps remain, such as no rulebook archival/deletion, no direct ruleset update tool, and no get_project or list_tests operation.

Maintenance

ActivityActive
ResponsivenessUnresponsive