ariadne is an MCP (Model Context Protocol) server that provides AI agents with the ability to identify affected tests.
claude mcp add ariadne -- docker run -i --rm /path/to/project{
"mcpServers": {
"ariadne": {
"command": "docker",
"args": ["run", "-i", "--rm", "/path/to/project"]
}
}
}Resumen de MCP Servers
<p align="center">
<img src="doc/ariadne-banner.svg" alt="ariadne banner" width="100%">
</p>
<p align="center">
<h1 align="center">ariadne</h1>
<p align="center">
<strong>MCP Server for Affected Test Selection</strong>
</p>
<p align="center">
<a href="https://github.com/MikhailHal/ariadne/releases"><img src="https://img.shields.io/github/v/release/MikhailHal/ariadne?style=flat-square&color=success" alt="Release"></a>
<a href="https://registry.modelcontextprotocol.io/v0/servers?search=io.github.MikhailHal/ariadne"><img src="https://img.shields.io/badge/MCP%20Registry-listed-6E56CF.svg?style=flat-square" alt="MCP Registry"></a>
<a href="https://github.com/MikhailHal/homebrew-tap"><img src="https://img.shields.io/badge/homebrew-mikhailhal%2Ftap-FBB040.svg?style=flat-square&logo=homebrew&logoColor=white" alt="Homebrew"></a>
<a href="https://github.com/MikhailHal/ariadne/pkgs/container/ariadne"><img src="https://img.shields.io/badge/ghcr.io-ariadne-2496ED.svg?style=flat-square&logo=docker&logoColor=white" alt="Container image"></a>
<a href="LICENSE"><img src="https://img.shields.io/badge/License-Apache%202.0-blue.svg?style=flat-square" alt="License"></a>
<a href="https://kotlinlang.org"><img src="https://img.shields.io/badge/Kotlin-2.3.0-7F52FF.svg?style=flat-square&logo=kotlin&logoColor=white" alt="Kotlin"></a>
</p>
</p>
<br>
**ariadne** is an MCP (Model Context Protocol) server that provides AI agents with the ability to identify affected tests. Powered by [sazanami](https://github.com/MikhailHal/sazanami), it analyzes code changes and returns only the tests that need to be run.
<p align="center">
<a href="https://glama.ai/mcp/servers/MikhailHal/ariadne">
<img src="https://glama.ai/mcp/servers/MikhailHal/ariadne/badges/card.svg" alt="ariadne MCP server" />
</a>
</p>
> [!IMPORTANT]
> ## ⚠️ MUST READ: Speed over Completeness
>
> ariadne is built for the agent inner loop — edit, verify, commit — where fast
> feedback matters more than exhaustive selection. Static analysis cannot trace
> every execution path: reflection, DI frameworks, and data-flow indirection
> (e.g., Flux/MVI dispatch) can hide dependencies from **any**
> affected-test-selection tool, not just ariadne.
>
> **Always keep a final line of defense in CI.** Run the full test suite (or a
> conservative selection) before merging. ariadne narrows what an agent runs
> while iterating; it is not a replacement for CI.
>
> When ariadne detects changes it cannot analyze (build scripts, resources,
> unscanned source sets), it says so explicitly in the tool response instead of
> silently reporting "no affected tests".
## Features
- **MCP Integration** — Works with Claude Code, Claude Desktop, and other MCP-compatible clients
- **Automatic Git Diff** — No need to pass diff manually; ariadne runs `git diff` internally
- **Powered by sazanami** — Uses Kotlin Analysis API for accurate static analysis
## Installation
### Homebrew (recommended)
```bash
brew install mikhailhal/tap/ariadne
```
Then register it with your MCP client — for Claude Code:
```bash
claude mcp add ariadne -- ariadne
```
Or add to your MCP client configuration manually (e.g., Claude Desktop):
```json
{
"mcpServers": {
"ariadne": {
"command": "ariadne"
}
}
}
```
### Docker
```bash
docker run -i --rm -v /path/to/project:/workspace ghcr.io/mikhailhal/ariadne
```
Mount the project you want analyzed and pass `/workspace` as `project_path`.
The image is also listed in the [official MCP Registry](https://registry.modelcontextprotocol.io/v0/servers?search=io.github.MikhailHal/ariadne) as `io.github.MikhailHal/ariadne`.
### Manual (release JAR)
Download `ariadne-<version>-all.jar` from [Releases](https://github.com/MikhailHal/ariadne/releases) (requires JDK 21+) and configure your client with `"command": "java", "args": ["-jar", "/path/to/ariadne-<version>-all.jar"]`.
### Build from Source
```bash
git clone --recursive https://github.com/MikhailHal/ariadne.git
cd ariadne
./gradlew shadowJar # fat JAR: build/libs/ariadne-<version>-all.jar
```
## Usage
Once configured, AI agents can use the `get_affected_tests` tool:
### Tool: `get_affected_tests`
**Parameters:**
- `project_path` (required) — Path to the Kotlin project
- `scope` (optional, `deep` | `shallow`, default `deep`) — how far back to look:
- **`deep`** — all changes since `base_branch` (committed *and* uncommitted). Safest; the whole branch is covered so nothing you already committed slips through unverified. May select more tests.
- **`shallow`** — uncommitted changes only (diff against `HEAD`). Fastest, for the tight edit loop. Verifying already-committed work is left to the caller. `base_branch` is ignored.
- `base_branch` (optional, `deep` scope only) — Branch to compare against. When omitted, ariadne uses the repository's default branch (`origin/HEAD`). If that is not set (e.g. a repo with no remote), it returns an error asking you to pass `base_branch` explicitly rather than guessing.
**Returns:**
- List of affected test FQNs (fully qualified names), sorted
- If the diff contains changes outside the analyzed Kotlin sources (build scripts,
resources, unscanned source sets), a note is appended recommending a full test run
for those changes
- Analysis is bounded by a 120s timeout; on timeout an explicit error is returned
### Example
Agent request:
```json
{
"name": "get_affected_tests",
"arguments": {
"project_path": "/path/to/your/kotlin/project"
}
}
```
Response:
```
com.example.UserServiceTest.testCreateUser
com.example.UserRepositoryTest.testSave
```
## How It Works
```
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ MCP Client │ ──▶ │ ariadne │ ──▶ │ sazanami │
│ (Agent) │ │ (MCP Server)│ │ (Analysis) │
└─────────────┘ └─────────────┘ └─────────────┘
│
▼
┌─────────────┐
│ git diff │
└─────────────┘
```
1. **Agent calls tool** — Passes project path to ariadne
2. **Run git diff** — ariadne executes `git diff --unified=0` against base branch
3. **Analyze with sazanami** — Build call graph and find affected tests
4. **Return results** — List of test FQNs returned to agent
## Real-World Validation: Now in Android
Measured against [Now in Android](https://github.com/android/nowinandroid)
(Google's reference Android app — 34 modules, ~268 Kotlin files):
| Metric | Result |
|---|---|
| Recall audit — 19 target functions across all layers | **18/18 valid targets detected** (the 19th had no exercising unit test; correctly not selected) |
| End-to-end response time | **~4s** (module discovery + call-graph build + BFS) |
| Module discovery | 34 modules via `settings.gradle.kts`, incl. nested modules and type-safe accessor dependencies |
| Source sets | `main`, `debug`, `prod`, `benchmark`, `testDemo`, … discovered per module (`androidTest*` excluded by design) |
Verified patterns include repositories behind project interfaces, a library-interface
override (`androidx.datastore.Serializer`), `operator fun invoke` use cases,
`@Composable` functions, extension mappers, ViewModel property-initializer chains,
and callable references. Two representative results:
- Changing `core:common`'s `asResult()` selects **14 tests across three modules**,
including ViewModel tests reachable only through `val uiState = ...stateIn(...)`
- Changing the mapper `PopulatedNewsResource.asExternalModel()` selects **14 tests**,
including 11 repository tests reachable only through `.map(Type::mapper)` chains
### Test-class selection rate
Every unit-test class in Now in Android was measured by changing a function in the
class it tests and checking whether that test class was selected:
| Test style | Selected |
|---|---|
| Plain unit tests (construct the object, call it) | 13 / 13 valid targets |
| Robolectric / Compose screenshot tests | **12 / 12** |
| Framework-dispatched callbacks (lint `Detector`) | 0 / 2 — see below |
Robolectric turned out **not** to be a barrier: those tests call the composable
themselves (`setContent { NiaTheme { ... } }`), so the call exists in the source.
What decides coverage is not the test runner but whether the test's own code
contains the call.
### What ariadne cannot see
The rule of thumb: **if the framework calls your code instead of your test calling
it, ariadne cannot connect them.** These are limits of static analysis, not bugs —
plan your CI safety net around them:
| Pattern | Status |
|---|---|
| Framework-invoked callbacks — Fragment/Activity lifecycle (`launchFragmentInContainer`), lint `Detector` methods, `Application.onCreate` | Not traced: no call written in the test |
| Reflection / DI-container wiring | Not traced |
| UDF dispatch (Flux/MVI) | `dispatch → collect` is never an edge, but wiring in `init` (or a `start()` the test calls) is covered conservatively via constructor chains. Subscriptions started by DI/lifecycle are **not** covered ([sazanami#38](https://github.com/MikhailHal/sazanami/issues/38)) |
| `stateIn` / `shareIn` chains (`map`, `onEach`, `flatMapLatest`, `combine`) | Covered — verified with exact selection |
| Instrumented tests (`androidTest*`) | Out of scope by design |
| Build scripts, resources, unscanned source sets | Not analyzed — reported explicitly in the tool response |
| Same-name top-level extensions in one package | Over-selected (receiver types are not part of top-level FQNs) — safe direction |
| KMP source sets (`commonMain`, `expect`/`actual`) | Enumerated, but resolution quality unverified ([#1](https://github.com/MikhailHal/ariadne/issues/1)) |
Full audit notes: [sazanami#29](https://github.com/MikhailHal/sazanami/issues/29),
[sazanami#38](https://github.com/MikhailHal/sazanami/issues/38).
## Requirements
- **JDK 21** or later
- **Git** — For diff detection
## Limitations
- Module discovery is convention-based: Lo que la gente pregunta sobre ariadne
¿Qué es MikhailHal/ariadne?
+
MikhailHal/ariadne es mcp servers para el ecosistema de Claude AI. ariadne is an MCP (Model Context Protocol) server that provides AI agents with the ability to identify affected tests. Tiene 1 estrellas en GitHub y se actualizó por última vez today.
¿Cómo se instala ariadne?
+
Puedes instalar ariadne clonando el repositorio (https://github.com/MikhailHal/ariadne) o siguiendo las instrucciones del README en GitHub. ClaudeWave también te ofrece bloques de instalación rápida en esta misma página.
¿Es seguro usar MikhailHal/ariadne?
+
MikhailHal/ariadne aún no ha sido auditado por nuestro agente de seguridad. Revisa el repositorio original en GitHub antes de usarlo en producción.
¿Quién mantiene MikhailHal/ariadne?
+
MikhailHal/ariadne es mantenido por MikhailHal. La última actividad registrada en GitHub es de today, con 1 issues abiertos.
¿Hay alternativas a ariadne?
+
Sí. En ClaudeWave puedes explorar mcp servers similares en /categories/mcp, ordenados por popularidad o actividad reciente.
Despliega ariadne en tu cloud
Lleva este repo a producción en minutos. Cada plataforma genera su propio entorno con variables de entorno editables.
¿Mantienes este repo? Añade un badge a tu README
Pega el badge en tu README de GitHub para mostrar que está auditado por ClaudeWave. Cada badge enlaza de vuelta a esta página y muestra el Trust Score actual.
[](https://claudewave.com/repo/mikhailhal-ariadne)<a href="https://claudewave.com/repo/mikhailhal-ariadne"><img src="https://claudewave.com/api/badge/mikhailhal-ariadne" alt="Featured on ClaudeWave: MikhailHal/ariadne" width="320" height="64" /></a>Más MCP Servers
Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.
User-friendly AI Interface (Supports Ollama, OpenAI API, ...)
An open-source AI agent that brings the power of Gemini directly into your terminal.
The fastest path to AI-powered full stack observability, even for lean teams.
Real-time global intelligence dashboard. AI-powered news aggregation, geopolitical monitoring, and infrastructure tracking in a unified situational awareness interface
🕷️ An adaptive Web Scraping framework that handles everything from a single request to a full-scale crawl!