Skip to main content
Glama
README.md
<div align="center">

<img src="docs/assets/repovive-logo.png" alt="Repovive" width="96" height="96" />

<h1>Repovive MCP Server</h1>

<p><strong>The competitive-programming platform, wired into your AI.</strong></p>

<p>
  <a href="https://www.python.org"><img alt="Python 3.10+" src="https://img.shields.io/badge/Python-3.10%2B-3776AB?style=flat-square&labelColor=1F1B45&logo=python&logoColor=white"></a>
  <a href="https://github.com/jlowin/fastmcp"><img alt="FastMCP v3" src="https://img.shields.io/badge/FastMCP-v3-6C5CE7?style=flat-square&labelColor=1F1B45"></a>
  <a href="https://modelcontextprotocol.io"><img alt="MCP server" src="https://img.shields.io/badge/MCP-server-20E3B2?style=flat-square&labelColor=1F1B45"></a>
  <img alt="httpx async" src="https://img.shields.io/badge/httpx-async-8B7CF6?style=flat-square&labelColor=1F1B45">
  <a href="docs/DEPLOYMENT.md"><img alt="Docker ready" src="https://img.shields.io/badge/Docker-ready-2496ED?style=flat-square&labelColor=1F1B45&logo=docker&logoColor=white"></a>
  <a href="deploy/kubernetes"><img alt="Kubernetes ready" src="https://img.shields.io/badge/Kubernetes-ready-326CE5?style=flat-square&labelColor=1F1B45&logo=kubernetes&logoColor=white"></a>
</p>

<p>
  <a href="docs/TOOLS.md"><img alt="102 tools" src="https://img.shields.io/badge/tools-102-6C5CE7?style=flat-square&labelColor=1F1B45"></a>
  <img alt="11 resources" src="https://img.shields.io/badge/resources-11-20E3B2?style=flat-square&labelColor=1F1B45">
  <img alt="8 prompts" src="https://img.shields.io/badge/prompts-8-8B7CF6?style=flat-square&labelColor=1F1B45">
  <img alt="End-to-end verified" src="https://img.shields.io/badge/tests-e2e_verified-00B894?style=flat-square&labelColor=1F1B45">
  <a href="docs/SECURITY.md"><img alt="Scoped bearer auth" src="https://img.shields.io/badge/auth-scoped_bearer-E17055?style=flat-square&labelColor=1F1B45"></a>
  <a href="docs/HISTORY.md"><img alt="Built-in revisions" src="https://img.shields.io/badge/revisions-built--in-00A8E8?style=flat-square&labelColor=1F1B45"></a>
  <a href="CONTRIBUTING.md"><img alt="PRs welcome" src="https://img.shields.io/badge/PRs-welcome-F1B24A?style=flat-square&labelColor=1F1B45"></a>
  <img alt="License: MIT" src="https://img.shields.io/badge/license-MIT-3FB950?style=flat-square&labelColor=1F1B45">
</p>

<img src="docs/assets/hero.svg" alt="Repovive MCP — an AI assistant connected through MCP to problems, contests, a code judge and ratings" width="100%" />

</div>

