---
license: cc-by-4.0
pretty_name: HISTOR — MCP tool definitions and how they change
language:
- en
tags:
- mcp
- model-context-protocol
- ai-security
- prompt-injection
- tool-poisoning
- transparency-log
size_categories:
- 10K<n<100K
configs:
- config_name: servers
  data_files: servers.jsonl.gz
- config_name: toolsets
  data_files: toolsets.jsonl.gz
- config_name: changes
  data_files: changes.jsonl.gz
- config_name: scans
  data_files: scans.jsonl.gz
- config_name: classifications
  data_files: classifications.jsonl.gz
---

# HISTOR snapshot 2026-10-20: what MCP servers advertise, and when it changes

HISTOR reads the tool list (`tools/list`) of every remote MCP server in the official MCP registry
once a day, and of npm/PyPI MCP packages run in a sandbox once per published version (new versions
first, a few hundred a day). It records the exact tool definitions,
pins them by digest, and writes a signed label to a public RFC 9162 Merkle log whenever a tool set
first appears, stays the same, or changes. This snapshot is that record as files.

- **81,879** listed servers (31,040 remote endpoints, 50,839 packages), plus 2,078 delisted
- **38,126** with a recorded tool set; **9,340** changed at least once
- **23,821** recorded changes, 2026-09-24 to 2026-10-20
- **57,846** distinct tool sets (current ones and every one a change replaced)
- **636** servers with a block-tier WARDEN pattern match, **14,379** advise-only

Live view and per-server pages: https://histor.modelmarket.dev · code: https://github.com/alexar76/histor

## Files

| File | Rows | Size | SHA-256 |
| --- | ---: | ---: | --- |
| `servers.jsonl.gz` | 83,957 | 16 MB | `7e96f47212faac4a…` |
| `toolsets.jsonl.gz` | 57,846 | 377 MB | `9d5f8493910741c0…` |
| `changes.jsonl.gz` | 23,821 | 28 MB | `8df3d75824a25050…` |
| `scans.jsonl.gz` | 21,060 | 1 MB | `93dc0b3ff3e21e65…` |
| `classifications.jsonl.gz` | 4,197 | 234 kB | `aff254e31a921157…` |
| `pattern-set.json` | — | 15 kB | `60acb871b98d3ad9…` |
| `record-set.json` | — | 2 kB | `9e531b7098f7b508…` |

`manifest.json` holds the full hashes and the counts, signed by the log's key `did:key:z6Mkw1CVxsPj9utYp7VXWEbuuGM9Ev47itwKu1UfKd5ByxR9`
(type `histor.dataset/v1`, Ed25519 over RFC 8785 JSON). It also carries the signed tree head the
export started under (tree size 792,295), so any label id below can be checked
against the live log with `GET https://histor.modelmarket.dev/api/v1/labels/<id>/proof`.

## Fields

Fields whose shape varies between servers are JSON text (`*Json`), so every file loads as a flat
table. Digests are SRI strings (`sha256-…`) over the RFC 8785 form of the value.

- **servers** — `id` (stable per name+endpoint), `name`, `title`, `description`, `endpoint`
  (`https://…` or `npm:`/`pypi:` for packages), `transport`, `registry`, `version`, `repository`,
  `firstListed`/`lastListed`, `delisted`, `skipReason` (why it was not dialled), `lastStatus` and
  `lastDetail` (the last attempt's outcome), `lastObserved`, `toolCount`, `toolSetDigest` (join to
  toolsets), `firstPinned`, `unchangedSince`, `attempts`, `observations`, `changes`,
  `blockMatches`/`adviseMatches`/`recordMatches`, `classifierFlags`, `chainLabel` (latest label id), `page`.
- **toolsets** — `digest`, `toolsJson` (the tool list exactly as served: names, descriptions, input schemas).
- **changes** — `serverId`, `observedAt`, `fromToolSetDigest` → `toToolSetDigest`, `summaryJson`
  (tools added, removed and changed, with the field that moved), `labelId` (the signed continuity label).
- **scans** — `toolSetDigest`, `patternSet`, `matchesJson` (rule code, tier, severity, tool, where).
  The rules are in `pattern-set.json`. A match is a pattern hit to look at, not a verdict.
- **classifications** — `toolSetDigest`, `model`, `verdictJson`: an LLM's advisory reading of the
  tool set. Not reproducible, so it never enters the signed log.

## Load it

```python
import pandas as pd
servers = pd.read_json("servers.jsonl.gz", lines=True)
changes = pd.read_json("changes.jsonl.gz", lines=True)
```

```sql
-- DuckDB
SELECT name, count(*) AS changes FROM 'changes.jsonl.gz' c
JOIN 'servers.jsonl.gz' s ON s.id = c.serverId GROUP BY name ORDER BY changes DESC LIMIT 20;
```

## What it is not

- A tool list is what a server advertised to an anonymous client on that day. Servers that need
  credentials, or that refused HISTOR, have no tool set here (`lastStatus`, `skipReason` say why).
- Pattern matches and classifier flags point at text worth reading; they do not say a server is malicious.
- A change is a change in the definitions, not a judgement of it. Most are ordinary releases.

## Cite

Artamokhov, A. (2026). *HISTOR snapshot 2026-10-20: MCP tool definitions and how they change* [Data set].
Zenodo. https://doi.org/10.5281/zenodo.23512760

This snapshot's DOI is 10.5281/zenodo.23512760; all snapshots: https://doi.org/10.5281/zenodo.23512759.
Also on Hugging Face: https://huggingface.co/datasets/alexar76/histor-mcp-tool-definitions (tag `snapshot-2026-10-20`).

## License and rights

The compilation, digests, labels, scans and verdicts are CC-BY-4.0. Tool names, descriptions and schemas are reproduced as each server
published them; their rights stay with their authors. They are included so the definitions can be
studied and checked. A server operator who wants out: open an issue on https://github.com/alexar76/histor with the
endpoint or host. Opted-out servers are left out of every later snapshot.
