Skip to main content
Glama
AlyssonM

HiveAuth MCP Server

by AlyssonM

batch_issue_credentials

Issue multiple verifiable credentials in batches of up to 50, with options for parallel or sequential processing, error handling, and performance tracking.

Instructions

Issue multiple verifiable credentials in parallel or sequentially. Supports up to 50 credentials per batch with comprehensive error handling and performance metrics.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
credentialsYes
parallelNoWhether to process credentials in parallel

Implementation Reference

  • The main handler function that implements the batch_issue_credentials tool. It validates input, issues multiple verifiable credentials via HiveAuth API in parallel or sequential mode, and returns detailed results with summary and JSON output.
    export async function batchIssueCredentials(args: any): Promise<CallToolResult> { // Validate and sanitize input const validation = validateAndSanitizeInput(BatchIssueCredentialsInputSchema, args, 'batch_issue_credentials'); if (!validation.success) { return createValidationErrorResult(validation.error!); } const data = validation.data!; const { credentials, parallel = true } = data; const HIVEAUTH_API_BASE_URL = process.env.HIVEAUTH_API_BASE_URL || 'http://localhost:3000'; const ISSUE_ENDPOINT = `${HIVEAUTH_API_BASE_URL}/api/issue`; const startTime = Date.now(); const results: any[] = []; const errors: any[] = []; try { console.log(`[BatchIssue] Starting batch issuance of ${credentials.length} credentials (parallel: ${parallel})`); if (parallel) { // Process credentials in parallel const promises = credentials.map(async (credentialData, index) => { try { const payload = { credentialSubject: credentialData.credentialSubject, type: credentialData.type, vcVersion: credentialData.vcVersion || '2.0', ...(credentialData.expirationDate && { expirationDate: credentialData.expirationDate }), ...(credentialData.validUntil && { validUntil: credentialData.validUntil }), ...(credentialData.context && { context: credentialData.context }), ...(credentialData.issuer && { issuer: credentialData.issuer }) }; const response = await fetch(ISSUE_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(`Credential ${index + 1}: ${errorData.message}`); } const result = await response.json(); return { index, success: true, credential: result.credential, result }; } catch (error: any) { return { index, success: false, error: error.message }; } }); const allResults = await Promise.all(promises); // Separate successful results from errors allResults.forEach(result => { if (result.success) { results.push(result); } else { errors.push(result); } }); } else { // Process credentials sequentially for (let index = 0; index < credentials.length; index++) { const credentialData = credentials[index]; try { const payload = { credentialSubject: credentialData.credentialSubject, type: credentialData.type, vcVersion: credentialData.vcVersion || '2.0', ...(credentialData.expirationDate && { expirationDate: credentialData.expirationDate }), ...(credentialData.validUntil && { validUntil: credentialData.validUntil }), ...(credentialData.context && { context: credentialData.context }), ...(credentialData.issuer && { issuer: credentialData.issuer }) }; const response = await fetch(ISSUE_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(`Credential ${index + 1}: ${errorData.message}`); } const result = await response.json(); results.push({ index, success: true, credential: result.credential, result }); } catch (error: any) { errors.push({ index, success: false, error: error.message }); } } } const endTime = Date.now(); const duration = endTime - startTime; const successCount = results.length; const errorCount = errors.length; const totalCount = credentials.length; // Generate summary const summary = [ `📊 **Batch Credential Issuance Results**`, ``, `• Total Credentials: ${totalCount}`, `• Successfully Issued: ${successCount} ✅`, `• Failed: ${errorCount} ❌`, `• Processing Mode: ${parallel ? 'Parallel' : 'Sequential'}`, `• Duration: ${duration}ms`, `• Average per credential: ${Math.round(duration / totalCount)}ms`, `` ]; if (successCount > 0) { summary.push(`**✅ Successfully Issued Credentials:**`); results.forEach(result => { const credId = result.credential?.id || 'unknown'; const vcVersion = result.result?.credential?.['@context']?.includes('credentials/v2') ? '2.0' : '1.1'; summary.push(`${result.index + 1}. **${credId}** (VC ${vcVersion})`); }); summary.push(``); } if (errorCount > 0) { summary.push(`**❌ Failed Credentials:**`); errors.forEach(error => { summary.push(`${error.index + 1}. ${error.error}`); }); summary.push(``); } // Performance insights if (parallel && totalCount > 1) { const sequentialEstimate = duration * totalCount; const speedup = Math.round((sequentialEstimate / duration) * 10) / 10; summary.push(`**⚡ Performance:**`); summary.push(`• Parallel speedup: ~${speedup}x faster than sequential`); summary.push(`• Estimated sequential time: ${sequentialEstimate}ms`); } return { content: [ { type: 'text', text: summary.join('\n') }, { type: 'text', text: `\`\`\`json\n${JSON.stringify({ summary: { total: totalCount, successful: successCount, failed: errorCount, duration: duration, parallel: parallel }, results: results.map(r => ({ index: r.index, credentialId: r.credential?.id, success: true })), errors: errors.map(e => ({ index: e.index, error: e.error, success: false })) }, null, 2)}\n\`\`\`` } ] }; } catch (error: any) { return { content: [ { type: 'text', text: `Failed to issue credentials in batch: ${error.message}` } ], isError: true }; } }
  • Zod input schema definition for the batch_issue_credentials tool, defining the structure for batch credentials and parallel processing option.
    export const BatchIssueCredentialsInputSchema = z.object({ credentials: z.array(IssueCredentialInputSchema).min(1).max(50, 'Maximum 50 credentials per batch'), parallel: z.boolean().default(true).describe('Whether to process credentials in parallel') });
  • Mapping of the tool name to its input schema in the TOOL_SCHEMAS object used for MCP tool registration.
    batch_issue_credentials: BatchIssueCredentialsInputSchema,
  • src/index.ts:101-102 (registration)
    Registration in the main switch statement that dispatches calls to the batchIssueCredentials handler function.
    case 'batch_issue_credentials': return await batchIssueCredentials(args);
  • src/index.ts:26-26 (registration)
    Import of the batchIssueCredentials handler into the main index file.
    import { batchIssueCredentials } from './tools/batchIssueCredentials.js';

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