MCP, Tool Governance & Distribution
Govern tool calls with the four-stage pre-execution chain, run a declarative MCP server registry with instant revocation, and distribute, version and roll back skills and plugins through signed catalogs.
On this page
TL;DR: A governed tool call passes a synchronous four-stage chain
before it runs: scope check, secret scan, blocklist, rate limit. Every
decision is audited under a trace id. The chain has run in warn mode since
2026-09-04. It records what it would have refused and lets the call
continue. Authentication and access-control entitlements are still enforced.
MCP servers are declared in services/mcp/ and administered at /admin/mcp,
with per-server OAuth scopes, entitlement by role or Entra group, and immediate
revocation. Skills and plugins are delivered through signed manifests. Each
marketplace version is a content hash that can be compared and rolled back.
Pre-execution governance
The chain runs before the tool executes, synchronously, on every
governed call. Local tools in Claude Code are governed through the hooks that
the dynapps-commons plugin installs. Routing model inference alone does not
govern local tools. The stages, as configured in
services/governance/config.yaml:
- Scope check. Tools prefixed
mcp__systemprompt__(the admin MCP server) need an admin caller. - Secret scan. The tool arguments are checked against credential
patterns owned by Dynapps (GitHub, Anthropic, OpenAI and Google keys, PEM
keys, JWTs, database URLs that embed a password, structured
password/secretfields). A high-entropy check runs alongside and only observes. - Blocklist. Tool names containing
delete,dropordestroy. - Rate limit. 300 calls per 60 seconds for each session and user.
Under enforce, the first deny wins and the call stops. Under warn, which
is how the instance runs today, each stage that would have denied writes a
decision = 'warn' row and the call proceeds, so a call can be recorded
against several stages at once. Governance Modes
explains the measurement window and how to switch each stage back to enforce.
systemprompt infra logs trace list --limit 20
systemprompt infra logs trace list --decision warn --since 24h
systemprompt infra logs trace show <trace-id>
systemprompt infra logs governance report --since 7d --group-by tool
What the secret and PII scanners detect on the gateway is covered in Content Safety, PII & Guardrails.
The MCP server registry
Each server is one YAML file under services/mcp/. This instance declares
five:
| Server | What it reaches |
|---|---|
systemprompt |
this platform's admin CLI. It cannot be removed and is admin-only |
atlassian |
Jira and Confluence, under each person's own Atlassian account |
salesforce |
Salesforce's hosted MCP, authenticated as the signed-in person |
sfcore_dev |
the SFCore team's development-workflow server, called with a short-lived token this instance signs |
Each server declares:
- Auth requirements: the OAuth audience (
mcp) and the scopes a caller's token must carry. - Entitlement: which roles, groups and projects reach it, declared in
services/access-control/rules.yaml. A person outside those bands sees no server at all, rather than an error on every call. - Revocation:
enabled: falsetakes a server out of service, and an entitlement can be removed or given an expiry in the console. Issued tokens are revoked one by one through JTI-based revocation, without waiting for them to expire.
/admin/mcp lists the fleet. /admin/mcp/<id> shows one server's tools,
callers, call log, connections, declaration, and who may reach it.
Tool schemas
A server with a missing or invalid manifest, or one whose declared database
schema fails to sync, is refused at registration, so a broken server is
caught before anyone calls it. Tool input schemas are captured at discovery.
On a gateway request, the request detail page puts the client's tools array
beside the one the gateway sent upstream, paired by name, so you can see what
the model was actually given.
Tool schema validation
A provider refuses a whole request when one offered tool schema is malformed,
so tool schemas are meta-validated before that can happen. Each inputSchema,
and the outputSchema when a tool declares one, is checked against:
- the JSON Schema meta-schema its
$schemanames, Draft 2020-12 when it names none (Draft 7 and the other standard drafts are recognised); - the shapes providers reject even when the meta-schema allows them: the top
level must be
type: object, a top-levelrequiredmay name only keys thatpropertiesdeclares, and no$refmay leave the document (only#/...references; nothing is fetched).
Where it runs:
| Where | What happens on a malformed schema |
|---|---|
The bundled systemprompt MCP server, at start |
It refuses to serve, and the error names the server, the tool, the schema side and the violation. |
| CI | The check-mcp-tool-schemas.sh gate checks every schema declared under services/mcp/ and proves the checker against fixtures; the unit tests run the full check over the bundled server's tools. |
| The request detail page | A client tool whose schema fails carries a schema errors badge and lists each violation. |
The checker is extensions/mcp/shared/src/tool_schema.rs. Servers that
list their tools only at runtime (external and connector servers) are
registered by core and are checked on the request page, not at registration.
Signed distribution, versions and rollback
Skills and plugins reach workstations through marketplaces, administered at
/admin/marketplaces, /admin/plugins and /admin/skills. The bridge
manifest records each skill's SHA-256 and is Ed25519-signed. A client
verifies the signature before installing, so nothing unsigned or tampered
with reaches a workstation. A signature proves integrity and origin; it
grants no model, MCP or tool access, which stays governed by access control.
Skills are the unit of prompt distribution, and they carry their own version lifecycle:
- Versions. A marketplace version is the content hash of what it
serves.
/admin/analysis/versionsshows each marketplace's history, compares two versions skill by skill, and shows which devices received which version. See Versions. - Updates. Content kept in an external kit is published by the kit's CI
and made live with Import on
/admin/sync, with no restart. See Update a Skill and Code ↔ Instance. - Revocation. A disabled skill is left out of every bundle, and a managed revision can be withdrawn. See Skills lifecycle.
- Rollback. Re-pin the kit to its previous digest and import it again. The cache keeps the last two trees, so a rollback is a re-point, not a download.
There is no separate parameterised prompt-template object. Prompts ship as skills.
Check it yourself
/admin/governance: the Decisions tab lists each chain stage's rows; under warn they are allwarn./admin/mcp: the five servers, each with its entitlement./admin/analysis/versions: marketplace versions by hash, with history and compare.systemprompt infra logs governance report --since 7d --group-by policysystemprompt core skills list