# crapkit (pypi · crapkit)

Twelve tools to inspect CRAP scores, find work, and check edited functions against their ceiling.

- Trust score: 68/100 (medium)
- Change this week: +15
- Registry status: active
- Liveness: live
- Owner verified: no
- Last scored: 2026-09-22

## Components

- pypi · `crapkit`: 68/100 (this document), [markdown](https://verifymcp.io/servers/jeanfrancoisgagne-crapkit/crapkit.md), [page](https://verifymcp.io/servers/jeanfrancoisgagne-crapkit/crapkit)

## Channel facts

- Registry: `pypi`
- Package: `crapkit`
- Version: `0.7.6`
- Transport: `stdio`

## Trust breakdown

How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. Scores are 0–100 per category. Scoring method: https://verifymcp.io/docs/scoring (what has changed: https://verifymcp.io/docs/scoring/changelog)

Scored 2026-09-22.

- **Supply Chain Security**: 100/100
  - No malware found by supply-chain analysis.
  - No known CVEs affecting this package version or its production dependencies.
  - Runs setuptools.build_meta at install time, a recognised native-build step with no shell scripting around it.
  - 0 of 3 dependencies flagged as unhealthy.
- **Provenance & Transparency**: 48/100
  - Source repository is publicly reachable at the declared URL.
  - Provenance check failed: no build-provenance attestation is published.
  - Clear OSI-approved license (MIT).
  - Actively maintained (last published 0 days ago).
  - Publishes a security disclosure policy (SECURITY.md).
- **Schema Quality & AI Usability**: 69/100
  - AI-judged instruction clarity (excellent).
  - Context-footprint check failed: tool/resource definitions use about 2325 tokens (~193/item across 12 items; 12 tools + 0 resources), over budget; trim descriptions and params.
  - Usage-examples check failed: none of the tools include examples.
- **Stability & Change Management**: 0/100
  - Stability check failed: the tool surface changed between 0.4.15 and 0.7.6: 9 tool removals, 0 breaking changes, 12 additions.
- **Tool Coverage**: 100/100
  - 100% of tools have a non-trivial description (not blank, and not just the tool's name).
  - 100% of tool parameters carry a description.
  - Structured output schemas are declared (100% of tools); any adoption earns full credit.
- **Tool Safety**: 100/100
  - No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.
  - We read all 12 captured tool definition(s), and no name or description among them implies an irreversible operation.
  - An AI judge read all 13 captured unit(s) of tool text and found none that tries to manipulate the model reading it.
- **Capabilities**: 60/100
  - Spec-recency check failed: implements MCP spec 2025-06-18; the latest is 2026-07-28.

## Install

### How do I install the crapkit MCP server?

crapkit runs locally as a PyPI package, launched with uvx crapkit. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.

### Claude

```bash
claude mcp add jeanfrancoisgagne-crapkit -- uvx crapkit
```

### Cursor

```json
{
  "mcpServers": {
    "jeanfrancoisgagne-crapkit": {
      "command": "uvx",
      "args": [
        "crapkit"
      ]
    }
  }
}
```

### VS Code

```json
{
  "servers": {
    "jeanfrancoisgagne-crapkit": {
      "command": "uvx",
      "args": [
        "crapkit"
      ]
    }
  }
}
```

### Codex

```bash
codex mcp add jeanfrancoisgagne-crapkit -- uvx crapkit
```

### opencode

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "jeanfrancoisgagne-crapkit": {
      "type": "local",
      "command": [
        "uvx",
        "crapkit"
      ],
      "enabled": true
    }
  }
}
```

### OpenClaw

```bash
openclaw mcp add jeanfrancoisgagne-crapkit --command uvx --arg crapkit
```

### Hermes

```yaml
mcp_servers:
  jeanfrancoisgagne-crapkit:
    command: "uvx"
    args: ["crapkit"]
