Skip to main content
Glama

http-semantics-mcp

Deterministic HTTP semantics judgement, delivered as an MCP server over stdio.

Status: released — v0.1.0. The server starts, completes the MCP handshake and reports five tools — cache_evaluate, conditional_evaluate, cors_evaluate, cors_simulate_fetch and vary_match. Each one ships a JSON Schema descriptor (input and output) under src/http_semantics_mcp/schemas/tools/, mirrored byte-identically to schemas/tools/. All five are judged against frozen golden cases (18 + 19 + 24 + 10 + 9) and produce byte-identical output; a contract gate proves the published output schema equals each tool's real key set and value shapes across every case, and a determinism gate proves same-input / same-sha256 across all of them. Tagged v0.1.0, and the four-leg CI matrix is green. See plan/05-里程碑.md.


What this is

An oracle for the corners of HTTP that fail silently: CORS, cache semantics, conditional requests and Vary. You hand it request/response headers as literals; it hands back a specification-derived verdict plus the rule IDs and clause references behind it.

  • No network. No DNS, no TCP, no HTTP. url is parsed for scheme/host/port only. There is nothing to capture, proxy or replay.

  • No capture. Input is caller-supplied header literals, not observed traffic.

  • No security scoring. No grades, no severity, no "is this site safe". Header security scanning is a different job and is out of scope.

  • Deterministic. Same input → byte-identical serialised output. No clock, no randomness, no environment reads. Time is an argument, not a lookup.

Tools

Tool

Question it answers

Milestone

cors_evaluate

Will the browser let this response through?

M2 ✅

cors_simulate_fetch

What happens across redirects, hop by hop?

M2 ✅

cache_evaluate

Can this stored response be served without revalidating?

M3 ✅

conditional_evaluate

Which conditional-request rule decides the status?

M4 ✅

vary_match

Does this cached entry match the incoming request?

M4 ✅

tools/list returns exactly the tools that are implemented. A stub descriptor would tell a client a capability exists that does not, which is why the remaining milestones add tools rather than plans.

A cache verdict by hand

Ask whether a stored response is still fresh, and what the numbers are:

printf '%s\n' \
  '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' \
  '{"jsonrpc":"2.0","method":"notifications/initialized"}' \
  '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"cache_evaluate","arguments":{"now":"2026-01-01T00:00:30Z","response_headers":{"Cache-Control":"max-age=60","Date":"Thu, 01 Jan 2026 00:00:00 GMT"},"stored":{"stored_at":"2026-01-01T00:00:10Z","age":"10"}}}}' \
  | python -m http_semantics_mcp
{"action":"serve","current_age":30,"freshness_lifetime":60,"is_fresh":true,"must_revalidate":false,"reasons":[],"stale_while_revalidate_window":0}

now is an argument, not a clock read: the same call always returns the same bytes, on any machine, at any time.

What it is not

  • Not a browser. Verdicts are spec-derived; where an implementation differs from the specification, the specification wins and the divergence is noted.

  • Not a substitute for mitmproxy / powhttp-style capture tools. Those need real traffic; this needs a JSON object.

  • Not a security scanner. Out of scope by design (see plan/01-题目文档.md section 6).


Related MCP server: judgment-pack-runtime

Install

Requires Python 3.8 or newer. The runtime has no third-party dependencies.

git clone https://github.com/yuluo554/http-semantics-mcp.git
cd http-semantics-mcp
python -m pip install -e ".[dev]"

.[dev] installs the test-time dependencies only (pytest, PyYAML). If you only want to run the server, python -m pip install -e . is enough.

Verify the install:

python -m http_semantics_mcp --version
python -m http_semantics_mcp --selftest

--selftest prints one line per check and exits 0 on pass, 1 on failure. It never prints a verdict — it checks the installation, not your headers.


Run

The server speaks newline-delimited JSON-RPC 2.0 on stdin/stdout.

python -m http_semantics_mcp

Or, after installation, the console script:

http-semantics-mcp

Client configuration

Claude Code (~/.claude.json or project .mcp.json):

{
  "mcpServers": {
    "http-semantics": {
      "command": "python",
      "args": ["-m", "http_semantics_mcp"],
      "env": {}
    }
  }
}

