Skip to main content

@leanmcp/env-injection

Request-scoped environment variable injection for LeanMCP tools. Enables user-specific secrets (API keys, tokens) to be securely fetched and accessed within MCP tool methods.
This package only works with the LeanMCP auth provider and requires a projectId to be configured. Users manage their own secrets through the LeanMCP dashboard.

Features

  • Request-scoped isolation - Each user’s secrets are isolated using AsyncLocalStorage
  • @RequireEnv decorator - Validate required secrets exist before method execution
  • getEnv() / getAllEnv() - Access user-specific secrets in your tool code
  • Concurrency safe - Each request has its own isolated context

Installation

npm install @leanmcp/env-injection @leanmcp/auth @leanmcp/core

Quick Start

1. Configure Auth Provider with projectId

import { AuthProvider } from "@leanmcp/auth";

const projectId = process.env.LEANMCP_PROJECT_ID;

const authProvider = new AuthProvider('leanmcp', {
  apiKey: process.env.LEANMCP_API_KEY
});

await authProvider.init();

2. Use @RequireEnv and getEnv()

import { Tool } from "@leanmcp/core";
import { Authenticated } from "@leanmcp/auth";
import { RequireEnv, getEnv } from "@leanmcp/env-injection";

@Authenticated(authProvider, { projectId })
export class SlackService {

  @Tool({ description: 'Send a message to Slack' })
  @RequireEnv(["SLACK_TOKEN", "SLACK_CHANNEL"])
  async sendMessage(args: { message: string }) {
    // getEnv() returns THIS USER's secret, not a global env var
    const token = getEnv("SLACK_TOKEN")!;
    const channel = getEnv("SLACK_CHANNEL")!;

    await slackApi.postMessage(channel, args.message, token);

    return { success: true, channel };
  }
}

How It Works

Request → @Authenticated(projectId) → Fetch Secrets → runWithEnv() → @RequireEnv → Method → Cleanup
           ↓                                             ↓                ↓
     Verify token                               Store in ALS        getEnv() works
  1. User makes request with auth token
  2. @Authenticated verifies token and fetches user’s secrets from LeanMCP API
  3. Secrets are stored in AsyncLocalStorage for this request only
  4. @RequireEnv validates required secrets exist
  5. getEnv() accesses secrets during method execution
  6. Context is automatically cleaned up after request completes

API Reference

@RequireEnv(keys)

Decorator to validate required environment variables exist before method execution.
import { RequireEnv, getEnv } from "@leanmcp/env-injection";

@RequireEnv(["SLACK_TOKEN", "SLACK_CHANNEL"])
async sendMessage(args: { message: string }) {
  // Method only executes if BOTH keys exist
  const token = getEnv("SLACK_TOKEN")!;  // Safe to use !
  const channel = getEnv("SLACK_CHANNEL")!;
}
Requirements:
  • Must be used with @Authenticated(authProvider, { projectId })
  • Throws clear error if projectId is not configured
  • Throws if required keys are missing

getEnv(key)

Get a single environment variable from the current request context.
import { getEnv } from "@leanmcp/env-injection";

const token = getEnv("SLACK_TOKEN");
// Returns undefined if key doesn't exist
// Throws if called outside env context

getAllEnv()

Get all environment variables from the current request context.
import { getAllEnv } from "@leanmcp/env-injection";

const env = getAllEnv();
// { SLACK_TOKEN: "xoxb-...", SLACK_CHANNEL: "#general" }

hasEnvContext()

Check if currently inside an env context.
import { hasEnvContext, getEnv } from "@leanmcp/env-injection";

if (hasEnvContext()) {
  const token = getEnv("API_KEY");  // Safe to call
}

runWithEnv(env, fn)

Run a function with environment variables in scope. Used internally by @Authenticated.
import { runWithEnv, getEnv } from "@leanmcp/env-injection";

await runWithEnv({ API_KEY: "secret123" }, async () => {
  console.log(getEnv("API_KEY"));  // "secret123"
});

Error Messages

Missing projectId Configuration

Environment injection not configured for SlackService.sendMessage().
To use @RequireEnv, you must configure 'projectId' in your @Authenticated decorator:
@Authenticated(authProvider, { projectId: 'your-project-id' })

Missing Required Variables

Missing required environment variables: SLACK_TOKEN, SLACK_CHANNEL.
Please configure these secrets in your LeanMCP dashboard for this project.

Called Outside Context

getEnv("SLACK_TOKEN") called outside of env context.
To use getEnv(), you must configure 'projectId' in your @Authenticated decorator:
@Authenticated(authProvider, { projectId: 'your-project-id' })

Environment Variables

VariableDescription
LEANMCP_API_KEYYour LeanMCP API key (with SDK scope)
LEANMCP_PROJECT_IDProject ID to scope secrets to

Best Practices

Environment injection requires the projectId option to know which project’s secrets to fetch.
@Authenticated(authProvider, { projectId: 'my-project' })
Fails fast with clear error messages if secrets are missing.
@RequireEnv(["API_KEY", "SECRET"])
After @RequireEnv validates, secrets are guaranteed to exist.
@RequireEnv(["API_KEY"])
async method() {
  const key = getEnv("API_KEY")!;  // Safe to use !
}
They’re request-scoped for security. Always call getEnv() when needed.