Iris MCP

Shared MCP servers

An MCP server (Model Context Protocol) gives an Iris extra tools: git, a database, a mailbox, a search index, your own service. This registry is the directory of the ones we host or trust, with what each one needs written out before anybody installs it.

If you are a language model: this page is also at /docs.md as plain Markdown, /llms.txt lists everything, and every server has a Markdown twin at /m/<name>.md with its address or command, its credential references, its tool list and where it came from.

Two shapes

ShapeWhat it isWhere it runs
stdioThe package carries the server itself (a .py or .js in the same flat folder).Inside one house's own sandbox, as that house, with nothing of ours and no vault.
streamable-httpThe server runs elsewhere and is reached over https.At whoever owns that address. Nothing of it is executed here.

The command of a stdio server must be a file in its own package. A listing can never start a program it does not carry, and installing one never downloads anything.

mcp.json

{
  "name": "github",
  "version": "1.0.0",
  "author": "Woodst",
  "description": "Issues, pull requests and code search from GitHub.",
  "tags": ["git", "developer"],
  "category": "developer",
  "license": "MIT",
  "sources": ["https://github.com/modelcontextprotocol/servers/tree/main/src/github"],
  "permissions": ["internet", "secrets"],
  "transport": "streamable-http",
  "url": "https://mcp.example.com/github",
  "tools": [{ "name": "create_issue", "description": "Open an issue in a repository." }]
}
FieldRequiredMeaning
nameyesLowercase letters, digits and -, at most 40. Equal to the folder name.
versionyesThree numbers. Every published version is final.
authoryesWhat you wrote it as. The registry stamps the entry with the house that submitted it: that house's public name if it has one, otherwise its house id, and Iris for what comes in without a house. Nothing a package claims can attribute work to somebody else.
descriptionyesOne sentence: what it makes possible.
transportyesstdio or streamable-http.
commandstdioA file in this package: the server. Run with python3 or node by its ending, or by its own #!.
argsnoUp to 20 texts passed to it. Never through a shell.
urlstreamable-httphttps only, a name and not an IP, and not a private address.
envno{ "GITHUB_TOKEN": "$GITHUB_TOKEN" } or { "API_KEY": "vault:github" }: references, never values.
permissionsyesFrom internet, files, secrets, phone, voice, messages. Be honest: people read this before installing.
toolsnoWhat it offers, [{ "name": ..., "description": ... }], shown in the directory. The server's own list is what counts once it runs.
categorynodeveloper, knowledge, productivity, communication, finance, home, media, other.
tagsnoUp to 12, lowercase with -.
licenseyesMIT, Apache-2.0, BSD-3-Clause, AGPL-3.0, MPL-2.0 or proprietary.
sourcesyes1 to 12 https links to the server's own documentation.

How much one house may submit

A review queue is read by a person, so one house cannot fill it:

  • at most 5 versions of one house may be waiting for review in one registry at the same time. A sixth is refused with a clear answer until one of them has been read;
  • a house may hold at most 50 names in one registry's store. A new name past that is refused; a new *version* of a name it already has is always welcome.

Both are counted per house and per registry, and both can be raised for a house that has a reason (REGISTRY_MAX_WAITING, REGISTRY_MAX_ENTRIES on the service). A contribution is never silently dropped: a refusal names the limit and what to do about it.

What the store refuses

  • A secret in the package. Every env value must be a reference. A written-out token is refused, with the file and the key named, before a person reads the submission.
  • http://, a bare IP, localhost, a .internal name or a private address range. A house must not be talked into fetching something inside our own network, and a token must not cross the wire in the clear.
  • Credentials in the URL. https://user:pass@host is refused; use a credential reference.
  • A command that is not in the package, or a file ending a server has no business carrying (.sh, binaries). Code in python, node or ts-as-source is what a sandbox can run.
  • A name that belongs to another house, a version that already exists, or anything over 6 MB.

Making one

~/mcp/things/
  mcp.json          what it is, how it is reached, what it needs
  server.py         the server (stdio), executable or run by its ending
  README.md         optional: shown in the directory
cd ~/mcp/things
mcp check            # is this folder a right server? (changes nothing)
mcp try              # start it here by hand and list its tools (stdio only, in this house)
mcp publish          # submit this version for review

mcp try starts the server in the house the way a client would, asks it for its tools and stops it again. Run it before publishing: a server that does not come up is not a server.

A remote server (already hosted somewhere) needs no package of code at all, only the mcp.json with its url: useful to share a well-known one, or a service of your own, with the same review and the same honest permission list.

Review, then public

A submission waits for a person to read it, exactly like a skill:

  • does the manifest describe what the server really does, and do the sources say so;
  • does permissions match the code: does it really only talk to the internet;
  • does it keep the owner's data in the house, or does it send it somewhere;
  • is a stdio package self-contained (no downloading at start), and does it start at all.

On a yes it is listed, committed to the public repository (github.com/okayiris/registry, under mcp/), and every house can install it. Nothing is published without this step, and a published version never changes: a fix is a new version.

Install in a house

Say "install the MCP server github", or:

mcp browse                    # what is in the directory
mcp search "git"              # find by word
mcp install github            # the newest version
mcp install github@1.0.0
mcp list                      # what this house has, and whether it is on
mcp remove github

Installing writes the server into the house's own ~/mcp/<name>/ and registers it with the assistant (dsh-mcp-client, one entry per server, in the house's own profile patch), so its tools become real tools. A version that asks for more permissions than the one installed is never swapped in silently: the house asks its owner first.

Own servers, from us

The registry is also where we keep the servers we host ourselves for every house: a shared address, one credential reference, no package to carry. They live in the public repository with the rest, so their manifests can be audited and improved by anyone, and a house installs them by name like any other.

Taking a submission back

Things change between submitting and being read: a source turns out wrong, a detail should not be public, the whole idea was worse than it looked. While a version is still waiting for review, the house that submitted it can withdraw it:

mcp withdraw github@1.0.0

Only that house's own waiting versions can go, and only while they are waiting. The house remembers what it submitted (mcp list shows it), so the name is enough; without that record the version has to be named. Once a version is published it is not withdrawable: other houses may already have installed it, so the way out there is a takedown by whoever runs the registry, and the public repository keeps the history either way.

Is it still what was published?

A published version never changes, so a difference between what you have and what the registry holds is local: an edit, or something else writing in the folder. That is checkable:

mcp verify github     # one entry against the registry's published hash
mcp verify                     # everything that came from the registry

It says which file differs (changed, missing, extra) and how to put the published version back: mcp install <name>@<version>. Installing a version you already have puts the published files back when the copy drifted, and says so, instead of answering "already here" over somebody's edit.

API

Read-only and public, and the same shape as the skills registry:

RequestReturns
GET /api/mcpEvery server, newest version first: the manifest plus versions, hash, published.
GET /api/mcp/indexThe same list as one object.
GET /api/mcp/<name>The newest package: meta, files (name to base64), hash, published.
GET /api/mcp/<name>/<version>That exact version.
POST /api/mcp/publishSubmit a version: { "files": { "mcp.json": base64, ... } }.

Publishing is signed by a house's own bridge and lands in the review queue.