derive_credential
Create privacy-preserving verifiable credentials by selectively disclosing specific attributes from original credentials using JSON-LD frames and zero-knowledge proofs.
Instructions
Derive credentials with selective disclosure using JSON-LD frames. Supports credential chaining and zero-knowledge proofs for privacy-preserving presentations.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| originalCredential | Yes | W3C Verifiable Credential | |
| frame | Yes | JSON-LD frame for selective disclosure | |
| nonce | No | Nonce for derived proof |
Implementation Reference
- src/tools/deriveCredential.ts:9-187 (handler)Core handler implementation for 'derive_credential' tool. Validates input using DeriveCredentialInputSchema, calls HiveAuth API (/api/derive) with originalCredential and frame for selective disclosure derivation, performs field analysis for privacy summary, generates detailed markdown+JSON output, and falls back to simulation mode if API unavailable.export async function deriveCredential(args: any): Promise<CallToolResult> { // Validate and sanitize input const validation = validateAndSanitizeInput(DeriveCredentialInputSchema, args, 'derive_credential'); if (!validation.success) { return createValidationErrorResult(validation.error!); } const data = validation.data!; const { originalCredential, frame, nonce } = data; const HIVEAUTH_API_BASE_URL = process.env.HIVEAUTH_API_BASE_URL || 'http://localhost:3000'; const DERIVE_ENDPOINT = `${HIVEAUTH_API_BASE_URL}/api/derive`; try { console.log(`[DeriveCredential] Starting credential derivation for credential: ${originalCredential.id}`); const payload = { credential: originalCredential, frame, ...(nonce && { nonce }) }; const response = await fetch(DERIVE_ENDPOINT, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(payload), }); if (!response.ok) { const errorData = await response.json().catch(() => ({ message: response.statusText })); throw new Error(`Failed to derive credential: ${errorData.message}`); } const result = await response.json(); // Analyze the derivation const originalFields = extractCredentialFields(originalCredential); const derivedFields = extractCredentialFields(result.derivedCredential); const hiddenFields = originalFields.filter(field => !derivedFields.includes(field)); const revealedFields = derivedFields; const summary = [ `π **Credential Derivation Results**`, ``, `β’ Original Credential ID: ${originalCredential.id || 'Not specified'}`, `β’ Derived Credential ID: ${result.derivedCredential?.id || 'Generated automatically'}`, `β’ Derivation Method: ${result.derivationMethod || 'JSON-LD Frame'}`, `β’ Selective Disclosure: ${hiddenFields.length > 0 ? 'Yes' : 'No'}`, ``, `**π Field Analysis:**`, `β’ Original Fields: ${originalFields.length}`, `β’ Revealed Fields: ${revealedFields.length}`, `β’ Hidden Fields: ${hiddenFields.length}`, `β’ Privacy Level: ${Math.round((hiddenFields.length / originalFields.length) * 100)}% fields hidden`, `` ]; if (revealedFields.length > 0) { summary.push(`**β Revealed Fields (${revealedFields.length}):**`); revealedFields.forEach((field, index) => { summary.push(`${index + 1}. ${field}`); }); summary.push(``); } if (hiddenFields.length > 0) { summary.push(`**π Hidden Fields (${hiddenFields.length}):**`); hiddenFields.forEach((field, index) => { summary.push(`${index + 1}. ${field} (protected by selective disclosure)`); }); summary.push(``); } // Proof information if (result.derivedCredential?.proof) { const proof = result.derivedCredential.proof; summary.push(`**π Derived Proof Information:**`); summary.push(`β’ Proof Type: ${proof.type || 'Unknown'}`); summary.push(`β’ Verification Method: ${proof.verificationMethod || 'Not specified'}`); summary.push(`β’ Created: ${proof.created || 'Not specified'}`); summary.push(`β’ Purpose: ${proof.proofPurpose || 'assertionMethod'}`); if (nonce) { summary.push(`β’ Nonce: ${nonce} (replay protection enabled)`); } summary.push(``); } // Derivation integrity checks summary.push(`**π‘οΈ Integrity Verification:**`); summary.push(`β’ Original signature preserved: ${result.signaturePreserved ? 'β Yes' : 'β No'}`); summary.push(`β’ Derivation proof valid: ${result.derivationValid ? 'β Yes' : 'β No'}`); summary.push(`β’ JSON-LD frame applied: ${result.frameApplied ? 'β Yes' : 'β No'}`); if (result.chainedCredential) { summary.push(`β’ Credential chaining: β Derived credential properly chained`); } // Usage recommendations summary.push(``); summary.push(`**π‘ Usage Recommendations:**`); if (hiddenFields.length > 0) { summary.push(`β’ Use this derived credential for privacy-sensitive scenarios`); summary.push(`β’ Original credential remains unchanged and can be used separately`); } if (nonce) { summary.push(`β’ Nonce provides replay protection - credential is single-use`); } summary.push(`β’ Verify derived credential independently before accepting`); summary.push(`β’ Consider the revealed fields sufficient for your use case`); return { content: [ { type: 'text', text: summary.join('\n') }, { type: 'text', text: `\`\`\`json\n${JSON.stringify({ derivationSummary: { originalCredentialId: originalCredential.id, derivedCredentialId: result.derivedCredential?.id, originalFields: originalFields.length, revealedFields: revealedFields.length, hiddenFields: hiddenFields.length, privacyLevel: Math.round((hiddenFields.length / originalFields.length) * 100), frameApplied: result.frameApplied, signaturePreserved: result.signaturePreserved }, derivedCredential: result.derivedCredential, derivationProof: result.derivationProof }, null, 2)}\n\`\`\`` } ] }; } catch (error: any) { // Check if it's a network error (HiveAuth API not available) if (error.message.includes('fetch failed') || error.message.includes('ECONNREFUSED')) { return { content: [ { type: 'text', text: `π **Credential Derivation (Simulation Mode)**\n\n` + `Since the HiveAuth API is not available, here's what the credential derivation would accomplish:\n\n` + `**Input Analysis:**\n` + `β’ Original Credential ID: ${originalCredential.id || 'Not specified'}\n` + `β’ Original Credential Type: ${originalCredential.type?.join(', ') || 'Unknown'}\n` + `β’ Derivation Frame: ${Object.keys(frame).length} frame properties specified\n` + `β’ Nonce: ${nonce ? 'Provided (replay protection)' : 'Not provided'}\n\n` + `**Expected Derivation Results:**\n` + `β’ New credential with selective disclosure applied\n` + `β’ Original signature preserved in derived proof\n` + `β’ Only specified fields revealed according to frame\n` + `β’ Cryptographic link to original credential maintained\n\n` + `**Privacy Benefits:**\n` + `β’ Sensitive fields hidden while maintaining verifiability\n` + `β’ Zero-knowledge proof of credential possession\n` + `β’ Granular control over revealed information\n\n` + `**To enable full derivation:** Ensure HiveAuth API is running at ${HIVEAUTH_API_BASE_URL}` } ] }; } return { content: [ { type: 'text', text: `Failed to derive credential: ${error.message}` } ], isError: true }; } }
- src/schemas/toolSchemas.ts:140-144 (schema)Zod schema defining the input structure for derive_credential: requires originalCredential (CredentialSchema), frame (JSON-LD object), optional nonce (string for replay protection).export const DeriveCredentialInputSchema = z.object({ originalCredential: CredentialSchema, frame: z.object({}).passthrough().describe('JSON-LD frame for selective disclosure'), nonce: z.string().optional().describe('Nonce for derived proof') });
- src/utils/schemaConverter.ts:56-60 (registration)MCP tool registration definition, mapping 'derive_credential' name to its description and input schema (converted to JSON Schema via zodToJsonSchema for MCP protocol compliance).{ name: 'derive_credential', description: 'Derive credentials with selective disclosure using JSON-LD frames. Supports credential chaining and zero-knowledge proofs for privacy-preserving presentations.', inputSchema: TOOL_SCHEMAS.derive_credential },
- src/index.ts:107-108 (registration)Runtime tool dispatch in main server switch statement, routing 'derive_credential' calls to the deriveCredential handler function.case 'derive_credential': return await deriveCredential(args);
- Utility helper to recursively extract claim field paths from a credential (excluding metadata like @context, id, type, proof) for deriving revealed/hidden fields in derivation analysis.function extractCredentialFields(credential: any): string[] { const fields: string[] = []; function extractFromObject(obj: any, prefix = ''): void { if (!obj || typeof obj !== 'object') return; for (const [key, value] of Object.entries(obj)) { const fieldPath = prefix ? `${prefix}.${key}` : key; // Skip metadata fields if (['@context', 'id', 'type', 'proof'].includes(key)) continue; if (value && typeof value === 'object' && !Array.isArray(value)) { extractFromObject(value, fieldPath); } else { fields.push(fieldPath); } } } extractFromObject(credential); return fields; }