Codex (~/.codex/config.toml):

[mcp_servers.http-semantics]
command = "python"
args = ["-m", "http_semantics_mcp"]

Any stdio MCP client works: spawn the process, write one JSON object per line, read one JSON object per line.

Protocol surface

Method

Result

initialize

protocolVersion, capabilities, serverInfo

notifications/initialized

no response

ping

{} (available before initialize)

tools/list

registered tools, ASCII-sorted by name

tools/call

tool result, or a JSON-RPC error for an unknown tool

anything else

-32601

Supported protocol versions: 2025-06-18, 2025-03-26, 2024-11-05. An unrecognised version is answered with 2025-06-18, which the specification permits; the client decides whether to continue.

Error codes: -32700 parse error, -32600 invalid request, -32601 unknown method, -32602 invalid params, -32002 not initialized, -32603 internal error. A tool-level bad input is not a JSON-RPC error: it returns a result with isError: true.

A handshake by hand

printf '%s\n' \
  '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18"}}' \
  '{"jsonrpc":"2.0","method":"notifications/initialized"}' \
  '{"jsonrpc":"2.0","id":2,"method":"tools/list"}' \
  | python -m http_semantics_mcp

A verdict by hand

Ask whether a cross-origin response is allowed, and what to change if not:

printf '%s\n' \
  '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' \
  '{"jsonrpc":"2.0","method":"notifications/initialized"}' \
  '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"cors_evaluate","arguments":{"method":"GET","url":"https://api.example.com/v1","origin":"https://app.example.com","credentials":"omit","request_headers":{},"response":{"status":200,"headers":{}},"is_preflight":false}}}' \
  | python -m http_semantics_mcp

The verdict arrives as one JSON string inside content[0].text:

{"decision":"block","missing_headers":["access-control-allow-origin"],"notes":{"allow_credentials_null_origin":false,"max_age_capped_by_client":false,"wildcard_with_credentials":false},"recommended_headers":{"access-control-allow-origin":"https://app.example.com"},"violations":[{"code":"CORS_MISSING_ALLOW_ORIGIN","detail":"response has no Access-Control-Allow-Origin (origin=https://app.example.com)","spec_ref":["Fetch §CORS check"]}]}

decision: "block" is a successful judgement, so isError stays false. Only a malformed request sets isError: true, and it still answers with a payload rather than a stack trace.


Development

python -m pytest
python tools/run_gates.py
python tools/mutate_check.py
python tools/smoke_stdio.py
python tools/gen_codes.py --check
python tools/gen_golden.py --check
python tools/gen_schemas.py --check
python scripts/check_release.py --pre-tag
  • pytest runs the full suite (protocol, transport framing, determinism, gates, packaging surface).

  • tools/run_gates.py runs the eight static gates and names the failing one.

  • tools/mutate_check.py breaks one behaviour per gate and asserts the gate goes red. A gate that cannot fail is decoration; this script is how that claim is kept honest rather than asserted.

  • tools/smoke_stdio.py starts the server as a real subprocess and asserts on the raw bytes: every stdout line is JSON, no \r, response count matches request count.

  • tools/gen_codes.py --check, tools/gen_golden.py --check and tools/gen_schemas.py --check recompute the generated artefacts (rule catalogue, golden cases, schema mirror) and compare bytes, so a hand edit that drifts from its source is caught rather than committed.

  • scripts/check_release.py --pre-tag is the release-terminal gate. It is not wired into CI on purpose: before a tag exists, several of its checks must be red, and a permanently red job carries no information.

Repository gates

Eight static gates run in tests, in CI, and inside the release check. Each one must be provably able to fail (tests/test_gates.py and tests/test_m1_gates.py inject a defect for every gate, and tools/mutate_check.py proves it end to end):

Gate

Rule

purity

src/http_semantics_mcp/judgement/ imports no clock, network, env, process, or filesystem module

no-nondeterminism

the whole runtime package imports no clock, randomness or network; no os.environ / getenv anywhere

single-serialiser

json.dumps appears exactly once, in canonical.py

absolute paths

no machine-specific path (drive letter, home directory, UNC share) in repository text

