openapi-agent-ready 0.4.0__tar.gz → 0.4.1__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.
- {openapi_agent_ready-0.4.0 → openapi_agent_ready-0.4.1}/CHANGELOG.md +10 -0
- {openapi_agent_ready-0.4.0 → openapi_agent_ready-0.4.1}/PKG-INFO +32 -32
- {openapi_agent_ready-0.4.0 → openapi_agent_ready-0.4.1}/README.md +30 -30
- {openapi_agent_ready-0.4.0 → openapi_agent_ready-0.4.1}/pyproject.toml +1 -1
- {openapi_agent_ready-0.4.0 → openapi_agent_ready-0.4.1}/src/agent_ready/cli.py +15 -3
- {openapi_agent_ready-0.4.0 → openapi_agent_ready-0.4.1}/src/agent_ready/rubric.py +4 -3
- {openapi_agent_ready-0.4.0 → openapi_agent_ready-0.4.1}/tests/test_audit.py +7 -0
- openapi_agent_ready-0.4.0/openapi.yaml +0 -11890
- {openapi_agent_ready-0.4.0 → openapi_agent_ready-0.4.1}/.github/workflows/ci.yml +0 -0
- {openapi_agent_ready-0.4.0 → openapi_agent_ready-0.4.1}/.github/workflows/publish.yml +0 -0
- {openapi_agent_ready-0.4.0 → openapi_agent_ready-0.4.1}/.gitignore +0 -0
- {openapi_agent_ready-0.4.0 → openapi_agent_ready-0.4.1}/CONTRIBUTING.md +0 -0
- {openapi_agent_ready-0.4.0 → openapi_agent_ready-0.4.1}/LICENSE +0 -0
- {openapi_agent_ready-0.4.0 → openapi_agent_ready-0.4.1}/examples/agent_ready_booking_api.yaml +0 -0
- {openapi_agent_ready-0.4.0 → openapi_agent_ready-0.4.1}/examples/sample_booking_api.yaml +0 -0
- {openapi_agent_ready-0.4.0 → openapi_agent_ready-0.4.1}/src/agent_ready/__init__.py +0 -0
- {openapi_agent_ready-0.4.0 → openapi_agent_ready-0.4.1}/src/agent_ready/auditor.py +0 -0
- {openapi_agent_ready-0.4.0 → openapi_agent_ready-0.4.1}/src/agent_ready/baseline.py +0 -0
- {openapi_agent_ready-0.4.0 → openapi_agent_ready-0.4.1}/src/agent_ready/mcp_generator.py +0 -0
- {openapi_agent_ready-0.4.0 → openapi_agent_ready-0.4.1}/src/agent_ready/report_generator.py +0 -0
- {openapi_agent_ready-0.4.0 → openapi_agent_ready-0.4.1}/tests/test_baseline.py +0 -0
- {openapi_agent_ready-0.4.0 → openapi_agent_ready-0.4.1}/tests/test_mcp_conformance.py +0 -0
|
@@ -5,6 +5,16 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [0.4.1] - 2026-10-24
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- **Swagger 2.0 specs are now rejected (exit 2)** instead of being audited.
|
|
12
|
+
They have `paths`, so they were scored, but auth lives in
|
|
13
|
+
`securityDefinitions`, so a spec with scoped OAuth2 was reported as having no
|
|
14
|
+
security schemes at all.
|
|
15
|
+
- **Progress bar counts operations, not paths.** A spec with 100 paths × 3
|
|
16
|
+
methods (300 operations) previously never showed progress.
|
|
17
|
+
|
|
8
18
|
## [0.4.0] - 2026-08-08
|
|
9
19
|
|
|
10
20
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: openapi-agent-ready
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.1
|
|
4
4
|
Summary: Audit any OpenAPI spec for AI-agent and MCP readiness, and generate an MCP server scaffold.
|
|
5
5
|
Project-URL: Homepage, https://github.com/sfaisal/agent-ready
|
|
6
6
|
Project-URL: Issues, https://github.com/sfaisal/agent-ready/issues
|
|
@@ -64,7 +64,7 @@ Description-Content-Type: text/markdown
|
|
|
64
64
|
**Audit any OpenAPI spec for AI-agent readiness — then generate an MCP server scaffold for the endpoints that pass.**
|
|
65
65
|
|
|
66
66
|
Your API works fine for human developers. That doesn't mean an AI agent can use
|
|
67
|
-
it reliably. `agent-ready` scores a spec against
|
|
67
|
+
it reliably. `agent-ready` scores a spec against eight categories of
|
|
68
68
|
agent-specific failure, tells you exactly which endpoints will cause trouble and
|
|
69
69
|
why, and can gate a CI pipeline so specs don't regress.
|
|
70
70
|
|
|
@@ -75,17 +75,18 @@ agent-ready https://example.com/openapi.yaml
|
|
|
75
75
|
|
|
76
76
|
```
|
|
77
77
|
Generic Booking Platform API (v1.0)
|
|
78
|
-
AI-readiness score:
|
|
79
|
-
Endpoints: 4 Fails:
|
|
78
|
+
AI-readiness score: 58.4/100
|
|
79
|
+
Endpoints: 4 Fails: 7 Warnings: 14
|
|
80
80
|
|
|
81
81
|
Category scores:
|
|
82
|
-
Description Clarity
|
|
83
|
-
Side Effects
|
|
84
|
-
Error Responses
|
|
85
|
-
Auth Clarity
|
|
86
|
-
Ambiguity
|
|
87
|
-
Parameter Explanation
|
|
88
|
-
Usage Guidelines
|
|
82
|
+
Description Clarity 37.5/100
|
|
83
|
+
Side Effects 70.0/100
|
|
84
|
+
Error Responses 62.5/100
|
|
85
|
+
Auth Clarity 50.0/100
|
|
86
|
+
Ambiguity 100.0/100
|
|
87
|
+
Parameter Explanation 10.0/100
|
|
88
|
+
Usage Guidelines 50.0/100
|
|
89
|
+
Tool Surface 100.0/100
|
|
89
90
|
```
|
|
90
91
|
|
|
91
92
|
## Why this exists
|
|
@@ -111,9 +112,8 @@ directly onto the rubric:
|
|
|
111
112
|
| **Frictionless authentication** | 4 (auth/scope clarity) |
|
|
112
113
|
| **Structured error handling** | 3 (actionable errors) |
|
|
113
114
|
|
|
114
|
-
Categories 2 (side effects) and 5 (ambiguity)
|
|
115
|
-
|
|
116
|
-
reward for actually building the thing you wrote about.
|
|
115
|
+
Categories 2 (side effects) and 5 (ambiguity) weren't in the article. They came
|
|
116
|
+
up once I started building, and they matter as much as the original three.
|
|
117
117
|
|
|
118
118
|
The gap is measurable, and enormous. A 2026 study of 856 tools across 103 MCP
|
|
119
119
|
servers found that **97.1% of tool descriptions contained at least one quality
|
|
@@ -219,6 +219,19 @@ future release does not invalidate your baseline.
|
|
|
219
219
|
|
|
220
220
|
As the team fixes the backlog, regenerate the baseline to lock in the progress.
|
|
221
221
|
|
|
222
|
+
### Python API
|
|
223
|
+
|
|
224
|
+
```python
|
|
225
|
+
from agent_ready import load_spec, run_audit
|
|
226
|
+
|
|
227
|
+
spec = load_spec("openapi.yaml")
|
|
228
|
+
result = run_audit(spec)
|
|
229
|
+
|
|
230
|
+
print(result["overall_score"])
|
|
231
|
+
for finding in result["gaps"]:
|
|
232
|
+
print(finding.severity, finding.endpoint, finding.message)
|
|
233
|
+
```
|
|
234
|
+
|
|
222
235
|
## Real-world results
|
|
223
236
|
|
|
224
237
|
Running it against Stripe's production spec (587 endpoints), as of v0.1.0.
|
|
@@ -244,8 +257,8 @@ Two things worth drawing out.
|
|
|
244
257
|
in this tool, not in Stripe.** Stripe documents errors via OpenAPI's `default`
|
|
245
258
|
response rather than enumerating explicit 4xx/5xx codes. Perfectly valid, and
|
|
246
259
|
arguably cleaner. The check only looked for `4`/`5` prefixes, so it failed all
|
|
247
|
-
587 endpoints. Fixed
|
|
248
|
-
|
|
260
|
+
587 endpoints. Fixed and regression-tested — and a good reason to run this
|
|
261
|
+
against your own real spec before trusting the score.
|
|
249
262
|
|
|
250
263
|
**Stripe is widely and correctly regarded as agent-ready, yet its raw OpenAPI
|
|
251
264
|
spec scores 62.9.** That isn't a contradiction — it's the whole point. Stripe's
|
|
@@ -260,19 +273,6 @@ Genuine findings that survived scrutiny: `GET /v1/account` and
|
|
|
260
273
|
uses bearer/basic API keys rather than scoped OAuth2, so there's no way to
|
|
261
274
|
express "this agent may only read."
|
|
262
275
|
|
|
263
|
-
### Python API
|
|
264
|
-
|
|
265
|
-
```python
|
|
266
|
-
from agent_ready import load_spec, run_audit
|
|
267
|
-
|
|
268
|
-
spec = load_spec("openapi.yaml")
|
|
269
|
-
result = run_audit(spec)
|
|
270
|
-
|
|
271
|
-
print(result["overall_score"])
|
|
272
|
-
for finding in result["gaps"]:
|
|
273
|
-
print(finding.severity, finding.endpoint, finding.message)
|
|
274
|
-
```
|
|
275
|
-
|
|
276
276
|
## The eight categories
|
|
277
277
|
|
|
278
278
|
| # | Category | What it catches | Published anchor |
|
|
@@ -336,7 +336,7 @@ doesn't:
|
|
|
336
336
|
|
|
337
337
|
- **The ambiguity check uses string similarity**, so it misses endpoints that
|
|
338
338
|
are semantically similar but differently worded. Embedding-based similarity
|
|
339
|
-
would be stronger. ([#1](https://github.com/sfaisal/agent-ready/issues))
|
|
339
|
+
would be stronger. ([#1](https://github.com/sfaisal/agent-ready/issues/1))
|
|
340
340
|
- **Category weights are judgement calls, not measured effect sizes.**
|
|
341
341
|
Description clarity is weighted highest on the prior that wrong tool selection
|
|
342
342
|
is the costliest failure — that prior is untested here.
|
|
@@ -359,7 +359,7 @@ doesn't:
|
|
|
359
359
|
- [ ] LLM-assisted rewriting of flagged descriptions (`--fix`)
|
|
360
360
|
- [ ] Live tool-selection testing against a generated MCP server
|
|
361
361
|
- [ ] GitHub Action wrapper
|
|
362
|
-
- [
|
|
362
|
+
- [x] Baseline mode (`--baseline`) so CI only fails on *new* regressions
|
|
363
363
|
|
|
364
364
|
## Contributing
|
|
365
365
|
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
**Audit any OpenAPI spec for AI-agent readiness — then generate an MCP server scaffold for the endpoints that pass.**
|
|
10
10
|
|
|
11
11
|
Your API works fine for human developers. That doesn't mean an AI agent can use
|
|
12
|
-
it reliably. `agent-ready` scores a spec against
|
|
12
|
+
it reliably. `agent-ready` scores a spec against eight categories of
|
|
13
13
|
agent-specific failure, tells you exactly which endpoints will cause trouble and
|
|
14
14
|
why, and can gate a CI pipeline so specs don't regress.
|
|
15
15
|
|
|
@@ -20,17 +20,18 @@ agent-ready https://example.com/openapi.yaml
|
|
|
20
20
|
|
|
21
21
|
```
|
|
22
22
|
Generic Booking Platform API (v1.0)
|
|
23
|
-
AI-readiness score:
|
|
24
|
-
Endpoints: 4 Fails:
|
|
23
|
+
AI-readiness score: 58.4/100
|
|
24
|
+
Endpoints: 4 Fails: 7 Warnings: 14
|
|
25
25
|
|
|
26
26
|
Category scores:
|
|
27
|
-
Description Clarity
|
|
28
|
-
Side Effects
|
|
29
|
-
Error Responses
|
|
30
|
-
Auth Clarity
|
|
31
|
-
Ambiguity
|
|
32
|
-
Parameter Explanation
|
|
33
|
-
Usage Guidelines
|
|
27
|
+
Description Clarity 37.5/100
|
|
28
|
+
Side Effects 70.0/100
|
|
29
|
+
Error Responses 62.5/100
|
|
30
|
+
Auth Clarity 50.0/100
|
|
31
|
+
Ambiguity 100.0/100
|
|
32
|
+
Parameter Explanation 10.0/100
|
|
33
|
+
Usage Guidelines 50.0/100
|
|
34
|
+
Tool Surface 100.0/100
|
|
34
35
|
```
|
|
35
36
|
|
|
36
37
|
## Why this exists
|
|
@@ -56,9 +57,8 @@ directly onto the rubric:
|
|
|
56
57
|
| **Frictionless authentication** | 4 (auth/scope clarity) |
|
|
57
58
|
| **Structured error handling** | 3 (actionable errors) |
|
|
58
59
|
|
|
59
|
-
Categories 2 (side effects) and 5 (ambiguity)
|
|
60
|
-
|
|
61
|
-
reward for actually building the thing you wrote about.
|
|
60
|
+
Categories 2 (side effects) and 5 (ambiguity) weren't in the article. They came
|
|
61
|
+
up once I started building, and they matter as much as the original three.
|
|
62
62
|
|
|
63
63
|
The gap is measurable, and enormous. A 2026 study of 856 tools across 103 MCP
|
|
64
64
|
servers found that **97.1% of tool descriptions contained at least one quality
|
|
@@ -164,6 +164,19 @@ future release does not invalidate your baseline.
|
|
|
164
164
|
|
|
165
165
|
As the team fixes the backlog, regenerate the baseline to lock in the progress.
|
|
166
166
|
|
|
167
|
+
### Python API
|
|
168
|
+
|
|
169
|
+
```python
|
|
170
|
+
from agent_ready import load_spec, run_audit
|
|
171
|
+
|
|
172
|
+
spec = load_spec("openapi.yaml")
|
|
173
|
+
result = run_audit(spec)
|
|
174
|
+
|
|
175
|
+
print(result["overall_score"])
|
|
176
|
+
for finding in result["gaps"]:
|
|
177
|
+
print(finding.severity, finding.endpoint, finding.message)
|
|
178
|
+
```
|
|
179
|
+
|
|
167
180
|
## Real-world results
|
|
168
181
|
|
|
169
182
|
Running it against Stripe's production spec (587 endpoints), as of v0.1.0.
|
|
@@ -189,8 +202,8 @@ Two things worth drawing out.
|
|
|
189
202
|
in this tool, not in Stripe.** Stripe documents errors via OpenAPI's `default`
|
|
190
203
|
response rather than enumerating explicit 4xx/5xx codes. Perfectly valid, and
|
|
191
204
|
arguably cleaner. The check only looked for `4`/`5` prefixes, so it failed all
|
|
192
|
-
587 endpoints. Fixed
|
|
193
|
-
|
|
205
|
+
587 endpoints. Fixed and regression-tested — and a good reason to run this
|
|
206
|
+
against your own real spec before trusting the score.
|
|
194
207
|
|
|
195
208
|
**Stripe is widely and correctly regarded as agent-ready, yet its raw OpenAPI
|
|
196
209
|
spec scores 62.9.** That isn't a contradiction — it's the whole point. Stripe's
|
|
@@ -205,19 +218,6 @@ Genuine findings that survived scrutiny: `GET /v1/account` and
|
|
|
205
218
|
uses bearer/basic API keys rather than scoped OAuth2, so there's no way to
|
|
206
219
|
express "this agent may only read."
|
|
207
220
|
|
|
208
|
-
### Python API
|
|
209
|
-
|
|
210
|
-
```python
|
|
211
|
-
from agent_ready import load_spec, run_audit
|
|
212
|
-
|
|
213
|
-
spec = load_spec("openapi.yaml")
|
|
214
|
-
result = run_audit(spec)
|
|
215
|
-
|
|
216
|
-
print(result["overall_score"])
|
|
217
|
-
for finding in result["gaps"]:
|
|
218
|
-
print(finding.severity, finding.endpoint, finding.message)
|
|
219
|
-
```
|
|
220
|
-
|
|
221
221
|
## The eight categories
|
|
222
222
|
|
|
223
223
|
| # | Category | What it catches | Published anchor |
|
|
@@ -281,7 +281,7 @@ doesn't:
|
|
|
281
281
|
|
|
282
282
|
- **The ambiguity check uses string similarity**, so it misses endpoints that
|
|
283
283
|
are semantically similar but differently worded. Embedding-based similarity
|
|
284
|
-
would be stronger. ([#1](https://github.com/sfaisal/agent-ready/issues))
|
|
284
|
+
would be stronger. ([#1](https://github.com/sfaisal/agent-ready/issues/1))
|
|
285
285
|
- **Category weights are judgement calls, not measured effect sizes.**
|
|
286
286
|
Description clarity is weighted highest on the prior that wrong tool selection
|
|
287
287
|
is the costliest failure — that prior is untested here.
|
|
@@ -304,7 +304,7 @@ doesn't:
|
|
|
304
304
|
- [ ] LLM-assisted rewriting of flagged descriptions (`--fix`)
|
|
305
305
|
- [ ] Live tool-selection testing against a generated MCP server
|
|
306
306
|
- [ ] GitHub Action wrapper
|
|
307
|
-
- [
|
|
307
|
+
- [x] Baseline mode (`--baseline`) so CI only fails on *new* regressions
|
|
308
308
|
|
|
309
309
|
## Contributing
|
|
310
310
|
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "openapi-agent-ready"
|
|
7
|
-
version = "0.4.
|
|
7
|
+
version = "0.4.1"
|
|
8
8
|
description = "Audit any OpenAPI spec for AI-agent and MCP readiness, and generate an MCP server scaffold."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -3,8 +3,8 @@ Command-line interface for agent-ready.
|
|
|
3
3
|
|
|
4
4
|
Exit codes (designed for CI use):
|
|
5
5
|
0 audit passed all configured gates
|
|
6
|
-
1 audit ran, but a gate failed (score below --min-score,
|
|
7
|
-
--max-fails exceeded)
|
|
6
|
+
1 audit ran, but a gate failed (score below --min-score,
|
|
7
|
+
--max-fails exceeded, or --max-new exceeded against --baseline)
|
|
8
8
|
2 the spec could not be loaded or parsed
|
|
9
9
|
"""
|
|
10
10
|
|
|
@@ -17,6 +17,7 @@ from . import __version__
|
|
|
17
17
|
from .auditor import (
|
|
18
18
|
SpecLoadError,
|
|
19
19
|
endpoints_ready_for_mcp,
|
|
20
|
+
extract_endpoints,
|
|
20
21
|
load_spec,
|
|
21
22
|
result_to_dict,
|
|
22
23
|
run_audit,
|
|
@@ -183,6 +184,16 @@ def _run(argv=None) -> int:
|
|
|
183
184
|
print(f"error: {exc}", file=sys.stderr)
|
|
184
185
|
return EXIT_SPEC_ERROR
|
|
185
186
|
|
|
187
|
+
# Swagger 2.0 has `paths` too, but keeps auth in `securityDefinitions` and
|
|
188
|
+
# bodies in `in: body` params, so auditing it yields confidently wrong scores.
|
|
189
|
+
if isinstance(spec, dict) and "swagger" in spec:
|
|
190
|
+
print(
|
|
191
|
+
f"error: Swagger {spec['swagger']} is not supported — only OpenAPI 3.x. "
|
|
192
|
+
"Convert it first (e.g. with swagger2openapi).",
|
|
193
|
+
file=sys.stderr,
|
|
194
|
+
)
|
|
195
|
+
return EXIT_SPEC_ERROR
|
|
196
|
+
|
|
186
197
|
if not isinstance(spec, dict) or not spec.get("paths"):
|
|
187
198
|
print(
|
|
188
199
|
"error: no 'paths' found — this does not look like an OpenAPI spec.",
|
|
@@ -190,7 +201,8 @@ def _run(argv=None) -> int:
|
|
|
190
201
|
)
|
|
191
202
|
return EXIT_SPEC_ERROR
|
|
192
203
|
|
|
193
|
-
|
|
204
|
+
# Operations, not paths — the audit (and the ambiguity check) is per operation.
|
|
205
|
+
endpoint_count = len(extract_endpoints(spec))
|
|
194
206
|
result = run_audit(spec, progress=_make_progress(endpoint_count, args.quiet))
|
|
195
207
|
|
|
196
208
|
if result["endpoint_count"] == 0:
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
2
|
AI-Readiness Rubric
|
|
3
3
|
-------------------
|
|
4
|
-
|
|
4
|
+
Eight categories used to score how ready an API (from an OpenAPI spec) is
|
|
5
5
|
for reliable use by AI agents / MCP servers. Each endpoint gets checked
|
|
6
6
|
against every category; failures become concrete, cite-able gaps.
|
|
7
7
|
|
|
@@ -13,8 +13,9 @@ Categories:
|
|
|
13
13
|
5. Ambiguity between endpoints -- Wang et al. (2026) found 73% repeated tool names
|
|
14
14
|
6. Parameter explanation -- "Opaque Parameters" smell: 84.3% prevalence
|
|
15
15
|
7. Usage guidelines (when to call) -- "Missing Usage Guidelines" smell: 89.3% prevalence
|
|
16
|
+
8. Tool surface & schema strictness -- OpenAI function-calling guidance (keep tool count small)
|
|
16
17
|
|
|
17
|
-
Provenance
|
|
18
|
+
Provenance:
|
|
18
19
|
Categories 1-5 were derived independently from how MCP tool selection works
|
|
19
20
|
plus standard API design principles. Categories 6-7 were added after checking
|
|
20
21
|
the rubric against published empirical work:
|
|
@@ -29,7 +30,7 @@ the rubric against published empirical work:
|
|
|
29
30
|
Server Descriptions," arXiv:2602.18914. 10,831 servers, 18 smell
|
|
30
31
|
categories across accuracy / functionality / completeness / conciseness.
|
|
31
32
|
|
|
32
|
-
IMPORTANT TRADE-OFF
|
|
33
|
+
IMPORTANT TRADE-OFF:
|
|
33
34
|
Hasan et al. found that augmenting ALL description components improved task
|
|
34
35
|
success by a median 5.85pp but increased execution steps by 67.46% and
|
|
35
36
|
REGRESSED performance in 16.67% of cases. More completeness is not strictly
|
|
@@ -477,6 +477,13 @@ def test_cli_bad_spec_exits_two(tmp_path, capsys):
|
|
|
477
477
|
assert main([str(p), "--quiet"]) == 2
|
|
478
478
|
|
|
479
479
|
|
|
480
|
+
def test_cli_rejects_swagger_2(tmp_path, capsys):
|
|
481
|
+
"""Swagger 2.0 has `paths`, so it used to be scored (wrongly) instead of rejected."""
|
|
482
|
+
spec = {"swagger": "2.0", "info": {"title": "Old", "version": "1"}, **GOOD_SPEC}
|
|
483
|
+
assert main([_write(tmp_path, spec), "--quiet"]) == 2
|
|
484
|
+
assert "Swagger 2.0 is not supported" in capsys.readouterr().err
|
|
485
|
+
|
|
486
|
+
|
|
480
487
|
def test_cli_json_output_is_valid(tmp_path, capsys):
|
|
481
488
|
main([_write(tmp_path, GOOD_SPEC), "--format", "json"])
|
|
482
489
|
payload = json.loads(capsys.readouterr().out)
|