Guided flow · ECZ-ID MCP Passport™
MCP guided flow
Carry an MCP server through the Accountability Chain: identify it, connect its operator, inspect and resolve it, understand its tools, bound tool use with Intent, evaluate invocations and re-verify the proof.
- Identify server
- Operator
- Inspect and resolve
- Tools
- Authority
- Intent
- Invocation
- Evidence
- Re-verify
Steps at a glance · what is live today
- 01Identify the MCP serverLive · public
- 02Connect the accountable operatorLive · public
- 03Inspect and resolveLive · public
- 04Understand its tools and capabilitiesLive · public
- 05Establish authorityLive · signed in
- 06Carry IntentLive · signed in
- 07Evaluate the invocationRelease-gated
- 08Keep the evidenceNo public retrieval
- 09Re-verify the proofLive · public
Live in production and publicly readable, with no account and no key.
GoalGive the MCP server a free ECZ-ID MCP Passport and declare it at your operator origin and in the MCP Registry.
Why it mattersOne logical MCP server is one Passport. Tools inside a server are never Passports, and endpoints, deployments and replicas are bindings.
Prerequisites
- An MCP server you operate.
- One identifier: its endpoint, its MCP Registry name, its repository or its package.
Example
curl -s https://developers.ecocitizenz.com/.well-known/ecz-mcp.jsonExpected output
{
"manifest_type": "ecz-mcp",
"operator_ecz_id": "ECZ-GB-RBS1NW",
"resolver_url": "https://resolver.ecocitizenz.org/p/ECZ-GB-RBS1NW",
"mcp_server": {
"name": "com.ecocitizenz/trust-mcp",
"transport": "streamable-http",
"endpoint": "https://trust-mcp.ecocitizenz.com/mcp"
}
}This is the first-party Trust MCP server’s declaration. It ties the server to its operator by declaration; the server does not hold an MCP Passport of its own.
What this proves
- Where the operator says the server belongs. A declaration is a pointer.
What this does not prove
- That the server is the operator’s: only a proven binding shows control.
- That its tools are safe.
Live in production and publicly readable, with no account and no key.
GoalResolve the Business Passport of the organisation that answers for the MCP server.
Why it mattersEvery child Passport resolves to one accountable organisation. A relying party who reaches the MCP server can always find who stands behind it, without asking.
Prerequisites
- The MCP server's ECZ-ID, or the parent ECZ-ID it names.
Example
curl -s https://api.ecocitizenz.com/api/p/ECZ-GB-RBS1NW.jsonExpected output
{
"ecz_id": "ECZ-GB-RBS1NW",
"resolver_v2": {
"record_type": "ECZ_ID_PARENT",
"state": {
"lifecycle_state": "ACTIVE",
"parent_tier": "VERIFIED",
"reliance_level": "PARENT_IDENTITY_ONLY"
},
"reliance": {
"can_rely_on": ["record_existence", "active_parent_state",
"current_parent_tier", "public_resolver_visibility"],
"reverify_before_reliance": true
}
}
}This is the operator record behind this site. Read parent_tier_context.tier_meaning on a child record: a parent tier is never inherited by a machine.
What this proves
- An accountable organisation exists and is publicly resolvable.
- Its current lifecycle state and parent tier, at the moment you read them.
What this does not prove
- That the organisation authorised any particular action by the MCP server.
- That the machine itself is verified, safe or compliant.
Live in production and publicly readable, with no account and no key.
GoalBefore a host connects, check the server’s public posture and inspect its configuration locally.
Why it mattersA host is about to give a server reach into its tools and data. Two cheap checks happen first: what the public record says, and what the configuration actually declares.
Prerequisites
- The server’s endpoint or ECZ-ID.
- Optional: VS Code with the free ECZ-ID MCP Trust extension.
Example
npx -y @ecocitizenz/ecz-id-mcp-verifier check --target https://trust-mcp.ecocitizenz.com/mcp --target-type mcp_serverExpected output
{
"target_type": "mcp_server",
"policy_mode": "OPEN",
"result_state": "NO_PUBLIC_RESOLVER_PROOF_FOUND",
"reason_codes": ["NO_PUBLIC_RESOLVER_PROOF_FOUND", "RESOLVER_READ_ONLY",
"LOCAL_POLICY_DECIDES"],
"primary_action": "CHOOSE_OPERATOR_PATH",
"exit_code": 0
}No MCP Passport proof for the first-party server, reported as absence. Locally, MCP Trust inventories the servers your workspace declares, with names, counts and key names only.
What this proves
- The server’s current public posture, and what your workspace declares about it.
What this does not prove
- That the server behaves as declared.
- Anything about servers your workspace does not declare.
Live in production and publicly readable, with no account and no key.
GoalKnow what the server’s tools can do before any agent calls them, and notice when that changes.
Why it mattersAn MCP server is only as consequential as its tools. A tool that quietly changes shape between versions is the change that matters most.
Prerequisites
- The ECZ-ID MCP Trust extension in VS Code.
What this proves
- What the server’s configuration declares, and what changed between your scans, all computed on your machine.
What this does not prove
- That a declared capability is safe, or that an undeclared one is absent.
Live in production and operated by the account holder, signed in, through the TrustOps Dashboard.
GoalState what the agent calling the server is authorised to do, within what bounds and for how long, and make every consequential action name that Intent.
Why it mattersThe Intent belongs to the actor, here the agent that calls the server. Tool patterns bound what it may invoke; excluded patterns always win.
Prerequisites
- An authorised ECZ-ID Intent in force (state
ACTIVE). - A single choke point in your code where consequential actions pass.
Example
{
"schema": "ecz.intent.v1",
"actor": { "kind": "ECZ_PASSPORT", "ecz_id": "ECZ-GB-EXAMPL::AGENT_PASSPORT-AB12CD", "family": "AGENT" },
"objective_summary": "Triage support tickets and issue small refunds",
"constraints": {
"actions": { "permitted": ["tool:search_tickets", "tool:create_refund"],
"excluded": ["tool:delete_*"] },
"financial": { "currency": "GBP", "max_per_action": 100, "max_total": 1000 },
"approval": { "required_for": [], "above_amount": 50 },
"rate": { "max_actions": 100, "window_seconds": 3600 }
},
"window": { "not_before": "2026-10-12T00:00:00Z", "expires_at": "2026-10-19T00:00:00Z" },
"state": "ACTIVE"
}In your system
// Your audit log: one entry per consequential action, written before it runs.
// ECZ-ID defines the Intent reference; the rest belongs to your system.
log.info('consequential_action', {
actor_ecz_id: 'ECZ-GB-EXAMPL::AGENT_PASSPORT-AB12CD',
intent_ref: { intent_id: 'INT-0000000000EXAMPLE0', version: 3 },
request_id: crypto.randomUUID(),
action: 'tool:create_refund',
amount: 40,
currency: 'GBP',
});Request identifiers, nonces and correlation IDs belong to the request, not the Intent. ECZ-ID defines no header for carrying an Intent reference over arbitrary protocols, and this site does not invent one.
What this proves
- What was authorised, as a versioned record with its bounds and window.
What this does not prove
- That any action stayed inside those bounds. Holding an Intent identifier authorises nothing by itself.
- That a sandbox Intent covers production. It never does.
Documented ahead of release.
GoalDecide whether the tool invocation's proposed action may proceed before it changes anything.
Why it mattersAn MCP gateway in front of the server is where an invocation can be held or blocked. IntentControl is designed to evaluate a proposed action against identity, authority, delegation, Intent, policy, current state and constraints. It is documented ahead of release, so today you decide with your own policy over live state.
Prerequisites
- A choke point in your code in front of the action.
- The counterparty or target ECZ-ID.
Example
// Runs today: your own policy over live Resolver state.
async function mayProceed(eczId) {
const res = await fetch('https://api.ecocitizenz.com/api/p/' + eczId + '.json');
if (res.status === 404) return { ok: false, why: 'NO_PUBLIC_ECZ_ID_FOUND' };
if (!res.ok) return { ok: false, why: 'RESOLVER_UNREADABLE', retry: true };
const v2 = (await res.json()).resolver_v2;
const failClosed = v2.machine_policy.fail_closed_states;
const ok = v2.state.lifecycle_state === 'ACTIVE'
&& !failClosed.includes(v2.state.lifecycle_state)
&& !failClosed.includes(v2.binding.state);
return { ok, why: v2.state.reliance_level };
}What this proves
- Your own decision, made on the current published state of the counterparty.
What this does not prove
- An Intent-bounded decision. That is IntentControl: its interface is release-gated and not callable, and commercially it is coming soon in TrustOps and not yet on sale.
- Enforcement. A decision only constrains actions routed through an enforcement point you run.
ECZ-ID Core records it, but public, unauthenticated retrieval and verification are not enabled.
GoalKeep a record of what the invocation did, and know what ECZ-ID publishes about it.
Why it mattersThe tool runs on the server; the result is the server’s output. A Receipt proves what the recording system recorded; it does not prove every real-world assertion behind it.
Prerequisites
- Your own audit log entry from the Intent step.
Example
curl -s https://api.ecocitizenz.com/api/p/ECZ-GB-RBS1NW.jsonExpected output
"evidence": {
"public_receipts_count": 0,
"public_receipt_state": "NO_PUBLIC_RECEIPT",
"public_receipt_retrievable": false,
"receipt_retrieval_state": "NONE_PUBLISHED",
"recorded_receipts_count": 1,
"reason_codes": ["RECEIPTS_RECORDED_NOT_PUBLICLY_RETRIEVABLE"]
}Recorded is not published. Decide on evidence.public_receipt_state and evidence.public_receipt_retrievable, the fields the record lists for machines.
What this proves
- Whether Core has recorded receipts for the subject, and whether any are publicly retrievable.
What this does not prove
- What any receipt says. Public retrieval and public verification are not enabled.
- That an action happened or succeeded. An allow is not a result, and a decision receipt is not an action receipt.
ReferenceReceiptsEvidenceReceipt reference
Live in production and publicly readable, with no account and no key.
GoalLet anyone who was not there re-check the server's public state, now and in CI.
Why it mattersEvery other link ends with a reader who was not present. Re-verifying closes the chain: the record is re-resolved live, never trusted from a cache.
Prerequisites
- Node 22.14+ for the verifier (its declared engine), or any HTTP client for the record.
Example
npx -y @ecocitizenz/ecz-id-mcp-verifier check --target ECZ-GB-RBS1NW --policy REQUIRE
# .github/workflows/ecz-id.yml — fails the job when proof is missing
- uses: Ecocitizenz/ecz-id-mcp-verifier@v0.9.0
with:
target: ${{ env.COUNTERPARTY_ECZ_ID }}
policy: REQUIREExpected output
{
"target": "ECZ-GB-RBS1NW",
"target_type": "ecz_id",
"policy_mode": "OPEN",
"result_state": "RESOLVER_VERIFIABLE",
"reason_codes": [],
"primary_action": "VIEW_RESOLVER_PROOF",
"verifier_writes_truth": false,
"exit_code": 0
}Measured the same day: an identifier with no public record returns NO_PUBLIC_RESOLVER_PROOF_FOUND, exit 0 under OPEN and exit 1 under REQUIRE.
What this proves
- The current published state, at the moment of the check, read live.
What this does not prove
- Safety, security, certification, compliance or approval.
- Anything about the state a minute later. Re-check before each reliance.
Where next
This page is explanation, not authority. Current state is only ever the live Resolver record. Commands were run read-only on 2026-10-10; illustrative examples are labelled.