line endings

every text file is LF-only and .gitattributes declares eol=lf

oracle independence

tools/golden_oracle/ never imports http_semantics_mcp, directly or dynamically

golden hygiene

every frozen case has the required fields and no observed_* key

code literals

no hand-written package source spells a rule code; the generated catalogue (references/codes.json and rules.py) is the only copy

Two further gates live in the test suite rather than in tools/gates.py, because they must run the tools instead of reading files:

Gate

Rule

schema parity

for every tool, outputSchema.properties equals both the key set frozen in data/README.md section 4.10 and the key set (and value shapes) of every frozen case's real output — an equality in both directions, not a subset

determinism

two calls on the same input serialise to the same sha256, for every tool and every case, and no output carries a machine-specific path or a date the caller did not supply

Layout

src/http_semantics_mcp/   server, protocol, registry, judgement layer
schemas/tools/            generated mirror of the in-package JSON Schemas
references/               generated mirror of the in-package code table
data/golden/              frozen golden cases (input + expected output)
data/wpt/                 WPT cors/ directory index (paths + blob shas only)
data/wpt-mapping.json     WPT cors/ mapping ledger
plan/                     the project plan, milestones and release records
tools/                    gates, smoke test, generators
scripts/check_release.py  release-terminal self-check

The in-package copies under src/http_semantics_mcp/ are the only editable sources for codes.json and the tool schemas; the top-level copies are byte-identical mirrors so an installed distribution and a reader both see the same contract.


Data and verification

All inputs are synthetic. Domains are reserved examples (example.com, example.org, example.net, localhost); ETags are explicit fakes; times are fixed literals. No real response headers, tokens, cookies, HAR or pcap files are collected, and .gitignore blocks those paths.

Golden cases freeze the input and the expected output. Expected values are produced by an independent oracle under tools/golden_oracle/, not by the implementation under test, and a gate forbids the oracle from importing the judgement layer — otherwise the benchmark would be comparing an implementation with itself.

Browser behaviour is cross-checked against web-platform-tests/wpt's cors/ suite (index pinned to commit 850b36a5, data day 2026-10-18), transcribed to header-level cases in data/golden/. The ledger in data/wpt-mapping.json accounts for all 45 files in the directory: 15 mapped, 30 listed with a reason (real network, TLS, timing, browser-proprietary behaviour, or out of scope). Nothing is guessed at, and no test body is copied into this repository.

Measured on this build

Every number below comes from the local double-interpreter run. CI is now wired up: the four-leg matrix {ubuntu, windows} × {3.8, 3.12} is green on both the main push (run 39141511111) and the v0.1.0 tag push (run 39141686281).

Metric

Value

Frozen golden cases, byte-identical to production

87 / 87

Rule codes reachable by at least one case (set equality, both directions)

31 / 31

WPT cors/ files mapped to golden cases

15 / 45 (30 / 45 listed with a reason; all 15 mapped rows re-run and reconcile with production)

Tool descriptors (input + output schema per tool)

5

Static gates

8

Mutations that must turn a gate red

43 / 43

Collected tests

379 (Python 3.8) / 379 (Python 3.12)

The three generated artefacts are recomputed and compared byte for byte on every run (gen_codes --check, gen_golden --check, gen_schemas --check), and every static gate has at least one mutation proving it can fail.


License

MIT. See LICENSE.

Project plan

Available Tools

5 tools
cache_evaluateA

Decide whether a stored response may be reused without revalidating. Applies the RFC 9111 age and freshness arithmetic (Date, Age, Cache-Control, Expires, Last-Modified) and returns action serve|revalidate|miss, the age and freshness lifetime in whole seconds, and the rule IDs with their clause references. now is an argument: the cache never reads a clock.

ParametersJSON Schema
NameRequiredDescriptionDefault
nowYesevaluation instant (YYYY-MM-DDTHH:MM:SSZ or an HTTP-date)
storedYes
request_headersNoheader name -> value
response_headersNoheader name -> value

Output Schema

