Zero-Trust Attestation
Prerequisites
Install MCP Fusion before following this guide: npm install @vinkius-core/mcp-fusion @modelcontextprotocol/sdk zod — or scaffold a project with npx fusion create.
- Sign at Build Time
- Verify at Startup
- Custom Signers
- Exposing Trust to MCP Clients
- Handling Attestation Failures
- Full CI/CD Pipeline
- Security Model
The Capability Lockfile captures the behavioral surface in version control. But what happens after deployment? A compromised dependency, a runtime mutation, or a misconfigured deploy could alter the tool surface between the lockfile check and the actual server startup.
CryptoAttestation closes this gap. Sign the server's behavioral digest at build time. Pin the expected digest as a deployment artifact. Verify it at startup. If the surface doesn't match, the server refuses to start.
When attestation is not configured, no cryptographic operations execute — the server startup path is identical to the default.
Sign at Build Time
import {
computeServerDigest,
attestServerDigest,
} from '@vinkius-core/mcp-fusion/introspection';
const serverDigest = computeServerDigest(contracts);
const attestation = await attestServerDigest(serverDigest, {
signer: 'hmac',
secret: process.env.FUSION_SIGNING_SECRET!,
});
console.log(attestation.signature);
// "a1b2c3d4e5f6..." (HMAC-SHA256 hex)
console.log(attestation.computedDigest);
// "7890abcdef12..."The built-in signer uses HMAC-SHA256 with a shared secret. This is sufficient for most production deployments — the secret never leaves your CI environment, and the signature proves the digest wasn't tampered with between build and deploy.
Verify at Startup
Store the computed digest from CI as an environment variable, then verify at startup:
import {
computeServerDigest,
verifyCapabilityPin,
} from '@vinkius-core/mcp-fusion/introspection';
const currentDigest = computeServerDigest(contracts);
await verifyCapabilityPin(currentDigest, {
signer: 'hmac',
secret: process.env.FUSION_SIGNING_SECRET!,
expectedDigest: process.env.FUSION_EXPECTED_DIGEST!,
failOnMismatch: true,
});If the behavioral surface changed between build and startup, the server refuses to start:
[MCP Fusion] Zero-Trust attestation failed:
computed digest 9a8b7c6d... does not match expected a1b2c3d4...This catches supply-chain attacks, dependency mutations, and deploy misconfigurations — anything that alters the tool surface after the CI check passed.
Custom Signers
For compliance requirements or external KMS integration, implement the AttestationSigner interface:
import type { AttestationSigner } from '@vinkius-core/mcp-fusion/introspection';
const kmsSigner: AttestationSigner = {
name: 'aws-kms',
async sign(digest: string): Promise<string> {
const { Signature } = await kmsClient.sign({
KeyId: process.env.KMS_KEY_ID!,
Message: Buffer.from(digest),
SigningAlgorithm: 'RSASSA_PKCS1_V1_5_SHA_256',
});
return Buffer.from(Signature!).toString('hex');
},
async verify(digest: string, signature: string): Promise<boolean> {
const { SignatureValid } = await kmsClient.verify({
KeyId: process.env.KMS_KEY_ID!,
Message: Buffer.from(digest),
Signature: Buffer.from(signature, 'hex'),
SigningAlgorithm: 'RSASSA_PKCS1_V1_5_SHA_256',
});
return SignatureValid!;
},
};Pass the signer instead of 'hmac':
const config: ZeroTrustConfig = {
signer: kmsSigner,
expectedDigest: process.env.FUSION_EXPECTED_DIGEST!,
};Any provider works — AWS KMS, GCP Cloud KMS, HashiCorp Vault, Sigstore. The interface requires two methods: sign(digest) and verify(digest, signature).
Exposing Trust to MCP Clients
After attestation, the server can expose a fusionTrust capability in the MCP server.capabilities object. This allows MCP clients to verify the server's behavioral identity before trusting tool responses:
import { buildTrustCapability } from '@vinkius-core/mcp-fusion/introspection';
const trustCapability = buildTrustCapability(
attestation,
Object.keys(contracts).length,
);The resulting FusionTrustCapability object:
{
serverDigest: "a1b2c3d4e5f6...", // SHA-256 behavioral identity
signature: "7890abcdef12...", // cryptographic signature
signerName: "hmac-sha256", // signer identity
attestedAt: "2026-02-26T12:00:00Z", // ISO-8601 timestamp
toolCount: 12, // tools covered
verified: true // attestation passed
}A client receiving this capability can verify that the server's behavioral surface matches what was signed at build time — before trusting any tool response.
Handling Attestation Failures
When failOnMismatch is true and the digest doesn't match, verifyCapabilityPin() throws an AttestationError:
import { AttestationError } from '@vinkius-core/mcp-fusion/introspection';
try {
await verifyCapabilityPin(currentDigest, config);
} catch (err) {
if (err instanceof AttestationError) {
console.error('Computed:', err.attestation.computedDigest);
console.error('Expected:', err.attestation.expectedDigest);
console.error('Error:', err.attestation.error);
process.exit(1);
}
}For standalone signature verification without capability pinning:
import { verifyAttestation } from '@vinkius-core/mcp-fusion/introspection';
const result = await verifyAttestation(currentDigest, storedSignature, {
signer: 'hmac',
secret: process.env.FUSION_SIGNING_SECRET!,
});
if (!result.valid) {
console.error(`Signature verification failed: ${result.error}`);
}All signature comparisons use timing-safe equality to prevent timing attacks.
Full CI/CD Pipeline
GitHub Actions
name: Capability Governance
on: [pull_request]
jobs:
governance:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: '22' }
- run: npm ci
- run: npx fusion lock --check --server ./src/server.ts
- name: Compute behavioral digest
env:
FUSION_SIGNING_SECRET: ${{ secrets.FUSION_SIGNING_SECRET }}
run: |
DIGEST=$(node -e "
import('./src/server.ts').then(mod => {
const { compileContracts, computeServerDigest } = require('@vinkius-core/mcp-fusion/introspection');
const contracts = compileContracts([...mod.registry.getBuilders()]);
console.log(computeServerDigest(contracts).digest);
});
")
echo "FUSION_EXPECTED_DIGEST=$DIGEST" >> $GITHUB_ENVDeployment-Time Verification
deploy:
runs-on: ubuntu-latest
env:
FUSION_SIGNING_SECRET: ${{ secrets.FUSION_SIGNING_SECRET }}
FUSION_EXPECTED_DIGEST: ${{ vars.FUSION_EXPECTED_DIGEST }}
steps:
- uses: actions/checkout@v4
- run: npm ci
- name: Verify attestation
run: |
node -e "
import { compileContracts, computeServerDigest } from '@vinkius-core/mcp-fusion/introspection';
import { registry } from './src/server.ts';
const contracts = compileContracts([...registry.getBuilders()]);
const digest = computeServerDigest(contracts).digest;
if (digest !== process.env.FUSION_EXPECTED_DIGEST) {
console.error('Digest mismatch'); process.exit(1);
}
console.log('Attestation verified:', digest);
"Security Model
| Threat | Mitigation |
|---|---|
| Secret compromise | Use short-lived secrets or external KMS with key rotation |
| Supply chain attack | Attestation detects if the behavioral surface changed post-build |
| Runtime tampering | verifyCapabilityPin() at startup compares against the pinned digest |
| Timing attacks | timingSafeEqual for all signature comparisons |
| Replay attacks | Timestamp in attestation + digest uniqueness prevent replay |
Never hardcode signing secrets. Always read them from environment variables or your platform's secret management (Vault, AWS Secrets Manager, etc.).