oaslint MCP
by 0xmortuex
README.md
# oaslint MCP — The Hard Way
Build a small MCP server that **lints OpenAPI specs and detects breaking changes between two
versions of an API**, from the first byte of YAML to an agent calling your tools over stdio.
At the end you will have built a compact version of
[oaslint-mcp](https://github.com/0xmortuex/oaslint-mcp) yourself, and you will understand the idea
that almost every API-diff tool gets subtly wrong: **a request and a response vary in opposite
directions**, so the very same edit is breaking in one and harmless in the other.
## Why This Exists
Most MCP tutorials wrap a REST call. The interesting work in a useful server is elsewhere:
- reading hostile, messy input safely (YAML bombs, `$ref` loops, `../../` paths, URLs that
want to be fetched);
- turning three dialects of a format into one model, so the rules are written once;
- deciding *what a change means*, not just that it happened;
- failing in ways that tell the agent what to do next.
## Who This Is For
Developers who have a "hello world" MCP server and want to build one that earns its keep, and
anyone who has shipped an API change and found out afterwards that it broke a client.
**Prerequisites:** Python and a rough idea of what OpenAPI is. Nothing to install except
`pip install -r requirements.txt` (the MCP SDK, PyYAML and anyio). No network, no other services.
## Modules
| # | Module | What You'll Build |
|---|--------|-------------------|
| 01 | [Load and Normalise](01-load-and-normalise/) | Read Swagger 2.0, OpenAPI 3.0 and 3.1 safely and squash them into one operation model |
| 02 | [Resolving Refs](02-resolving-refs/) | `$ref` with cycle detection, relative file refs in a sandbox, and remote refs that are never fetched |
| 03 | [Walking Schemas](03-walking-schemas/) | A schema walker that survives recursive schemas, and the outline an agent reads |
| 04 | [Flattening allOf](04-flattening-allof/) | Merge `allOf`, fold `nullable` / `type: [x, "null"]` / `const`, so equal things look equal |
| 05 | [Classifying Changes](05-classifying-changes/) | The core idea: request vs response variance, and a diff that says BREAKING, POTENTIALLY BREAKING or safe |
| 06 | [Validating Examples](06-validating-examples/) | A JSON Schema subset validator that reports a JSON pointer for every violation |
| 07 | [The MCP Wrapper](07-the-mcp-wrapper/) | Three tools, errors that instruct, a sandboxed `--dir`, and testing over real stdio |
Each module contains:
- `README.md`: the concept, the listing of the new `lite/` file (embedded from the real file, and
CI fails if they drift apart), a walk-through, how to run it, how to break it, and what the full
server does differently;
- `main.py`: runnable code that uses the new file and **asserts** its results.
## Running It
```
pip install -r requirements.txt
python verify.py # every module, the way CI does
python verify.py 05 # one module
python 05-classifying-changes/main.py
```
The sample APIs are in `specs/`: the same small shop written as Swagger 2.0, OpenAPI 3.0 and 3.1, a
second version with real breaking changes, a recursive schema, and a split spec with file refs
plus an `evil.yaml` that tries to read outside the sandbox.
## The Library, File by File
```
lite/loader.py 01 parse, detect the version, normalise operations
lite/refs.py 02 Resolver: $ref, cycles, sandboxed files
lite/walk.py 03 outline of a (possibly recursive) schema
lite/flat.py 04 flatten allOf, normalise nullable
lite/diff.py 05 classify changes by direction
lite/validate.py 06 validate a JSON document
lite/server.py 07 the MCP server
```
Each module adds exactly one file. Nothing is hidden in a framework.
MIT licensed.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo recent community issues