An [MCP](https://modelcontextprotocol.io) server that exposes the
[Repovive](https://repovive.com) competitive-programming platform to any MCP client
(Claude Desktop, Claude Code, IDE extensions, …). Built with **FastMCP v3** and **httpx**.

It provides **102 tools**, **11 resources** (1 templated), and **8 prompts** covering
problems, contests, ratings, courses, blog posts, direct messages, notifications,
mock-interview info, Vive points, account/profile management, **real code submission**,
**contest standings**, **production problem/contest authoring** in Repovive's build editor,
and a **built-in local judge** — with **built-in version control** over everything it edits,
all behind **scoped bearer authentication** when served over HTTP.

Every tool has been tested end-to-end — read/write tools against the live Repovive API,
submission verified with a real `Accepted` verdict, and the authoring/judge tools by
generating full contests and running every reference solution to `Accepted`.

<table>
<tr>
<td width="33%" align="center" valign="top">
<img src="docs/assets/feature-authoring.svg" alt="Author problems: statement, test cases, model solution" width="100%" /><br/>
<b>Author &amp; problemset</b><br/>
<sub>Draft a whole problem — statement, tests, model solution, editorial, validator — in Repovive's build editor, with every edit versioned.</sub>
</td>
<td width="33%" align="center" valign="top">
<img src="docs/assets/feature-judge.svg" alt="Local judge running test cases to green" width="100%" /><br/>
<b>Local judge</b><br/>
<sub>Judge solutions offline (py/c/c++/java/js) before you submit. Generated problems are correct by construction.</sub>
</td>
<td width="33%" align="center" valign="top">
<img src="docs/assets/feature-contests.svg" alt="Contest podium, rating curve and standings" width="100%" /><br/>
<b>Contests &amp; ratings</b><br/>
<sub>Browse contests, submit for a real verdict, and read standings, results and announcements.</sub>
</td>
</tr>
<tr>
<td width="33%" align="center" valign="top">
<img src="docs/assets/feature-submit.svg" alt="Submit a solution and get an Accepted verdict" width="100%" /><br/>
<b>Submit &amp; get AC</b><br/>
<sub>Submit for a real verdict and poll to <code>Accepted</code> — verified with a genuine 18/18 pass.</sub>
</td>
<td width="33%" align="center" valign="top">
<img src="docs/assets/feature-deploy.svg" alt="Deploy anywhere: Docker, Kubernetes, Helm, OpenTofu, Ansible, Vagrant" width="100%" /><br/>
<b>Deploy anywhere</b><br/>
<sub>stdio or HTTP behind scoped bearer auth, with Docker, Compose, Kubernetes, Helm, OpenTofu, Ansible and Vagrant paths.</sub>
</td>
<td width="33%" align="center" valign="top">
<img src="docs/assets/feature-community.svg" alt="Community: direct messages, notifications, blocks" width="100%" /><br/>
<b>Community</b><br/>
<sub>Read and send direct messages, triage notifications, and manage conversations and blocks.</sub>
</td>
</tr>
</table>

---

## Contents

- [How it works](#how-it-works)
- [What you can do](#what-you-can-do)
- [Submitting code](#submitting-code)
- [Quick start](#quick-start)
- [Install](#install)
- [Access control](#access-control)
- [Configure your MCP client](#configure-your-mcp-client)
- [Tool reference](#tool-reference)
- [Authoring & local judge](#authoring--local-judge)
- [History & rollback](#history--rollback)
- [Repovive house style](#repovive-house-style)
- [Resources & prompts](#resources--prompts)
- [Example agent session](#example-agent-session)
- [The two authentications](#the-two-authentications)
- [Deployment](#deployment)
- [Project layout](#project-layout)
- [Documentation](#documentation)
- [Development & tests](#development--tests)
- [Security notes](#security-notes)

---

## How it works

<div align="center">
<img src="docs/assets/workflow.svg" alt="How it works: connect over MCP, read and author, judge locally, then submit or publish" width="100%" />
</div>

1. **Connect** your MCP client (Claude Desktop, Claude Code, an IDE) to the server over
   stdio or HTTP.
2. **Read & author** — browse problems and contests, or generate and draft new ones in
   Repovive's build editor.
3. **Judge locally** — verify a solution against its tests with the built-in judge before
   anything leaves your machine.
4. **Submit / publish** — submit for a real verdict, or (with approval) publish a draft to
   a contest.

## What you can do

- **Browse & read problems** — list a contest's problems with full statements,
  constraints, I/O formats, time/memory limits, tags, and **sample test cases**.
- **Explore contests** — list upcoming/ongoing/past contests, view details, check and
  manage your registrations, get invite links.
- **Submit & track** — submit a solution for a **real verdict**, read your submission
  history, and pull a contest's **ranking, results and announcements**.
- **Ratings** — page and filter the global leaderboard by country / name / tier.
- **Courses & blog** — list courses and posts; manage course editors/metadata (with the
  right permissions).
- **Community** — read/send direct messages, manage conversations and blocks, read and
  mark notifications.
- **Interviews & Vive** — read mock-interview pricing/capacity/sessions; view Vive earn
  methods and create a Vive checkout link.
- **Account** — who am I, profile, update country, search users, sign out.
- **Scoped access** — hand out keys that can read but not submit, author but not publish,
  or call the platform but not run code on your host.
- **Undo your edits** — every change to a draft, contest, course or profile is versioned
  automatically, with a diff and a one-call rollback.
- **Author for production** — create problem drafts in Repovive's editor and fill in
  statement, tests, model solution, editorial and validator; generate and verify whole
  rounds; judge solutions locally — see [Authoring](#authoring--local-judge).

![System architecture](docs/diagrams/architecture.png)

## Submitting code

`repovive_submit_solution` submits to `POST /api/code/submit` and polls until the verdict
is final — a **real submission** recorded on your account. Verify locally first with
`repovive_judge_solution`; Repovive rate-limits submissions to roughly 10 per minute.

```text
repovive_submit_solution(contest_id="<24-hex>", problem_slug="remainder-count",
                         source=..., language="pypy")
#  -> {"submissionId": "...", "status": "Accepted", "passed": 18, "total": 18}
```

Language ids for submission follow the Judge0 set (`python` 71, `pypy` 220, `cpp` 54,
`java` 62, …), which differs from the problem editor's own ids — the tool maps names for
you. `repovive_list_my_submissions` lists your submission history.

![Submission and verdict flow](docs/diagrams/submit_flow.png)

> **Notes.** The curated **problem sets** (Classics / FAANG / Quant / Math) are premium
> content served only through the website, so their problem lists are not available via the
> API — `repovive_list_problem_sets` returns their metadata and website URLs; for
> API-readable problems use contests (`repovive_list_contest_problems`). A problem
> **like/dislike vote** endpoint exists but keys on browser-URL identifiers that can't be
> resolved reliably from the public API, so it is intentionally not exposed.

---

## Quick start

```bash
pip install repovive-mcp               # or, from a clone: pip install -e .

export REPOVIVE_EMAIL="you@example.com"
export REPOVIVE_PASSWORD="your-password"
python -m repovive_mcp                  # stdio transport (or: repovive-mcp)
```

Then point your MCP client at it (see [below](#configure-your-mcp-client)) and try
`repovive_whoami` or `repovive_list_contests`.

Serving it over HTTP instead? You also need an access token, because the port would
otherwise let anyone act as your Repovive account — see [Access control](#access-control).

```bash
export REPOVIVE_MCP_AUTH_TOKEN="$(make auth-token)"
make run-http                          # or: docker compose up --build
```

## Install

Requires Python ≥ 3.10.

```bash
pip install repovive-mcp
```

Or from a clone, for development:

```bash
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"   # fastmcp>=3, httpx, pytest, ruff
```

Prefer a container? Images are published multi-arch, signed, and carry an SBOM:

```bash
docker pull ghcr.io/dwin-gharibi/repovive-mcp:latest
```

Run it directly (stdio transport):

```bash
export REPOVIVE_EMAIL="you@example.com"
export REPOVIVE_PASSWORD="your-password"
python -m repovive_mcp          # or: repovive-mcp
```

## Access control

Two different things are being authenticated, and it is worth keeping them apart:

| | What it is | Configured with |
|---|---|---|
| **Repovive account** | who the server acts as *on the platform* | `REPOVIVE_EMAIL` + `REPOVIVE_PASSWORD`, or `REPOVIVE_TOKEN` |
| **MCP access** | who may *call this server* | `REPOVIVE_MCP_AUTH_TOKEN` (or `..._TOKENS`, or JWT settings) |

Over **stdio** your MCP client spawns the process, so the process boundary is the trust
boundary and there is nothing to configure. Over **HTTP** the server refuses to start
without an access token — an open port there is an open door to your account: submitting
code, sending direct messages, deleting contests.

```bash
export REPOVIVE_MCP_AUTH_TOKEN="$(python -c 'import secrets; print(secrets.token_urlsafe(32))')"
```

Callers then send `Authorization: Bearer <token>`. You can store a `sha256:<hex>` digest
instead of the secret itself, hand out several keys with different privileges, or verify
JWTs from your own issuer.

**Scopes.** Every tool declares what it needs, and a caller without that scope doesn't get
an error — the tool is simply absent from `tools/list`, so a model never sees a capability
it can't use.

| Scope | Grants |
|---|---|
| `repovive:read` | Problems, contests, standings, leaderboard, posts, courses, inbox. |
| `repovive:write` | Mutating your account: DMs, blocks, notifications, profile, registrations, Vive checkout. |
| `repovive:submit` | Real submissions recorded against your account. |
| `repovive:author` | Creating and editing problem drafts. |
| `repovive:admin` | Contest and course administration; deletions. |
| `repovive:execute` | Running code on the server host (local judge, generators). |
| `repovive:history` | Reading the action log and revision history, and rolling a change back. |

```bash
# a read-only key for a dashboard, and a full key for your own agent
export REPOVIVE_MCP_AUTH_TOKENS='{
  "sha256:<hex>": {"client_id": "dashboard", "scopes": ["repovive:read"]},
  "sha256:<hex>": {"client_id": "agent"}
}'
```

Full details — digests, expiry, JWT settings, and the `REPOVIVE_MCP_ALLOW_ANONYMOUS`
escape hatch for a port already behind an authenticating proxy — in
[docs/SECURITY.md](docs/SECURITY.md).

## Configure your MCP client

Add a server entry. Example (Claude Desktop `claude_desktop_config.json` /
Claude Code `mcp` config):

```json
{
  "mcpServers": {
    "repovive": {
      "command": "python",
      "args": ["-m", "repovive_mcp"],
      "env": {
        "REPOVIVE_EMAIL": "you@example.com",
        "REPOVIVE_PASSWORD": "your-password"
      }
    }
  }
}
```

If you installed into a virtualenv, point `command` at that interpreter (e.g.
`/path/to/.venv/bin/python`) or use the `repovive-mcp` console script.

For a server you're running over HTTP, point the client at the endpoint and pass the
access token:

```json
{
  "mcpServers": {
    "repovive": {
      "type": "http",
      "url": "https://mcp.example.com/mcp",
      "headers": { "Authorization": "Bearer YOUR_ACCESS_TOKEN" }
    }
  }
}
```

---

## Tool reference

All tools are prefixed `repovive_`. Read tools accept `response_format` (`markdown`
default, or `json`) where a summary view is useful. Each carries the access scope it needs
(see [Access control](#access-control)). The list below is grouped by area; the
always-current, auto-generated reference — with per-tool scopes and full descriptions — is
[docs/TOOLS.md](docs/TOOLS.md).

![Tool map](docs/diagrams/tool_map.png)

### Account & profile (7)
| Tool | Description |
|---|---|
| `repovive_whoami` | Current account (id, role, premium, Vive, streaks). |
| `repovive_get_my_profile` | Profile document (job role, org, socials, location). |
| `repovive_update_my_location` | Update profile country (idempotent). |
| `repovive_search_users` | Find users by name (for DMs). |
| `repovive_list_my_documents` | Your uploaded documents. |
| `repovive_build_version` | Deployed build/release info (no auth). |
| `repovive_logout` | Invalidate session (auto re-auth next call). |

### Problems (4)
| Tool | Description |
|---|---|
| `repovive_list_problem_sets` | Curated sets (Classics/FAANG/Quant/Math) + URLs. |
| `repovive_list_contest_problems` | All problems in a contest (summaries or full). |
| `repovive_get_problem` | One problem: statement, constraints, limits, samples. |
| `repovive_get_problem_workspace_url` | Browser URL to solve/submit a problem. |

### Contests & ratings (12)
| Tool | Description |
|---|---|
| `repovive_list_contests` | List contests, filter by upcoming/ongoing/past. |
| `repovive_get_contest` | One contest by number or id. |
| `repovive_get_contest_registrations` | Your registrations & permissions. |
| `repovive_register_for_contest` | Register (normal or virtual). |
| `repovive_get_contest_invite_link` | Shareable invite link. |
| `repovive_check_invite_eligibility` | Invite eligibility. |
| `repovive_get_contest_permissions` | List collaborators *(admin)*. |
| `repovive_set_contest_permission` | Grant a role *(admin)*. |
| `repovive_remove_contest_permission` | Revoke a role *(admin)*. |
| `repovive_update_contest` | Edit contest settings *(admin)*. |
| `repovive_delete_contest` | Delete a contest *(admin, destructive)*. |
| `repovive_get_leaderboard` | Global ratings leaderboard (paged/filtered). |

### Standings & results (4)
| Tool | Description |
|---|---|
| `repovive_get_contest_ranking` | Final standings for a contest. |
| `repovive_get_contest_results` | Your per-problem results in a contest. |
| `repovive_get_contest_announcements` | Contest announcements/clarifications. |
| `repovive_get_problem_submissions` | Submissions for one contest problem. |

### Submissions (3)
| Tool | Description |
|---|---|
| `repovive_submit_solution` | Submit a solution and await the verdict *(real submission)*. |
| `repovive_list_my_submissions` | Your submission history. |
| `repovive_get_submission` | Read a submission's status/verdict by id. |

### Content — courses & blog (8)
| Tool | Description |
|---|---|
| `repovive_list_posts` | Blog posts (paged). |
| `repovive_get_post_categories` | Blog categories. |
| `repovive_list_courses` | Courses with your enrollment. |
| `repovive_get_course_editors` | List course editors. |
| `repovive_add_course_editor` | Add an editor. |
| `repovive_remove_course_editor` | Remove an editor *(destructive)*. |
| `repovive_update_course_details` | Update title/description/tags. |
| `repovive_set_course_visibility` | Public/private *(admin)*. |

### Community — notifications & DMs (14)
| Tool | Description |
|---|---|
| `repovive_list_notifications` | In-app notifications. |
| `repovive_get_unread_notifications_count` | Unread count. |
| `repovive_mark_notifications_read` | Mark notifications read. |
| `repovive_list_conversations` | DM conversations. |
| `repovive_get_conversation_messages` | Messages in a conversation. |
| `repovive_send_direct_message` | Send a message. |
| `repovive_start_conversation` | Start a conversation. |
| `repovive_mark_conversation_read` | Mark a conversation read. |
| `repovive_delete_conversation` | Delete a conversation *(destructive)*. |
| `repovive_delete_direct_message` | Delete a message *(destructive)*. |
| `repovive_get_unread_dm_count` | Total unread DMs. |
| `repovive_list_blocked_users` | Blocked users. |
| `repovive_block_user` | Block a user. |
| `repovive_unblock_user` | Unblock a user *(destructive)*. |

### Interviews & Vive (5)
| Tool | Description |
|---|---|
| `repovive_get_interview_prices` | Mock-interview prices. |
| `repovive_check_interview_capacity` | Interview capacity. |
| `repovive_list_interview_sessions` | Your interview sessions. |
| `repovive_get_vive_earn_methods` | Ways to earn Vive. |
| `repovive_create_vive_checkout` | Create a Vive purchase link (no charge). |

### Authoring & judge — local (11)
| Tool | Description |
|---|---|
| `repovive_list_problem_templates` | Built-in problem generators. |
| `repovive_generate_problem` | Generate a complete, self-consistent problem. |
| `repovive_new_problem_template` | Empty problem skeleton + field reference. |
| `repovive_validate_problem` | Validate a problem against the schema. |
| `repovive_judge_solution` | Run a solution against tests (local judge). |
| `repovive_available_judge_languages` | Languages the host can run. |
| `repovive_build_contest` | Generate + validate + judge a whole contest. |
| `repovive_list_house_templates` | Generators that match Repovive's published style. |
| `repovive_generate_house_problem` | Generate a house-style problem. |
| `repovive_check_house_style` | Check a problem against house conventions. |
| `repovive_build_house_round` | Assemble & verify a full house-style round. |

### Problem editor — build sessions (25)
| Tool | Description |
|---|---|
| `repovive_build_list_sessions` / `repovive_build_create_session` | List / create problem drafts. |
| `repovive_build_update_problem_info` | Slug, difficulty, limits, interactive flag. |
| `repovive_build_update_statement` | Statement, I/O format, constraints. |
| `repovive_build_add_testcases` / `list_testcases` / `clear_testcases` / `delete_testcase` | Manage draft test cases. |
| `repovive_build_set_solutions` / `get_solutions` | Model & alternative solutions (language→judgeId). |
| `repovive_build_set_learn_pages` | Editorial / learn pages. |
| `repovive_build_set_validator` / `set_custom_checker` | Input validator, custom checker. |
| `repovive_build_set_generator` / `set_gen_data` / `delete_generator` / `update_sources` | Generators, gen-data, sources. |
| `repovive_build_prepare_judge_target` / `run_status` / `cancel_run` | Generate & verify tests. |
| `repovive_build_push_problem` | Push a whole generated problem into a draft. |
| `repovive_build_author_complete_problem` | Metadata+statement+tests+solution+editorial+validator in one call. |
| `repovive_build_delete_session` | Delete a problem draft *(destructive)*. |
| `repovive_build_list_admin_contests` / `repovive_build_add_to_contest` | Publish step (explicit). |

### History & revisions (9)
| Tool | Description |
|---|---|
| `repovive_list_history` | Browse the local log of state-changing calls. |
| `repovive_get_history_entry` | One entry in full, with its (redacted) arguments. |
| `repovive_history_status` | Where the database lives, what it holds, retention limits. |
| `repovive_list_revisions` | An entity's saved versions, newest first. |
| `repovive_get_revision` | One revision including its full snapshot. |
| `repovive_diff_revisions` | What changed between two revisions, field by field. |
| `repovive_restore_revision` | Roll back to a revision (or into a different entity). |
| `repovive_undo_last_change` | Step one change back. |
| `repovive_purge_history` | Delete history entries *(destructive)*. |

Drafts are not visible on the platform until reviewed; publishing is the separate
`repovive_build_add_to_contest` call. Details in [docs/AUTHORING.md](docs/AUTHORING.md).
Every edit above is versioned automatically — see [History & rollback](#history--rollback).

## Authoring & local judge

The server can **generate complete problems, build full contests, and evaluate them with a
local judge** — offline, with no writes to the live platform. Every generated problem's
expected outputs are computed by running its reference solution, so it is correct by
construction; `repovive_build_contest(..., verify=True)` judges every reference solution
and only reports success when all are `Accepted`.

```text
repovive_build_house_round(title="Repovive Starter Round 8")
  -> {round, verification: {all_passed: true, ...}}   # 7 problems, house-style, all AC
```

When you're ready to put a draft into Repovive's editor, the build-session tools write
everything and leave publishing to you:

![Build-session authoring flow](docs/diagrams/authoring_flow.png)

Verified example artifacts live in [`examples/`](examples/) (12 problems, 4 contests). Full
details in [docs/AUTHORING.md](docs/AUTHORING.md). A ready-to-use agent skill is in
[`skills/repovive-contest-dev/`](skills/repovive-contest-dev/SKILL.md).

## History & rollback

Repovive has no version control for problem drafts, so the server keeps its own. Every
state-changing call is logged, and every change to a **problem draft, contest, course or
your profile** is snapshotted automatically — you don't opt in, and you don't call anything
to save a version.

```text
repovive_list_revisions(target_kind="build_session", target_id="<session id>")
#  seq 4  auto      Updated the draft statement      <- the mistake
#  seq 3  auto      Added draft test cases
#  seq 2  auto      Updated the draft statement
#  seq 1  baseline  before the first tracked change

repovive_diff_revisions(from_revision_id=…, to_revision_id=…)
#  statement.title:       'Array Sum' -> 'OOPS wrong title'
#  statement.description: 'Sum the array.' -> 'Broken.'

repovive_undo_last_change(target_kind="build_session", target_id="<session id>")
#  -> statement restored, test cases untouched, undo recorded as a new revision
```

- **Nothing is destroyed.** A restore re-applies an old snapshot through the normal API and
  is recorded as a new revision, so you can undo the undo.
- **Deleting a draft doesn't delete its history.** Create a fresh build session and pass
  `into_target_id` to rebuild it there.
- **`dry_run=True`** reports exactly which sections would be written before anything changes.
- **Honest about coverage.** Repovive exposes no read endpoint for a draft's statement or
  generators, so those sections are reconstructed from what this server wrote; test cases and
  solutions are read back and always authoritative. Each revision names the sections it
  actually knows instead of pretending to more.
- **Irreversible things stay irreversible.** A sent direct message, a recorded submission and
  a Vive checkout are logged, never claimed as undoable.

The log doubles as an audit trail — filter it by actor to see what a given access token did,
or by tool to see who ran code on the host:

```text
repovive_list_history(status="error", days=7)
repovive_list_history(tool="repovive_judge_solution")
```

Everything lives in one local SQLite file (mode `0600`), holds no secrets — argument keys
that look like credentials are redacted before writing — and is bounded by retention limits.
Reading needs `repovive:history`; restoring additionally needs the write scope of whatever is
being restored — so a `repovive:history` token alone is a genuine read-only audit key, and the
restore tools are not even listed for it. Full details in [docs/HISTORY.md](docs/HISTORY.md).

## Repovive house style

The generators and the skill follow Repovive's **measured** conventions — read from all 98
published problems and 23 contests, and exposed as the `repovive://house-style` resource:

- **Problems** are multi-test (every problem starts with `t`), use a braced-array input
  format, a markdown-bullet constraints list, exactly one sample holding several sub-cases,
  and one explanation paragraph per sub-case. Memory limit 256 MB; time limits 1–2 s.
- **Rounds** are 7 problems (A–G) on the `500…3500` points ladder with the difficulty curve
  *easy, easy, medium, medium, medium, hard, hard*, 120 minutes, tags drawn from a fixed
  12-word vocabulary.

`repovive_check_house_style` validates a problem against these rules, and
`repovive_build_house_round` assembles a whole conforming round and verifies every problem.

## Resources & prompts

**Resources** (read via URI) — 11, one templated:
`repovive://me`, `repovive://profile`, `repovive://contests`,
`repovive://contests/{contest_id}/problems` *(templated)*, `repovive://problem-sets`,
`repovive://leaderboard`, `repovive://posts`, `repovive://courses`,
`repovive://notifications`, `repovive://house-style`, `repovive://auth-scopes`.

**Prompts** (parameterised workflows) — 8:
`solve_problem`, `prepare_for_contest`, `study_plan`, `analyze_leaderboard`,
`inbox_triage`, `build_repovive_round`, `problemset_contest`, `author_and_verify_problem`.

## Example agent session

A typical "solve a real problem" loop chains a handful of tools:

```text
1. repovive_list_contests(status="ongoing")            # find a contest id
2. repovive_list_contest_problems(contest_id=…)        # pick a problem slug
3. repovive_get_problem(contest_id=…, problem_slug=…)  # statement + samples
4. …write a solution…
5. repovive_judge_solution(problem=…, source=…)        # local check → Accepted
6. repovive_submit_solution(contest_id=…, problem_slug=…, source=…, language="pypy")
   # -> {"status": "Accepted", "passed": 18, "total": 18}
7. repovive_get_contest_ranking(contest_id=…)          # see where you land
```

![Solve & problemset flow](docs/diagrams/solve_flow.png)

---

## The two authentications

**Inbound — who may call this server.** Nothing to configure over stdio; over HTTP a bearer
token is required and the server refuses to start without one. Tokens are held as SHA-256
digests and carry scopes that decide which tools a caller can even see. See
[Access control](#access-control) and [docs/SECURITY.md](docs/SECURITY.md).

**Outbound — who this server is on Repovive.**

- With `REPOVIVE_EMAIL` + `REPOVIVE_PASSWORD`, the server logs in on first use, keeping
  both the JWT bearer token **and** the `auth_token` session cookie (some routes need the
  cookie). It re-authenticates automatically on a 401 — and a concurrent caller reuses a
  token another has already refreshed rather than logging in again — and caches the token
  (`REPOVIVE_TOKEN_CACHE`, mode `0600`, written atomically) to avoid login rate limits.
- With `REPOVIVE_TOKEN` only, it uses the bearer token (cookie-gated routes may not work).
- A `429` from Repovive surfaces as a typed rate-limit error carrying `Retry-After` rather
  than being retried indefinitely.
- The server sends a descriptive `User-Agent` and standard `Origin` header, exactly like
  any first-party API client.

![Authentication flow](docs/diagrams/auth_flow.png)

## Deployment

Runs over **stdio** (local) or **HTTP** (`REPOVIVE_MCP_TRANSPORT=http`, endpoint `/mcp`).
Docker, Docker Compose, Kubernetes (kustomize), Helm, OpenTofu/Terraform, Ansible, and
Vagrant paths are all provided under [`deploy/`](deploy/) and the root Docker/Vagrant files.

```bash
docker compose up --build            # HTTP on :8000 (reads .env, incl. REPOVIVE_MCP_AUTH_TOKEN)
# or: helm install rv deploy/helm/repovive-mcp \
#       --set credentials.email=... --set credentials.password=... --set access.token=...
# or: kubectl apply -k deploy/kubernetes   (after creating the secret)
```

Every path carries an access token, and the Helm chart refuses to render without one.

![Deployment topology](docs/diagrams/deployment.png)

Full guide: [docs/DEPLOYMENT.md](docs/DEPLOYMENT.md). Handy targets in the `Makefile`
(`make help`) and a [`Taskfile.yml`](Taskfile.yml) for [go-task](https://taskfile.dev)
(`task --list`).

## Project layout

```
repovive-mcp/
├── repovive_mcp/          the server package
│   ├── app.py             shared FastMCP instance, RepoviveClient, auth provider, lifespan
│   ├── auth.py            access control for the server itself (tokens, JWT, scope guard)
│   ├── scopes.py          the scope vocabulary
│   ├── client.py          async httpx client (login, re-auth, rate limits, token cache)
│   ├── history.py         local SQLite action log + revision store
│   ├── tracking.py        which tools change what; the middleware that records it
│   ├── revisions.py       per-entity snapshot capture and restore
│   ├── tools_*.py         tool groups (account, contests, submit, build, …)
│   ├── resources.py       MCP resources        prompts.py   MCP prompts
│   ├── authoring.py housestyle.py templates_house.py production.py   local authoring
│   ├── localjudge.py      Judge0-style subprocess judge
│   └── server.py          registers everything; stdio or HTTP (refusing an open port)
├── scripts/gen_tools_doc.py   regenerates docs/TOOLS.md from the live server
├── scripts/release.py         one-source version management + changelog rolling
├── .github/workflows/         ci.yml (lint, tests, auth gate) and release.yml
├── docs/                  architecture, tools, authoring, deployment, api map, security
├── deploy/                docker, kubernetes, helm, opentofu, ansible
├── examples/              verified problems & contests
├── skills/                repovive-contest-dev agent skill
└── tests/                 smoke, offline authoring, and live e2e tests
```

## Documentation

- [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) — components + diagrams
- [docs/TOOLS.md](docs/TOOLS.md) — full tool reference (auto-generated)
- [docs/AUTHORING.md](docs/AUTHORING.md) — problem/contest generation + local judge
- [docs/DEPLOYMENT.md](docs/DEPLOYMENT.md) — Docker/K8s/Helm/OpenTofu/Ansible/Vagrant
- [docs/API_MAP.md](docs/API_MAP.md) — the Repovive endpoints the tools use
- [docs/HISTORY.md](docs/HISTORY.md) — the action log, automatic revisions, and rollback
- [docs/RELEASING.md](docs/RELEASING.md) — how a version reaches PyPI, GHCR and the Releases tab
- [docs/SECURITY.md](docs/SECURITY.md) — access tokens, scopes, credentials, boundaries, judge sandboxing
- [skills/repovive-contest-dev/](skills/repovive-contest-dev/SKILL.md) — production contest-development skill
- [CONTRIBUTING.md](CONTRIBUTING.md) · [CHANGELOG.md](CHANGELOG.md)

## Development & tests

```bash
pip install -e ".[dev]"
# Live tests require real credentials and are skipped without them:
REPOVIVE_EMAIL=... REPOVIVE_PASSWORD=... pytest -q
make check               # lint + offline tests + docs freshness (no credentials needed)
make test-offline        # or: task test:offline
make docs                # regenerate docs/TOOLS.md from the live server
```

`tests/test_smoke.py` boots the server in-memory (`fastmcp.Client(mcp)`), lists
tools/resources/prompts, and exercises representative read tools plus error handling.
`tests/test_auth.py` covers token parsing and verification, the scope guard, and the
fail-closed HTTP start; `tests/test_client_behaviour.py` drives the HTTP client through a
mock transport (re-login, rate limits, token-cache permissions); `tests/test_history.py`
runs the whole edit → snapshot → diff → undo loop.
`docs/TOOLS.md` is generated by `scripts/gen_tools_doc.py` (CI enforces freshness with
`--check`).

## Security notes

- **The HTTP transport will not serve without an access token.** Every caller acts as your
  Repovive account, so that port is the boundary that matters.
- Credentials come only from environment variables — never hard-code them.
- Treat the JWT/cookie as secrets; they grant access to your account. The token cache lives
  outside the repo (`REPOVIVE_TOKEN_CACHE`, default
  `$XDG_CACHE_HOME/repovive-mcp/token.json`, mode `0600`).
- Write tools (submission, DMs, registration, deletes, course/contest admin) perform real
  actions; their annotations (`destructiveHint`, etc.) let clients gate them, and scopes let
  you withhold them entirely.
- The local judge runs the code you give it. `repovive:execute` is a separate scope for
  exactly that reason.
- The history database holds your statements, tests and solution source. It is written
  `0600`, never leaves the host, redacts credential-shaped arguments, and can be turned off
  with `REPOVIVE_HISTORY=off`.
- Authoring writes **drafts**; publishing a draft to a live contest is a separate, explicit
  call. See [docs/SECURITY.md](docs/SECURITY.md).

---

<div align="center">

<img src="docs/assets/social-card.svg" alt="Repovive MCP — 102 tools, 11 resources, 8 prompts, a local judge, built-in revisions and real submissions" width="100%" />

</div>

TDQS

A3.7/5.0

Scored across 102 tools

Disambiguation4/5

Most tools are clearly separated by resource and action, and descriptions explicitly distinguish near-twins like get_my_profile vs whoami and push_problem vs author_complete_problem. However, with 102 tools there are several clusters (history vs revisions, contest ranking vs leaderboard, build status vs build actions) where an agent could still misselect without careful reading.

Naming Consistency4/5

The overwhelming majority of tools follow a consistent repovive_verb_noun snake_case pattern, which makes the set predictable. Minor deviations like whoami, new_problem_template, available_judge_languages, and build_run_status keep it from being a perfect 5.

Tool Count1/5

102 tools is far beyond the 50+ threshold for an extreme mismatch. Even if each tool is individually useful, the surface is too large for an agent to navigate efficiently and for a user to audit coherently.

Completeness3/5

The server covers many domains thoroughly: contest problems, draft building, submissions, DMs, notifications, and revision history. Notable gaps remain, however, including no contest creation, no contest unregistration, no mock-interview booking/cancellation, and no course creation or content management.

Maintenance

ActivityMaintained
ResponsivenessNo issues