Contents
- 1. Why this study
- 2. Population and sampling
- 3. How the probe works
- 4. How outcomes were classified
- 5. Results — does the endpoint answer as an MCP server? (RQ1)
- 6. Results — which protocol revision do they speak? (RQ2)
- 7. Results — can an agent follow the auth challenge? (RQ3)
- 8. Results — is tool metadata usable? (RQ4)
- 9. Results — are errors reported in-channel? (RQ5)
- 10. Results — re-test reliability (RQ6)
- 11. How the study actually ran
- 12. Validation
- 13. Pre-registration deviations
- 14. Limitations
- 15. Ethics and what went wrong
- 16. Reproducing the study
- → Data, code & links
1. Why this study
The Model Context Protocol is how AI agents discover and call tools hosted by other people. A remote MCP server is an HTTP endpoint: an agent connects, learns which protocol revision it speaks, asks for the list of tools, and calls them. When something goes wrong, the server is supposed to say so in a structured way the agent can reason about.
In July 2026 the protocol changed substantially. Revision `2026-07-28` made MCP stateless: the initialize/initialized handshake and the Mcp-Session-Id header were retired, every request now carries its own protocol version, client identity and capabilities in _meta, and a new server/discover method lets clients learn what a server supports. Servers built for earlier revisions still use the old handshake. An agent meeting an unknown endpoint therefore has to work out which era it is talking to before it can do anything.
Registries such as the official MCP Registry list tens of thousands of remote endpoints, but listings are self-submitted and unvetted. Before this study there was no systematic, reproducible measurement of how many listed endpoints actually work, how many speak the new revision, whether auth-gated servers tell agents how to authenticate, and whether errors come back in a form an agent can use.
Research questions (descriptive, no directional hypotheses)
| # | Question |
|---|---|
| RQ1 | What share of remote MCP endpoints listed in the official registry are reachable and answer the MCP protocol? |
| RQ2 | Among endpoints that complete a handshake, which protocol era and version do they speak — modern 2026-07-28 (per-request metadata) or legacy initialize-based revisions? |
| RQ3 | Among auth-gated endpoints, what share present a challenge an agent can follow: a Bearer WWW-Authenticate header and valid RFC 9728 protected-resource metadata? |
| RQ4 | Among endpoints that list tools anonymously, what share declare strict input schemas, safety annotations (readOnlyHint, destructiveHint) and descriptions? |
| RQ5 | What share return an in-channel error (JSON-RPC error or result.isError: true) when asked to call a tool that does not exist? |
| RQ6 | How repeatable is each endpoint's classification between two rounds? (Reported as re-test reliability; see Deviation 1.) |
- Not a quality ranking: it does not judge whether a server's tools are useful or correct.
- Not a security audit: no security payloads were sent and no real tool was ever called.
- Not a census of the private ecosystem: only publicly listed remote endpoints were measured.
2. Population and sampling
Source. The official MCP Registry API, GET https://registry.modelcontextprotocol.io/v0/servers?version=latest, fully paginated on 2026-10-12 between 02:34 and 02:48 UTC. All 422 raw response pages are archived in the repository so the population can be rebuilt exactly.
Unit. One remote endpoint (server.remotes[].url) of a server whose registry metadata says status: "active" and isLatest: true. Endpoints were de-duplicated by normalised URL (lower-case scheme and host; no query, fragment or trailing slash) but probed at their registered URL exactly as written, because some servers only answer at a trailing-slash path.
| Step | Count |
|---|---|
| Registry entries read (latest version of every server) | 42,176 |
| Latest, active servers | 41,660 |
| Servers listing at least one remote endpoint | 26,619 |
| Remote endpoint entries | 27,282 |
Excluded: URL contains template variables ({…}), needs per-user configuration | −283 |
| Excluded: non-HTTPS, invalid, private-address or opted-out hosts | 0 |
| Duplicate URLs merged | −634 |
| Sampling frame (unique remote endpoints) | 26,365 |
Frame SHA-256 ae90e534… and sample SHA-256 8e89d36d… are recorded in data/frame/*_meta.json.
Sample. The pre-registered rule was: probe the whole frame if it has ≤ 5,000 endpoints, otherwise draw a simple random sample of 3,000 with random.Random(20261012). The frame was far larger, so 3,000 endpoints were drawn. They sit on 2,245 distinct hosts; the largest single host accounts for 261 of them.
Smithery's registry API needs an account key and Glama publishes no list endpoint, so both were left out rather than scraped. This is a stated limitation: the study describes the official registry, not every MCP listing site.
Host clustering
A 25-endpoint pilot (run before the pre-registration was frozen and excluded from all results) showed that a handful of hosts publish hundreds of registry entries — one host had 276 of the first ~12,000. A few bulk publishers could therefore dominate endpoint-level percentages. Every headline share is reported twice: per endpoint (the primary result) and host-weighted, where each host counts once (the mean of within-host shares).
3. How the probe works
The harness (harness/probe.py) is a dual-era client: it follows the client-side backward-compatibility procedure written into MCP 2026-07-28 (Streamable HTTP § Backward Compatibility; Versioning § Backward Compatibility with Initialization-Based Versions). It tries the modern protocol first, falls back to the legacy handshake, and finally checks for the deprecated HTTP+SSE transport.
| Step | Request | When |
|---|---|---|
| 1 | POST server/discover with MCP-Protocol-Version: 2026-07-28, Mcp-Method and _meta (protocolVersion, clientInfo, clientCapabilities) | always |
| 2–3 | modern tools/list, then a modern tools/call on the non-existent tool __glintbase_probe_nonexistent_tool__ | server is modern-only: a supportedVersions result, or error −32020 / −32021 |
| 2 | legacy initialize with protocolVersion: 2025-11-25, retried once with 2025-03-26 if rejected with a JSON-RPC error | otherwise |
| 3–5 | notifications/initialized, tools/list, canary tools/call — with Mcp-Session-Id and MCP-Protocol-Version where the negotiated revision defines them | initialize returned a result |
| 6 | GET with Accept: text/event-stream, waiting ≤ 5 s for the HTTP+SSE endpoint event | initialize got no JSON-RPC answer |
| 7–8 | GET RFC 9728 protected-resource metadata: the URL in WWW-Authenticate resource_metadata, then /.well-known/oauth-protected-resource{path}, then the root | any step returned 401, or 403 with WWW-Authenticate |
- No real tool is ever called. The only
tools/calltargets a tool name that cannot exist, to observe how errors come back. - No security payloads. Nothing tries to break, bypass or stress a server.
- At most 8 requests per endpoint, one endpoint per host at a time, global concurrency 8, 10 s timeout per request (5 s for the SSE check).
- Up to 3 redirects are followed; redirects to private network addresses are refused.
- Honest identity:
User-Agent: GlintbaseResearch/1.0 (+https://glintbase.dev/research/bot; research@glintbase.dev)and MCPclientInfo.name: GlintbaseResearch. The public bot page explains the study and how to opt out; an opt-out list is checked before every request.
Responses are parsed robustly: plain JSON and Server-Sent Events (data: lines) are both handled, SSE streams are read only until the matching JSON-RPC response arrives, and bodies are capped at 512 KB. Only a 2 KB snippet of each response is kept in the private raw logs; the published data contains derived fields only.
Tested before use. The probe and classifier were tested against 12 local fixture servers that imitate every case the study distinguishes — a stateless 2026-07-28 server, a stateful legacy server with sessions and SSE replies, a legacy server that rejects the newest version, a legacy server answering unknown methods with HTTP 404, a server refusing 2026-07-28 with UnsupportedProtocolVersion, an SSE-only server, compliant and non-compliant auth, an HTML page, a 502, a server that never answers, and a paid (HTTP 402) endpoint. All 21 checks pass.
Vantage point. All probing ran from a single residential connection (AS36873, Airtel Networks, Nigeria). Latency and reachability figures reflect that location.
4. How outcomes were classified
Each endpoint receives exactly one primary status, checked in this order (harness/classify.py):
| Status | Rule |
|---|---|
excluded | opted out, or resolves to a private address at probe time |
unreachable | every protocol request failed below HTTP (DNS, connect, TLS, timeout) |
auth_compliant | 401 with a Bearer challenge and valid protected-resource metadata (resource string + non-empty authorization_servers) |
auth_noncompliant | 401, or 403 + WWW-Authenticate, without that |
ok | handshake succeeded (server/discover or initialize result) and tools/list returned a tools array |
handshake_only | handshake succeeded; tools/list did not |
modern_rejected | modern-only error code, but no successful result |
legacy_sse | HTTP+SSE endpoint event received (deprecated transport; not probed further) |
jsonrpc_error | answered in JSON-RPC but rejected initialize in both versions |
payment_required | HTTP 402 on the protocol requests (paid or disabled deployment) |
server_error | 5xx or 429 on the protocol requests |
not_mcp | anything else (HTML page, 404, non-JSON-RPC body…) |
Secondary fields recorded per endpoint: protocol era and version, supportedVersions, dual-era status (a modern server that also lists legacy versions), capabilities, whether a session was issued, handshake latency, tool count and pagination (only the first page of tools/list is analysed), the share of tools with a strict schema (an object inputSchema whose every property declares type/enum/const/anyOf/oneOf/allOf/$ref), the share declaring readOnlyHint or destructiveHint as booleans, the share with descriptions, whether the canary error came back in-channel and its HTTP status, and for auth-gated endpoints whether the challenge is Bearer and the metadata valid.
Statistics. Proportions with Wilson 95% confidence intervals; RQ1 also broken down by registry transport type; re-test agreement as percentage agreement and Cohen's κ. Every number on this page is produced by harness/compute_stats.py from the published data.
5. Results — does the endpoint answer as an MCP server? (RQ1)
Full size| Status | Endpoints | Share (95% CI) | Host-weighted |
|---|---|---|---|
ok — handshake + anonymous tools/list | 1,708 | 56.9% (55.2–58.7) | 48.1% |
auth_compliant | 726 | 24.2% (22.7–25.8) | 30.5% |
auth_noncompliant | 152 | 5.1% (4.3–5.9) | 6.4% |
unreachable | 142 | 4.7% (4.0–5.6) | 6.2% |
not_mcp | 122 | 4.1% (3.4–4.8) | 4.3% |
payment_required (HTTP 402) | 64 | 2.1% (1.7–2.7) | 1.2% |
server_error (5xx / 429) | 43 | 1.4% (1.1–1.9) | 1.8% |
jsonrpc_error | 16 | 0.5% (0.3–0.9) | 0.6% |
legacy_sse (deprecated transport) | 15 | 0.5% (0.3–0.8) | 0.6% |
handshake_only | 11 | 0.4% (0.2–0.7) | 0.2% |
modern_rejected | 1 | 0.0% (0.0–0.2) | 0.0% |
Host-weighted: each of the 2,245 hosts counts once. The gap between 56.9% and 48.1% shows that large bulk publishers are, on average, slightly more likely to work anonymously than single-endpoint hosts.
By transport listed in the registry
| Registry transport | Endpoints | `ok` | Notable |
|---|---|---|---|
streamable-http (current) | 2,868 | 1,698 | 715 auth-compliant, 147 auth-non-compliant, 120 unreachable |
sse (deprecated since 2025-03-26) | 132 | 10 | 54 returned HTTP 402 (mostly paid deployments); 15 still serve the legacy SSE handshake; 22 unreachable |
Endpoints still registered with the deprecated SSE transport are overwhelmingly paid, unreachable or legacy: only 10 of 132 work the modern way.
6. Results — which protocol revision do they speak? (RQ2)
1,772 endpoints completed a handshake. The probe always tries server/discover first, so a server is counted as modern only if it actually implements the 2026-07-28 revision.
Full size| Revision | Servers | Share of handshakes | Share of legacy servers |
|---|---|---|---|
| `2026-07-28` (modern) | 235 | 13.3% (11.8–14.9) | — |
2025-11-25 | 768 | 43.3% | 50.0% (47.5–52.5) |
2025-03-26 | 495 | 27.9% | 32.2% (29.9–34.6) |
2025-06-18 | 188 | 10.6% | 12.2% (10.7–14.0) |
2024-11-05 | 72 | 4.1% | 4.7% (3.7–5.9) |
non-conformant (claims 2026-07-28 via initialize) | 14 | 0.8% | 0.9% |
- Adoption is early. Eleven weeks after the revision shipped, about one in seven connecting servers speak it. A quarter of those (25.1%, 59 of 235) are dual-era: they also advertise legacy versions, so old and new clients can both connect.
- Legacy sessions are uncommon. Only 17.1% of legacy servers issued an
Mcp-Session-Id; most legacy deployments are effectively stateless already. - Non-conformant replies. 14 endpoints, all on one hosting platform, answer
server/discoverwithout the requiredsupportedVersionsfield and claim2026-07-28in reply toinitialize— a method that revision removed. Under the pre-registered rule they count as legacy-era. - Latency. The median handshake took 418 ms from the residential vantage point in Nigeria.
7. Results — can an agent follow the auth challenge? (RQ3)
When a server needs credentials, the MCP authorisation spec expects it to answer 401 with a WWW-Authenticate: Bearer header that points to RFC 9728 protected-resource metadata, which in turn names the authorisation server. An agent that finds both can start a standard OAuth flow without a human reading documentation.
| Measure | Endpoints | Share (95% CI) |
|---|---|---|
| Auth-gated endpoints (of 3,000) | 878 | 29.3% (27.7–30.9) |
| Compliant challenge — Bearer + valid metadata (of 878) | 726 | 82.7% (80.0–85.0) |
Sent a Bearer challenge (of 878) | 774 | 88.2% (85.8–90.1) |
| Served valid protected-resource metadata (of 878) | 743 | 84.6% (82.1–86.9) |
Nearly a third of listed endpoints need credentials, and more than four in five of those advertise a standard, machine-followable path to get them. The remaining 152 reject anonymous agents without saying how to authenticate — typically a bare 401, a custom error body, or a metadata URL that returns 404.
Auth only at call time. 53 auth-gated endpoints (37 compliant, 16 non-compliant) completed the handshake and listed their tools anonymously, but demanded credentials only when a tool was called. Under the frozen rule order (auth is checked before ok) they are counted as auth-gated.
8. Results — is tool metadata usable? (RQ4)
Agents choose and call tools from the metadata a server publishes: a name, a description, an input schema and, since 2025, optional hints that say whether a tool only reads data (readOnlyHint) or may destroy it (destructiveHint).
Full size| Measure | Value |
|---|---|
Median tool count (first page of tools/list) | 9 |
| Endpoints listing zero tools | 2 |
| Every tool strictly typed | 98.7% (98.0–99.1) |
| Every tool has a description | 100% (99.8–100) |
At least one readOnlyHint declared | 56.7% (54.3–59.0) |
At least one destructiveHint declared | 50.5% (48.1–52.8) |
Where tools are listed, the basic metadata is excellent — typed inputs and descriptions are nearly universal, which suggests SDKs generate them by default. Safety hints are the gap: around half of servers never say which tools are safe to call freely and which can destroy data, so an agent cannot tell a read from a delete without guessing from the name.
9. Results — are errors reported in-channel? (RQ5)
To see how errors come back, the probe called a tool that cannot exist (__glintbase_probe_nonexistent_tool__). A well-behaved server answers with a JSON-RPC error object or a result marked isError: true, so the agent knows the call failed and why.
Of the 1,773 endpoints that answered this call over HTTP, 75.1% (73.0–77.0) reported the error in-channel. The other 442 did not:
Full size| Response to the unknown-tool call | Endpoints | Share |
|---|---|---|
| JSON-RPC `error` or `isError: true` (correct) | 1,331 | 75.1% |
| HTTP 200 with no error signal (e.g. an error message inside a normal result) | 272 | 15.3% |
| Bare HTTP 404 | 133 | 7.5% |
| Required auth just to call a tool | 22 | 1.2% |
| Rate-limited (429) | 9 | 0.5% |
| Other | 6 | 0.3% |
272 servers answered a call to a non-existent tool with an ordinary successful result. An agent reading that response cannot tell the call failed — the classic setup for an agent confidently reporting a task as done when nothing happened. Of all the basics measured, error signalling is the weakest.
10. Results — re-test reliability (RQ6)
Round 3 re-probed all 3,000 endpoints immediately after round 2, with the same harness.
| Comparison | Endpoints | Same primary status | Cohen's κ |
|---|---|---|---|
| All endpoints | 3,000 | 93.4% (92.4–94.2) | 0.895 |
| Excluding one quota-limited gateway host | 2,806 | 99.6% (99.3–99.8) | 0.994 |
Almost every change between rounds — 183 of 199 — came from one gateway host with 194 sampled endpoints, which moved from ok to auth_compliant. The reason was us: the gateway's free anonymous tier allows 500 discovery requests and 50 tool calls per day, and our own repeated probing that day (including rounds later discarded) used up the quota. In round 3 the gateway correctly answered with a compliant auth challenge; in round 2, 9 of its endpoints were already partly affected.
With that host excluded, 99.6% of classifications reproduce, so the measurement is highly repeatable over short intervals. Because the rounds ran back to back (Deviation 1), this says nothing about how stable servers are over hours, days or weeks.
11. How the study actually ran
This is the complete record of what was done, in order, including the problems. All times are UTC on 2026-10-12.
- 02:34–02:48Registry snapshot
422 pages of the official MCP Registry (
version=latest) downloaded and archived. - ≈02:4125-endpoint pilot
Harness tested on real servers. Two changes followed: a separate
payment_requiredcategory for HTTP 402 responses, and the host-weighted view after finding one host with 276 registry entries. Pilot data is excluded from all results. - 03:17Frame and sample built
26,365 unique endpoints; seeded random sample of 3,000.
- ≈08:25Pre-registration frozen, bot page live
Protocol committed (
6112785) before any real data; https://glintbase.dev/research/bot published so operators could see who was probing and opt out. - 08:26–08:48Round 1 (later discarded)
Full sample probed. Re-test interval shortened to back-to-back for a one-day schedule and logged as Deviation 1 before round 2 began.
- ≈08:50Bug found in our own era-detection rule
273 endpoints (262 on one host) were labelled
modern_rejectedwithout ever being tried with the legacy handshake. The rule — written into the pre-registration — misread404+-32601onserver/discoveras a modern server. Round 2 was stopped after 449 endpoints. - 16:42Deviation 2 committed; both rounds restarted
Rule corrected to follow the spec, two new fixture tests added, faulty data archived as discarded (
41665a0). - 16:42–17:24Corrected round 1 contaminated
It overlapped another study's crawl on the same home connection;
unreachabledoubled from 140 to 271. Discarded and logged as Deviation 3. - 17:24–17:53Round 2 — the headline round
Run with the connection otherwise idle.
unreachable= 142, matching the isolated morning baseline of 140. - 17:53–18:16Round 3 — re-test
Same sample, back to back. Validation (30 endpoints, one sequential connection) ran alongside.
- after 18:16Analysis, quota finding, report
Statistics computed; the gateway quota exhaustion identified and reported; host names hashed in all summaries.
12. Validation
Before any number could be published, the pre-registration required ≥ 90% agreement on a stratified draw of 30 endpoints (seed 20261012), re-checked independently. A separate minimal client (harness/validate.py, written from the spec and sharing no request code with the probe) re-checked each endpoint live, and every disagreement was then reviewed against the raw logs.
| Probe said | Validator said | Cause |
|---|---|---|
auth_noncompliant | ok | Tools listed anonymously but tools/call returned 401 with no metadata; the frozen rule checks auth before ok, so the probe is correct by design. |
handshake_only | modern_rejected | The validator still used the pre-Deviation-2 rule for error −32022; the probe correctly fell back to initialize, after which the server returned 502s. |
jsonrpc_error | not_mcp | Python's urllib does not follow a POST 307 redirect; the probe did, and the server then rejected even initialize ("Missing session ID"). |
legacy_sse (×2) | not_mcp | The validator's blocking read timed out on the open SSE stream; the raw log shows the endpoint event clearly. |
ok | handshake_only | The validator was rate-limited (429) by a host with 194 sampled endpoints; at probe time tools/list returned tools. |
ok | jsonrpc_error | The validator lacks the pre-registered retry with 2025-03-26, which succeeded for the probe. |
The reviewer also wrote the probe, so this is a documented self-check, not an independent audit. An outside reviewer is recommended before the report is finalised.
13. Pre-registration deviations
The protocol was frozen in commit 6112785 before data collection. Three deviations were made afterwards, each logged and committed before the data it affects was analysed.
Deviation 1 — back-to-back re-test
- Change: the re-test interval was shortened from ≥ 6 hours to immediately after the headline round.
- Reason: the study timeline was compressed to one day.
- Consequence: RQ6 is reported as re-test reliability (probe repeatability and very short-term flakiness), not as same-day server stability.
Deviation 2 — era-detection rule corrected, both rounds re-run
- What was wrong: the frozen procedure treated
404+ JSON-RPC-32601onserver/discoveras a sign of a modern server. MCP2026-07-28requires modern servers to implementserver/discover, so that reply actually identifies a non-modern server. The rule also stopped on-32022(UnsupportedProtocolVersion), where the spec tells a dual-era client to retry with a supported version. - Fix: only a
DiscoverResultor a-32020/-32021error marks a server as modern-only;404/-32601and-32022fall back toinitialize; fixture tests added for both. - Impact: 271 endpoints (262 on one host) returned
404/-32601and 2 returned-32022; all had been labelledmodern_rejected. - Action: round 1 and the partial round 2 (449 endpoints) were archived as discarded and both rounds re-run in full. No discarded result was analysed.
Deviation 3 — contaminated round discarded
- What happened: the corrected round 1 re-run overlapped another study's crawl on the same residential connection. Its
unreachablecount was 271 against 140 in the isolated morning run; 151 endpoints that were reachable in the morning failed. - Action: the re-run was discarded; round 2 (connection otherwise idle) became the headline round and a round 3 in isolation the re-test. From then on no other study's traffic ran during MCP rounds.
- Scope: only the
unreachablecount was compared, as a contamination check, before the decision.
14. Limitations
- One registry. Listings are self-submitted and unvetted; Smithery and Glama are not included.
- One vantage point, back-to-back rounds. All traffic came from one residential connection in Nigeria; stability over hours, days or weeks is not measured.
- First page only. Only the first page of
tools/listis analysed. - Deprecated HTTP+SSE servers are detected but not handshaken.
- Some "failures" are deliberate — paid endpoints (HTTP 402) and servers that expect configuration headers declared in their registry entry.
- Measurement can change the measured. A gateway with a daily anonymous quota began requiring auth after our repeated rounds; bulk-hosted endpoints that share a quota are sensitive to repeated probing.
- The protocol revision is recent.
2026-07-28was published about 11 weeks before data collection, so adoption figures are an early snapshot. - Self-check validation. The validation reviewer also wrote the harness.
15. Ethics and what went wrong
The study sent metadata and protocol requests only, identified itself honestly with a public bot page and opt-out, probed one endpoint per host at a time and kept volumes small (at most 8 requests per endpoint per round). Raw responses are not published, and the report names no servers; host names in the published summaries are replaced by hashes.
Across this study's rounds, including discarded ones, we used up one gateway's free daily anonymous quota (500 discovery requests and 50 calls). Mitigation for future rounds: a per-host daily request cap set below published anonymous quotas, and fewer re-runs per day.
16. Reproducing the study
Everything needed to rebuild the frame, re-run the probe and recompute every number is in the public repository:
pip install -r requirements.txt python test_probe.py # 12 fixture servers; must print ALL PASSED python build_frame.py crawl # snapshot the official MCP Registry python build_frame.py frame # frame.csv + exclusion counts python build_frame.py sample --n 3000 --seed 20261012 python probe.py --sample ../data/frame/sample.csv --round 2 python classify.py --round 2 python compute_stats.py --round 2 --retest 3 --sensitivity-exclude-host-sha256 54b786edf0f9 python figures.py # the four figures on this page
Registry contents change daily, so a fresh crawl gives a different frame; the archived snapshot, frame and sample in data/frame/ reproduce this study exactly.
Data, code & links
Everything above is in this page. For readers who want the source material, the files below are the frozen pre-registration, the full report as plain text, the computed statistics and the open repository with the harness and per-endpoint data.
- Pre-registration and deviations The frozen protocol and all three logged deviations
- Full report (Markdown) The report this page is built from
- Summary statistics Every number with its denominator and 95% interval
- Validation results The 30 re-checked endpoints and reviewer notes
- Harness and per-endpoint data (GitHub) Probe, classifier, fixtures, registry snapshot, round data
- About the research bot What GlintbaseResearch requests and how to opt out
@techreport{glintbase2026mcpreliability,
title = {Remote MCP Server Reliability (2026): A Pre-registered Census of the Official MCP Registry},
author = {{Glintbase Research}},
institution = {Glintbase},
year = {2026},
month = {October},
type = {Draft Research Report},
url = {https://glintbase.dev/research/remote-mcp-server-reliability}
}Agent-readable version of this report: /research/remote-mcp-server-reliability.md