List Available Secrets
list-secretsRetrieve names of secret keys for use with {secrets.key} syntax without exposing actual values.
Instructions
Get a list of available secret keys that can be used with {secrets.key} syntax. Only shows the key names, never the actual secret values.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Implementation Reference
- src/index.ts:695-794 (registration)Registration of the 'list-secrets' tool via server.registerTool() with name 'list-secrets', title 'List Available Secrets', and description about listing secret keys without exposing values.
server.registerTool( "list-secrets", { title: "List Available Secrets", description: "Get a list of available secret keys that can be used with {secrets.key} syntax. Only shows the key names, never the actual secret values.", inputSchema: {} }, async () => { try { const secretKeys = Object.keys(secrets); if (secretKeys.length === 0) { return { content: [{ type: "text" as const, text: "No secrets are currently configured. To add secrets, set environment variables with the HAL_SECRET_ prefix.\n\nExample:\n HAL_SECRET_API_KEY=your_api_key\n HAL_SECRET_TOKEN=your_token\n\nThen use them in requests like: {secrets.api_key} or {secrets.token}\n\nFor namespaced secrets with URL restrictions:\n HAL_SECRET_MICROSOFT_API_KEY=your_api_key\n HAL_ALLOW_MICROSOFT=\"https://azure.microsoft.com/*\"\n Usage: {secrets.microsoft.api_key}" }] }; } let response = `Available secrets (${secretKeys.length} total):\n\n`; // Group secrets by namespace const namespacedSecrets: Record<string, string[]> = {}; const unrestrictedSecrets: string[] = []; for (const [key, secretInfo] of Object.entries(secrets)) { if (secretInfo.namespace) { const namespaceTemplate = secretInfo.namespace.toLowerCase().replace(/-/g, '.'); if (!namespacedSecrets[namespaceTemplate]) { namespacedSecrets[namespaceTemplate] = []; } namespacedSecrets[namespaceTemplate].push(key); } else { unrestrictedSecrets.push(key); } } // Show unrestricted secrets first if (unrestrictedSecrets.length > 0) { response += "**Unrestricted Secrets** (can be used with any URL):\n"; unrestrictedSecrets.forEach((key, index) => { response += `${index + 1}. {secrets.${key}}\n`; }); response += "\n"; } // Show namespaced secrets with their restrictions for (const [namespace, keys] of Object.entries(namespacedSecrets)) { const firstKey = keys[0]; const secretInfo = secrets[firstKey]; response += `**Namespace: ${namespace}**\n`; if (secretInfo.allowedUrls && secretInfo.allowedUrls.length > 0) { response += `Restricted to URLs: ${secretInfo.allowedUrls.join(', ')}\n`; } else { response += "No URL restrictions (can be used with any URL)\n"; } response += "Secrets:\n"; keys.forEach((key, index) => { response += `${index + 1}. {secrets.${key}}\n`; }); response += "\n"; } response += "**Usage examples:**\n"; const exampleKey = secretKeys[0] || 'token'; response += `- URL: "https://api.example.com/data?token={secrets.${exampleKey}}"\n`; response += `- Header: {"Authorization": "Bearer {secrets.${exampleKey}}"}\n`; response += `- Body: {"username": "{secrets.${secretKeys.find(k => k.includes('user')) || 'username'}}"}\n\n`; response += "**Security Notes:**\n"; response += "- Only the key names are shown here. The actual secret values are never exposed to the AI.\n"; response += "- Secrets are substituted securely at request time.\n"; const restrictedCount = Object.values(secrets).filter(s => s.allowedUrls).length; if (restrictedCount > 0) { response += `- ${restrictedCount} secrets have URL restrictions for enhanced security.\n`; response += "- If a secret is restricted, it will only work with URLs matching its allowed patterns.\n"; } return { content: [{ type: "text" as const, text: response }] }; } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; return { content: [{ type: "text" as const, text: `Error listing secrets: ${redactSecretsFromText(errorMessage)}` }], isError: true }; } } ); - src/index.ts:702-793 (handler)The handler function for 'list-secrets' tool. It lists all available secret keys grouped by namespace, shows URL restrictions, usage examples, and security notes. Never exposes actual secret values.
async () => { try { const secretKeys = Object.keys(secrets); if (secretKeys.length === 0) { return { content: [{ type: "text" as const, text: "No secrets are currently configured. To add secrets, set environment variables with the HAL_SECRET_ prefix.\n\nExample:\n HAL_SECRET_API_KEY=your_api_key\n HAL_SECRET_TOKEN=your_token\n\nThen use them in requests like: {secrets.api_key} or {secrets.token}\n\nFor namespaced secrets with URL restrictions:\n HAL_SECRET_MICROSOFT_API_KEY=your_api_key\n HAL_ALLOW_MICROSOFT=\"https://azure.microsoft.com/*\"\n Usage: {secrets.microsoft.api_key}" }] }; } let response = `Available secrets (${secretKeys.length} total):\n\n`; // Group secrets by namespace const namespacedSecrets: Record<string, string[]> = {}; const unrestrictedSecrets: string[] = []; for (const [key, secretInfo] of Object.entries(secrets)) { if (secretInfo.namespace) { const namespaceTemplate = secretInfo.namespace.toLowerCase().replace(/-/g, '.'); if (!namespacedSecrets[namespaceTemplate]) { namespacedSecrets[namespaceTemplate] = []; } namespacedSecrets[namespaceTemplate].push(key); } else { unrestrictedSecrets.push(key); } } // Show unrestricted secrets first if (unrestrictedSecrets.length > 0) { response += "**Unrestricted Secrets** (can be used with any URL):\n"; unrestrictedSecrets.forEach((key, index) => { response += `${index + 1}. {secrets.${key}}\n`; }); response += "\n"; } // Show namespaced secrets with their restrictions for (const [namespace, keys] of Object.entries(namespacedSecrets)) { const firstKey = keys[0]; const secretInfo = secrets[firstKey]; response += `**Namespace: ${namespace}**\n`; if (secretInfo.allowedUrls && secretInfo.allowedUrls.length > 0) { response += `Restricted to URLs: ${secretInfo.allowedUrls.join(', ')}\n`; } else { response += "No URL restrictions (can be used with any URL)\n"; } response += "Secrets:\n"; keys.forEach((key, index) => { response += `${index + 1}. {secrets.${key}}\n`; }); response += "\n"; } response += "**Usage examples:**\n"; const exampleKey = secretKeys[0] || 'token'; response += `- URL: "https://api.example.com/data?token={secrets.${exampleKey}}"\n`; response += `- Header: {"Authorization": "Bearer {secrets.${exampleKey}}"}\n`; response += `- Body: {"username": "{secrets.${secretKeys.find(k => k.includes('user')) || 'username'}}"}\n\n`; response += "**Security Notes:**\n"; response += "- Only the key names are shown here. The actual secret values are never exposed to the AI.\n"; response += "- Secrets are substituted securely at request time.\n"; const restrictedCount = Object.values(secrets).filter(s => s.allowedUrls).length; if (restrictedCount > 0) { response += `- ${restrictedCount} secrets have URL restrictions for enhanced security.\n`; response += "- If a secret is restricted, it will only work with URLs matching its allowed patterns.\n"; } return { content: [{ type: "text" as const, text: response }] }; } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; return { content: [{ type: "text" as const, text: `Error listing secrets: ${redactSecretsFromText(errorMessage)}` }], isError: true }; } } - src/index.ts:696-700 (schema)Input schema for 'list-secrets' tool - an empty object meaning no parameters required.
"list-secrets", { title: "List Available Secrets", description: "Get a list of available secret keys that can be used with {secrets.key} syntax. Only shows the key names, never the actual secret values.", inputSchema: {}