ParametersJSON Schema
NameRequiredDescription
actionYes
reasonsYes
is_freshYes
current_ageYesRFC 9111 section 4.2.3 age, whole seconds
must_revalidateYes
freshness_lifetimeYeswhole seconds
stale_while_revalidate_windowYeswhole seconds; 0 when undeclared

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does well: it states the tool is a pure evaluator whose evaluation instant is an argument ('the cache never reads a clock'), which tells the agent the result is deterministic and independent of wall-clock state. It also discloses the exact header classes consumed and the returned action vocabulary. It stops short of explicitly declaring no side effects or network access.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three dense sentences, no filler. The purpose is front-loaded, followed by the rule set, the return shape, and the key 'now is an argument' caveat that an agent must not miss. Every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a nested-input evaluator with an output schema (so return values needn't be spelled out), the description covers purpose, rule basis, return vocabulary, and the clock-independence constraint. The remaining gap is the missing editorial distinction between stored.headers and response_headers, and no note on error behavior for malformed dates or missing required fields.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 75%, so the schema already documents now, stored, stored_at, and age; baseline is 3. The description adds value by naming the semantically relevant headers (Date, Age, Cache-Control, Expires, Last-Modified) and stressing that now must be supplied, but request_headers and response_headers themselves get no explanation and the split between stored.headers and response_headers is never clarified.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific verb and resource: deciding whether a stored response may be reused without revalidating, computed via RFC 9111 age and freshness arithmetic. That is far more precise than a generic 'evaluate cache'. It never distinguishes itself from siblings such as conditional_evaluate or vary_match, so an agent gets no explicit routing help.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The framing 'Decide whether a stored response may be reused without revalidating' implies the use case (checking cache freshness before serving), but there is no explicit when-to-use, when-not-to-use, or named alternative. An agent must infer that conditional_evaluate handles the conditional-request path instead. Usage is implied, not stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

conditional_evaluateA

Judge one request's preconditions and report the status they decide. Evaluates If-Match, If-Unmodified-Since, If-None-Match and If-Modified-Since in the RFC 9110 section 13.2.2 precedence order, stopping at the first applicable one, and returns status 200|304|412, which rule decided it, and the rule IDs with their clause references.

ParametersJSON Schema
NameRequiredDescriptionDefault
methodYesHTTP request method
resourceYes
request_headersYesheader name -> value

Output Schema

ParametersJSON Schema
NameRequiredDescription
statusYes
explainYes
rule_appliedYes
weak_comparison_usedYes

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does well: it discloses the precedence order applied, the short-circuit behavior ('stopping at the first applicable one'), and the discrete outcome set (200|304|412) plus the deciding rule and clause references. It stops short of stating that evaluation is side-effect free and does not touch the resource.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single dense sentence that front-loads the action and then the algorithm and outputs in descending priority. Every clause carries information, though the comma-chained precedence/return list is slightly heavy to parse; a second short sentence would have been cleaner without adding length.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a nested-schema tool with an output schema (so return values need not be explained) and no annotations, the description supplies the algorithm, precedence rule, and outcome set an agent needs. It lacks only the sibling-disambiguation and side-effect/purity statement, which are modest gaps given how self-contained the tool is.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 67%, so the schema documents most of method, resource.etag, resource.last_modified, and request_headers. The description indirectly signals which header names in request_headers are meaningful (the four conditional headers), which is some added semantic value, but it explains nothing about how method or resource interact with those headers.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Names a specific verb+resource: judging one request's precondition headers and reporting the resulting status. The scope (If-Match, If-Unmodified-Since, If-None-Match, If-Modified-Since) clearly separates it from siblings like cache_evaluate, cors_evaluate, and vary_match; an agent can route without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The RFC 9110 §13.2.2 framing implies the context (HTTP conditional request evaluation), so usage is inferable. However, it never states when to prefer this over cache_evaluate or vary_match, nor any when-not condition or prerequisite (e.g. that resource state must be supplied). No explicit routing guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

cors_evaluateA

Judge one HTTP response against the Fetch Standard CORS check. Returns decision allow|block, the violated rule IDs with their clause references, the headers that are missing, and what to send instead. No network: url is parsed for scheme/host/port only.

ParametersJSON Schema
NameRequiredDescriptionDefault
urlYestarget URL; only its origin is used
methodYesHTTP request method
originNorequest Origin; omit or null for a same-origin request
responseYes
credentialsNocredentials mode of the request
is_preflightYesis this the preflight response?
request_headersNoheader name -> value

Output Schema

ParametersJSON Schema
NameRequiredDescription
notesYes
decisionYes
violationsYes
missing_headersYeslowercase header names, ASCII-sorted
recommended_headersYeslowercase header name -> value to send instead

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full disclosure burden, and it does well: 'No network' establishes this as a pure, side-effect-free evaluation, and it enumerates the return shape (decision allow|block, violated rule IDs with clause references, missing headers, remediation headers). It stops short of explicitly stating determinism or that no state is mutated.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three dense, front-loaded sentences with no filler: purpose first, then output contract, then the no-network constraint. Every clause carries information an agent needs.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need not be explained, yet the description still summarizes them usefully. Combined with 7 parameters at 86% schema coverage and the key 'no network' caveat, nothing material an agent needs in order to call this correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 86%, so the baseline is 3, but the description adds real meaning beyond the schema: 'url is parsed for scheme/host/port only' clarifies how the url parameter is consumed, refining the schema's 'only its origin is used.' It also frames response headers as the object to be judged, which sharpens the nested schema's intent.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

Specific verb and resource: 'Judge one HTTP response against the Fetch Standard CORS check,' with the scope constraint that only the URL's origin is used. This implicitly separates it from cors_simulate_fetch (this one does no network work and evaluates a given response), but no sibling is named, so sibling differentiation is inferred rather than explicit.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied by 'Judge one HTTP response' and by the statement that the URL is only parsed for scheme/host/port, telling the agent this tool takes an already-observed response. However, there is no explicit when-to-use, when-not-to-use, or named alternative (e.g. cors_simulate_fetch) for the case where the agent has no response yet.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

cors_simulate_fetchB

Walk a redirect chain hop by hop and judge each hop with the CORS check. Reports the ordered redirect events (origin_set_to_null, credentials_dropped), the visible response headers, and the effective Access-Control-Max-Age.

ParametersJSON Schema
NameRequiredDescriptionDefault
urlYestarget URL; only its origin is used
modeNofetch mode; defaults to cors
methodYesHTTP request method
originNorequest Origin; omit or null for a same-origin request
responseYes
redirectsNo
credentialsNocredentials mode of the request
is_preflightNois this the preflight response?
request_headersNoheader name -> value

Output Schema

ParametersJSON Schema
NameRequiredDescription
hopsYesin occurrence order, not sorted
eventsYesin occurrence order, not sorted
decisionYes
final_typeYes
visible_headersYeslowercase header names, ASCII-sorted
max_age_effectiveYeswhole seconds
preflight_occurredYes
preflight_cache_keyYesper data/README.md section 4.7

TDQS

B3.2/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are supplied, so the description carries the full burden. It does usefully disclose the observed behaviors it reports (origin_set_to_null, credentials_dropped, effective Max-Age), which signals a pure, side-effect-free simulation. It does not state that the tool performs no network I/O, that credentials mode changes mid-chain, or how the simulated stack decides hops, leaving some behavioral questions open.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two tight sentences, front-loaded with the core action and followed by the reporting surface. Every clause carries information, though the parenthetical event list is slightly list-shaped rather than explanatory.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so the description legitimately need not spell out return shapes, and it nonetheless sketches them. For a 9-parameter, nested-object tool with no annotations and a sibling that overlaps in intent, the description stops short of the routing and semantics detail an agent needs to call it correctly versus cors_evaluate.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 78% with 9 parameters, so the schema does most of the documentation work. The description adds no parameter-level meaning at all: nothing explains how is_preflight interacts with redirects, or how mode/credentials shape the hop judgments. Baseline 3 is appropriate given the schema covers most fields, though the description could have clarified the semantically loaded ones.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description gives a specific verb and resource: it walks a redirect chain hop by hop and judges each hop with the CORS check, and it enumerates the outputs (redirect events, visible headers, effective Access-Control-Max-Age). That is much clearer than a restated name. However, it never distinguishes itself from the sibling cors_evaluate, which an agent could easily mistake for this tool.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no when-to-use guidance, no statement of prerequisites, and no mention of alternatives, even though cors_evaluate is a direct sibling that plausibly competes for the same intent. The agent must infer from the name alone that this tool is for multi-hop redirect scenarios while cors_evaluate covers a single exchange.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

vary_matchB

Decide whether a stored response can be reused for an incoming request, per RFC 9111 section 4.1. Compares the fields named by the stored Vary value under that field's normalisation policy and returns match hit|miss, the fields that differ, the normalised Vary members, and the rule IDs with their clause references.

ParametersJSON Schema
NameRequiredDescriptionDefault
cachedYes
incomingYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
matchYes
reasonsYes
normalized_varyYeslowercase header names, ASCII-sorted
differing_headersYeslowercase header names, ASCII-sorted

TDQS

B3.4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are supplied, so the description carries the full burden. It does disclose meaningful behavior: comparison is governed by each field's normalisation policy and the result is a hit/miss classification plus differing fields and rule IDs, which implies a read-only, deterministic evaluation. It does not state the safety profile (pure function, no mutation, no network or auth) or how missing headers are treated.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with the decision and the normative basis, with the return payload listed afterwards. Dense but every clause carries information; no filler or tautology.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need not be elaborated (the description nonetheless enumerates them). For a nested two-object computation grounded in an RFC, the definition covers intent and output but omits the parameter-to-field mapping and edge-case semantics, leaving an agent with gaps given 0% schema description coverage.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description has to compensate for two required nested-object parameters. It does convey the split semantically — the stored Vary value with headers at store time versus the incoming request headers — but never maps this onto the cached.vary, cached.request_headers_at_store and incoming.request_headers fields by name, and says nothing about repeated-header or array handling.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ('Decide whether') and a precise resource (a stored response can be reused for an incoming request), anchored to RFC 9111 section 4.1 and the Vary mechanism. It is far more specific than the sibling names alone, though it never explicitly distinguishes itself from the conceptually adjacent cache_evaluate.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Use is implied by the RFC citation and the 'stored response vs incoming request' framing, but there is no explicit when-to-use, when-not-to-use, or pointer to alternatives such as cache_evaluate or conditional_evaluate. The agent must infer routing from the RFC reference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 5 tool updatesv0.1.0
    • First observedcache_evaluate
    • First observedconditional_evaluate
    • First observedcors_evaluate
    • First observedcors_simulate_fetch
    • First observedvary_match

TDQS

A3.7/5.0

Scored across 5 tools

Disambiguation4/5

Most tools target clearly distinct HTTP semantics concerns (cache freshness, Vary matching, conditional preconditions, CORS). The two CORS tools (cors_evaluate for a single response, cors_simulate_fetch for a redirect chain) and the two cache-related tools (cache_evaluate for freshness, vary_match for field matching) are related but their scopes are differentiated in the descriptions.

Naming Consistency4/5

All names use snake_case with a domain_prefixed convention (cors_*, cache_*, conditional_*, vary_match). Mostly consistent, though cors_simulate_fetch breaks the domain_action pattern slightly with an extra verb.

Tool Count5/5

Five focused tools are well-scoped for a narrow HTTP semantics/RFC-conformance evaluator, with no redundant or filler entries. Each tool earns its place.

Completeness4/5

The set covers the core RFC 9111 cache reuse path (freshness + Vary), RFC 9110 preconditions, and CORS including redirects, which is solid coverage. Minor gaps exist (e.g., no explicit cache storage/no-store decision or combined end-to-end request evaluation), but agents can work around them.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    A
    maintenance
    Serves offline document validation and evaluation operations of the Judgment Pack Specification to MCP clients over stdio, enabling agents to validate and evaluate JPS documents as tool calls. Supports conformance validation, experimental evaluation with disposition and error classes, and corpus testing.
    2
    Apache 2.0
  • A
    license
    Not graded
    quality
    B
    maintenance
    Provides a deterministic pre-install security scan for Agent skills, plugins, and MCP servers via stdio, returning verdicts, audited badges, CI gates, and reports without executing code or making network calls.
    74 npm
    MIT