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(),
    }));
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It adds valuable context about security ('secure - never exposes actual values'), which is crucial for a credentials-related tool. However, it doesn't describe what the analysis actually returns, error conditions, or any rate limits or authentication requirements.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is perfectly concise at just 9 words. It's front-loaded with the core purpose, followed by important behavioral context about security. Every word earns its place with no wasted text or redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter tool with no output schema and no annotations, the description provides adequate but minimal information. It covers the purpose and a critical security constraint, but doesn't explain what the analysis returns or how to interpret results. Given the complexity (credentials analysis could involve various outputs), more completeness would be helpful.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already fully documents the single 'action' parameter with its enum values. The description adds no parameter-specific information beyond what's in the schema. According to the rules, when schema coverage is high (>80%), the baseline is 3 even with no param info in the description.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: 'Analyze credential requirements for workflows' with the specific verb 'analyze' and resource 'credential requirements'. It distinguishes itself from siblings like 'list_credentials' by focusing on analysis rather than listing. However, it doesn't fully differentiate from 'analyze' (a sibling tool) beyond the credential-specific focus.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives. With siblings like 'list_credentials', 'configure_tracking', and 'analyze' (general), there's no indication of when this credential analysis tool is appropriate versus those other tools. The description only states what it does, not when to choose it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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