top of page
Search

# Approved MCP Servers — Registry & Governance

Writer: Mark Kendall
Mark Kendall
2 days ago
6 min read

# Approved MCP Servers — Registry & Governance


## Why this document exists


Connecting to an MCP server is easy — that’s the point of the protocol.

A developer gets a URL (and maybe a header), points a client at it, calls

`list_tools()`, and starts calling capabilities. No new SDK, no bespoke

auth flow, no custom response parsing to learn per system.


That ease is exactly why this document matters. The protocol standardizes

*how* you connect. It says nothing about *what you’re allowed to touch*

once you’re connected. A read-only docs server and a server that can

write to production are indistinguishable at the protocol level — both

are just a URL and a `call_tool()` line. The governance has to live

somewhere else. This is that somewhere else.


## What this document is not


This is not an MCP tutorial. Developers can learn the plumbing — server,

client, transport, discover-then-call — from the project’s own

`README.md` and `docs/MCP_PLUMBING.md`. This document assumes that

literacy and focuses on one question: **which servers are your

developers allowed to connect to, and what is each one actually

authorized to do?**


## The registry


Every approved server gets one row. No server should be in active use

by a team without a row here.


|Server name |Connection string |Auth|Scope / capabilities |Uses sampling|Data sensitivity|Owner |Approved by|Review date|

|---------------------------------------|---------------------------|----|--------------------------------------------|-------------|----------------|------------------|-----------|-----------|

|*(example)* Joke of the Day (local dev)|`http://127.0.0.1:8000/mcp`|none|`joke_of_the_day`, `hello` — no side effects|no |none |Learning/demo only|— |— |

| | | | | | | | | |

| | | | | | | | | |


Fill in real rows as servers are approved. Column definitions:


- **Connection string** — the exact URL a client should be given.

Never a URL a developer has to guess or construct.

- **Auth** — `none`, `bearer token`, `OAuth`, or an internal scheme.

State it plainly; don’t make someone go read the server’s source.

- **Scope / capabilities** — the actual tool names and what each one

can do, not a vague category. “Can read tickets” and “can read and

close tickets” are different scopes and need different approval.

- **Uses sampling** — `yes` if any tool on this server can send a

request back to the connected client’s LLM (MCP’s sampling

capability) rather than just fetching or writing data. See “Servers

that call an LLM” below — this is a distinct risk category from

ordinary tool calls and needs its own sign-off.

- **Data sensitivity** — what kind of data flows through this server:

public, internal, confidential, regulated. This drives who’s allowed

to connect to it, not just whether it works.

- **Owner** — the team or person who runs the server and answers when

it breaks or is misused.

- **Approved by / review date** — who signed off, and when this row is

next due for re-review. Servers don’t stay approved forever by

default.


## Distributing this to developers


Two common patterns:


1. **A `MCP.md` per project or team**, checked into the repo itself,

listing only the servers relevant to that codebase — a subset of

this registry, scoped down. This is what a developer (or an AI

coding assistant reading the repo) actually consults day to day.

1. **A central registry** (this document, or a real internal service)

that project-level `MCP.md` files are generated from or link back

to, so there’s one source of truth for what’s actually approved.


Either way, a developer should never need to ask “is this server okay

to use” in a chat channel. The answer should be sitting in the repo.


## Scoping a new server before it’s approved


Before a server gets a row in the registry, whoever owns it should be

able to answer:


- **What can each tool actually do?** Read-only and read-write tools

should usually be separate tools, not one tool with a `mode` flag —

it’s easier to review and easier to restrict access to just the

read-only half.

- **What’s the blast radius of a bad call?** A tool that returns

documentation and a tool that deletes a record carry very different

risk even if both take one string argument.

- **Who can authenticate to it, and how is that credential scoped?**

Prefer tokens scoped to the minimum permission the tool needs, not

a general-purpose account credential reused across systems.

- **Is it logged?** If a tool call goes wrong, can you find out who

called it, when, and with what arguments?

- **What happens on a bad or unauthorized request?** A 401/403 is the

server doing its job. Confirm it actually returns one rather than

failing open.


## Servers that call an LLM


Most MCP servers just fetch or write data — a docs lookup, a ticket

query, a file read. Some servers do something different: a tool call

triggers its own LLM reasoning step, not just a data operation. This

is a distinct category and deserves its own line of review, because

the risk isn’t just “what data can this touch” — it’s “what can this

get a model to say or decide.”


There are two different mechanisms, and they carry different risk:


**1. The server calls its own LLM.** The tool holds its own API key

(OpenAI, Anthropic, whoever) and makes a model call as part of doing

its job — summarizing a document, classifying a ticket, drafting a

reply. This is straightforward from a governance angle: it’s really

just another external API call the server happens to make, and it

should be reviewed the same way you’d review any outbound call to a

third-party API — what data leaves, what comes back, who’s paying for

it, what happens if that model call fails or is slow.


**2. The server uses MCP sampling.** Instead of holding its own model

subscription, the server sends a request *back* to whichever LLM is

already connected as the client — the same model the developer or

agent is using — asks it to reason about something, and uses that

response inside the tool’s logic. No separate API key for the server

owner, no model lock-in. A server built this way can have no LLM of

its own at all; it’s pure orchestration that borrows the intelligence

already in the loop.


Sampling is the one to flag carefully in this registry, for two

reasons:


- **It’s a prompt-injection surface.** A sampling call lets a server

put text in front of *your* connected model and get it to act on

that text with your model’s authority — including, potentially,

authority to call other tools you’ve approved. A malicious or

compromised server can use sampling to try to manipulate the very

model that’s supposed to be deciding what to trust.

- **It’s not visible from the tool list alone.** `list_tools()` won’t

tell you a tool uses sampling — you have to know, or be told, or

read the server’s implementation. That’s exactly why it belongs as

its own column in this registry rather than folded into “scope.”


Any server with `Uses sampling: yes` should get the same level of

scrutiny you’d give a server that can call other approved tools on

your behalf — because that’s effectively what it can do.


## Header and credential handling — the short version


(Full detail in this project’s `README.md`, under “A note on headers

and security.” Restated briefly here because it’s the part most likely

to go wrong at organizational scale.)


- Credentials belong in environment variables or a secrets manager —

never hardcoded into a client script, a config file, or this

document.

- Prefer scoped, revocable tokens over shared or account-level

credentials. A leaked scoped token is a contained incident; a leaked

account credential is not.

- Connection strings in this registry should always be `https://` for

anything beyond local development. A credential sent over plain

`http://` is not actually protected by having one at all.

- Rotate and re-review tokens on a schedule, not only when something

goes wrong.


## Review cadence


Treat this registry the way you’d treat any access-control list: it

should be reviewed on a schedule, not just when a new server shows up.

A server that’s still approved but no longer used is a bigger risk

than one that was never approved — nobody’s watching it. At minimum:


- New servers: approved before first production use, not after.

- Existing servers: re-reviewed at the cadence set in the “Review

date” column — quarterly is a reasonable default absent a better

reason.

- Deprecated servers: removed from the registry and, ideally, from

DNS/routing — not just left off the list while still reachable.

 
 
 

Recent Posts

See All

Comments

Rated 0 out of 5 stars.
No ratings yet

Add a rating
Post: Blog2_Post

Subscribe Form

Thanks for submitting!

©2020 by LearnTeachMaster DevOps. Proudly created with Wix.com

bottom of page