ariadne

io.github.MikhailHal由 GitHub 帳號 MikhailHal 發布v0.4.0更新於 Oct 24, 2026

Returns only the unit tests affected by your current Kotlin/Android code changes.

已驗證STDIO僅桌面開發者工具資料與分析

概覽

AI 產生的概覽

一個 MCP 伺服器,分析 Kotlin/Android 程式碼變更並只回傳受影響的單元測試。

可以做什麼
Ariadne 提供 get_affected_tests 工具,接收 Kotlin 專案路徑並回傳排序後的受影響測試完整限定名稱清單。它會在內部對基準分支或 HEAD 執行 git diff,再用 sazanami 的 Kotlin 分析 API 建立呼叫圖並找出受影響的測試。當變更位於已分析原始碼之外(例如建置指令碼、資源)時,它會明確說明;分析超過 120 秒會回傳錯誤。
適用情境
適合在 Kotlin 或 Android 專案的代理「編輯—驗證」循環中使用,只執行受影響的測試以獲得更快回饋。它不能取代 CI:README 建議合併前仍執行完整或保守的測試。
執行需求
以本機程序透過 stdio 執行。需要 JDK 21 或更新版本,以及用於差異偵測的 Git。可透過 Homebrew、Docker 映像或發行版 JAR 安裝;Docker 方式需掛載專案並將 /workspace 作為 project_path 傳入。未宣告帳號、API 金鑰或環境變數。
安裝前請注意
它在本機讀取專案並執行 git diff,不要求任何憑證。選擇基於靜態分析,可能漏掉由反射、依賴注入、框架回呼或生命週期啟動的訂閱所隱藏的依賴,也不分析建置指令碼、資源或儀器化測試。合併前應保留完整的 CI 測試。

安裝

在 SourceWeft 中

  1. 開啟 儀表板中的 ariadne,將其新增到工作區。
  2. 為需要使用其工具的對話啟用該服務。

Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。

其他 MCP 客戶端

參照 儲存庫 中的啟動說明。

README

[ariadne banner]

ariadne

MCP Server for Affected Test Selection

[Release] [MCP Registry] [Homebrew] [Container image] [License] [Kotlin]


ariadne is an MCP (Model Context Protocol) server that provides AI agents with the ability to identify affected tests. Powered by sazanami, it analyzes code changes and returns only the tests that need to be run.

[ariadne MCP server]

[!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 as io.github.MikhailHal/ariadne.

Manual (release JAR)

Download ariadne-<version>-all.jar from 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.gitcd 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.testCreateUsercom.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 (Google's reference Android app — 34 modules, ~268 Kotlin files):

MetricResult
Recall audit — 19 target functions across all layers18/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 discovery34 modules via settings.gradle.kts, incl. nested modules and type-safe accessor dependencies
Source setsmain, 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 styleSelected
Plain unit tests (construct the object, call it)13 / 13 valid targets
Robolectric / Compose screenshot tests12 / 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:

PatternStatus
Framework-invoked callbacks — Fragment/Activity lifecycle (launchFragmentInContainer), lint Detector methods, Application.onCreateNot traced: no call written in the test
Reflection / DI-container wiringNot 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)
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 setsNot analyzed — reported explicitly in the tool response
Same-name top-level extensions in one packageOver-selected (receiver types are not part of top-level FQNs) — safe direction
KMP source sets (commonMain, expect/actual)Enumerated, but resolution quality unverified (#1)

Full audit notes: sazanami#29, sazanami#38.

Requirements

  • JDK 21 or later
  • Git — For diff detection

Limitations

  • Module discovery is convention-based: it parses settings.gradle(.kts) includes, enumerates src/<sourceSet>/{kotlin,java} layouts, and reads project(":x") / type-safe accessor dependencies from build files. Dynamic includes, projectDir remapping, custom srcDirs, and dependencies injected by convention plugins are not detected — see #1
  • Full graph rebuild on each request (no caching yet); analysis is capped at 120s
  • See What ariadne cannot see for analysis-level gaps

License

Copyright 2025 ariadne contributors
Licensed under the Apache License, Version 2.0 (the "License");you may not use this file except in compliance with the License.You may obtain a copy of the License at
    http://www.apache.org/licenses/LICENSE-2.0

See LICENSE for the full text.

來源:README.md,提交 057144e

工具

0
SourceWeft 尚未在沙箱中啟動過該軟體包,因此其工具未知。

版本歷史

1
  1. v0.4.0最新Sep 16, 2026

評分

已滿足適用檢查項的 50%

該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。

  • 近 30 天內可連通25 分

    請保持端點能夠回應 MCP 握手;SourceWeft 每 30 天探測一次。

  • 已宣告認證方式10 分

    請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。

  • 已列出工具15 分

    請讓伺服器在無憑證時回應 tools/list,或發布可在沙箱中無憑證啟動的軟體包。

  • 描述必需15 分
  • 圖示10 分
  • 文件15 分
  • 授權條款10 分