A person confirms which tools and values the agent may call on an MCP server. The guard refuses every other call before the server receives it. Permission is not proof: with no compiled integration the verdict is UNVERIFIABLE, never VERIFIED.
The guard costs one connection and one confirmation. A VERIFIED verdict costs a compiler run and a conformance run.
- Your agent calls a tool on the MCP server.
- The guard compares the call with the permission envelope: the tool names and argument values a person confirmed.
- The call runs, or the guard refuses it and the server receives nothing.
- The verifier reads the provider on a separate connection.
- The runtime evaluates the completion contract against that evidence and signs an Ed25519 receipt.
What is an MCP server? What is an integration?
An MCP server is a process that publishes a list of tools over the Model Context Protocol. Your agent calls them to act on a provider.
An integration is the package Provely compiles for one provider and signs. It states what "done" means there, and what proves it.
Explain: MCP servers, integrations, and Agent Skills
A server answers tools/list with one declaration per tool: a name and a JSON Schema for its arguments. One method, callTool({ name, arguments }), runs every tool. Provely reads that catalogue on connection, with no compiler run and no language model call.
An integration holds one completion contract for each completion level, the evidence channels each contract reads, the correlation strategy, the conformance results, and the certification. Provely signs the manifest with Ed25519, so a receipt names the version that judged an action.
Example: the Stripe integration holds 2 contracts, stripe.refund.created and stripe.refund.succeeded. Each one is a different completion level, and a lower level never proves a higher one. Read the Stripe integration.
An Agent Skill is the other object: one SKILL.md file in the Anthropic format that an agent loads and follows. Provely ships two kinds. The product skill provely-outcome-verification teaches any agent to verify before it claims done, and it renders for each host. Each integration also ships its own skill, for example provely-stripe, so an agent knows how to verify that provider. The machine plan stays in the signed manifest, and never in that file. An Agent Skill from someone else can call a provider itself, and Provely guards it at the call.
Provely publishes its own MCP server, with the four tools begin, verify, status, and receipt. Each handler reads the bearer token from the request, never from a tool argument. Read the Provely MCP server documentation.
What does the guard refuse?
Every call that the confirmed envelope does not name, before the MCP server receives it.
Example: a person confirmed 500 on charge ch_1001. A call for 5,000 never reached Stripe.
Explain: how the guard derives and enforces the envelope
deriveEnvelope reads the tool declarations of the server and the confirmed input, and it writes a policy. Every bound comes from a declaration: a value bound is a const on an argument whose declared name equals a confirmed input key. The comparison is exact, never a similarity.
The envelope is an allow list, not a checklist. A checklist asks whether the confirmed steps happened; an allow list also refuses everything else, so the policy states unlisted: 'refuse'. Provely closes each derived schema with additionalProperties: false, because an undeclared member is how a compromised server smuggles a payload past a check.
Every argument that no confirmed value bounds is marked REQUIRES_REVIEW. Provely never drops a part of a call in silence. The check compares two documents: it reads no text as an instruction, and it asks no language model. A schema that the checker cannot evaluate refuses the call, so the check fails closed.
| What the agent called | What the guard does | The reason code |
|---|---|---|
| A tool that the envelope does not name | The call does not run | step_not_in_confirmed_plan |
| A named tool with an argument value that no person confirmed | The call does not run | argument_outside_confirmed_input |
| An argument that the server never declared | The call does not run | argument_outside_confirmed_input |
| A declared schema that the checker cannot evaluate | The call does not run | argument_check_undecidable |
| A permitted tool of a provider that no integration covers | The call runs, and the verdict is UNVERIFIABLE | outcome_not_compiled |
A refusal happens before the provider call, and never after it. A control that reports a call after it ran is honest, and the money has already moved.
| The question | An MCP server with no integration | A compiled provider |
|---|---|---|
| Which calls may run? | The envelope, derived from the tool declarations | The envelope, derived from the confirmed contract input |
| A call outside the envelope | Refused before the provider | Refused before the provider |
| The verdict on the outcome | UNVERIFIABLE, reason outcome_not_compiled | VERIFIED, CONTRADICTED, FAILED, or PENDING |
| What you do first | Connect the server | Compile the provider |
| What that costs | One connection and one confirmation | A compiler run and a conformance run |
Does a permitted call prove the outcome? No.
Permission and completion are separate answers. With no integration the verdict is UNVERIFIABLE, reason outcome_not_compiled.
Explain: why a tool declaration cannot state completion
A tool schema states that a call takes an object and answers an object. It cannot state that a Shopify Refund object does not prove that money moved, or that a Square APPROVED payment is a hold.
| Provider | Completion level | What only a signed contract knows |
|---|---|---|
| Shopify | `created` | The created level proves that the Refund record exists with the requested amount and a refunds/create webhook. It does not prove that money moved. |
| Shopify | `financially_completed` | A Refund record does not prove money movement. This level proves the SUCCESS status on the refund transaction with the requested amount. |
| Square | `approved` | The card issuer authorised the amount, and Square holds the authorisation. This level does not prove a capture. The money did not move. |
| Square | `completed` | An approved payment is an authorisation hold, not a captured payment. This level reads the payment status and the card timeline together. |
The Square integration 0.1.0 records the row above under provider API version 2026-08-19. The compiler read it from the provider document below. A tool named create_payment declares an object, and the declaration names no hold and no capture.
Source: square.docs.payments · retrieved 2026-09-08
A completion contract derived from a tool schema could assert only "the tool answered". That is an acknowledgement at evidence level E1, and safety rule 5 forbids an acknowledgement as terminal success. So Provely writes no contract from a tool schema, and it states UNVERIFIABLE. Read the UNVERIFIABLE definition and what each verdict obliges an agent to do.
Provely publishes 16 compiled integrations today. Each one states the levels it certifies and its last conformance run. Read the compiled integrations.
A call to a provider with no integration never reaches VERIFIED. Only a compiled provider reaches VERIFIED.
Why not read the provider through that server?
That server sits on the action path. You give the verifier a separate connection.
Explain: the independence rule for a mediator
An MCP server is a transport. It is not an evidence channel. A verifier that reads a provider through the server that the agent used is no longer independent of the action path.
The evidence hierarchy rests on that independence. It runs from E0, a bare agent assertion, to E5, an outcome in an external system. E2 means a provider readback that the verifier made itself, and a reading that the action path returns is E1 at best. A compromised server would otherwise report a success and supply the evidence for it, which is a false VERIFIED.
- Give the verifier a separate connection to the provider.
- Make that credential read only, where the provider permits it. The agent never holds it.
- The verifier calls the provider directly, and never through the server of the agent.
- A provider that offers no direct read has no E2 channel, and the verdict is UNVERIFIABLE.
Never give an MCP server the credentials of the verifier. A hop on the action path is never new evidence. Read the evidence level definition.
What does the envelope not cover?
The envelope bounds the calls of the wrapped client. Three limits follow.
Explain: the three limits
| The limit | What the guard does not stop | What you must do |
|---|---|---|
| A side effect beside the guarded call | An Agent Skill that opens its own socket, writes a file, or calls a second server that no wrapper covers | Wrap every client that the file can reach, and read the file |
| An unbounded argument | An argument that no confirmed input names carries only the schema of the server | Read each argument that the envelope marks REQUIRES_REVIEW |
| A host with no blocking point | A host that reports a tool call after it ran cannot refuse it | Use a host that can block a call, and read the page of your agent host |
Provely contains the consequence of an attack. It reads no prompt, and it judges no reason for an action. The contract states what a person authorised, the evidence states what happened, and the difference decides the verdict.
How do you guard a server?
Read the tool declarations, let a person confirm them, wrap the client.
Explain: the code, and the questions readers ask
Guard a third-party MCP server with Provely
- Read the catalogueAsk the server for its tool declarations under
tools/list. - Confirm the planShow the person the tools and the input. Their decision bounds the envelope.
- Derive the envelopeCall
deriveEnvelope. It answers a policy and a review list. - Wrap the clientCall
guardMcpClient. Every later call passes the check first.
import { createToolGuard, deriveEnvelope, guardMcpClient, Provely } from '@provely/sdk';
const provely = new Provely();
// The declarations of the server. Provely reads them, and it reads no prose.
const declared = await client.listTools();
const envelope = deriveEnvelope({
source: 'payments-mcp',
tools: declared.tools,
// The input that the person confirmed. Each name bounds the argument of that name.
confirmed: { charge: 'ch_1001', amount: 500 },
});
// Every argument that no confirmed value bounds. A person reads each one.
for (const part of envelope.review) console.log(part.reason);
const guard = createToolGuard(provely, { policy: envelope.policy });
// The same client, with the one member replaced. The agent code does not change.
const guarded = guardMcpClient(guard, client);
The wrapper reads the tool name from each call, so one guard covers every tool of the server.
Does Provely need a compiler run before it guards a new MCP server?
No. The envelope comes from the tool declarations of the server and from the confirmed input. It guards a server that nobody has ever compiled, on the day you connect it.
What is the difference between an integration and an Agent Skill?
An integration is the signed package of completion contracts, evidence channels, and conformance results that Provely compiles for one provider. An Agent Skill is one SKILL.md file in the Anthropic format that an agent loads and follows. Each integration ships one, so an agent knows how to verify that provider.
May the verifier use the same MCP server as the agent?
No. That server is on the action path, so its reading is not independent evidence. You give the verifier its own connection, and the verifier calls the provider directly.