agentcheckup 0.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. agentcheckup-0.4.0/.gitattributes +13 -0
  2. agentcheckup-0.4.0/.github/ISSUE_TEMPLATE/bug_report.yml +63 -0
  3. agentcheckup-0.4.0/.github/ISSUE_TEMPLATE/config.yml +8 -0
  4. agentcheckup-0.4.0/.github/ISSUE_TEMPLATE/rule_request.yml +72 -0
  5. agentcheckup-0.4.0/.github/pull_request_template.md +35 -0
  6. agentcheckup-0.4.0/.github/workflows/action-selftest.yml +59 -0
  7. agentcheckup-0.4.0/.github/workflows/ci.yml +66 -0
  8. agentcheckup-0.4.0/.github/workflows/publish.yml +59 -0
  9. agentcheckup-0.4.0/.gitignore +31 -0
  10. agentcheckup-0.4.0/CHANGELOG.md +141 -0
  11. agentcheckup-0.4.0/CODE_OF_CONDUCT.md +40 -0
  12. agentcheckup-0.4.0/CONTRIBUTING.md +122 -0
  13. agentcheckup-0.4.0/LICENSE +21 -0
  14. agentcheckup-0.4.0/Makefile +35 -0
  15. agentcheckup-0.4.0/PKG-INFO +261 -0
  16. agentcheckup-0.4.0/README.md +233 -0
  17. agentcheckup-0.4.0/README.zh-CN.md +174 -0
  18. agentcheckup-0.4.0/SECURITY.md +52 -0
  19. agentcheckup-0.4.0/action.yml +121 -0
  20. agentcheckup-0.4.0/conftest.py +15 -0
  21. agentcheckup-0.4.0/docs/github-action.md +117 -0
  22. agentcheckup-0.4.0/docs/rules.md +209 -0
  23. agentcheckup-0.4.0/pyproject.toml +53 -0
  24. agentcheckup-0.4.0/scripts/bootstrap.ps1 +151 -0
  25. agentcheckup-0.4.0/scripts/bootstrap.sh +58 -0
  26. agentcheckup-0.4.0/src/agentcheckup/__init__.py +27 -0
  27. agentcheckup-0.4.0/src/agentcheckup/__main__.py +6 -0
  28. agentcheckup-0.4.0/src/agentcheckup/cli.py +242 -0
  29. agentcheckup-0.4.0/src/agentcheckup/conflicts.py +253 -0
  30. agentcheckup-0.4.0/src/agentcheckup/discovery.py +206 -0
  31. agentcheckup-0.4.0/src/agentcheckup/engine.py +146 -0
  32. agentcheckup-0.4.0/src/agentcheckup/loader.py +214 -0
  33. agentcheckup-0.4.0/src/agentcheckup/models.py +166 -0
  34. agentcheckup-0.4.0/src/agentcheckup/report.py +274 -0
  35. agentcheckup-0.4.0/src/agentcheckup/rules/__init__.py +12 -0
  36. agentcheckup-0.4.0/src/agentcheckup/rules/base.py +91 -0
  37. agentcheckup-0.4.0/src/agentcheckup/rules/config_rules.py +180 -0
  38. agentcheckup-0.4.0/src/agentcheckup/rules/docs.py +124 -0
  39. agentcheckup-0.4.0/src/agentcheckup/rules/injection.py +127 -0
  40. agentcheckup-0.4.0/src/agentcheckup/rules/naming.py +100 -0
  41. agentcheckup-0.4.0/src/agentcheckup/rules/safety.py +131 -0
  42. agentcheckup-0.4.0/src/agentcheckup/rules/schema.py +143 -0
  43. agentcheckup-0.4.0/src/agentcheckup/tokens.py +69 -0
  44. agentcheckup-0.4.0/tests/fixtures/bad_tools.json +80 -0
  45. agentcheckup-0.4.0/tests/fixtures/ci_config.json +12 -0
  46. agentcheckup-0.4.0/tests/fixtures/claude_desktop_config.json +24 -0
  47. agentcheckup-0.4.0/tests/fixtures/good_tools.json +38 -0
  48. agentcheckup-0.4.0/tests/fixtures/mock_server.py +168 -0
  49. agentcheckup-0.4.0/tests/test_cli.py +101 -0
  50. agentcheckup-0.4.0/tests/test_conflicts.py +130 -0
  51. agentcheckup-0.4.0/tests/test_discovery.py +144 -0
  52. agentcheckup-0.4.0/tests/test_rules.py +277 -0
  53. agentcheckup-0.4.0/tests/test_scoring.py +118 -0
