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
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Secret name - must be UPPERCASE_WITH_UNDERSCORES | |
| type | No | Type of secret to generate (default: "password") | |
| length | No | Length of the secret (default: 32, range: 8-256) | |
| environment | No | Environment to store the secret in (default: "development") |
Implementation Reference
- src/tools/generate.ts:120-214 (handler)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, }; } } - src/tools/generate.ts:16-21 (schema)The 'GenerateArgs' interface defines the input arguments for the 'keyway_generate' tool.
interface GenerateArgs { name: string; type?: SecretType; length?: number; environment?: string; } - src/tools/generate.ts:70-101 (helper)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); } }