mcplint-cli 0.1.0__py3-none-any.whl

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 (71) hide show
  1. mcplint/__about__.py +1 -0
  2. mcplint/__init__.py +3 -0
  3. mcplint/benchmark/__init__.py +0 -0
  4. mcplint/benchmark/dataset.py +34 -0
  5. mcplint/benchmark/providers/__init__.py +0 -0
  6. mcplint/benchmark/providers/anthropic_provider.py +92 -0
  7. mcplint/benchmark/providers/base.py +26 -0
  8. mcplint/benchmark/providers/factory.py +51 -0
  9. mcplint/benchmark/providers/fake.py +26 -0
  10. mcplint/benchmark/providers/openai_provider.py +25 -0
  11. mcplint/benchmark/runner.py +43 -0
  12. mcplint/benchmark/scorer.py +147 -0
  13. mcplint/cli/__init__.py +0 -0
  14. mcplint/cli/commands/__init__.py +0 -0
  15. mcplint/cli/commands/benchmark_cmd.py +88 -0
  16. mcplint/cli/commands/compare_cmd.py +139 -0
  17. mcplint/cli/commands/fix_cmd.py +60 -0
  18. mcplint/cli/commands/inspect_cmd.py +44 -0
  19. mcplint/cli/commands/rules_cmd.py +30 -0
  20. mcplint/cli/commands/scan_cmd.py +113 -0
  21. mcplint/cli/commands/snapshot_cmd.py +33 -0
  22. mcplint/cli/main.py +49 -0
  23. mcplint/compare/__init__.py +0 -0
  24. mcplint/compare/differ.py +148 -0
  25. mcplint/config/__init__.py +0 -0
  26. mcplint/config/loader.py +36 -0
  27. mcplint/config/schema.py +40 -0
  28. mcplint/core/__init__.py +0 -0
  29. mcplint/core/engine.py +40 -0
  30. mcplint/core/registry.py +52 -0
  31. mcplint/core/rules/__init__.py +0 -0
  32. mcplint/core/rules/ambiguity.py +157 -0
  33. mcplint/core/rules/ambiguity_rules.py +109 -0
  34. mcplint/core/rules/base.py +39 -0
  35. mcplint/core/rules/builtin.py +45 -0
  36. mcplint/core/rules/completeness_rules.py +217 -0
  37. mcplint/core/rules/description_rules.py +110 -0
  38. mcplint/core/rules/safety_rules.py +139 -0
  39. mcplint/core/rules/schema_rules.py +101 -0
  40. mcplint/core/score.py +132 -0
  41. mcplint/fix/__init__.py +0 -0
  42. mcplint/fix/suggest.py +183 -0
  43. mcplint/mcp_client/__init__.py +0 -0
  44. mcplint/mcp_client/canonical.py +25 -0
  45. mcplint/mcp_client/persistence.py +17 -0
  46. mcplint/mcp_client/session.py +80 -0
  47. mcplint/mcp_client/stdio.py +17 -0
  48. mcplint/models/__init__.py +0 -0
  49. mcplint/models/benchmark.py +67 -0
  50. mcplint/models/common.py +23 -0
  51. mcplint/models/comparison.py +53 -0
  52. mcplint/models/contracts.py +39 -0
  53. mcplint/models/findings.py +44 -0
  54. mcplint/models/fixes.py +13 -0
  55. mcplint/models/score.py +25 -0
  56. mcplint/models/snapshot.py +27 -0
  57. mcplint/py.typed +0 -0
  58. mcplint/reporters/__init__.py +0 -0
  59. mcplint/reporters/benchmark_terminal.py +46 -0
  60. mcplint/reporters/comparison_terminal.py +61 -0
  61. mcplint/reporters/fix_markdown.py +34 -0
  62. mcplint/reporters/html.py +71 -0
  63. mcplint/reporters/json_reporter.py +9 -0
  64. mcplint/reporters/sarif.py +77 -0
  65. mcplint/reporters/templates/report.html.j2 +176 -0
  66. mcplint/reporters/terminal.py +52 -0
  67. mcplint_cli-0.1.0.dist-info/METADATA +392 -0
  68. mcplint_cli-0.1.0.dist-info/RECORD +71 -0
  69. mcplint_cli-0.1.0.dist-info/WHEEL +4 -0
  70. mcplint_cli-0.1.0.dist-info/entry_points.txt +2 -0
  71. mcplint_cli-0.1.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,392 @@
