@machinegrade/validate
Advanced tools
@@ -21,3 +21,3 @@ #!/usr/bin/env node | ||
| function buildServer() { | ||
| const server = new Server({ name: "machinegrade-validate-mcp", version: "0.1.1" }, { capabilities: { tools: {} } }); | ||
| const server = new Server({ name: "machinegrade-validate-mcp", version: "0.1.2" }, { capabilities: { tools: {} } }); | ||
| server.setRequestHandler(ListToolsRequestSchema, async () => ({ | ||
@@ -24,0 +24,0 @@ tools: [VALIDATE_TOOL], |
@@ -19,5 +19,13 @@ /** | ||
| artifact: { | ||
| description: "The artifact to validate (object for json_schema/openapi_response, SQL string for sql).", | ||
| // The explicit union matters: with no `type` at all, callers serialize | ||
| // the value to a JSON string ("{\"a\":1}") and every object-shaped | ||
| // contract then fails on a bogus top-level type error. Declaring the | ||
| // types is the fix; src/artifact.ts is the safety net for callers | ||
| // that stringify regardless. | ||
| type: ["object", "array", "string", "number", "boolean", "null"], | ||
| description: "The artifact to validate, as a JSON value — not a JSON-encoded string. " + | ||
| "json_schema/openapi_response: the object/array/value itself. sql: the SQL statement as a string.", | ||
| }, | ||
| contract: { | ||
| type: "object", | ||
| description: "Validator-specific contract. json_schema: { schema }. openapi_response: { spec, path, method, status }. sql: { dialect }.", | ||
@@ -24,0 +32,0 @@ }, |
+1
-1
| { | ||
| "name": "@machinegrade/validate", | ||
| "version": "0.1.1", | ||
| "version": "0.1.2", | ||
| "description": "Deterministic validation of AI-generated artifacts: JSON Schema conformance, OpenAPI response conformance, SQL syntax. Metered API + MCP adapter with typed verdicts and fix hints.", | ||
@@ -5,0 +5,0 @@ "type": "module", |
+39
-8
@@ -5,3 +5,3 @@ # machinegrade validate | ||
| - **`json_schema`** — validate `artifact` against a JSON Schema (ajv, all errors collected). | ||
| - **`json_schema`** — validate `artifact` against a JSON Schema (all errors collected). | ||
| - **`openapi_response`** — validate a response body against the response schema for a given `path` + `method` + `status` in an OpenAPI spec. | ||
@@ -15,4 +15,6 @@ - **`sql`** — check a SQL string for syntax errors in a given dialect. | ||
| Built on Hono — one codebase, runs locally on Node today and is written to | ||
| be Cloudflare Workers-compatible for deploy later (see "Deploy" below). | ||
| Live at **https://api.machinegrade.dev** — free tier, self-service key, | ||
| try it in 30 seconds (first example below). Built on Hono; the same | ||
| codebase runs on Cloudflare Workers (production) and plain Node (local | ||
| dev), and is MIT-licensed if you'd rather self-host. | ||
@@ -38,4 +40,4 @@ ## Why | ||
| ```bash | ||
| # Get an API key | ||
| curl -s -X POST http://localhost:8787/keys \ | ||
| # Get an API key (live service — works as-is) | ||
| curl -s -X POST https://api.machinegrade.dev/keys \ | ||
| -H 'content-type: application/json' \ | ||
@@ -46,3 +48,3 @@ -d '{"email": "you@example.com"}' | ||
| # Validate a JSON artifact against a JSON Schema | ||
| curl -s -X POST http://localhost:8787/v1/validate \ | ||
| curl -s -X POST https://api.machinegrade.dev/v1/validate \ | ||
| -H 'content-type: application/json' \ | ||
@@ -170,2 +172,31 @@ -H 'X-Api-Key: sk_...' \ | ||
| ## Sending the artifact | ||
| `artifact` must be a JSON **value**, not a JSON-encoded string: | ||
| ```jsonc | ||
| {"type": "json_schema", "artifact": {"name": "Ada"}, "contract": {"schema": {"type": "object"}}} // correct | ||
| {"type": "json_schema", "artifact": "{\"name\": \"Ada\"}", "contract": {"schema": {"type": "object"}}} // wrong | ||
| ``` | ||
| For `type: "sql"` the artifact *is* a string — the statement itself. | ||
| Because MCP callers stringify values often enough (and did so through Claude | ||
| Desktop until the tool schema declared `artifact`'s types), the service | ||
| tolerates the wrong form narrowly: if `artifact` is a string, the type is | ||
| `json_schema` or `openapi_response`, and the contract's **top-level schema | ||
| declares types that exclude `string`**, the string is JSON-decoded before | ||
| validation and the verdict carries `"decoded_from_string": true`. The field is | ||
| additive; `{valid, errors, latency_ms}` is unchanged. | ||
| It deliberately does not decode otherwise, because a string artifact is often | ||
| legitimate: | ||
| | Sent | Contract schema | Result | | ||
| |---|---|---| | ||
| | `"42"` | `{"type": "number"}` | decoded to `42`, `valid: true`, `decoded_from_string: true` | | ||
| | `"42"` | `{"type": "string"}` | left alone, `valid: true` | | ||
| | `"{\"a\":1}"` | `{"type": "string"}` | left alone, `valid: true` | | ||
| | `"{\"a\":1}"` | `{"required": ["a"]}` | left alone — no top-level `type`, intent unknown | | ||
| ## Storage | ||
@@ -202,4 +233,4 @@ | ||
| This template runs on Cloudflare Workers (Hono + D1 + Workers Static | ||
| Assets). To deploy to a fresh Cloudflare account: | ||
| The service runs on Cloudflare Workers (Hono + D1 + Workers Static | ||
| Assets). To self-host on a fresh Cloudflare account: | ||
@@ -206,0 +237,0 @@ ```bash |
17555
13.85%115
7.48%271
12.92%