get-secret
Retrieve encrypted secrets like API keys and passwords from SecureCode vault, injecting values into local files to prevent exposure in conversations. Use reveal mode to view raw values with audit logging.
Instructions
Get a secret by name. By default, injects the value into a local file so it never appears in the AI conversation. Use reveal:true to see the raw value (audited as conscious action). Use cleanup:true to remove all injected secrets from disk.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | The exact name of the secret (e.g. STRIPE_SECRET_KEY) | |
| tags | No | Filter tags to disambiguate same-name secrets, e.g. { "env": "production", "project": "acme" } | |
| reveal | No | If true, returns the raw value in the conversation (audited as reveal). Default: false (inject mode — value written to local file, never shown) | |
| cleanup | No | If true, removes all injected secret files from disk |
Implementation Reference
- src/index.ts:346-429 (handler)The implementation of the get-secret MCP tool which fetches a secret and either reveals it or injects it into a temporary environment file.
// Tool: get-secret server.tool( 'get-secret', 'Get a secret by name. By default, injects the value into a local file so it never appears in the AI conversation. Use reveal:true to see the raw value (audited as conscious action). Use cleanup:true to remove all injected secrets from disk.', { name: z.string().optional().describe('The exact name of the secret (e.g. STRIPE_SECRET_KEY)'), tags: z.record(z.string(), z.string()).optional().describe('Filter tags to disambiguate same-name secrets, e.g. { "env": "production", "project": "acme" }'), reveal: z.boolean().optional().describe('If true, returns the raw value in the conversation (audited as reveal). Default: false (inject mode — value written to local file, never shown)'), cleanup: z.boolean().optional().describe('If true, removes all injected secret files from disk'), }, async ({ name, tags, reveal, cleanup }) => { // Cleanup mode if (cleanup) { cleanupSessionFiles(); return wrapResponse([{ type: 'text', text: '✓ All injected secrets have been cleaned up from disk.' }]); } if (!name) { return wrapResponse([{ type: 'text', text: 'Error: name is required (unless using cleanup:true)' }], true); } try { const client = getClient(); // Fetch secret metadata for tip evaluation (best-effort) let tipResult: { tip: string; blocking: boolean } | null = null; try { const secrets = await client.listSecrets({ tags }); const meta = secrets.find(s => s.name === name); if (meta) { tipResult = evaluateTips({ secretName: name, secretTags: meta.tags || {}, secretExpiresAt: meta.expiresAt, secretCreatedAt: meta.metadata.createdAt, secretAccessCount: meta.metadata.accessCount, }); } } catch { // Tip evaluation failed — proceed without tip } // Blocking tip: return ONLY the tip, without the secret value if (tipResult?.blocking) { return wrapResponse([{ type: 'text', text: `[IMPORTANT] ${tipResult.tip}\n\nPlease acknowledge this message, then call get-secret again to retrieve the value.`, }]); } // Fetch the actual secret value const pendingAck = ruleAckState.get(name); let value: string; try { value = await client.getSecret(name, tags, pendingAck || undefined, { reveal: !!reveal }); if (pendingAck) ruleAckState.delete(name); } catch (err) { if (err instanceof McpRuleBlockedError && err.ruleAction === 'require_confirmation') { ruleAckState.set(name, err.ruleId); } throw err; } tipSessionState.secretsAccessed++; // REVEAL mode: return raw value to LLM (conscious, audited action) if (reveal) { const content = [{ type: 'text' as const, text: value }]; if (tipResult) content.push({ type: 'text' as const, text: `\n---\n[Tip] ${tipResult.tip}` }); return wrapResponse(content); } // INJECT mode (default): write to local file, never show value to LLM injectSecrets({ [name]: value }); const envPath = SESSION_ENV_FILE.replace(/\\/g, '/'); const content = [ { type: 'text' as const, text: `✓ ${name} injected → ${envPath}\n\nUse: source ${envPath} && your-command\n\nThe value is NOT in this conversation. It exists only in that file until the next inject overwrites it or you run byebye.` }, ]; if (tipResult) content.push({ type: 'text' as const, text: `\n---\n[Tip] ${tipResult.tip}` }); return wrapResponse(content); } catch (error) { return errorResult(error); } } );