```

### Netclaw

```json
{
  "McpServers": {
    "jeanfrancoisgagne-crapkit": {
      "Transport": "stdio",
      "Command": "uvx",
      "Arguments": [
        "crapkit"
      ]
    }
  }
}
```

### Vellum

```bash
assistant mcp add jeanfrancoisgagne-crapkit -t stdio -c uvx -a crapkit
```

### Other

```json
{
  "mcpServers": {
    "jeanfrancoisgagne-crapkit": {
      "command": "uvx",
      "args": [
        "crapkit"
      ]
    }
  }
}
```

## Changelog

Every change recorded for this component, newest first. Days that predate change tracking, or that we cannot explain, say so: "we were watching and nothing happened" and "we were not watching" are different claims.

### 2026-09-22 (score 68, +15)

- [security improvement] Malware scan: unverified → pass

### 2026-09-21 (score 53, −15)

- [security regression] Malware scan: pass → unverified
- [functional] Package version: 0.7.5 → 0.7.6

### 2026-09-17 (score 68, +15)

- [security improvement] Malware scan: unverified → pass

### 2026-09-16 (score 53, 0)

- [functional] Package version: 0.7.4 → 0.7.5

### 2026-09-15 (score 53, −15)

- [security regression] Malware scan: pass → unverified
- [functional] Package version: 0.7.3 → 0.7.4

### 2026-09-12 (score 68, 0)

- [security regression] Stability: fail → unverified
- [security regression] Tool safety: pass → unverified
- [functional regression] Capabilities: fail → unverified
- [functional regression] Tool coverage: 100 → unverified
- [functional] First check of Schema quality: unverified
- [functional] Package version: 0.7.2 → 0.7.3

### 2026-09-09 (score 68, +15)

- [security regression] Stability: fail → unverified
- [security regression] Tool safety: pass → unverified
- [security improvement] Malware scan: unverified → pass
- [functional regression] Capabilities: fail → unverified
- [functional regression] Tool coverage: 100 → unverified
- [functional] First check of Schema quality: unverified
- [functional] Package version: 0.7.0 → 0.7.2

### 2026-09-08 (score 53, −16)

- [security regression] Malware scan: pass → unverified
- [functional] Package version: 0.6.0 → 0.7.0

## MCP tools (12)

### `get_next_item` (~220 tokens)

Next function to fix

Returns the next function to fix as a work packet, the newest trusted run's worst row by crap. Use it to start a fix, list_worklist to survey the same run by risk, and get_function_brief once a function is chosen. It runs no tests, and empty true means the queue is spent, not the work, so read reasons. Filters cut before top counts: top 3 with exclude ["tests/"] returns the three worst rows outside tests, and an unknown scope name is a config error.

Input parameters:

- `exclude` (array): skip rows whose path or long function name contains any of these fragments (one --exclude each)
- `repo` (string): path to the scored repo's root (default: the repo the server was started in)
- `scope` (array): restrict the ranking to these declared scopes (exact [[scope]] names from crapkit.toml, one --scope each)
- `top` (integer): return the next N packets as items instead of one item (N >= 1, default 1)

Output parameters:

- `commit` (string): that run's commit, full sha
- `empty` (boolean): true when the queue has nothing to hand out; then reasons is present and item and items are absent
- `item` (object): the one packet, present when empty is false and top is absent or 1
- `items` (array): up to top packets in crap-descending order, present when empty is false and top is above 1
- `reasons` (object): why the queue is empty, present only when empty is true; the stop condition is empty true with skipped_claimed and no_lane_over_target both 0 or absent
- `run_id` (integer): id of the run these numbers come from: the newest trusted run (a coverage run, or a verify run whose verdict passed)
- `schema` (integer): payload schema version, 1
- `skipped_claimed` (integer): rows another session's claim hid; present only when non-zero, and list_claims names the holders
- `skipped_no_lane` (integer): rows above the floor that no lane measures, kept out of the ranking because their cov 0 is a tooling gap, not a testing gap
- `stale` (boolean): true when the run's commit is not HEAD, so cov, crap and uncovered_lines describe an older tree; crapkit coverage --reuse-unchanged (get_function_brief's commands.refresh) clears it

### `list_worklist` (~205 tokens)

Risk ranking of every function

Lists the newest trusted run's whole risk ranking, every admitted function ordered by ccn times recency-weighted churn. Use it to survey a repo or split work by file, and get_next_item for the one crap-ranked packet to fix now. It runs no tests, keeps finished rows so it never empties, and reads the churn cache, not git. scope narrows before top caps, so scope ["core"] with top 20 returns the 20 riskiest in core, an unknown scope name is a config error, and repo may be any directory under the measured checkout.

Input parameters:

- `repo` (string): path to the scored repo's root (default: the repo the server was started in)
- `scope` (array): restrict the ranking to these declared scopes (exact [[scope]] names from crapkit.toml, one --scope each)
- `top` (integer): cap the active list (default: the config's worklist_top, 50)

Output parameters:

- `active` (array): the ranking: functions in files with churn in the window, risk descending, cut at top or worklist_top
- `active_total` (integer): active rows admitted before the cap: what top or worklist_top hid
- `churn_window_months` (integer): months of git history the churn weights cover
- `commit` (string): that run's commit, full sha
- `dormant_count` (integer): ranked functions whose file had no commits in the window
- `dormant_top` (array): the first 10 dormant functions, same shape as active: sleeping hazards kept out of the queue
- `floor` (integer): the effective worklist_floor: rows under this ccn are listed only when over their ceiling or in a hot file
- `run_id` (integer): id of the run these numbers come from: the newest trusted run (a coverage run, or a verify run whose verdict passed)
- `schema` (integer): payload schema version, 1
- `stale` (boolean): true when the run's commit is not HEAD, so cov, crap and uncovered_lines describe an older tree; crapkit coverage --reuse-unchanged (get_function_brief's commands.refresh) clears it

### `list_runs` (~154 tokens)

Scored run history

Lists every run in the store, oldest first by id. Use it to date the store or to see which commit the other tools answer from. Use get_trend for per-run totals and get_function_history for one function's scores per run. It reads the store only and spawns no git. repo may be any directory under the checkout, because the server walks up to the nearest crapkit.toml, and a relative path resolves from the server's start directory. No crapkit.toml above it answers an init pointer, and a checkout never scored answers a coverage pointer, both as isError true.

Input parameters:

- `repo` (string): path to the scored repo's root (default: the repo the server was started in)

Output parameters:

- `runs` (array): every run in the store, oldest first
- `schema` (integer): payload schema version, 1

### `get_trend` (~145 tokens)

Debt trend per run

Returns per-run totals for every trusted run, oldest first, with a grade per scope. Use it for the whole repo's trajectory. Use get_function_history for one function and get_ratchet_report for marked debt. It runs no lane and spawns no git. The first call on a large store sums every run into a rollup cache and takes seconds. Later calls read the cache back. repo may be any directory under a checkout where crapkit init and crapkit coverage have run. An unmeasured one answers isError true with the setup pointer.

Input parameters:

- `repo` (string): path to the scored repo's root (default: the repo the server was started in)

Output parameters:

- `runs` (array): one row per trusted run, oldest first
- `schema` (integer): payload schema version, 1
- `target` (integer): the [crapkit] target: the default ccn ceiling every scope inherits unless it sets its own

### `get_function_brief` (~222 tokens)

Start-editing packet for one function

Returns one function's start-editing packet from the newest trusted run: scored row, uncovered lines and the refresh, test, gate and verify command lines, none of them run. Use it once a function is chosen. Skip it for picking what to fix, that is get_next_item, and for a score across runs, get_function_history. Every call shingles the repo for twins, seconds on a large corpus. name must live in path. name takes the long name, a bare identifier, a start line or NAME#2, exact match first. A miss lists the file's functions instead of erroring.

Input parameters:

- `name` (string, required): the bare identifier (classify, or route for a Rust `route cmd : & Cmd`) or the whole long_name get_next_item printed (classify( score , late )); both resolve, exact match first
- `path` (string, required): repo-relative source file, forward slashes
- `repo` (string): path to the scored repo's root (default: the repo the server was started in)

Output parameters:

- `attempts` (array): every claim ever taken on this function, oldest first; [] on a first attempt, and a row with closed null is a claim still open
- `churn` (object|null): the file's churn, or null when it had no commits in the window
- `commands` (object): the rest of the loop as whole command lines for this file and scope; run them as given
- `commit` (string): that run's commit, full sha
- `coupling` (array): up to 5 change-coupling partners at support 5 and confidence 0.5, strongest first; empty when none qualify; list_coupled_files has the repo-wide list
- `duplication_twins` (array): up to 10 near-duplicate functions at similarity 0.8, best first; empty is normal; list_duplicate_functions has the repo-wide pairs
- `est_splits` (integer): 0 when ccn <= target, else ceil(ccn / target)
- `est_uncovered_paths` (integer): round((1 - cov) x ccn)
- `file_functions` (array): every scored function in the same file: where an extracted helper lands, and which names are taken
- `file_totals` (object): the file rolled up
- `function` (string): the resolved lizard long name, whichever name form was asked with
- `gate_rule` (object): what check_gate will judge this edit by
- `handle` (string): short name form: the bare identifier or (anonymous)#N, the same value get_next_item prints
- `lane` (object|null): the lane whose artifact produced cov and uncovered_lines, verbatim from the config; null when no lane covers the scope
- `notes` (object): prose the config carries for whoever edits here
- `params` (array): parameters in declaration order, so a test can call the function without opening the file
- `path` (string): the resolved file, repo-relative
- `ratchet_mark` (number|null): the committed ratchet mark, or null when the function carries none or the repo has no ratchet file
- `regrowth` (object): did this get fixed before
- `remedy` (string): decompose, split-lines, add-tests or ok: the branch the session takes; scored.remedy carries the same value
- `run_id` (integer): id of the run these numbers come from: the newest trusted run (a coverage run, or a verify run whose verdict passed)
- `schema` (integer): payload schema version, 1
- `scored` (object): the whole scored row from the run
- `source` (string): the function's own text, start to end inclusive, newlines intact: editable without reading the file
- `stale` (boolean): true when the run's commit is not HEAD, so every number here describes an older tree; run commands.refresh first
- `target` (integer): this scope's effective ccn ceiling, the same value as gate_rule.ceiling
- `uncovered_lines` (array|null): line numbers no test ran; [] when the span is fully covered; null when no artifact could answer, then uncovered_lines_note says why
- `uncovered_lines_note` (string): present only when uncovered_lines is null: the reason and the move (stale artifact, no test imports the file, coverage_optional scope)
- `versions` (object): what produced these numbers

### `get_function_history` (~257 tokens)

One function's score across runs

Returns one function's ccn, coverage, crap and flag in every run that measured it, oldest first, plus its ratchet mark. Use it to tell improving from decaying or regrown, and get_function_brief instead to start an edit. history true spawns git log -L capped at 10 commits, and tests true is null unless the lane recorded contexts. name resolves off the newest run that scored path, so a substring such as "eval" fans out to one entry per long name matched, and repo may be any directory under the measured checkout.

Input parameters:

- `history` (boolean): also list the commits that touched this function (git log -L), as commits
- `name` (string, required): the bare identifier (classify, or route for a Rust `route cmd : & Cmd`) or the whole long_name get_next_item printed (classify( score , late )); both resolve, exact match first
- `path` (string, required): repo-relative source file, forward slashes
- `repo` (string): path to the scored repo's root (default: the repo the server was started in)
- `tests` (boolean): also list the tests covering this function (coverage.py contexts), as tests

Output parameters:

- `functions` (array): the functions name resolved to, in store order
- `name` (string): the name argument as given
- `path` (string): the file asked about
- `schema` (integer): payload schema version, 1

### `check_config` (~137 tokens)

Config and repo health check

Checks that crapkit.toml agrees with the repo: typo keys, empty scopes, missing lane cwds, runners that fail to start. Run it first when any tool answers strangely or the ranking misses a file, and list_runs when only the history is in question. It needs no run, probes each runner once, runs no lane, and any problem arrives with isError true. repo can be any directory under the checkout, and one with no crapkit.toml above it answers a pointer, never a parent's config.

Input parameters:

- `repo` (string): path to the scored repo's root (default: the repo the server was started in)

Output parameters:

- `analysis_version` (integer): the analysis semantics version; with the lizard version it stamps every ratchet mark, so a bump refuses old marks until the repo re-seeds
- `lanes` (array): per declared lane
- `newest_run` (object|null): the newest run, or null when nothing has run
- `problems` (array): FAIL findings as sentences naming the fix; non-empty is exit 1 and the result carries isError true
- `resources` (object): effective resource policy; limits and estimates, not sampled utilization
- `schema` (integer): payload schema version, 1
- `store` (object): the run store
- `versions` (object): the tools behind every number
- `warnings` (array): WARN findings: unmeasured directories, scopes with a lane but no scoped_tests template, artifacts written outside .crapkit, lanes without results_artifact; exit stays 0

### `list_coupled_files` (~203 tokens)

Files that change together

Lists file pairs that keep landing in the same commits over the churn window, strongest first, at most 50. Use it before editing a file to learn what an edit drags along. Use list_duplicate_functions for copied code rather than co-change. It reads git log once per call, not the scored run. An empty list means no pair cleared both thresholds, not a missing run. A pair must clear both thresholds: min_support 5 needs five shared commits, min_confidence 0.5 means the rarer file moved with its partner half the time. repo defaults to the server's own root.

Input parameters:

- `min_confidence` (number): minimum P(pair changes together), 0 to 1 (default 0.5)
- `min_support` (integer): minimum shared commits before a pair counts (default 5)
- `repo` (string): path to the scored repo's root (default: the repo the server was started in)

Output parameters:

- `pairs` (array): pairs clearing both thresholds, ordered by support x confidence descending, at most 50
- `schema` (integer): payload schema version, 1
- `window_months` (integer): months of git history the pairs were counted over (the config's churn_window_months)

### `list_duplicate_functions` (~172 tokens)

Near-duplicate function pairs

Lists near-duplicate function pairs in the newest run, at most 50. Use it before a refactor so twins are folded together, and get_function_brief for one function's twins. It shingles source on every call, seconds on a large repo, skips functions under 8 lines and same-file pairs, and an empty list means no pair reached similarity. similarity is shared shingles over the smaller function: 1.0 admits only a function found whole inside another, 0.8 four lines in five, and repo may be any directory under the checkout.

Input parameters:

- `repo` (string): path to the scored repo's root (default: the repo the server was started in)
- `similarity` (number): containment threshold, shared over smaller, 0 to 1 (default 0.8)

Output parameters:

- `pairs` (array): pairs at or above similarity, best containment first, at most 50
- `run_id` (integer): the newest run whose rows were compared
- `schema` (integer): payload schema version, 1

### `get_ratchet_report` (~135 tokens)

Ratchet debt burn-down

Reports the ratchet debt burn-down: open marks with their age, repayments and policy findings. Use it to judge whether marked debt is repaid or piling up, and get_function_history for one function's mark. It reads the marks file and its git log only, ages count back from the newest commit touching that file, never the clock, and no marks file means zeros. repo can be any directory under a measured checkout, and an unmeasured one answers isError true with the setup pointer.

Input parameters:

- `repo` (string): path to the scored repo's root (default: the repo the server was started in)

Output parameters:

- `anchor_ts` (integer): unix seconds of the newest commit that touched the ratchet file; every age and window counts back from here, never from the wall clock; 0 with no ratchet history
- `dropped_last_30d` (integer): marks repaid in the 30 days before anchor_ts
- `dropped_last_90d` (integer): marks repaid in the 90 days before anchor_ts
- `dropped_total` (integer): marks repaid over the whole committed history
- `oldest` (array): up to 20 open marks, oldest first
- `open` (integer): marks open on disk, working tree included: an uncommitted seed counts
- `policy_violations` (array|null): null when no debt policy is configured, [] when the policy ran clean, else the findings as sentences
- `schema` (integer): payload schema version, 1
- `uncommitted` (integer): marks the working tree and the newest committed ratchet file disagree on: added, repaid or tightened but not committed

### `check_gate` (~171 tokens)

Commit gate verdict for an edited file

Checks whether an edited file clears the hook's commit gate: fresh ccn per changed function against its scope's ceiling less pardoned ratchet debt. Call it after an edit once get_function_brief states the rule. CLI verify gives the repo-wide verdict. It runs no tests, and a breach reads gate.ok false, not an error. path is repo-relative or absolute inside repo, outside or missing is a config error. A tracked file is judged on its diff from HEAD, an untracked one in full, an unchanged or unscoped one judges 0. repo may be any directory under the checkout.

Input parameters:

- `path` (string, required): repo-relative source file to judge as edited
- `repo` (string): path to the scored repo's root (default: the repo the server was started in)

Output parameters:

- `baseline_commit` (string): that run's commit, full sha
- `baseline_run` (integer): id of the run whose coverage was reused
- `functions` (array): every function in the file, rescored
- `gate` (object): the verdict block
- `note` (string): fixed reminder that coverage is the baseline run's and complexity the working tree's; crapkit verify gives the real verdict
- `schema` (integer): payload schema version, 1

### `list_claims` (~152 tokens)

Open queue claims

Lists open claims on queue items, oldest first. Use it when get_next_item answers empty or skipped_claimed above 0, and use get_function_brief to see one function's own attempts. No tool here writes a claim: the CLI releases a stale one with crapkit claims release PATH NAME, and verify closes one at the ceiling. repo may be any directory under the checkout, since the server walks up to the nearest crapkit.toml. No crapkit.toml above it answers an init pointer, and a checkout never scored answers a coverage pointer, both as isError true.

Input parameters:

- `repo` (string): path to the scored repo's root (default: the repo the server was started in)

Output parameters:

- `claims` (array): open claims, oldest first
- `open` (integer): number of open claims
- `schema` (integer): payload schema version, 1

## Diagnostics

Captured diagnostic sections: Provenance, Install scripts, Dependencies. The full working is on the page: https://verifymcp.io/servers/jeanfrancoisgagne-crapkit/crapkit#diagnostics

## Score history

- 2026-09-22: 68
- 2026-09-21: 53
- 2026-09-20: 68
- 2026-09-19: 68
- 2026-09-18: 68
- 2026-09-17: 68
- 2026-09-16: 53
- 2026-09-15: 53
- 2026-09-14: 68
- 2026-09-13: 68
- 2026-09-12: 68
- 2026-09-11: 68
- 2026-09-10: 68
- 2026-09-09: 68
- 2026-09-08: 53
- 2026-09-07: 69
- 2026-09-06: 54
- 2026-09-05: 55
- 2026-09-04: 50
- 2026-09-03: 65
- 2026-09-02: 50

## Common questions

### What is the crapkit MCP server?

crapkit is an MCP server listed in the public MCP registry as io.github.JeanFrancoisGagne/crapkit. Twelve tools to inspect CRAP scores, find work, and check edited functions against their ceiling. This page covers its PyPI package (crapkit).

### Is the crapkit MCP server safe to use?

crapkit scores 68 out of 100 on VerifyMCP. We found no known CVEs affecting it as of 22 September 2026. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.

### What tools does the crapkit MCP server expose?

crapkit exposes 12 tools: get_next_item, list_worklist, list_runs, get_trend, get_function_brief, and 7 more. Their descriptions and schemas cost roughly 2,173 tokens of context every time the server is loaded.

### Is the crapkit MCP server still maintained?

crapkit is still listed as active in the MCP registry. We last reached this channel on 22 September 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.

### What licence is the crapkit MCP server under?

crapkit declares the MIT licence, which is OSI-approved. That covers the source only, and says nothing about the cost of any service it calls.

## Links

- PyPI project: https://pypi.org/project/crapkit/
- Socket report: https://socket.dev/pypi/package/crapkit
- Repository: https://github.com/JeanFrancoisGagne/crapkit
- Website: https://www.jfgagne.com/crapkit/
- Changelog RSS feed: https://verifymcp.io/servers/jeanfrancoisgagne-crapkit/crapkit.xml
- Changelog JSON feed: https://verifymcp.io/servers/jeanfrancoisgagne-crapkit/crapkit.json
- HTML version of this page: https://verifymcp.io/servers/jeanfrancoisgagne-crapkit/crapkit
