Skip to main content
Glama
keywaysh

Keyway MCP Server

by keywaysh

keyway_generate

Generate secure secrets like passwords and API keys, storing them directly in a vault without exposing values in conversation.

Instructions

Generate a secure secret and store it directly in the vault. The value is never exposed in the conversation.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
nameYesSecret name - must be UPPERCASE_WITH_UNDERSCORES
typeNoType of secret to generate (default: "password")
lengthNoLength of the secret (default: 32, range: 8-256)
environmentNoEnvironment to store the secret in (default: "development")

Implementation Reference

  • The 'generate' function acts as the handler for the 'keyway_generate' tool, responsible for generating a secure secret, updating the vault, and returning the result.
    export async function generate(args: GenerateArgs): Promise<CallToolResult> {
      const { name, type = 'password', length = 32, environment = 'development' } = args;
    
      // Validate name
      if (!name) {
        return {
          content: [{ type: 'text', text: 'Error: Secret name is required' }],
          isError: true,
        };
      }
    
      if (!isValidSecretName(name)) {
        return {
          content: [
            {
              type: 'text',
              text: `Error: Invalid secret name "${name}". Must be UPPERCASE_WITH_UNDERSCORES (e.g., DATABASE_URL, API_KEY)`,
            },
          ],
          isError: true,
        };
      }
    
      // Validate type
      const validTypes: SecretType[] = ['password', 'uuid', 'api-key', 'jwt-secret', 'hex', 'base64'];
      if (!validTypes.includes(type)) {
        return {
          content: [
            {
              type: 'text',
              text: `Error: Invalid type "${type}". Valid types: ${validTypes.join(', ')}`,
            },
          ],
          isError: true,
        };
      }
    
      // Validate length
      if (length < 8 || length > 256) {
        return {
          content: [{ type: 'text', text: 'Error: Length must be between 8 and 256' }],
          isError: true,
        };
      }
    
      try {
        const token = await getToken();
        const repository = getRepository();
    
        // Generate the secret value
        const secretValue = generateSecret(type, length);
    
        // Pull existing secrets
        let existingSecrets: Record<string, string> = {};
        try {
          const content = await pullSecrets(repository, environment, token);
          existingSecrets = parseEnvContent(content);
        } catch {
          // Environment might not exist yet, that's OK
        }
    
        // Check if secret already exists
        const isUpdate = name in existingSecrets;
    
        // Add/update the secret
        existingSecrets[name] = secretValue;
    
        // Push to vault (API expects Record<string, string>)
        await pushSecrets(repository, environment, existingSecrets, token);
    
        const response = {
          success: true,
          action: isUpdate ? 'updated' : 'created',
          name,
          type,
          length: secretValue.length,
          preview: maskSecret(secretValue),
          environment,
          repository,
          message: `Secret "${name}" ${isUpdate ? 'updated' : 'created'} with a secure ${type} value. The actual value is stored in Keyway and was never exposed in this conversation.`,
        };
    
        return {
          content: [{ type: 'text', text: JSON.stringify(response, null, 2) }],
          isError: false,
        };
      } catch (error) {
        const message = error instanceof Error ? error.message : 'Unknown error';
        return {
          content: [{ type: 'text', text: `Error generating secret: ${message}` }],
          isError: true,
        };
      }
    }
  • The 'GenerateArgs' interface defines the input arguments for the 'keyway_generate' tool.
    interface GenerateArgs {
      name: string;
      type?: SecretType;
      length?: number;
      environment?: string;
    }
  • The 'generateSecret' helper function handles the logic for creating different types of secrets.
    function generateSecret(type: SecretType, length: number): string {
      switch (type) {
        case 'password':
          return generatePassword(length);
    
        case 'uuid':
          return randomUUID();
    
        case 'api-key':
          // Format: prefix_base62 (like sk_live_xxx or key_xxx)
          return `key_${randomString(length, CHARSET_ALPHANUMERIC)}`;
    
        case 'jwt-secret': {
          // 256-bit minimum for HS256
          const jwtLength = Math.max(length, 32);
          return randomBytes(jwtLength).toString('base64url');
        }
    
        case 'hex':
          return randomBytes(Math.ceil(length / 2))
            .toString('hex')
            .slice(0, length);
    
        case 'base64':
          return randomBytes(Math.ceil((length * 3) / 4))
            .toString('base64')
            .slice(0, length);
    
        default:
          return generatePassword(length);
      }
    }
Behavior4/5

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

With no annotations provided, the description carries full burden and does well by disclosing key behavioral traits: it generates secrets (creation action), stores them in a vault (persistence), and importantly states 'The value is never exposed in the conversation' (security/privacy behavior). However, it doesn't mention authentication requirements, rate limits, or error conditions.

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?

Two concise sentences with zero waste. The first sentence states the core functionality, the second adds crucial behavioral context. Every word earns its place, and the most important information is front-loaded.

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

Completeness4/5

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

For a creation tool with no annotations and no output schema, the description provides good context about the generation and storage behavior. However, it doesn't describe what happens on success (e.g., confirmation message, secret reference) or failure conditions. The 'never exposed' statement partially compensates for lack of output schema.

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 all 4 parameters. The description adds no additional parameter semantics beyond what's in the schema descriptions. This meets the baseline expectation when schema coverage is complete.

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

Purpose5/5

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

The description clearly states the specific action ('Generate a secure secret and store it directly in the vault') and distinguishes it from siblings like keyway_set_secret (which likely sets an existing value) and keyway_list_secrets (which lists existing secrets). The phrase 'The value is never exposed in the conversation' adds important differentiation about output behavior.

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

Usage Guidelines4/5

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

The description implies usage context ('store it directly in the vault') and distinguishes from alternatives by noting the value is never exposed, but doesn't explicitly state when to use this vs. siblings like keyway_set_secret or keyway_validate. It provides clear operational context but lacks explicit comparison guidance.

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/keywaysh/keyway-mcp'

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