1
+ Metadata-Version: 2.4
2
+ Name: mcplint-cli
3
+ Version: 0.1.0
4
+ Summary: Lint and benchmark MCP tool contracts before ambiguous descriptions break LLM tool selection.
5
+ Project-URL: Homepage, https://github.com/akashkokare2910/mcplint
6
+ Project-URL: Repository, https://github.com/akashkokare2910/mcplint
7
+ Project-URL: Issues, https://github.com/akashkokare2910/mcplint/issues
8
+ Project-URL: Changelog, https://github.com/akashkokare2910/mcplint/blob/main/CHANGELOG.md
9
+ Author-email: Akash Kokare <akashkokare2017@gmail.com>
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: agent,ai,evaluation,lint,llm,mcp,model-context-protocol,tool-calling
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Environment :: Console
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Software Development :: Quality Assurance
23
+ Classifier: Topic :: Software Development :: Testing
24
+ Classifier: Typing :: Typed
25
+ Requires-Python: >=3.11
26
+ Requires-Dist: anyio>=4.4
27
+ Requires-Dist: httpx>=0.27
28
+ Requires-Dist: jinja2>=3.1
29
+ Requires-Dist: jsonschema>=4.22
30
+ Requires-Dist: mcp>=1.28
31
+ Requires-Dist: pydantic>=2.7
32
+ Requires-Dist: pyyaml>=6.0
33
+ Requires-Dist: rich>=13.7
34
+ Requires-Dist: typer>=0.12
35
+ Provides-Extra: anthropic
36
+ Requires-Dist: anthropic>=0.34; extra == 'anthropic'
37
+ Provides-Extra: dev
38
+ Requires-Dist: anthropic>=0.34; extra == 'dev'
39
+ Requires-Dist: mypy>=1.10; extra == 'dev'
40
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
41
+ Requires-Dist: pytest-cov>=5.0; extra == 'dev'
42
+ Requires-Dist: pytest>=8.2; extra == 'dev'
43
+ Requires-Dist: ruff>=0.5; extra == 'dev'
44
+ Requires-Dist: types-jsonschema; extra == 'dev'
45
+ Requires-Dist: types-pyyaml; extra == 'dev'
46
+ Provides-Extra: openai
47
+ Requires-Dist: openai>=1.40; extra == 'openai'
48
+ Provides-Extra: semantic
49
+ Requires-Dist: sentence-transformers>=3.0; extra == 'semantic'
50
+ Description-Content-Type: text/markdown
51
+
52
+ # MCPLint
53
+
54
+ **Your MCP server can pass schema validation while the model still chooses the wrong tool.**
55
+
56
+ MCPLint is an "ESLint for MCP tool contracts." It connects to a [Model
57
+ Context Protocol](https://modelcontextprotocol.io) server, retrieves its
58
+ tool definitions, detects description and schema problems that cause LLM
59
+ agents to select the wrong tool or construct invalid arguments, suggests
60
+ improvements, and benchmarks tool-selection behaviour before and after
61
+ changes.
62
+
63
+ A tool can have a perfectly valid `inputSchema` and still be a trap for an
64
+ agent: two tools whose descriptions overlap, a destructive action with no
65
+ warning, a required parameter whose constraints are never mentioned in
66
+ prose. JSON Schema validation doesn't catch any of that. MCPLint does.
67
+
68
+ ---
69
+
70
+ ## 60-second quick start
71
+
72
+ ```bash
73
+ pip install mcplint-cli
74
+
75
+ # Point it at any MCP server's launch command
76
+ mcplint scan --server "python my_server.py"
77
+ ```
78
+
79
+ That's it — no config file, no API key, no LLM required for the core
80
+ linter. `mcplint scan` connects over stdio, retrieves the tool list, runs
81
+ 15 deterministic rules, and prints a scored report with a non-zero exit
82
+ code when something's wrong (so it gates a PR the same way `eslint` does).
83
+
84
+ ## Example output
85
+
86
+ ```
87
+ $ mcplint scan --server "python examples/bad_server/server.py"
88
+
89
+ bad-customer-server — 34 finding(s) (6 error, 13 warning, 15 info) — score: 32/100
90
+ -8.0 1 critical/error finding(s) x 8 pts (capped at 40)
91
+ -20.0 18 warning/info finding(s) x 2 pts (capped at 20)
92
+ -10.0 2 ambiguity finding(s) x 5 pts (capped at 15)
93
+ -15.0 9 schema-completeness finding(s) x 3 pts (capped at 15)
94
+ -15.0 4 safety-clarity finding(s) x 5 pts (capped at 15)
95
+
96
+ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
97
+ ┃ Rule ┃ Severity ┃ Tool ┃ Message ┃
98
+ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
99
+ │ missing-tool-description │ error │ ping │ Tool 'ping' has no description. │
100
+ │ description-repeats-name │ warning │ get_status │ Description only restates its name. │
101
+ │ vague-tool-description │ warning │ get_status │ Description is very short (2 words). │
102
+ │ missing-parameter-description │ warning │ fetch_record │ Parameter 'record_id' has no description. │
103
+ │ ... │ │ │ (30 more) │
104
+ └──────────────────────────────────┴──────────┴───────────────┴────────────────────────────────────────────┘
105
+ ```
106
+
107
+ Every finding carries a rule ID, severity, evidence, remediation text, and
108
+ a confidence score — heuristic findings are never presented as certain (see
109
+ `undocumented-error-behaviour` above at confidence 0.5 vs.
110
+ `missing-tool-description` at 1.0).
111
+
112
+ ## Architecture
113
+
114
+ ```
115
+ mcp_client/ stdio connection to the MCP server -> MCPServerSnapshot
116
+ (untrusted-process boundary; canonicalization for stable JSON)
117
+ core/ Rule ABC + RuleRegistry + lint_snapshot() engine
118
+ core/rules/ 15 built-in rules + the cross-tool ambiguity engine
119
+ core/score.py explainable 0-100 score
120
+ config/ mcplint.yaml loading (severity overrides, thresholds, ignores)
121
+ benchmark/ dataset format, ToolCallingProvider protocol, scorer, runner
122
+ providers/ fake (tests), anthropic (real), openai (stub)
123
+ compare/ pure diff functions between two snapshots/lint reports/benchmarks
124
+ fix/ deterministic rewrite suggestions from JSON Schema + annotations
125
+ models/ every persisted artifact as a typed Pydantic model
126
+ reporters/ terminal (Rich), JSON, SARIF 2.1.0, standalone HTML, Markdown
127
+ cli/ Typer commands — thin wrappers around the modules above
128
+ ```
129
+
130
+ The deterministic linter (`core/`) never imports an LLM client. Only
131
+ `benchmark/providers/anthropic_provider.py` (and the `openai` stub) touch a
132
+ model API, and only when you explicitly ask for `--provider anthropic`.
133
+
134
+ ## Rule catalogue
135
+
136
+ Run `mcplint rules` for the live list (id, title, default severity, tags).
137
+ All 15 are deterministic — no LLM key required.
138
+
139
+ | Rule | Default severity | What it catches |
140
+ |---|---|---|
141
+ | `missing-tool-description` | error | No description at all |
142
+ | `description-repeats-name` | warning | Description just restates the tool name |
143
+ | `vague-tool-description` | warning | Description under 4 words |
144
+ | `missing-parameter-description` | warning | A parameter with no description |
145
+ | `missing-return-semantics` | warning | No outputSchema and no return-related wording |
146
+ | `undocumented-error-behaviour` | info | Description never mentions failure/error conditions |
147
+ | `undocumented-required-constraint` | warning | Required param's enum/min/max not mentioned in prose |
148
+ | `schema-description-type-conflict` | error | Description implies a type the schema doesn't declare |
149
+ | `tool-name-action-conflict` | error | Name reads read-only but is annotated destructive |
150
+ | `destructive-tool-without-warning` | error | Destructive annotation, no warning in the description |
151
+ | `state-changing-tool-marked-read-only` | error | Name reads as a mutation but `readOnlyHint` is true |
152
+ | `ambiguous-tool-overlap` | warning | Two tools score above the ambiguity threshold |
153
+ | `missing-tool-distinction` | info | Ambiguous pair never states when to use which |
154
+ | `excessive-description-length` | info | Description over the configured character limit |
155
+ | `undefined-domain-term` | info | An unexplained acronym/jargon term |
156
+
157
+ See `examples/bad_server/server.py` for one deliberate trigger per rule, and
158
+ `examples/good_server/server.py` for a server that scores 0 findings against
159
+ all 15.
160
+
161
+ ### The ambiguity engine
162
+
163
+ `ambiguous-tool-overlap` and `missing-tool-distinction` are backed by
164
+ `core/rules/ambiguity.py::compute_ambiguity`, a pairwise score (0-1) built
165
+ from:
166
+
167
+ - name token similarity (25%)
168
+ - description token similarity, stopword-filtered (45%)
169
+ - parameter-name overlap (30%)
170
+
171
+ Every flagged pair carries **evidence**, not just a number: shared verbs,
172
+ shared entities, overlapping parameters, and three explicit booleans for
173
+ whether the pair states an exact-vs-search, one-vs-many, or read-vs-write
174
+ distinction. This is deliberately explainable rather than an opaque
175
+ embedding score — see `examples/ambiguous_customer_server` for a worked
176
+ example (`get_customer` vs `search_customers`).
177
+
178
+ An optional `semantic` extra (`sentence-transformers`) is planned as an
179
+ additional signal on top of this token-based score, not a replacement —
180
+ not yet wired in (see Limitations).
181
+
182
+ ## Configuration
183
+
184
+ `mcplint.yaml`, auto-loaded from the current directory (`--config` to
185
+ override the path):
186
+
187
+ ```yaml
188
+ severity:
189
+ missing-tool-description: error
190
+ excessive-description-length: info
191
+
192
+ thresholds:
193
+ ambiguity: 0.78
194
+ max_description_characters: 800
195
+
196
+ ignore:
197
+ - tool: internal_debug
198
+ rules:
199
+ - missing-return-semantics
200
+
201
+ benchmark:
202
+ provider: anthropic
203
+ model: claude-sonnet
204
+ runs: 3
205
+ ```
206
+
207
+ Invalid config fails with a specific, actionable field-level error rather
208
+ than a generic traceback.
209
+
210
+ ## Benchmark guide
211
+
212
+ Deterministic linting catches contract problems; the benchmark measures
213
+ whether a real model actually picks the right tool.
214
+
215
+ ```yaml
216
+ # evals.yaml
217
+ name: customer-tools
218
+ version: "1"
219
+ cases:
220
+ - id: exact-customer-lookup
221
+ prompt: Retrieve customer CUST-1042.
222
+ expected:
223
+ tool: get_customer
224
+ arguments:
225
+ customer_id: CUST-1042
226
+ forbidden_tools:
227
+ - delete_customer
228
+ ```
229
+
230
+ ```bash
231
+ # No API key needed — dry-run against a live server
232
+ mcplint benchmark evals.yaml --server "python my_server.py" --provider fake
233
+
234
+ # Real model
235
+ export ANTHROPIC_API_KEY=sk-...
236
+ mcplint benchmark evals.yaml --server "python my_server.py" \
237
+ --provider anthropic --model claude-sonnet-5 --runs 3
238
+ ```
239
+
240
+ Metrics are entirely deterministic: exact tool-selection accuracy,
241
+ valid-argument rate (checked against the tool's real JSON Schema),
242
+ required-argument accuracy, forbidden-tool invocation rate, no-tool rate,
243
+ mean/P95 latency, estimated cost, and per-case stability across repeated
244
+ trials. **No LLM judge is used anywhere** — every pass/fail is a literal
245
+ comparison.
246
+
247
+ `examples/ambiguous_customer_server/customer-tools.evals.yaml` is a worked
248
+ example showing get/search/update/delete-customer confusion.
249
+
250
+ ## Compare & fix
251
+
252
+ ```bash
253
+ mcplint snapshot --server "python my_server.py" --output before.json
254
+ # ... edit your tool descriptions ...
255
+ mcplint snapshot --server "python my_server.py" --output after.json
256
+
257
+ mcplint compare --baseline before.json --candidate after.json \
258
+ --dataset evals.yaml --provider fake --min-accuracy-delta -0.02
259
+ ```
260
+
261
+ `compare` diffs tool contracts (added/removed tools, schema/description
262
+ changes), findings (new vs. resolved), and ambiguity scores between two
263
+ snapshots, and — if you pass `--dataset` — re-runs the benchmark against
264
+ both tool lists and reports the accuracy/latency/cost deltas. Exits 1 if
265
+ `--min-accuracy-delta` isn't met, so it gates a PR.
266
+
267
+ ```bash
268
+ mcplint fix --snapshot before.json --output fix-report.md
269
+ ```
270
+
271
+ `fix` proposes rewrites for whatever it can derive mechanically from the
272
+ JSON Schema and annotations (output shape, enum values, numeric bounds,
273
+ destructive warnings, tool-distinction placeholders). It **never writes to
274
+ your source files** — only a Markdown patch report you review by hand.
275
+ Purely semantic issues (a vague description, one that just restates the
276
+ name) get an honest low-confidence TODO placeholder, since the
277
+ deterministic engine has no LLM to invent real prose.
278
+
279
+ ## CI guide
280
+
281
+ ```bash
282
+ mcplint scan --server "python my_server.py" --format sarif --output results.sarif --fail-on error
283
+ ```
284
+
285
+ `--fail-on error` (the default) exits 1 on any error-severity finding, 0
286
+ otherwise; `--fail-on never` always exits 0 (useful for a report-only job).
287
+ See `.github/workflows/example-scan-mcp-server.yml` for a complete,
288
+ documented example workflow: install MCPLint, invoke your server, scan,
289
+ upload SARIF to GitHub code scanning, fail on error. No custom JavaScript
290
+ GitHub Action is required.
291
+
292
+ ## Plugin guide
293
+
294
+ Third-party rules register via a Python entry point — no changes to this
295
+ repo needed:
296
+
297
+ ```toml
298
+ # your_package's pyproject.toml
299
+ [project.entry-points."mcplint.rules"]
300
+ my-custom-rule = "your_package.rules:MyCustomRule"
301
+ ```
302
+
303
+ ```python
304
+ from mcplint.core.rules.base import Rule, RuleContext
305
+ from mcplint.models.contracts import ToolContract
306
+ from mcplint.models.findings import Finding, Severity
307
+
308
+ class MyCustomRule(Rule):
309
+ id = "my-custom-rule"
310
+ title = "My custom rule"
311
+ description = "Explain what this catches."
312
+ default_severity = Severity.WARNING
313
+
314
+ def check(self, tool: ToolContract, context: RuleContext) -> list[Finding]:
315
+ ...
316
+ ```
317
+
318
+ `RuleRegistry().load_entry_point_plugins()` discovers everything registered
319
+ under the `mcplint.rules` group and merges it with the 15 built-ins.
320
+
321
+ ## Limitations
322
+
323
+ - Stdio transport only — HTTP MCP servers aren't supported yet (planned:
324
+ connection timeout, response-size limit, header redaction; see
325
+ `SECURITY.md`).
326
+ - The ambiguity engine's token overlap does no stemming/lemmatization, so
327
+ "customer" vs. "customers" reduces measured similarity between genuinely
328
+ related tools. Real, observed trade-off — not a bug — see
329
+ `IMPLEMENTATION_STATUS.md`.
330
+ - `undefined-domain-term`'s acronym heuristic is intentionally conservative
331
+ (info severity, confidence 0.4) and will both under- and over-flag.
332
+ - The OpenAI benchmark provider is a typed stub, not a working
333
+ implementation, per the spec's "don't let it block Anthropic" guidance.
334
+ - `fix --llm-provider` is accepted as a flag but always rejected — no
335
+ LLM-assisted rewriting path exists yet.
336
+ - The overall score is a documented, capped-per-category heuristic, **not**
337
+ a scientifically validated or universal quality metric. It exists so a
338
+ regression in one category can't silently zero out the total.
339
+
340
+ Full detail, including every deferred item and the reasoning behind it, is
341
+ in `IMPLEMENTATION_STATUS.md`.
342
+
343
+ ## Roadmap
344
+
345
+ - HTTP MCP server transport with the security constraints above
346
+ - Sentence-transformer embeddings as an additional ambiguity signal
347
+ - OpenAI benchmark provider
348
+ - LLM-assisted rewriting for `mcplint fix`
349
+ - A JavaScript GitHub Action wrapper, if the composite-workflow approach
350
+ proves insufficient for real users
351
+
352
+ ## Comparison
353
+
354
+ - **[MCP Inspector](https://modelcontextprotocol.io/docs/tools/inspector)**
355
+ is an interactive debugger for poking at a running MCP server by hand.
356
+ MCPLint is a non-interactive, deterministic linter meant to run
357
+ unattended in CI — the two are complementary, not competing.
358
+ - **Generic JSON Schema diff/validation tools** verify that a schema is
359
+ well-formed and check argument values against it. They cannot tell you
360
+ that two tools are semantically confusable, that a destructive tool lacks
361
+ a warning, or that a required constraint isn't documented in prose —
362
+ those require understanding the *description*, not just the schema.
363
+ - **Generic LLM evaluation frameworks** (promptfoo, LangSmith evals, etc.)
364
+ can benchmark tool-selection accuracy, and MCPLint's `benchmark` command
365
+ covers similar ground for MCP tools specifically. MCPLint's distinct
366
+ contribution is the deterministic linter (rules 1-15) that runs without
367
+ any model key, plus tying static analysis and benchmark deltas together
368
+ in one `compare` command.
369
+
370
+ We don't claim MCPLint is strictly better than any of the above at what
371
+ they're actually built for — it's scoped specifically to the MCP tool
372
+ description/schema/ambiguity problem.
373
+
374
+ ## Development
375
+
376
+ ```bash
377
+ git clone https://github.com/mcplint/mcplint.git && cd mcplint
378
+ python3.11 -m venv .venv && source .venv/bin/activate
379
+ pip install -e ".[dev]"
380
+
381
+ ruff check src tests examples
382
+ mypy src
383
+ pytest --cov=mcplint --cov-report=term-missing
384
+ ```
385
+
386
+ See `CONTRIBUTING.md` for the rule/provider extension guides,
387
+ `IMPLEMENTATION_STATUS.md` for exactly what's done vs. deferred, and
388
+ `CHANGELOG.md` for the phase-by-phase build history.
389
+
390
+ ## License
391
+
392
+ MIT — see `LICENSE`.
@@ -0,0 +1,71 @@
1
+ mcplint/__about__.py,sha256=kUR5RAFc7HCeiqdlX36dZOHkUI5wI6V_43RpEcD8b-0,22
2
+ mcplint/__init__.py,sha256=ca0-zflxm7XLn0GvipZJXMOkhasdJclz_owtLZnJMN8,69
3
+ mcplint/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ mcplint/benchmark/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ mcplint/benchmark/dataset.py,sha256=lfAY6jznYA1ikkonEpaS6yQWPjTwFgYE8gQWh2fA5yU,1049
6
+ mcplint/benchmark/runner.py,sha256=AvkLF_HwNnnbjwPOTpFhAz01t_TvAiony6goIUzD1Mc,1414
7
+ mcplint/benchmark/scorer.py,sha256=DZdgudAKQCFZeaAaSVxRx5gWiitTPFVmRh7KHBs3_AE,5284
8
+ mcplint/benchmark/providers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ mcplint/benchmark/providers/anthropic_provider.py,sha256=YF7qotrnj4Gvt1r4_b9ti88PV5MhpSLtPv-hBtGGLJ4,3485
10
+ mcplint/benchmark/providers/base.py,sha256=Jn-0V2NT6s7v8nN1WQouneqUo61eaCV0Ih-mR_V_82I,687
11
+ mcplint/benchmark/providers/factory.py,sha256=9oxmmlKgySwrT5VeCGxHCcGJrtnM4kDp7FUvvLhssD0,1991
12
+ mcplint/benchmark/providers/fake.py,sha256=T3LuBKDTOdupXHt1pBmAvadu-2ggsOLMl4d5UfyCl6U,763
13
+ mcplint/benchmark/providers/openai_provider.py,sha256=DibmbvGSVqUnuvWK6Lj1mZJ-ReBxLx5UwK6Wz0wuH6k,940
14
+ mcplint/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
+ mcplint/cli/main.py,sha256=ij0Mo3apa83MiWzvt8GIsb8FAfztRKh03a90D2wa_4g,1349
16
+ mcplint/cli/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
+ mcplint/cli/commands/benchmark_cmd.py,sha256=0bLlWb9NpgqwFj7-pzm1V1WfahoSpvd91MqhMAp0_bw,3429
18
+ mcplint/cli/commands/compare_cmd.py,sha256=F1BgHWkjCWW3oeNGiC30Nia4wefjjNUJymFAmyS4AI4,5675
19
+ mcplint/cli/commands/fix_cmd.py,sha256=87FS7mcrvxmKcZMp58eSBfGqjB53gB4hNSWwbEVvb0g,1963
20
+ mcplint/cli/commands/inspect_cmd.py,sha256=EcdvUkhswzg8sg-4Z2NSNAP-P7NRrcIhQZKHOnJGQlU,1371
21
+ mcplint/cli/commands/rules_cmd.py,sha256=XYsBtyyOue3ah0oKqydbW1q-6Errxt-BV5-8f_BQIIw,749
22
+ mcplint/cli/commands/scan_cmd.py,sha256=Ej7WX8U_i9h67rrehV84HayCuGGnBcMNsjrPubI2KqA,4112
23
+ mcplint/cli/commands/snapshot_cmd.py,sha256=hQJOaZ_Ux46ND-0yveGzImboVqXXzJ3tVxHQwXWh90o,1162
24
+ mcplint/compare/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
+ mcplint/compare/differ.py,sha256=936Sc95xVWbDagX8_KP-GwE8TWnw0n5EsJlpTcMrId0,5995
26
+ mcplint/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
+ mcplint/config/loader.py,sha256=fPJfNrrxlp-nbrAtaTHYCESLxVp2gbzic2wqMluNvPM,1020
28
+ mcplint/config/schema.py,sha256=-RLrv0NWPh7s7pXEmMGaXHUU-Wr25Sp944hxYC9rmvA,1359
29
+ mcplint/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
+ mcplint/core/engine.py,sha256=ZRe_GlFwQWdReM9lZ8wHwAUhgjpRgh5x41Byq_yWaII,1438
31
+ mcplint/core/registry.py,sha256=yhvmj5W3_bNbzex5GE0korD6WvuUeeRn-iipdPQ3q5g,1865
32
+ mcplint/core/score.py,sha256=7Q5qgG4LMV172fIbv-hsY-5w4-fL2B-rWPotuwc0-oc,4907
33
+ mcplint/core/rules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
34
+ mcplint/core/rules/ambiguity.py,sha256=p4M2BR9L-ZbzUqpPywCNjdBReW0rCRfrYtq2T40nreA,5201
35
+ mcplint/core/rules/ambiguity_rules.py,sha256=pDGly9js3UqDjy3FoXJK4JbMWbFf1SB23ZWHSklLfiY,4693
36
+ mcplint/core/rules/base.py,sha256=AIsDyV783VUqhCpxC26gyZfiDoC23sOqL7RFP0l6A6M,1055
37
+ mcplint/core/rules/builtin.py,sha256=Ew3u_PPiG2sqDcn-LSVEgK5tmiDw4E_Vff2roAOpoYQ,1437
38
+ mcplint/core/rules/completeness_rules.py,sha256=ibqFdWFcuuIGG_nqvTqFYiIi1g-1uH5lLUpL5lk5Y8A,8478
39
+ mcplint/core/rules/description_rules.py,sha256=jCAGha0ivPbZ8yRd0gsbZwDzWUyJK0JuYoVKlSWeyZs,4241
40
+ mcplint/core/rules/safety_rules.py,sha256=BmAIXDvTBEX-hUIGH_kQEPSa0R8ocv18YporIFOztmg,5061
41
+ mcplint/core/rules/schema_rules.py,sha256=4oTRMWVn3OeeonUEgLAFB0q4teyJuuGF6SdU2a2AiI8,4397
42
+ mcplint/fix/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
43
+ mcplint/fix/suggest.py,sha256=lWTk_5ghnkVtHLtaGZNlqtLCg8dUOLKyif81s2Y9uVQ,7635
44
+ mcplint/mcp_client/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
45
+ mcplint/mcp_client/canonical.py,sha256=bZ8UUBGLfJrZdvom3MPEj6VTN6I3kuGONuGudU_YJtE,799
46
+ mcplint/mcp_client/persistence.py,sha256=BQe2q2T0kS9X1wsinHEXa_1BRWx_jQvm2OmPgHaF57E,556
47
+ mcplint/mcp_client/session.py,sha256=MGifPhD9HWMzH-FvJtGTqsEF4QxpGui_p5jjV5wsCW0,2905
48
+ mcplint/mcp_client/stdio.py,sha256=3JASLZNorfOsmUExk0fpttVXabGIi539QY2AomEVa98,501
49
+ mcplint/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
50
+ mcplint/models/benchmark.py,sha256=ikQ-jDz1LUD7atuZrBCIS498Y72oqI4-IuSk7dwS8kU,1792
51
+ mcplint/models/common.py,sha256=aYgGmsXEoHZ2tYv6LJFQLbfMCJZLLA1-YH-NhdKXXGk,592
52
+ mcplint/models/comparison.py,sha256=wZsHSIrrQgvxonEe8HG_QHMqd43XecZ3aVN_eiBlIOc,1670
53
+ mcplint/models/contracts.py,sha256=mxBfMt95pUAIqgXc0I3gRGOYT9MR1ViXNBEbb3I0jx4,965
54
+ mcplint/models/findings.py,sha256=HuoWVzYtaAwblB-xuREPnsKrf0S23A3p01yCbca9sIQ,992
55
+ mcplint/models/fixes.py,sha256=Ce_EojAwyzmEIgQPZ679g_JQQD5cyescGIXhxvu7_iQ,371
56
+ mcplint/models/score.py,sha256=bV8lKGl5Ek7hYoodz0mT50sZXZsXTBspCuo3q_pVT2o,774
57
+ mcplint/models/snapshot.py,sha256=5zC1rgyaMc4x6ng4Hn40uBTHucmxc3mlr8fmEUfGHGc,701
58
+ mcplint/reporters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
59
+ mcplint/reporters/benchmark_terminal.py,sha256=9IDERvQunN1-Wt7JvOWKjiUZAwOYwpUD5AMjB7taWOo,1871
60
+ mcplint/reporters/comparison_terminal.py,sha256=byqzD78EtHEXYaqogh4HOqHiC4aldIFQT5uyn9CDQ0M,2511
61
+ mcplint/reporters/fix_markdown.py,sha256=Xkp5Gpfy_H9_ReWMxmMHZh9I3dMylrRevos5S-9iT_0,1246
62
+ mcplint/reporters/html.py,sha256=VDC9Eru4Th-ieRZCvz9nLJo04Y74qdbsxc9qyQUkWj4,2411
63
+ mcplint/reporters/json_reporter.py,sha256=SgPWPbCMBl859C6SAsb7ZsNHJNuXK63kLbCHYFQi5tA,209
64
+ mcplint/reporters/sarif.py,sha256=_gQMuguCgf2MNsItifdzcCr4XGHD15OeQh5fHr10JEY,2595
65
+ mcplint/reporters/terminal.py,sha256=11mxX8cJ2S8utdWpvD_krUMq-qiRQVvZCCdrsnSHk7c,1739
66
+ mcplint/reporters/templates/report.html.j2,sha256=pdLtikIuOh_M-xcy8y0KNpr9RRu004TwozNeQ0lmybw,7039
67
+ mcplint_cli-0.1.0.dist-info/METADATA,sha256=Sz_Qo4lci4yox61T8WPNuS8HnPDMuNMCUNZLCqrQ2UI,17000
68
+ mcplint_cli-0.1.0.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
69
+ mcplint_cli-0.1.0.dist-info/entry_points.txt,sha256=hgR9Ewf6VZp-OVKc2Jcn7yY8QQo7Ften-K-miTTbKXA,49
70
+ mcplint_cli-0.1.0.dist-info/licenses/LICENSE,sha256=rnJsLqapccqSz8P-vEmig8WmIgwkrf7zZUeeVlsZCRw,1077
71
+ mcplint_cli-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.31.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ mcplint = mcplint.cli.main:app
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 MCPLint contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.