Skip to main content
Glama

credentials

Analyze credential requirements for n8n workflows to identify needed variables and generate setup instructions without exposing actual values.

Instructions

Analyze credential requirements for workflows (secure - never exposes actual values)

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
actionYesAction to perform: analyze requirements, show setup instructions, or generate .env.example

Implementation Reference

  • Schema definition for the 'credentials' MCP tool, specifying input parameters (action: analyze, instructions, generate-env)
    name: 'credentials', description: 'Analyze credential requirements for workflows (secure - never exposes actual values)', inputSchema: { type: 'object', properties: { action: { type: 'string', enum: ['analyze', 'instructions', 'generate-env'], description: 'Action to perform: analyze requirements, show setup instructions, or generate .env.example', }, }, required: ['action'], }, },
  • Main handler logic for 'credentials' tool: dispatches to CredentialHelper methods based on action parameter
    case 'credentials': const credAction = args?.action as string; switch (credAction) { case 'analyze': return await this.credentialHelper.analyzeCredentialRequirements(); case 'instructions': return await this.credentialHelper.getCredentialSetupInstructions(); case 'generate-env': return await this.credentialHelper.generateSecureEnvExample(); default: throw new Error(`Unknown credential action: ${credAction}`); }
  • CredentialHelper class providing the core implementation: analyzeCredentialRequirements(), generateSecureEnvExample(), getCredentialSetupInstructions()
    export class CredentialHelper { private workflowsPath: string; constructor(workflowsPath: string) { this.workflowsPath = workflowsPath; } /** * Analyze workflows to determine required credentials */ async analyzeCredentialRequirements(): Promise<any> { try { const flowsDir = path.join(this.workflowsPath, 'flows'); const files = await fs.readdir(flowsDir); const requirements = new Map<string, CredentialRequirement>(); const workflowCredentials = new Map<string, string[]>(); // Analyze each workflow for (const file of files) { if (!file.endsWith('.json') || file.includes('package.json')) continue; const content = await fs.readFile(path.join(flowsDir, file), 'utf-8'); const workflow = JSON.parse(content); const workflowName = file.replace('.json', ''); const credTypes: string[] = []; if (workflow.nodes) { for (const node of workflow.nodes) { // Check for credential requirements if (node.credentials) { Object.keys(node.credentials).forEach(credType => { credTypes.push(credType); // Map credential types to environment variables switch (credType) { case 'openAiApi': requirements.set('OPENAI_API_KEY', { envVar: 'OPENAI_API_KEY', n8nType: 'OpenAI API', displayName: 'OpenAI API Key', instructions: '1. Go to https://platform.openai.com/api-keys\n2. Create a new API key\n3. Add to .env: OPENAI_API_KEY=sk-...', }); break; case 'replicateApi': requirements.set('REPLICATE_API_TOKEN', { envVar: 'REPLICATE_API_TOKEN', n8nType: 'Replicate API', displayName: 'Replicate API Token', instructions: '1. Go to https://replicate.com/account/api-tokens\n2. Create a new token\n3. Add to .env: REPLICATE_API_TOKEN=...', }); break; case 'airtableApi': requirements.set('AIRTABLE_API_KEY', { envVar: 'AIRTABLE_API_KEY', n8nType: 'Airtable API', displayName: 'Airtable API Key or Personal Access Token', instructions: '1. Go to https://airtable.com/create/tokens\n2. Create a personal access token\n3. Add to .env: AIRTABLE_API_KEY=pat...', }); break; case 'slackApi': requirements.set('SLACK_WEBHOOK_URL', { envVar: 'SLACK_WEBHOOK_URL', n8nType: 'Slack Webhook', displayName: 'Slack Webhook URL', instructions: '1. Go to https://api.slack.com/apps\n2. Create an app and add Incoming Webhook\n3. Add to .env: SLACK_WEBHOOK_URL=https://hooks.slack.com/...', }); break; case 'githubApi': requirements.set('GITHUB_TOKEN', { envVar: 'GITHUB_TOKEN', n8nType: 'GitHub API', displayName: 'GitHub Personal Access Token', instructions: '1. Go to https://github.com/settings/tokens\n2. Generate new token (classic)\n3. Add to .env: GITHUB_TOKEN=ghp_...', }); break; } }); } } } if (credTypes.length > 0) { workflowCredentials.set(workflowName, credTypes); } } // Check which credentials exist in .env const envVars = await this.checkEnvFile(); // Format output let output = 'šŸ” Credential Requirements Analysis\n\n'; if (requirements.size === 0) { output += 'āœ… No credentials required for these workflows.\n'; } else { output += `šŸ“‹ Required Credentials (${requirements.size}):\n\n`; for (const [envVar, req] of requirements) { const hasEnv = envVars.has(envVar); const status = hasEnv ? 'āœ…' : 'āŒ'; output += `${status} ${req.displayName}\n`; output += ` Environment Variable: ${envVar}\n`; output += ` n8n Credential Type: ${req.n8nType}\n`; if (!hasEnv) { output += ` āš ļø Not found in .env\n`; } output += '\n'; } // Show which workflows need which credentials output += 'šŸ“Š Workflows and Their Credential Requirements:\n\n'; for (const [workflow, creds] of workflowCredentials) { output += `• ${workflow}: ${creds.join(', ')}\n`; } // Instructions for missing credentials const missing = Array.from(requirements.entries()).filter(([env]) => !envVars.has(env)); if (missing.length > 0) { output += '\nāš ļø Missing Credentials Setup Instructions:\n\n'; for (const [, req] of missing) { output += `### ${req.displayName}\n${req.instructions}\n\n`; } output += 'šŸ”’ Security Best Practices:\n'; output += '1. Never commit .env files to git\n'; output += '2. Use strong, unique API keys\n'; output += '3. Rotate keys regularly\n'; output += '4. Limit API key permissions to minimum required\n'; output += '5. Add credentials through n8n UI at http://localhost:5678\n'; } } return { content: [ { type: 'text', text: output, }, ], }; } catch (error: any) { throw new Error(`Failed to analyze credentials: ${error.message}`); } } /** * Check which environment variables exist (NOT their values) */ private async checkEnvFile(): Promise<Set<string>> { const envVars = new Set<string>(); const envPaths = [ path.join(this.workflowsPath, '.env'), path.join(this.workflowsPath, '.env'), ]; for (const envPath of envPaths) { try { const envContent = await fs.readFile(envPath, 'utf-8'); const parsed = dotenv.parse(envContent); // Only store variable names, NEVER values Object.keys(parsed).forEach(key => { if (parsed[key] && parsed[key].length > 0) { envVars.add(key); } }); break; // Use first .env found } catch { // Try next path } } return envVars; } /** * Generate secure .env.example without exposing any real values */ async generateSecureEnvExample(): Promise<any> { try { const requirements = await this.getRequirementsFromWorkflows(); let content = '# n8n Workflow Credentials\n'; content += '# SECURITY: Never commit this file with real values to git!\n'; content += '# Copy to .env and add your actual API keys\n\n'; content += '# === Required API Credentials ===\n'; content += '# Get these from the respective service providers\n\n'; for (const req of requirements) { content += `# ${req.displayName}\n`; content += `# ${req.instructions.split('\n')[0]}\n`; // First line of instructions content += `${req.envVar}=\n\n`; } content += '# === Security Reminders ===\n'; content += '# 1. Add .env to .gitignore\n'; content += '# 2. Never share or log these values\n'; content += '# 3. Rotate keys regularly\n'; content += '# 4. Use environment-specific keys (dev/prod)\n'; const envExamplePath = path.join(this.workflowsPath, '.env.example'); await fs.writeFile(envExamplePath, content, 'utf-8'); return { content: [ { type: 'text', text: 'āœ… Generated secure .env.example\n\n' + 'šŸ“ Location: workflows/.env.example\n\n' + 'Next steps:\n' + '1. Copy .env.example to .env\n' + '2. Add your API keys to .env\n' + '3. Never commit .env to git\n' + '4. Add credentials in n8n UI at http://localhost:5678', }, ], }; } catch (error: any) { throw new Error(`Failed to generate .env.example: ${error.message}`); } } /** * Get credential requirements from workflows */ private async getRequirementsFromWorkflows(): Promise<CredentialRequirement[]> { // This would analyze workflows and return requirements // For now, return common ones return [ { envVar: 'OPENAI_API_KEY', n8nType: 'OpenAI API', displayName: 'OpenAI API Key', instructions: 'Get from https://platform.openai.com/api-keys', }, // Add more as needed based on workflow analysis ]; } /** * Provide instructions for setting up credentials securely */ async getCredentialSetupInstructions(): Promise<any> { return { content: [ { type: 'text', text: `šŸ” Secure Credential Setup for n8n 1ļøāƒ£ **Prepare Your Credentials** • Copy workflows/.env.example to workflows/.env • Add your API keys to the .env file • Never commit .env to version control 2ļøāƒ£ **Add Credentials in n8n UI** • Open http://localhost:5678 • Go to Credentials (left sidebar) • Click "Add Credential" • Select the credential type • Enter your API key/token • Save the credential 3ļøāƒ£ **Link Credentials to Workflows** • Open each workflow • Click on nodes that need credentials • Select the credential from dropdown • Save the workflow 4ļøāƒ£ **Security Best Practices** āœ… Use environment-specific credentials (dev/staging/prod) āœ… Rotate API keys regularly āœ… Use minimal required permissions āœ… Enable 2FA where available āœ… Monitor API usage for anomalies āŒ Never log or print credentials āŒ Never commit credentials to git āŒ Never share credentials in messages 5ļøāƒ£ **Troubleshooting** • If a workflow fails with "Credentials not found": - Check the credential exists in n8n - Verify the credential name matches - Ensure the credential has correct permissions • If API calls fail: - Test credentials directly with the service - Check rate limits - Verify API endpoint URLs For detailed setup per service: • OpenAI: https://platform.openai.com/docs/api-reference/authentication • GitHub: https://docs.github.com/en/authentication • Slack: https://api.slack.com/authentication • Airtable: https://airtable.com/developers/web/api/authentication`, }, ], }; } }
  • MCP server registers tools list handler which returns getToolDefinitions() including 'credentials' tool definition
    this.server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: getToolDefinitions(), }));

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/mckinleymedia/mcflow-mcp'

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