Skip to main content

MCP server for Rosentic - cross-branch conflict detection for parallel AI coding agents: catches breaking signature changes, HTTP route breaks, and schema drift between agent branches before merge

Project description

Rosentic MCP Server

CI checks each PR against main. It doesn't check open PRs against each other.

Rosentic does. Install one package, then ask your coding agent to check for cross-branch conflicts before you merge.

One agent changes a function signature. Another agent still calls the old version. Both pass CI. Git merges the text cleanly. Main breaks.

Rosentic compares active branches against each other. Deterministic static analysis across 13 languages (Python, JavaScript, TypeScript, Go, Java, Rust, Swift, C++, Kotlin, C#, Ruby, PHP, Dart). No LLM. In local MCP mode, code and scan metadata stay on your machine.

MCP gives your editor or coding agent access to Rosentic tools on demand. It is not a hard automatic gate by itself: a CLAUDE.md instruction is advisory, and an agent can forget or ignore it. For a gate that BLOCKS, run rosentic-mcp install-hooks and commit the result (see Enforce below), or use the GitHub Action as a CI backstop.

Freshness and offline behavior

  • Scan results are cached for 60 seconds per (repo, base, branch-set); a repeat call inside that window returns the cached result only while the scanned refs still match. Cached answers identify themselves as CACHED.
  • check_file marks sibling-branch index data stale after 300 seconds (stale_after_seconds to override). Stale, skipped, moved, or newly unindexed sibling coverage is DEGRADED, never SAFE by implication.
  • Sibling context comes from your local git refs: run git fetch to pick up new sibling work; the server never fetches for you.
  • Offline: check_file, check_conflicts, explain_conflict, list_branches, run_status, and which_lane are fully local and work with no network. get_policy, get_verdict, and get_remediation_queue read the dashboard API and degrade gracefully offline - they return an explanatory payload (never raise), and get_policy reports the built-in default (advisory, UNSAFE fails), which is exactly what the CI gate falls back to.
  • Linked git worktrees are supported (repo detection uses git rev-parse, not a .git-directory test). One caveat: when the engine runs via Docker (no local checkout), scan the MAIN checkout rather than a linked worktree - a worktree's gitdir lives outside the mounted path. With a local engine (dev checkout / ROSENTIC_ENGINE_PATH), worktrees work everywhere.
  • Call metering is a local counter at ~/.rosentic/mcp-usage.json. Nothing is billed and the counter never blocks a call.

Every answer names whether its check was EXECUTED, served from a validated CACHED result, DEGRADED, or NOT_EXECUTED. A degraded answer says in its model-facing message that it is not a clear result; nested metadata is evidence, not the only warning.

Install

pip3 install --upgrade rosentic-mcp

Use --upgrade even on a machine that already has the package: a plain pip install is a no-op for returning users and silently keeps stale code. If pip3 is not on PATH, use python3 -m pip install --upgrade rosentic-mcp.

Configure

Claude Code

Add to ~/.claude.json:

{
  "mcpServers": {
    "rosentic": {
      "command": "rosentic-mcp"
    }
  }
}

Add this instruction to your repo's CLAUDE.md:

Before running git push, call the Rosentic check_conflicts MCP tool to verify your branch is compatible with other active branches.

Codex

Add to ~/.codex/config.toml:

[mcp_servers.rosentic]
command = "rosentic-mcp"
args = []

Add the same push-boundary instruction to AGENTS.md.

Cursor / VS Code

Add to MCP settings:

{
  "rosentic": {
    "command": "rosentic-mcp"
  }
}

Enforce (make the gate block, not advise)

The steps above give agents the tools and an instruction. Nothing yet blocks a bad push. One command installs the committed enforcement path:

cd your-repo
rosentic-mcp install-hooks
git add .githooks .claude/settings.json
git commit -m "Add Rosentic enforcement gate"

What it installs:

  • .githooks/pre-push - a committed git hook that runs rosentic-mcp gate and exits nonzero on UNSAFE findings. The gate fails closed: if the scan cannot run, the push is blocked with an explanation. Bypass one push with ROSENTIC_SKIP=1 git push; make WARNING findings block too with ROSENTIC_STRICT=1.
  • git config core.hooksPath .githooks - the per-clone wiring. git config cannot be committed, so each fresh clone runs rosentic-mcp install-hooks once (it is idempotent).
  • .claude/settings.json - committed Claude Code hooks: PreToolUse blocks an UNSAFE write before it lands, and Stop keeps the agent working while UNSAFE cross-branch findings exist. Because this file is committed, every fresh clone gates Claude Code sessions immediately, with zero per-user setup. If the file already exists, install-hooks appends the Rosentic entries and never removes yours.

You can also run the gate directly, in CI or by hand:

rosentic-mcp gate --repo . --base main   # exit 0 clean, 1 UNSAFE, 2 scan error

Tools

Tool Local answer
check_file Checks proposed file content against sibling branches.
check_conflicts Scans active branches for deterministic compatibility conflicts.
explain_conflict Explains one finding from a recent scan.
list_branches Lists local branches by last commit.
run_status Reads manifest lanes, local heads, merge state, sequence, and landing readiness.
which_lane Resolves declared path ownership without guessing.
get_verdict Reads a recorded gate verdict for a checkout and SHA.
get_policy Reads the effective merge-gate policy.
get_remediation_queue Reads the ranked remediation queue.

check_conflicts

Scan a git repo for cross-branch conflicts affecting your current branch.

Parameters:

  • repo_path (required) - path to local git repository
  • branch - branch to check (defaults to current branch)
  • base - base branch to compare against (defaults to main)
  • format - "summary" (natural language) or "json" (structured findings)

JSON responses wrap findings with execution_status and a model-facing message; an empty list is meaningful only when the status is EXECUTED or CACHED.

Example response:

Rosentic found 4 unique conflict(s) for feature/auth-refactor: 2 UNSAFE, 2 WARNING. Layer breakdown: 3 L1 signature, 1 L2 route. Most critical: createUser() in src/auth/users.ts - changed from 2 to 3 required params. Recommendation: inspect the UNSAFE findings first and update the stale branch before merging.

check_file

Check proposed complete file content against active sibling branches before writing.

Parameters:

  • repo_path (required) - path to local git repository
  • file (required) - repository-relative file path being edited
  • content (required) - proposed complete post-edit file content
  • branch - current branch to use as the proposed-content overlay
  • base - base branch to compare against (defaults to main)
  • stale_after_seconds - mark branch index data stale after this many seconds

The response includes SAFE/WARNING/UNSAFE verdict, conflict direction, consumers with branch attribution, checked branches, skipped branches with reasons, and index freshness metadata.

explain_conflict

Get detailed explanation of a specific finding, including affected branches, consumer locations, and remediation steps.

Parameters:

  • repo_path (required) - path to local git repository
  • finding_id (required) - ID from a previous check_conflicts result

list_branches

List local branches sorted by most recent commit date. The rows are returned under branches beside the common execution status and message.

Parameters:

  • repo_path (required) - path to local git repository

run_status

Read .rosentic/run.yaml plus local Git branch heads and merge state. Returns each lane's sequence position, whether it is merged into the manifest's base branch, the lane currently clear to land, and old branches still ahead of base. Checkout state is current by definition, so the Remote-only RESCAN_REQUIRED staleness case does not apply here.

Parameters:

  • repo (required) - path to local git repository
  • cursor - pagination cursor from a prior response
  • limit - number of lanes to return (default 25, maximum 100)

which_lane

Match repository-relative paths against the manifest's declared protected_paths. Missing or ambiguous ownership is returned explicitly; the tool never guesses.

Parameters:

  • repo (required) - path to local git repository
  • paths (required) - one to 100 repository-relative paths

get_verdict

Look up recorded gate verdicts in the Rosentic audit ledger by SHA (append-only gate ledger via the dashboard API). Requires ROSENTIC_API_KEY (a ros_live_ workspace key) for the org's workspace. Degrades gracefully offline - returns an explanatory payload instead of raising.

Parameters:

  • repo (required) - path to local git repository
  • sha (required) - branch head SHA to look up

get_policy

Fetch the effective Rosentic gate policy (repo > org default > built-in): gate mode, severity threshold, per-layer enforce/advisory, branch-pattern rules, and the stamped policy version. Public read - no key needed. Degrades gracefully offline with the built-in default and a notice.

Parameters:

  • org (required) - GitHub org/owner of the repository
  • repo - repository name; omit for the org default policy

Troubleshooting

A user-scope entry shadows the project .mcp.json

A rosentic entry in your user scope (mcpServers.rosentic in ~/.claude.json) silently takes precedence over a repo's committed .mcp.json under the same server name. Every session in that repo then talks to whatever the user-scope entry points at (often a dev checkout) instead of the published package the project pins, and results can come from a different engine version. This is most likely on developer machines that have both.

The server detects the common case: on the first scan of a repo whose committed .mcp.json declares a different rosentic server than the one actually answering, the tool result opens with MCP CONFIG SHADOWING DETECTED, naming the repo's .mcp.json and the running server.

Remedy:

claude mcp get rosentic          # Scope shows where the entry resolves from
claude mcp remove rosentic -s user
# or keep the dev server under a different name so it cannot collide:
# rename the user-scope entry to rosentic-dev

Then restart the session and re-check claude mcp get rosentic: Scope should say project.

What it detects

Layer What Example
L1 Function signature mismatches Branch A adds required param, Branch B still calls with old arity
L2 HTTP route contract breaks Route path or method changes, consumers still call old endpoint
L3 Schema incompatibilities Proto field removed, GraphQL type changed, OpenAPI contract broken

How it works

  • Deterministic - no LLM in the scan path. Tree-sitter AST parsing + evidence-gated verdicts.
  • Fast - scans 30 branches in under 30 seconds for most repos.
  • Evidence-based - every finding includes proof: which symbol changed, where it's called, why it's linked.

Requirements

  • Python 3.11+
  • Git repository with branches to scan
  • Works on macOS, Linux, Windows (WSL)

Verify

From a checkout that has this repository's helper scripts:

python3 scripts/mcp-smoke-test.py

Expected output:

Rosentic MCP OK: check_conflicts, check_file, explain_conflict, get_policy, get_remediation_queue, get_verdict, list_branches, run_status, which_lane

Links

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

rosentic_mcp-0.2.0.tar.gz (45.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

rosentic_mcp-0.2.0-py3-none-any.whl (47.9 kB view details)

Uploaded Python 3

File details

Details for the file rosentic_mcp-0.2.0.tar.gz.

File metadata

  • Download URL: rosentic_mcp-0.2.0.tar.gz
  • Upload date:
  • Size: 45.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.0

File hashes

Hashes for rosentic_mcp-0.2.0.tar.gz
Algorithm Hash digest
SHA256 97d7b5788506385c60876dcc8a3c21c8ad68ce9bf57e8c191539975fd1138076
MD5 45c999023bcc04d9033d88b8677da141
BLAKE2b-256 e0d2d6d087b5f3f71baee10f20b0d42cf5420ca9688b9aba620df200958c6f54

See more details on using hashes here.

File details

Details for the file rosentic_mcp-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: rosentic_mcp-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 47.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.0

File hashes

Hashes for rosentic_mcp-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 61b167b98024ebef0fa96d5fba6a2b3ed526cc6ffa08b0abde4106fc173d8472
MD5 43738bde5532e0f3a4d8307b614a81a3
BLAKE2b-256 77edc95f0b32f1c597e702be700a47a390c0c8e19fab2149827810110f473c0b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page