ratemyagent 0.1.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 (40) hide show
  1. ratemyagent-0.1.0/LICENSE +21 -0
  2. ratemyagent-0.1.0/PKG-INFO +361 -0
  3. ratemyagent-0.1.0/README.md +324 -0
  4. ratemyagent-0.1.0/pyproject.toml +56 -0
  5. ratemyagent-0.1.0/ratemyagent/__init__.py +82 -0
  6. ratemyagent-0.1.0/ratemyagent/cli.py +461 -0
  7. ratemyagent-0.1.0/ratemyagent/models.py +523 -0
  8. ratemyagent-0.1.0/ratemyagent/outputs/__init__.py +25 -0
  9. ratemyagent-0.1.0/ratemyagent/outputs/agents_md.py +792 -0
  10. ratemyagent-0.1.0/ratemyagent/outputs/common.py +130 -0
  11. ratemyagent-0.1.0/ratemyagent/outputs/report.py +313 -0
  12. ratemyagent-0.1.0/ratemyagent/outputs/scorecard.py +167 -0
  13. ratemyagent-0.1.0/ratemyagent/policies/production-default.yaml +50 -0
  14. ratemyagent-0.1.0/ratemyagent/policy.py +420 -0
  15. ratemyagent-0.1.0/ratemyagent/probes/__init__.py +139 -0
  16. ratemyagent-0.1.0/ratemyagent/probes/base.py +137 -0
  17. ratemyagent-0.1.0/ratemyagent/probes/behavior.py +235 -0
  18. ratemyagent-0.1.0/ratemyagent/probes/concurrency.py +252 -0
  19. ratemyagent-0.1.0/ratemyagent/probes/contract.py +316 -0
  20. ratemyagent-0.1.0/ratemyagent/probes/cost.py +293 -0
  21. ratemyagent-0.1.0/ratemyagent/probes/fault.py +282 -0
  22. ratemyagent-0.1.0/ratemyagent/probes/latency.py +222 -0
  23. ratemyagent-0.1.0/ratemyagent/scanner.py +115 -0
  24. ratemyagent-0.1.0/ratemyagent/targets/__init__.py +90 -0
  25. ratemyagent-0.1.0/ratemyagent/targets/base.py +113 -0
  26. ratemyagent-0.1.0/ratemyagent/targets/fault_proxy.py +336 -0
  27. ratemyagent-0.1.0/ratemyagent/targets/llm.py +292 -0
  28. ratemyagent-0.1.0/ratemyagent/targets/mcp.py +298 -0
  29. ratemyagent-0.1.0/ratemyagent/targets/mock.py +303 -0
  30. ratemyagent-0.1.0/ratemyagent.egg-info/PKG-INFO +361 -0
  31. ratemyagent-0.1.0/ratemyagent.egg-info/SOURCES.txt +38 -0
  32. ratemyagent-0.1.0/ratemyagent.egg-info/dependency_links.txt +1 -0
  33. ratemyagent-0.1.0/ratemyagent.egg-info/entry_points.txt +2 -0
  34. ratemyagent-0.1.0/ratemyagent.egg-info/requires.txt +22 -0
  35. ratemyagent-0.1.0/ratemyagent.egg-info/top_level.txt +1 -0
  36. ratemyagent-0.1.0/setup.cfg +4 -0
  37. ratemyagent-0.1.0/tests/test_cli.py +437 -0
  38. ratemyagent-0.1.0/tests/test_models.py +253 -0
  39. ratemyagent-0.1.0/tests/test_policy.py +271 -0
  40. ratemyagent-0.1.0/tests/test_scanner.py +234 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Wadood Sultan
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.
@@ -0,0 +1,361 @@
1
+ Metadata-Version: 2.4
2
+ Name: ratemyagent
3
+ Version: 0.1.0
4
+ Summary: SRE reliability scanner for AI agents, MCP servers, and LLM tools. Scorecard + fix-it guide.
5
+ License: MIT
6
+ Classifier: Development Status :: 3 - Alpha
7
+ Classifier: Intended Audience :: Developers
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Programming Language :: Python :: 3.10
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Classifier: Topic :: Software Development :: Testing
15
+ Classifier: Topic :: System :: Monitoring
16
+ Requires-Python: >=3.10
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ Requires-Dist: httpx>=0.27.0
20
+ Requires-Dist: click>=8.0
21
+ Requires-Dist: pyyaml>=6.0
22
+ Provides-Extra: mcp
23
+ Requires-Dist: mcp>=1.0.0; extra == "mcp"
24
+ Provides-Extra: anthropic
25
+ Requires-Dist: anthropic>=0.30.0; extra == "anthropic"
26
+ Provides-Extra: openai
27
+ Requires-Dist: openai>=1.0.0; extra == "openai"
28
+ Provides-Extra: all
29
+ Requires-Dist: mcp>=1.0.0; extra == "all"
30
+ Requires-Dist: anthropic>=0.30.0; extra == "all"
31
+ Requires-Dist: openai>=1.0.0; extra == "all"
32
+ Provides-Extra: dev
33
+ Requires-Dist: pytest>=8.0; extra == "dev"
34
+ Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
35
+ Requires-Dist: ruff>=0.4.0; extra == "dev"
36
+ Dynamic: license-file
37
+
38
+ # ratemyagent
39
+
40
+ **Test AI agents like production services.**
41
+
42
+ Existing agent evaluation asks whether an agent can accomplish a task. RateMyAgent asks
43
+ whether it stays reliable when operated like a production service — under load, latency,
44
+ faults, and dependency failures.
45
+
46
+ Think k6 + Chaos Monkey + pytest, but for agents and MCP tools.
47
+
48
+ ---
49
+
50
+ ## The problem
51
+
52
+ Everyone is shipping MCP servers and agent tools. Almost nobody is testing them the way
53
+ they test the rest of their infrastructure.
54
+
55
+ The tools that exist answer different questions. Langfuse and LangSmith *observe*
56
+ production. DeepEval and RAGAS check *output quality*. MCP-Scan checks whether a tool is
57
+ *malicious*. k6 load-tests HTTP endpoints without understanding what an agent does with
58
+ the failures.
59
+
60
+ None of them answer the operational one:
61
+
62
+ > **What happens when your agent's tools and dependencies fail?**
63
+
64
+ That question has a specific shape for agents that it does not have for a web service. An
65
+ agent retries on its own. It fans out three tool calls in a turn and inherits the p95 of
66
+ each. It sends malformed arguments as *normal traffic*, because a model that has just been
67
+ told a tool exists guesses at its schema. And when a call times out after the work already
68
+ completed, the retry runs the mutation twice.
69
+
70
+ RateMyAgent breaks your target on purpose and measures what it does next.
71
+
72
+ ## Install
73
+
74
+ ```bash
75
+ uv venv --python 3.12
76
+ uv pip install -e '.[dev]' # add '.[mcp]', '.[anthropic]', '.[openai]', or '.[all]'
77
+ ```
78
+
79
+ Python 3.10+.
80
+
81
+ ## 30 seconds, no API key
82
+
83
+ There is a built-in mock target, so you can see the whole thing work before pointing it at
84
+ anything real. No key, no server, no network.
85
+
86
+ ```bash
87
+ uv run ratemyagent scan --target mock --profile degraded --requests 40 \
88
+ --concurrency 16 --fault-rate 0.3
89
+ ```
90
+
91
+ ```
92
+ RateMyAgent Scan Results
93
+ ========================
94
+
95
+ Target: degraded-mock (mock)
96
+ Probes: 6/6 complete Duration: 0.01s
97
+
98
+ Phase 1 baseline
99
+ Latency ................ p50 3.36s, p95 7.99s, p99 8.48s over 40 requests (0.0% errors)
100
+ Cost ................... 647 in / 120 out tokens per request, no price known for this model
101
+ Concurrency ............ no saturation up to 16 concurrent, sustained 16
102
+ Contract ............... 18 edge cases across 3 tools: 0 rejected cleanly, 18 accepted, 0 crashed
103
+
104
+ Phase 2 chaos (fault injection)
105
+ Fault tolerance ........ 20 faults injected, 10/10 operations recovered (100%), 1.30x call amplification
106
+
107
+ Phase 3 behavior analysis
108
+ Behavior ............... 10/10 disrupted operations recovered (100%), 1.30x call amplification, 0 duplicate mutations
109
+
110
+ actual target status
111
+ p95 latency 7.99s 5.00s FAIL
112
+ schema violations accepted 9 0 FAIL
113
+ p99 latency 8.48s 10.00s pass
114
+ error rate 0.0% 5.0% pass
115
+ sustained concurrency 16 5 pass
116
+ recovery rate 100.0% 90.0% pass
117
+ retry amplification 1.30x 2.00x pass
118
+ duplicate mutations 0 0 pass
119
+ cost per request - $0.1000 n/a
120
+
121
+ Score breakdown:
122
+ latency 16/20 (p95 latency was 7,988ms, policy allows at most 5,000ms)
123
+ cost -/15 (not measured against this target)
124
+ concurrency 15/15
125
+ contract 8/15 (invalid inputs accepted was 9, policy allows at most 0)
126
+ behavior 35/35
127
+
128
+ Score: 86/100 (policy production-default)
129
+
130
+ 9 findings across 6 probes. Run with --output agents-md to generate a fix guide.
131
+
132
+ PASS: score 86 meets pass threshold 75.
133
+ Biggest gaps: contract (8/15), latency (16/20).
134
+ ```
135
+
136
+ Actual sits next to target so the gap is the information. `n/a` means the probe could not
137
+ measure this target — those are excluded from the score rather than counted as failures.
138
+
139
+ Then point it at something real:
140
+
141
+ ```bash
142
+ # An MCP server over stdio or SSE
143
+ ratemyagent scan --target mcp --uri stdio://./server.py
144
+ ratemyagent scan --target mcp --uri sse://localhost:8080/sse --requests 100
145
+
146
+ # A chat completions endpoint (this one spends money — keep --requests low)
147
+ ratemyagent scan --target llm --provider anthropic --model claude-opus-5 --requests 5
148
+ ratemyagent scan --target llm --provider openai --model gpt-4o-mini --requests 5
149
+ ```
150
+
151
+ Probing invokes a discovered tool for real, once per request. Pass `--tool` and
152
+ `--tool-args` to choose which one; the default is the first tool the server reports.
153
+
154
+ ## How a scan works
155
+
156
+ Three phases, in order. Phase 2 needs phase 1 to compare against; phase 3 reads what phase
157
+ 2 recorded.
158
+
159
+ **Phase 1 — Baseline.** Measures the target as it is: latency distribution, token cost and
160
+ prompt bloat, the concurrency level where it saturates, and whether its tools honour their
161
+ own JSON Schema. These are the numbers everything else is compared against.
162
+
163
+ **Phase 2 — Fault injection.** A `FaultProxy` wraps the target and injects timeouts, 429s,
164
+ 500s, malformed responses and refused connections at a configurable rate. Probes cannot
165
+ tell they are wrapped, so the same probes run against a sabotaged target and any
166
+ difference is attributable to the faults.
167
+
168
+ **Phase 3 — Behavior analysis.** Reads the trajectory of every operation phase 2 disrupted
169
+ and reports what the target *did*: did it recover, how long did that take, how many calls
170
+ did one operation cost, did anything succeed twice. This is the part that is not a load
171
+ test — it measures behaviour under failure, not failure counts.
172
+
173
+ Per-probe detail is in [docs/PROBES.md](docs/PROBES.md).
174
+
175
+ ## Scoring
176
+
177
+ Results are scored 0–100 against a YAML policy. Probes measure; the policy decides.
178
+
179
+ - Meeting a threshold scores **100** for that check — a threshold is a limit, not a target.
180
+ - Missing it decays **linearly to 0 at twice the limit**, so a near miss and a catastrophe
181
+ do not score alike.
182
+ - A metric the scan could not produce is **skipped, not zeroed**. Missing evidence is not
183
+ a failure.
184
+
185
+ ```yaml
186
+ # my-policy.yaml
187
+ name: my-service
188
+ thresholds:
189
+ p95_latency_ms: 3000
190
+ error_rate_max: 0.02
191
+ recovery_rate_min: 0.95
192
+ retry_amplification_max: 1.5
193
+ duplicate_mutation_max: 0
194
+ pass_score: 80
195
+ ```
196
+
197
+ ```bash
198
+ ratemyagent policy # show the shipped defaults
199
+ ratemyagent scan --target mock --policy my-policy.yaml
200
+ ```
201
+
202
+ Every threshold is optional, and validation is strict — an unknown key is an error listing
203
+ the valid ones, because a typo that silently stopped scoring something is worse than a
204
+ crash. Full reference, including the shipped default explained threshold by threshold:
205
+ [docs/POLICY.md](docs/POLICY.md).
206
+
207
+ ## CI integration
208
+
209
+ ```bash
210
+ ratemyagent ci --target mcp --uri stdio://./server.py --policy production.yaml
211
+ echo $? # 0 pass, 1 fail, 2 the scan could not run
212
+ ```
213
+
214
+ Exit code 2 matters: a broken scanner is not a failing target, and a gate that cannot tell
215
+ them apart is not worth having in a pipeline. Failed checks are printed individually, so a
216
+ red build says which threshold moved rather than that the score dropped.
217
+
218
+ `ci` writes nothing and never prompts. Nothing in the tool does — it stays pipeable.
219
+
220
+ ```yaml
221
+ # .github/workflows/reliability.yml
222
+ name: reliability
223
+
224
+ on: [push, pull_request]
225
+
226
+ jobs:
227
+ scan:
228
+ runs-on: ubuntu-latest
229
+ steps:
230
+ - uses: actions/checkout@v4
231
+ - uses: astral-sh/setup-uv@v5
232
+ with:
233
+ python-version: "3.12"
234
+
235
+ - run: uv pip install --system '.[mcp]'
236
+
237
+ - name: Reliability gate
238
+ run: |
239
+ ratemyagent ci \
240
+ --target mcp --uri stdio://./server.py \
241
+ --policy production.yaml \
242
+ --requests 120 --concurrency 16 --fault-rate 0.25 \
243
+ --json-out scan.json
244
+
245
+ - uses: actions/upload-artifact@v4
246
+ if: always()
247
+ with:
248
+ name: reliability-scan
249
+ path: scan.json
250
+ ```
251
+
252
+ Use enough requests that the numbers mean something. `recovery_rate` from the default 20
253
+ requests is measured over roughly 4 disrupted operations, which is an anecdote rather than
254
+ a rate.
255
+
256
+ ## AGENTS.md
257
+
258
+ ```bash
259
+ ratemyagent scan --target mcp --uri stdio://./server.py --output agents-md
260
+ # AGENTS.md written to AGENTS.md (7 recommendations, 3 critical)
261
+ ```
262
+
263
+ A fix guide for *your* target. Each finding states what was observed, why it matters in
264
+ production, the root cause — weighted toward what AI-generated servers actually get wrong
265
+ — and a copy-pasteable fix naming the tool that failed:
266
+
267
+ > **FINDING: 9 schema-forbidden inputs accepted**
268
+ >
269
+ > Your tool declares required fields and types in its JSON Schema but does not enforce
270
+ > them at runtime. This is common in AI-generated MCP servers where the schema is correct
271
+ > but the handler trusts its input. Every field marked "required" needs an explicit check
272
+ > before the handler touches the data, because the calling agent WILL send malformed
273
+ > arguments — that is normal traffic, not an attack.
274
+ >
275
+ > Suggested fix for tool "search_database":
276
+ >
277
+ > ```python
278
+ > if "query" not in args or not isinstance(args["query"], str):
279
+ > return {"error": "query is required and must be a string"}
280
+ > ```
281
+
282
+ Sections are ordered by severity — duplicate mutations and crashes before latency and cost
283
+ — so the first thing you read is the thing most worth fixing.
284
+
285
+ Re-scanning the same file reports movement:
286
+
287
+ ```
288
+ ## Since the last scan
289
+
290
+ - Score improved from 33 to 91/100.
291
+ - P95 latency improved from 44.22s to 0.44s.
292
+ - Schema violations regressed from 4 to 9.
293
+ ```
294
+
295
+ **See the real thing without installing:** [`examples/AGENTS.md`](examples/AGENTS.md) and
296
+ [`examples/report.md`](examples/report.md), both generated from a scan of the deliberately
297
+ broken mock profile.
298
+
299
+ ## Markdown report
300
+
301
+ ```bash
302
+ ratemyagent scan --target mcp --uri stdio://./server.py --output report
303
+ ratemyagent scan --target mcp --uri stdio://./server.py --output all
304
+ ```
305
+
306
+ The whole scan organized by phase, with the actual-vs-target table, the score breakdown,
307
+ per-level concurrency numbers, every finding, and the settings needed to reproduce the
308
+ run. Example: [`examples/report.md`](examples/report.md).
309
+
310
+ ## What it can do today
311
+
312
+ - **Latency profiler** — p50/p95/p99, TTFT, tool call overhead, heavy-tail detection
313
+ - **Cost analyzer** — tokens per request, prompt-bloat detection and what caching it would
314
+ save, $/request. Prices are never guessed
315
+ - **Concurrency tester** — ramps 1→N, finds the saturation point and the latency knee
316
+ - **Contract tester** — audits tool schemas and sends six edge-case payloads per tool
317
+ - **Fault injection** — five fault kinds at a configurable rate, deterministic per seed
318
+ - **Behavior analysis** — recovery rate and latency, retry amplification, duplicate
319
+ mutations, stuck loops
320
+ - **Adapters** — MCP over stdio and SSE; Anthropic and OpenAI chat completions; five mock
321
+ profiles for testing without any of them
322
+ - **Outputs** — terminal scorecard, markdown report, AGENTS.md, JSON export
323
+
324
+ Every scan reproduces under `--seed`. 500 tests, none of which need a network or a key.
325
+
326
+ ## Roadmap
327
+
328
+ - **v1.1** — `ratemyagent chaos` for targeted single-fault scenarios; streaming TTFT for
329
+ LLM targets
330
+ - **v2** — sustained outage windows (current faults are independent per attempt, which
331
+ models transient failure well and outages not at all); timeout-after-completion faults
332
+ to exercise duplicate mutations properly; `AgentTarget` wrapping a Python script;
333
+ historical trending across scans
334
+
335
+ Deliberately out of scope: web dashboards, continuous monitoring, framework-specific
336
+ adapters, security scanning, and anything requiring a database.
337
+
338
+ ## Contributing
339
+
340
+ ```bash
341
+ uv run pytest # 500 tests, ~1s, no network or API keys
342
+ uv run ruff check .
343
+ ```
344
+
345
+ Start with [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) — it is written for contributors
346
+ and covers the `Target` interface, the `FaultProxy`, the trajectory model, and the policy
347
+ engine, including the parts that are load-bearing and the reasoning behind them.
348
+
349
+ House rules, in short:
350
+
351
+ - Every probe needs tests that run without API keys, a network, or an MCP server. Use the
352
+ mock targets in `tests/conftest.py`.
353
+ - Probes measure, the policy judges. A probe that emits a verdict is a bug.
354
+ - The `FaultProxy` is the only place faults are injected.
355
+ - No interactive prompts. This is an SRE tool; it has to stay pipeable.
356
+ - Say what you measured, not what you would like to be true. Findings call out thin
357
+ evidence rather than letting it pass quietly.
358
+
359
+ ## License
360
+
361
+ MIT