Methodology
This page sets out where the data comes from, which part of it is published, and by which rule every derived value is formed. Values derived from a vendor's own declaration are published without human review only when the derivation rule is disclosed here, the raw declaration is shown next to the derived value, and the rule applies without judgement.
Where the data comes from
The stock rests on 2 sources in operation: MCP-Register and Agentensaat.
The MCP servers come from the public MCP registry at registry.modelcontextprotocol.io, endpoint /v0/servers. It is collected once a day at 01:17, in a single pass over all pages, in full and without selection. That describes the collection; which part of it is published is set out in the next section. The coding agents do not come from there: they come from a curated file that ships with the source code and appears in this registry under the source name Agentensaat.
Only what the source itself states is collected. This registry does not fetch any of the URLs it lists and does not look at what is behind them; it adds nothing from other sources and builds no profiles. Where a value is derived from a source's declaration, the raw declaration is shown beside it and the rule is listed in the table below.
Built and not switched on
ACP-Register, switched off since 2026-08-16.
Address: https://cdn.agentclientprotocol.com/registry/v1/latest/registry.json
Values from it stand on 0 entries of this stock.
Reason, quoted unchanged from the operating record: Gebaut, aber nicht eingeschaltet: Die Anbindung einer fremden Quelle ist eine Entscheidung des Betreibers (Lizenzlage der Fremddaten, Abwaegung nach Art. 6 Abs. 1 lit. f DSGVO wegen des Feldes authors, Zuordnung der Autoritaet). Einschalten mit UPDATE quelle SET abgeschaltet_seit = NULL, abgeschaltet_grund = NULL WHERE bezeichnung = 'ACP-Register';
A source that is switched off is fetched by no run. It stands here because switching off would otherwise be hiding.
What is published
The full set of entries is published. The registry holds 24,507 entries, 24,507 of them are publicly available, and 0 are withheld.
Until 8 August 2026 part of the set was withheld: every entry whose identifier carries the account name of a person. Those entries have been public since. If you are a data subject and do not want to appear in this registry, object informally to the address given in the legal notice; the entry is then deleted and the identifier blocked permanently.
Of the entries that are published, 24,507 are released to search engines; that is the sum of the figures the home page gives per section. All four figures are counted from the database on every request.
Licence status, checked on 2026-08-06: the modelcontextprotocol/registry project covers only code and documentation in its LICENSE; it says nothing about the server entries submitted to it. This is a documented status with a check date and not legal advice. This registry reports what its sources state and gives no assurance that those statements are correct.
The published rules
Every rule by which this registry forms something else out of a source's declaration is set out here with its version. The tables are read from the source code, not copied: a rule added there appears here the same day.
Derivation rules
Derivation rule version: 2
| zugangsdaten_erforderlich | True when the registry lists at least one environment variable OR at least one remote endpoint header with isSecret = true and isRequired = true. Both raw values are listed separately.
Raw declaration:
roh_geheime_pflichtvariablenApplies to:
mcp_serverApplies without judgement |
|---|---|
| ausfuehrungsort | "remote" when only remotes or HTTP transports are listed, otherwise "local". The registry stores these as "entfernt" and "lokal".
Raw declaration:
roh_transportartenApplies to:
mcp_serverApplies without judgement |
| dateisystem_pfadargument | True when at least one package or runtime argument OR at least one environment variable carries format = filepath.
Raw declaration:
roh_pfadargumenteApplies to:
mcp_serverApplies without judgement |
| quelloffen_einsehbar | True when the registry lists a repository URL. That says nothing about what is behind it: the registry never fetches the URL.
Raw declaration:
roh_repository_urlApplies to:
mcp_serverApplies without judgement |
Decomposition rules for raw declarations 17 rules · Version 1
How a field of the raw record becomes a stored value: which parts are joined, how they are sorted and what separates them. A decomposition does not judge, it rewrites.
| Rule | Field in the raw record | What it does |
|---|---|---|
roh_geheime_pflichtkopfzeilen | remotes[].headers[] | The names of all remote endpoint headers with isSecret = true AND isRequired = true, deduplicated, alphabetical, comma separated. A header without a name appears as "Kopfzeile ohne Bezeichnung". |
roh_pfad_umgebungsvariablen | packages[].environmentVariables[] mit format = filepath | The names of all environment variables with format = filepath, deduplicated, alphabetical, comma separated. |
roh_remote_adressen | remotes[].url | Every URL unchanged, deduplicated, alphabetical, comma separated. Measured on 15 Aug 2026, none of the 11600 URLs in the raw dump contains whitespace, so the separator is unambiguous. |
roh_remote_hosts | remotes[].url, Hostname | The hostname of every remote URL, without port, deduplicated, alphabetical. A URL that cannot be parsed yields no host; the URL itself remains listed next to it. Two entries naming the same host says nothing about who owns it. |
roh_statusmeldung | _meta["io.modelcontextprotocol.registry/official"].statusMessage | The registry text accompanying a status change, unchanged and not truncated. No text means the registry does not carry one. |
roh_veroeffentlicht_am | _meta["io.modelcontextprotocol.registry/official"].publishedAt | The calendar day of the first registry entry. The timestamp is truncated to the day; the full value remains in the archived raw dump. |
roh_aktualisiert_am | _meta["io.modelcontextprotocol.registry/official"].updatedAt | The calendar day of the last change in the registry, truncated as above. If it differs from the first entry, the record was updated afterwards. |
roh_schemafassung | server.$schema | The URL of the schema the raw record was published against, unchanged. |
roh_bereitstellungsform | packages[] und remotes[] | "paket" when the raw record lists packages and no remotes; "remote" the other way round; "paket und remote" when both; "keines" when neither. This counts whether the list has entries, nothing more. |
roh_repository_quelle | repository.source | The repository platform as stated, unchanged. That says nothing about what is behind it: the registry never fetches the URL. |
roh_repository_unterordner | repository.subfolder | The subfolder inside the repository, unchanged. It is present where the server lives inside a shared repository. |
roh_paketbezeichner | packages[].identifier | ALL package identifiers, deduplicated, alphabetical, comma separated. The column `paket_koordinate` carries only the highest ranked one; measured on 15 Aug 2026 that dropped the rest for 173 entries. |
roh_paketversionen | packages[].version | The version strings of all packages, deduplicated, alphabetical. They may differ from the server version. |
roh_laufzeithinweise | packages[].runtimeHint | The runtime hints of all packages, deduplicated, alphabetical, separated by " · ". The field is free text: measured on 15 Aug 2026, 2 of 396 values contain a comma themselves, one an entire paragraph. Hence not the comma. |
roh_umgebungsformate | packages[].environmentVariables[].format | The format values that occur, deduplicated and alphabetical. Which variable carries which format is not stated here. |
roh_umgebungsbeschreibungen | packages[].environmentVariables[].description | For each environment variable with a description, a pair "NAME=text", sorted by name, separated by " · ". Split at the FIRST equals sign: measured on 15 Aug 2026, 12 of 1720 descriptions contain one themselves, but not a single one contains the separator " · ". The text is left unchanged. |
roh_symbolformate | icons[].mimeType | The format values of the icons, deduplicated and alphabetical. The IMAGE URL is deliberately not carried: measured on 15 Aug 2026, 895 icon URLs are spread over 601 third party hosts, and shipping one would hand each of them the visitor IP. |
read from: lib/ableitung.js
Matching rules of the coordinate search 9 rules · Version 2
Which input forms the coordinate search extracts a package identifier from. The order is part of the rule: the command forms match before the bare identifier. If none matches, nothing is guessed.
Pattern and example are language-neutral in the source code and are reproduced verbatim.
| Rule | Pattern | Example | What it does |
|---|---|---|---|
koordinate | ^(npm|pypi|oci|nuget|mcpb|cargo|name):(@?[\w.-]+(?:\/[\w.-]+)*)$ | pypi:unraid-mcp | A package coordinate in the form this registry itself prints: source, colon, identifier. The part after the colon must itself be an identifier. |
purl | ^pkg:(?:npm|pypi|oci|nuget|cargo|mcpb)\/(\S+?)(?:@[^/@\s]*)?$ | pkg:npm/@modelcontextprotocol/server-filesystem | A package URL in purl notation. |
npx | \bnpx\s+(?:-{1,2}[a-z-]+\s+)*(@?[\w.-]+(?:\/[\w.-]+)?) | npx -y @modelcontextprotocol/server-filesystem | A start command using npx. The switches of npx itself are skipped. |
uvx | \b(?:uvx|pipx\s+run)\s+(?:-{1,2}[a-z-]+\s+)*([\w.-]+) | uvx mcp-server-git | A start command using uvx or pipx run. |
pip | \b(?:uv\s+)?pip\s+install\s+(?:-{1,2}[a-z-]+\s+)*([\w.-]+) | pip install mcp-server-git | An installation with pip or uv pip. |
docker | \b(?:docker|podman)\s+run\b[^\n]*?\s((?:[\w.-]+\/)+[\w.-]+)(?::[\w.-]+)?\s*$ | docker run -i --rm mcp/everything | A container image from a docker or podman command. A trailing version tag is dropped, because the command in front says what is meant. |
dnx | \bdnx\s+(?:-{1,2}[a-z-]+\s+)*([\w.-]+) | dnx Some.Mcp.Server | A start command using dnx. |
registername | ^([\w.-]+\/[\w.-]+)$ | io.github.modelcontextprotocol/servers | Two parts separated by a slash, the shape of a registry identifier. The rule describes the shape, not the origin. |
bezeichner | ^(@?[\w.-]+(?:\/[\w.-]+)*)$ | @modelcontextprotocol/server-filesystem | A bare package name, with or without a scope. |
read from: lib/koordinatenfund.js
Start templates of the configuration builder 3 rules · Version 1
Which start command is formed from which package registry. For a package registry without a template nothing is produced, not even cautiously.
| Package registry | Command | What it does |
|---|---|---|
npm | npx -y {kennung} | Package registry npm: invoked through npx with the identifier from the package coordinate. |
pypi | uvx {kennung} | Package registry PyPI: invoked through uvx with the identifier from the package coordinate. |
oci | docker run -i --rm {kennung} | Package registry OCI: invoked through docker run with the image name from the package coordinate. |
read from: lib/konfiguration.js
How the namespace is formed 1 rule · Version 1
How the namespace of an entry is formed from its registry name. That two entries carry the same namespace means they carry the same measured value, and nothing beyond that.
| Rule | What it does |
|---|---|
namensraum | The part of the registry name before the first slash. If the name contains no slash, it has no namespace. The rule applies without judgement; it says nothing about who owns a namespace. |
read from: lib/namensraum.js
Name neighbours 5 rules · Version 1
By which rule two identifiers count as close. The threshold decides every figure on the tool page: the same comparison yields 2161 pairs without it and 165 with it.
| Rule | What it does |
|---|---|
anzeigename | Two entries carry the same display name. The comparison ignores case and surrounding whitespace, and counts only across the namespace boundary. |
lokalname | Two entries carry the same part after the first slash, in different namespaces. Purely generic names are left out: mcp, mcp-server, server, api. |
abstand | The Levenshtein distance between two complete identifiers, lowercased. Distance 1 and distance 2 appear in separate sections, because they are differently wide. |
kontoname | If an identifier carries a person's account name, its distance to other identifiers is not computed - neither over the full identifier nor over the local name, and on both sides of the comparison. Equality is still shown: that two entries carry the same local name is a finding. A distance is a claim about how close two names are, and this registry makes no claims about people's names. |
mindestlaenge | A minimum length of 6 characters applies to the similarity comparison over the local name. Measured on 15 Aug 2026, the same comparison yields 2161 pairs without it and 165 with it: "mcp" is one step from "mc" and one from "rmcp". It does not apply to equality - that two entries carry the same local name is a finding, not a guess. |
read from: lib/nachbarn.js
Environment variables 4 rules · Version 1
How single variable names are formed from a stored raw declaration, why ordinary and secret ones are never added, and how a description line splits into name and text.
| Rule | What it does |
|---|---|
namen | The names are formed by splitting the stored raw declaration at the separator this registry set when reading it in. Duplicates are removed per entry: naming the same variable twice still makes one entry that names it. |
getrennt | Ordinary and secret required variables are counted SEPARATELY and never added. The same name can appear in both - measured, APIFY_TOKEN does so 30 times - and a sum would therefore not be imprecise but wrong. |
beschreibung | A description line from the source has the form NAME=text and is split at the FIRST equals sign. The text after it often contains more; splitting at the last one would turn the measured text into a different one. A piece without an equals sign is dropped rather than shown as a name with empty text. |
variablensatz | What is compared is the SET of names of an entry: deduplicated and sorted. The order in which the source names them is left out of account - it is not a statement. All that is established is that two entries carry the same measured value. |
read from: lib/variablen.js
Domains 4 rules · Version 1
How a domain is formed from an address, why homepage and remote endpoint are counted separately, and what expressly does not follow from a shared domain.
| Rule | What it does |
|---|---|
domaene | The domain is formed by reading the address as a URL and taking its host name, lowercased and without a leading www. The port belongs to the address, not to the domain. An address that cannot be read as a URL drops out of the count and is named on the page. |
getrennt | Homepage and remote endpoint are counted SEPARATELY. Where the page of an entry lives and where its server connects to are two different declarations; a single figure would assert a connection that does not exist. |
plattform | Domains on which many unrelated parties publish appear in a table of their own: github.com, gitlab.com, bitbucket.org, codeberg.org, gitea.com, git.sr.ht, github.io, gitlab.io, sourceforge.net. Measured, github.com is named as a homepage by 816 namespaces; next to a domain with six that figure would look like a finding about 816 vendors, and it is none. |
keine_identitaet | NOTHING is derived from a shared domain. All that is said is that these namespaces name the same domain - not that the same vendor is behind them or that one belongs to the other. Who owns a domain is stated in no source this registry reads. |
read from: lib/domaenen.js
Splitting multi-valued raw declarations 4 rules · Version 1
How a cell holding several values is split back into those values. This rule decides every figure of the transport profile, the variable directory and the domain mirror; splitting at a different character invents values the source never stated.
| Rule | What it does |
|---|---|
trenner_liste | A raw declaration made of short identifiers is split at ", ", and expressly not at every comma. Measured on 15 August 2026 over the published set: splitting at every comma produced 5795 pieces from the remote addresses, 44 of them cut in half; splitting at the full separator produced 5751 and none cut. |
trenner_freitext | 2 raw declarations carry sentences rather than identifiers and are therefore split at " · ": roh_laufzeithinweise and roh_umgebungsbeschreibungen. In each of them, the comma demonstrably occurs inside the text itself. |
keine_entdopplung | If a cell states the same value twice, it appears twice. The repetition is an observation about the source and not noise; measured, 93 entries state "stdio, stdio" and 61 state "npm, npm". Neither is anything re-sorted: the order is the source's. |
leere_zelle | An empty cell yields no mention, not an empty one. In this registry it means "the source expressly declares nothing" and is therefore a measurement - but not a mention. |
read from: lib/mehrwert.js
Two registry names, one package 5 rules · Version 1
When two entries count as the same object, and how their agreement is measured. The result is an observation about the source and not a judgement about which of the two entries is the right one.
| Rule | What it does |
|---|---|
gruppe | A group is two or more entries carrying the same package coordinate. The coordinate is the identity of the PACKAGE, the registry name that of the ENTRY; where two registry names fall on one coordinate, the source has entered the same package twice. |
vergleichswert | Whether two entries of a group agree on a property is decided by the SORTED SET of their projection rows, not by the first row. Otherwise the figure on the page would depend on the insertion order of the database. |
gemessene_merkmale | Only the properties the holdings actually carry are compared, not those of the schema. A property no entry carries would count as "equal" in every group and would inflate the number of agreements without anything having been measured. |
name_koordinate | An entry without a package carries "name:<registry name>" as its coordinate. Such coordinates are not excluded; they simply can never form a group, because the registry name is unique. Measured, 5222 entries carry one and not a single group arises from them. An exception that never applies would be a rule whose failure nobody would notice. |
kein_urteil | The finding states that two records name the same coordinate, and nothing beyond that: no word about confusion, no statement which of them is the "right" entry, no recommendation. The registry has no basis for any of that. |
read from: lib/zwillinge.js
Reading version declarations 6 rules · Version 1
How a version declaration yields its numbers and those a class. The class describes which digits are present; it is not a grade for maturity or maintenance.
| Rule | What it does |
|---|---|
muster | Only the strict form is read: three dot-separated runs of digits at the start of the declaration. Whatever follows is kept as a suffix and not interpreted. Nothing is guessed - no "v1.0.0", no "1.0", no "nightly". Measured, this puts 13 of 6486 entries into the class unlesbar, which is the correct answer and not a gap. |
vor_eins | Major version 0. With it the SOURCE itself states that the interface is not yet settled (that is how SemVer 2.0.0 is worded). The registry reports that statement and does not make it. |
erstfassung | x.0.0 with x at least 1: neither the minor nor the patch position has been incremented. |
weitere | Any other readable declaration. |
zwei_fassungen | The version of the REGISTRY RECORD and the version of the PACKAGE stand side by side and are never added up. They answer different questions, and a sum would count the same entries twice. |
keine_note | The class describes which digits the declaration contains. It is not a judgement about maturity, maintenance or fitness; the registry knows nothing about those. |
read from: lib/versionsreife.js
Measuring the delivered wording 6 rules · Version 1
How names and description texts are counted, bucketed and checked for duplicates. What follows, follows from the count: a description at the maximum length is measured, "truncated" would be an inference.
| Rule | What it does |
|---|---|
laenge | CODE POINTS are counted, not bytes and not UTF-16 units. Measured, 830 entry names of the published set carry characters beyond the basic plane, and "x".length counts those twice. Changing this changes both median and maximum. |
anzeigename | An entry carries no display name of its own exactly when its name equals the registry identifier. The bare identifier then serves as the heading. |
dublette | A duplicate is a description text carried VERBATIM by more than one entry. The text is compared unchanged, without truncation and without normalisation. |
am_hoechstwert | What is counted is how many descriptions sit exactly at the maximum length of the holdings. That they are therefore "truncated" is an inference, not a measurement: a cap on the source's side is plausible and not proven. Hence the figure is called at the maximum and not truncated. |
raster | Lengths are bucketed into bands of 10 characters. The upper edge of the last band is the measured maximum and not the end of the grid: a band "100 to 109" would promise a range in which the measurement knows only a single value. |
sackgasse | Two separate figures, because there are two questions: who carries no homepage, and who carries neither a homepage nor a repository address. From an entry of the second kind no line leads out of the registry. |
read from: lib/wortlaut.js
The time axis of the source 5 rules · Version 1
How the two dates given by the source become days and months. The curve shows the history of the foreign registry, not this one's growth; this registry's own collection is shown separately beside it.
| Rule | What it does |
|---|---|
kalendertag | Counting is per calendar day as stated by the source itself: roh_veroeffentlicht_am and roh_aktualisiert_am. An entry counts once per day, even where several rows point to it. |
leerer_wert | The empty string is reported separately and is not counted as a day. It means "the source expressly declares nothing" and is therefore a measurement, but not a date. |
monatsraster | Days are bucketed into months, and the grid is GAPLESS: a month with no entry is shown as 0 and does not drop out. Otherwise the picture would draw eleven quiet months and one busy one as two bars of equal width side by side. |
nachgepflegt | An entry counts as maintained where its change date is LATER than its publication date. Both dates come from the source; the statement is theirs, not ours. |
eigene_erhebung | The time axis is the SOURCE's, not the growth of this registry. The registry's own collection is shown separately; its number of days is the statement that there is no history here, not the beginning of a curve. |
read from: lib/quellhistorie.js
Resolving the account name 4 rules · Version 1
How the account name contained in an identifier is extracted. This rule decides which identifiers belong to an objection – a rule by which data is erased belongs in the open.
| Rule | What it does |
|---|---|
plattform_praefix | This resolution covers identifiers starting with one of the 6 platform namespaces: io.github, io.gitlab, io.bitbucket, io.codeberg, io.gitea, ht.sr. An identifier outside them usually names a domain; that it may still carry an account name is a measured fact and is detected separately by comparing it with the repository address. |
bis_zum_schraegstrich | The account name is everything between that prefix and the FIRST slash. Without a slash there is no package and therefore no account part. |
normalisierung | Comparison runs through exactly one normalisation (surrounding whitespace removed, lowercased across all of Unicode) - the same one the erasure path uses. Measured, 3976 of 20380 identifiers carry capitals; two normalisations side by side would be the finding of 7 August 2026. |
kein_schluss | The resolution splits a string and nothing else. No vendor, identity or affiliation is inferred from the account name; two entries with the same account name carry the same measured value in their identifier, and nothing more is stated here. |
read from: lib/konto.js
tracevero · https://tracevero.com/methodik