Skip to main content
Glama
AlyssonM

HiveAuth MCP Server

by AlyssonM

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
NameRequiredDescriptionDefault
originalCredentialYesW3C Verifiable Credential
frameYesJSON-LD frame for selective disclosure
nonceNoNonce for derived proof

Implementation Reference

  • 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
        };
      }
    }
  • 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')
    });
  • 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;
    }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/AlyssonM/hiveauth-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server