@@ -0,0 +1,13 @@
1
+ # Normalise line endings so Windows contributors don't produce whole-file diffs.
2
+ * text=auto eol=lf
3
+
4
+ # Windows-only scripts keep CRLF.
5
+ *.ps1 text eol=crlf
6
+ *.bat text eol=crlf
7
+ *.cmd text eol=crlf
8
+
9
+ # Binary-ish
10
+ *.png binary
11
+ *.jpg binary
12
+ *.gif binary
13
+ *.ico binary
@@ -0,0 +1,63 @@
1
+ name: Bug report
2
+ description: Something is wrong — a crash, a wrong finding, a missed finding.
3
+ title: "[bug] "
4
+ labels: ["bug"]
5
+ body:
6
+ - type: markdown
7
+ attributes:
8
+ value: |
9
+ Thanks for the report. The two most useful things you can include are the
10
+ **rule id** and a **minimal manifest** that reproduces it.
11
+
12
+ - type: textarea
13
+ id: what-happened
14
+ attributes:
15
+ label: What happened
16
+ description: What did agentcheckup do, and what did you expect instead?
17
+ validations:
18
+ required: true
19
+
20
+ - type: input
21
+ id: rule
22
+ attributes:
23
+ label: Rule id (if the report is about a specific rule)
24
+ placeholder: AGT040
25
+ validations:
26
+ required: false
27
+
28
+ - type: textarea
29
+ id: repro
30
+ attributes:
31
+ label: Minimal reproduction
32
+ description: >
33
+ The smallest manifest or config that triggers it. Redact anything
34
+ sensitive — a single tool entry is usually enough.
35
+ render: json
36
+ placeholder: |
37
+ {"tools": [{"name": "x", "description": "..."}]}
38
+ validations:
39
+ required: true
40
+
41
+ - type: input
42
+ id: command
43
+ attributes:
44
+ label: Command you ran
45
+ placeholder: agentcheckup scan tools.json --fail-on warning
46
+ validations:
47
+ required: true
48
+
49
+ - type: textarea
50
+ id: output
51
+ attributes:
52
+ label: Actual output
53
+ render: shell
54
+ validations:
55
+ required: false
56
+
57
+ - type: input
58
+ id: version
59
+ attributes:
60
+ label: agentcheckup version and Python version
61
+ placeholder: agentcheckup 0.1.0, Python 3.12.7, Windows 11
62
+ validations:
63
+ required: true
@@ -0,0 +1,8 @@
1
+ blank_issues_enabled: false
2
+ contact_links:
3
+ - name: Question or idea
4
+ url: https://github.com/wanjiaqing/agentcheckup/discussions
5
+ about: For open-ended discussion, use Discussions instead of an issue.
6
+ - name: Security vulnerability
7
+ url: https://github.com/wanjiaqing/agentcheckup/security/advisories/new
8
+ about: Please report security issues privately, not in a public issue.
@@ -0,0 +1,72 @@
1
+ name: Rule request
2
+ description: Propose a new lint rule, or argue that an existing one is wrong.
3
+ title: "[rule] "
4
+ labels: ["rule"]
5
+ body:
6
+ - type: markdown
7
+ attributes:
8
+ value: |
9
+ Rules are the point of this project. A good proposal is mostly *evidence*:
10
+ what goes wrong in the real world, and why a linter is the right place to
11
+ catch it.
12
+
13
+ - type: dropdown
14
+ id: kind
15
+ attributes:
16
+ label: What kind of request is this?
17
+ options:
18
+ - New rule
19
+ - Existing rule has false positives
20
+ - Existing rule should be a different severity
21
+ - Existing rule misses a case
22
+ validations:
23
+ required: true
24
+
25
+ - type: input
26
+ id: rule-id
27
+ attributes:
28
+ label: Rule id (leave empty for a new rule)
29
+ placeholder: AGT015
30
+ validations:
31
+ required: false
32
+
33
+ - type: textarea
34
+ id: failure
35
+ attributes:
36
+ label: What goes wrong without this rule
37
+ description: >
38
+ Describe the concrete failure — a wrong tool call, a leaked credential, a
39
+ confusing retry loop. "It's bad practice" is not enough.
40
+ validations:
41
+ required: true
42
+
43
+ - type: textarea
44
+ id: example
45
+ attributes:
46
+ label: Example input that should (or should not) be flagged
47
+ render: json
48
+ placeholder: |
49
+ {"name": "read_file", "description": "TODO: describe this tool"}
50
+ validations:
51
+ required: true
52
+
53
+ - type: dropdown
54
+ id: severity
55
+ attributes:
56
+ label: Proposed severity
57
+ options:
58
+ - error — breaks a run or endangers the host
59
+ - warning — likely to cause wrong behaviour
60
+ - info — a human should decide
61
+ validations:
62
+ required: true
63
+
64
+ - type: textarea
65
+ id: false-positives
66
+ attributes:
67
+ label: What legitimate input might this wrongly flag?
68
+ description: >
69
+ This is the question that decides acceptance. If you cannot think of any,
70
+ you probably have not looked hard enough.
71
+ validations:
72
+ required: true
@@ -0,0 +1,35 @@
1
+ ## What this changes
2
+
3
+ <!-- One or two sentences. Link the issue if there is one. -->
4
+
5
+ Closes #
6
+
7
+ ## Type
8
+
9
+ - [ ] New rule
10
+ - [ ] Rule fix (false positive / false negative / severity)
11
+ - [ ] Loader or output format
12
+ - [ ] Docs
13
+ - [ ] Refactor (no behaviour change)
14
+
15
+ ## If this adds a rule
16
+
17
+ - Rule id:
18
+ - Severity:
19
+ - What it catches:
20
+ - **What legitimate input it might wrongly flag, and how you narrowed it:**
21
+
22
+ ## Checklist
23
+
24
+ - [ ] `pytest` is green
25
+ - [ ] `ruff check .` is clean
26
+ - [ ] A test covers the new behaviour (both a positive and a negative case)
27
+ - [ ] No new runtime dependency
28
+ - [ ] `docs/rules.md` updated (for rule changes)
29
+ - [ ] Rule id is unused — checked with `agentcheckup rules`
30
+ - [ ] Severity is honest: `error` means "breaks a run or endangers the host"
31
+
32
+ ## Notes for the reviewer
33
+
34
+ <!-- Anything you are unsure about. Saying "I'm not confident about the
35
+ false-positive rate here" is more useful than silence. -->
@@ -0,0 +1,59 @@
1
+ name: Action self-test
2
+
3
+ # Exercises action.yml on a real runner, including spawning two MCP servers that
4
+ # collide. Without this the action is only ever tested by reading it.
5
+
6
+ on:
7
+ push:
8
+ branches: [main]
9
+ pull_request:
10
+ workflow_dispatch:
11
+
12
+ permissions:
13
+ contents: read
14
+
15
+ jobs:
16
+ self-test:
17
+ runs-on: ubuntu-latest
18
+ steps:
19
+ - uses: actions/checkout@v4
20
+
21
+ - uses: ./
22
+ id: doctor
23
+ with:
24
+ config: tests/fixtures/ci_config.json
25
+ fail-on: never
26
+ sarif-file: agentcheckup.sarif
27
+
28
+ - name: Assert the action produced a usable result
29
+ run: |
30
+ set -eu
31
+ echo "score=${{ steps.doctor.outputs.score }}"
32
+ echo "grade=${{ steps.doctor.outputs.grade }}"
33
+ echo "findings=${{ steps.doctor.outputs.findings }}"
34
+
35
+ test -n "${{ steps.doctor.outputs.score }}" || { echo "::error::score output is empty"; exit 1; }
36
+ test -n "${{ steps.doctor.outputs.grade }}" || { echo "::error::grade output is empty"; exit 1; }
37
+ test -f agentcheckup.sarif || { echo "::error::sarif file was not written"; exit 1; }
38
+
39
+ # The fixture deliberately exposes read_file from two servers.
40
+ grep -q "AGT201" agentcheckup.sarif || {
41
+ echo "::error::expected a hard-collision finding in the SARIF output"
42
+ cat agentcheckup.sarif
43
+ exit 1
44
+ }
45
+
46
+ - name: Assert the gate fails when it should
47
+ run: |
48
+ set +e
49
+ # Re-run through the CLI directly so the action's own exit-code plumbing
50
+ # is not what we are measuring here.
51
+ PYTHONPATH=src python -m agentcheckup audit \
52
+ --no-discover \
53
+ --config tests/fixtures/ci_config.json \
54
+ --fail-on error
55
+ code=$?
56
+ if [ "$code" -ne 1 ]; then
57
+ echo "::error::expected exit 1 for an error-level finding, got $code"
58
+ exit 1
59
+ fi
@@ -0,0 +1,66 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ workflow_dispatch:
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ test:
14
+ runs-on: ${{ matrix.os }}
15
+ strategy:
16
+ fail-fast: false
17
+ matrix:
18
+ os: [ubuntu-latest, windows-latest, macos-latest]
19
+ python: ["3.10", "3.11", "3.12", "3.13"]
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+ - uses: actions/setup-python@v5
23
+ with:
24
+ python-version: ${{ matrix.python }}
25
+ - name: Install dev tools
26
+ run: python -m pip install --upgrade pip pytest ruff
27
+ - name: Lint
28
+ run: ruff check .
29
+ - name: Test
30
+ run: pytest -q
31
+
32
+ self-lint:
33
+ # Dogfood: agentcheckup lints its own fixtures. If this job fails, the fixtures
34
+ # or a rule regressed.
35
+ runs-on: ubuntu-latest
36
+ permissions:
37
+ contents: read
38
+ # Required by upload-sarif. Without it the upload fails with
39
+ # "Resource not accessible by integration", which is how this job first
40
+ # broke in CI.
41
+ security-events: write
42
+ steps:
43
+ - uses: actions/checkout@v4
44
+ - uses: actions/setup-python@v5
45
+ with:
46
+ python-version: "3.12"
47
+ - name: Lint the clean fixture (must pass)
48
+ run: PYTHONPATH=src python -m agentcheckup scan tests/fixtures/good_tools.json --min-score 90
49
+ - name: Lint the dirty fixture (must fail)
50
+ run: |
51
+ set +e
52
+ PYTHONPATH=src python -m agentcheckup scan tests/fixtures/bad_tools.json --fail-on error
53
+ code=$?
54
+ if [ "$code" -ne 1 ]; then
55
+ echo "expected exit 1, got $code"
56
+ exit 1
57
+ fi
58
+ - name: Emit SARIF
59
+ if: always()
60
+ run: PYTHONPATH=src python -m agentcheckup scan tests/fixtures/bad_tools.json --format sarif --fail-on never > agentcheckup.sarif
61
+ - name: Upload SARIF
62
+ if: always()
63
+ # v3 is deprecated in December 2026.
64
+ uses: github/codeql-action/upload-sarif@v4
65
+ with:
66
+ sarif_file: agentcheckup.sarif
@@ -0,0 +1,59 @@
1
+ name: Publish
2
+
3
+ # Publishes to PyPI using Trusted Publishing (OIDC). No API token is stored
4
+ # anywhere: PyPI trusts this repository's workflow identity directly.
5
+ #
6
+ # One-time setup on PyPI (the project does not exist yet, so use "pending
7
+ # publisher"):
8
+ # https://pypi.org/manage/account/publishing/
9
+ # PyPI Project Name : agentcheckup
10
+ # Owner : wanjiaqing
11
+ # Repository name : agentcheckup
12
+ # Workflow name : publish.yml
13
+ # Environment : pypi
14
+
15
+ on:
16
+ # Re-enable the release trigger once the PyPI pending publisher exists:
17
+ # on: release: types: [published]
18
+ # Until then a release would run this and fail with "environment: MISSING",
19
+ # which is noise on the repository home page.
20
+ workflow_dispatch:
21
+
22
+ permissions:
23
+ contents: read
24
+
25
+ jobs:
26
+ build:
27
+ runs-on: ubuntu-latest
28
+ steps:
29
+ - uses: actions/checkout@v4
30
+ - uses: actions/setup-python@v5
31
+ with:
32
+ python-version: "3.12"
33
+ - name: Build sdist and wheel
34
+ run: |
35
+ python -m pip install --upgrade build
36
+ python -m build
37
+ - name: Check metadata
38
+ run: |
39
+ python -m pip install --upgrade twine
40
+ python -m twine check dist/*
41
+ - uses: actions/upload-artifact@v4
42
+ with:
43
+ name: dist
44
+ path: dist/
45
+
46
+ publish:
47
+ needs: build
48
+ runs-on: ubuntu-latest
49
+ # Must match the "Environment name" field of the PyPI pending publisher.
50
+ # PyPI recommends a dedicated environment so that only this job can publish.
51
+ environment: pypi
52
+ permissions:
53
+ id-token: write # required for Trusted Publishing
54
+ steps:
55
+ - uses: actions/download-artifact@v4
56
+ with:
57
+ name: dist
58
+ path: dist/
59
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,31 @@
1
+ # --- Python ---
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ build/
6
+ dist/
7
+ .eggs/
8
+
9
+ # --- Virtualenv (project-local, never committed) ---
10
+ .venv/
11
+ venv/
12
+ env/
13
+ .conda/
14
+
15
+ # --- Test / lint caches ---
16
+ .pytest_cache/
17
+ .ruff_cache/
18
+ .mypy_cache/
19
+ .coverage
20
+ htmlcov/
21
+
22
+ # --- Editors / OS ---
23
+ .vscode/
24
+ .idea/
25
+ *.swp
26
+ .DS_Store
27
+ Thumbs.db
28
+
29
+ # --- Local scratch ---
30
+ *.local.json
31
+ scratch/
@@ -0,0 +1,141 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project adheres
5
+ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ Rule ids are permanent: once shipped, an id never changes meaning. New rules get
8
+ new ids, and removing a rule is a breaking change.
9
+
10
+ ## [Unreleased]
11
+
12
+ ## [0.4.0] - 2026-11-07
13
+
14
+ Calibration release, driven by the first run against real servers rather than
15
+ fixtures. Installing `mcp-server-fetch`, `mcp-server-git` and `mcp-server-time`
16
+ and auditing all three produced **Grade F, 0/100, 89 findings across 18 tools**.
17
+ A tool that scores the official reference implementations zero is a tool nobody
18
+ trusts, so the scoring and the report both changed.
19
+
20
+ ### Changed
21
+
22
+ - **Score is normalised per tool.** Budget is 20 points per tool; a flat
23
+ subtraction punished manifests for being large and scored the official servers
24
+ 0/100. Calibrated against four real inputs: clean 100, official servers 87,
25
+ a collision-plus-token config 79, deliberately broken 36.
26
+ - **Info findings are capped at 10 points total.** `AGT022` fired on 18 of 18
27
+ official tools and `AGT023` on 17 of 18 — a rule that fires on everything is a
28
+ preference, not a defect, and charging one point each buried the two findings
29
+ that mattered.
30
+ - **Repeated findings collapse.** Twelve tools missing parameter descriptions now
31
+ print as one line naming all twelve instead of twelve near-identical blocks.
32
+ Info findings are summarised one line per rule. The official-server report went
33
+ from 40 lines to 18.
34
+ - **`AGT011` (short description) is now `info`.** Short is a nudge; *missing* is
35
+ `AGT010`'s error.
36
+ - **`AGT105` (server did not return a tool list) is now `info`.** It means "not
37
+ checked", not "your config is wrong" — it fired on a machine without `npx` and
38
+ dragged the score down for an environment issue.
39
+ - **`AGT107` (plaintext credentials) is now `warning`.** It was `info`, which
40
+ under the new model made a stored token cost nothing.
41
+
42
+ ### Added
43
+
44
+ - `tests/test_scoring.py`: score calibration, per-tool normalisation, info cap,
45
+ and aggregation behaviour, including the "12 findings print as one block" case.
46
+ - README section documenting the score model with the four calibration inputs.
47
+
48
+ ### Notes
49
+
50
+ - Conflict detection produced **zero false positives** across the 18 real tools
51
+ from the three official servers. That is the number this project lives or dies
52
+ on, and it held.
53
+
54
+ ## [0.3.0] - 2026-11-07
55
+
56
+ Distribution release. The tool worked; nobody could reach it from CI.
57
+
58
+ ### Added
59
+
60
+ - **GitHub Action** (`action.yml`). Installs from its own checkout, so pinning
61
+ the action version pins the tool version and a PyPI release is not required.
62
+ Inputs: `config`, `fail-on`, `min-score`, `sarif-file`, `args`. Outputs:
63
+ `score`, `grade`, `findings`, `exit-code` — published even when the gate fails,
64
+ so a workflow can gate on score without parsing the log.
65
+ - `--json-out PATH` and `--sarif-out PATH`. One run now yields the human report,
66
+ machine-readable JSON and SARIF, instead of re-spawning every server to get a
67
+ second format.
68
+ - Config discovery covers **27 paths**: Claude Desktop, Claude Code, Cursor,
69
+ VS Code, Cline, Roo Code, Kilo Code, Windsurf, Zed, Codex CLI, Continue, plus
70
+ project-local files.
71
+ - VS Code's `mcp.servers` nesting and Zed's `context_servers` key are read.
72
+ - Codex CLI's TOML config is parsed via `tomllib` on Python 3.11+, and skipped
73
+ rather than adding a dependency on 3.10.
74
+ - `docs/github-action.md`.
75
+
76
+ ### Changed
77
+
78
+ - Cline, Roo Code and Kilo Code paths are generated for every editor flavour on
79
+ every OS. Previously they were hardcoded Windows-only, so macOS and Linux users
80
+ got no Cline coverage at all.
81
+
82
+ ### Fixed
83
+
84
+ - `discover()` walked a hardcoded Windows branch for extension paths; it now
85
+ derives from one platform table.
86
+
87
+ ## [0.2.0] - 2026-11-07
88
+
89
+ Repositioned from "MCP manifest linter" to "agent setup doctor". The manifest
90
+ rules were already there; what was missing was the one question no other tool
91
+ answers: *what happens when five servers are loaded at once?*
92
+
93
+ ### Added
94
+
95
+ - **Cross-server conflict detection** (`AGT201`–`AGT203`). Hard name collisions,
96
+ normalised-name collisions, and description overlap between tools from
97
+ different servers. No embeddings, no network — token Jaccard with a shared-head-
98
+ noun guard to keep the false-positive rate usable.
99
+ - **`agentcheckup` with no arguments** now audits everything it can find: Claude
100
+ Desktop, Claude Code (including per-project `mcpServers`), Cursor, Windsurf,
101
+ Cline, and project-local `.mcp.json` / `.cursor/mcp.json` / `.vscode/mcp.json`.
102
+ - **`audit` subcommand** with `--config`, `--no-discover`, `--no-spawn`, `--timeout`.
103
+ - `AGT105` for servers that fail to start or cannot be introspected over stdio.
104
+ Reported and skipped, never fatal.
105
+ - `StdioSession` accepts an argv list and an `env` dict, so servers are launched
106
+ without shell quoting (which matters on Windows) and with the environment their
107
+ config declares.
108
+ - `discovery` module with config discovery and Claude Code's nested project layout.
109
+ - Report splits findings into **CONFLICTS** and **RISKS** sections for `audit`.
110
+
111
+ ### Changed
112
+
113
+ - Renamed from `mcplint` to `agentcheckup`; rule prefix `MCP` → `AGT`.
114
+ - `Report` carries `server_count`; JSON output includes it.
115
+ - The text header for `audit` reports servers, tools and tokens on one line.
116
+
117
+ ### Fixed
118
+
119
+ - Plural stemming treated `files` as an `-es` plural and produced `fil`, so
120
+ `read_file` and `read_files` were not recognised as the same word.
121
+ - Conflict scoring was name-weighted enough that two tools with 71% description
122
+ overlap scored 0.543 and slipped under a 0.55 threshold. Description overlap is
123
+ now a primary signal, because that is what the model actually reads.
124
+
125
+ ## [0.1.0] - 2026-11-07
126
+
127
+ First release. 32 rules, three output formats, two input modes.
128
+
129
+ ### Added
130
+
131
+ - `scan` for saved manifests (`{"tools": [...]}`, a bare list, a JSON-RPC
132
+ `result.tools` envelope, or a session log with `messages`) and for live stdio
133
+ servers via `--cmd`.
134
+ - `config` to audit MCP client config files (`mcpServers`, `servers`,
135
+ `mcp_servers`).
136
+ - `rules` to list every rule with its id and severity.
137
+ - 32 rules across naming, documentation, schema, safety, injection, and config.
138
+ - Output formats: `text`, `json`, `sarif` (SARIF 2.1.0 for GitHub code scanning).
139
+ - `--fail-on error|warning|info|never` and `--min-score N` for CI gates.
140
+ - Manifest token estimation, reported on every run.
141
+ - Zero runtime dependencies. Python 3.10+.
@@ -0,0 +1,40 @@
1
+ # Code of Conduct
2
+
3
+ ## The short version
4
+
5
+ Be decent. Assume competence. Attack the idea, not the person.
6
+
7
+ ## Scope
8
+
9
+ This applies to issues, pull requests, discussions, commit messages, and any
10
+ other space where you are representing this project.
11
+
12
+ ## Expected
13
+
14
+ - Critique the code, the rule, or the reasoning — with specifics.
15
+ - Assume the other person knows something you do not. Most rule disagreements
16
+ come from different deployment contexts, not from carelessness.
17
+ - Accept "no" on a PR gracefully. A declined rule is not a judgement of you.
18
+ - Give credit for work you build on.
19
+
20
+ ## Not acceptable
21
+
22
+ - Insults, dismissiveness, or "this is obviously wrong" without explanation.
23
+ - Harassment of any kind, public or private.
24
+ - Discriminatory language or imagery.
25
+ - Publishing someone's private information.
26
+ - Sustained disruption of discussions.
27
+
28
+ ## Enforcement
29
+
30
+ Maintainers may edit, remove, or reject contributions that violate this, and may
31
+ block repeat offenders. If you need to report something, open a private security
32
+ advisory or contact the maintainer directly.
33
+
34
+ Reports are read by the maintainer and kept confidential.
35
+
36
+ ## Attribution
37
+
38
+ This is a short, project-specific code of conduct rather than a full adoption of
39
+ the Contributor Covenant. It is deliberately brief because a long document nobody
40
+ reads protects nobody.