---
title: MCP Server
description: Envlock MCP server for Claude and other AI agents – validate and inspect environment contracts via Claude Desktop or other MCP clients
url: https://pr-1-8289d63b6330.thally.app/envlock/mcp
---

# MCP Server

Envlock MCP server for Claude and other AI agents – validate and inspect environment contracts via Claude Desktop or other MCP clients

The `@envlock/mcp` package provides an MCP server that exposes Envlock functionality to Claude, Cursor, and other AI agents via the Model Context Protocol.

## Installation

Install as a dev dependency:

```sh
npm install -D @envlock/mcp
```

The server binary is available as `envlock-mcp` and runs on stdio transport.

## Configuration

### Claude Desktop

Add Envlock to your Claude Desktop configuration at `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or the Windows/Linux equivalent:

```json
{
  "mcpServers": {
    "envlock": {
      "command": "npx",
      "args": ["-y", "@envlock/mcp"]
    }
  }
}
```

Restart Claude Desktop to load the server.

### Claude Code / Cursor

Add to `.mcp.json` in your project root:

```json
{
  "mcpServers": {
    "envlock": {
      "command": "npx",
      "args": ["-y", "@envlock/mcp"]
    }
  }
}
```

The server will guide you through available tools in the initial system prompt.

---

## Tools

All tools are marked as read-only and idempotent. Tools that produce JSON output include both text and structured content blocks.

### `envlock_check`

Validates an environment against a schema.

**Input:**

```json
{
  "schemaPath": "envlock.config.mjs",
  "envFilePath": ".env",
  "strict": true
}
```

**Parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `schemaPath` | string | yes | Path to schema file (relative to server cwd) |
| `envFilePath` | string | no | Path to `.env` file; omit to validate process.env |
| `strict` | boolean | no | Report undeclared variables (files only) |

**Output:**

```json
{
  "ok": true,
  "source": ".env",
  "issues": []
}
```

On failure:

```json
{
  "ok": false,
  "source": ".env",
  "issues": [
    {
      "key": "PORT",
      "code": "invalid",
      "message": "expected a finite number",
      "received": "abc"
    }
  ]
}
```

---

### `envlock_inspect`

Describes all variables in a schema.

**Input:**

```json
{
  "schemaPath": "envlock.config.mjs"
}
```

**Parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `schemaPath` | string | yes | Path to schema file (relative to server cwd) |

**Output:**

```json
{
  "schemaPath": "envlock.config.mjs",
  "variables": [
    {
      "key": "NODE_ENV",
      "type": "enum",
      "required": true,
      "hasDefault": true,
      "default": "development",
      "secret": false,
      "description": null,
      "example": null,
      "constraints": "one of: development, test, production"
    },
    {
      "key": "DATABASE_URL",
      "type": "url",
      "required": true,
      "hasDefault": false,
      "secret": true,
      "description": "Connection string",
      "constraints": "absolute URL with protocol postgres: or postgresql:"
    }
  ]
}
```

---

### `envlock_render_example`

Generates a `.env.example` file content from a schema.

**Input:**

```json
{
  "schemaPath": "envlock.config.mjs"
}
```

**Parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `schemaPath` | string | yes | Path to schema file (relative to server cwd) |

**Output:** Plain text (not JSON) containing the rendered `.env.example`:

```
# Environment contract rendered by envlock.
# Copy to .env and fill in the values; never commit real secrets here.

# HTTP listen port
# port · required · default: 3000 · integer 1-65535
PORT=3000

# Database connection string
# url · required · absolute URL with protocol postgres: · secret
DATABASE_URL=
```

---

### `envlock_diff`

Compares a `.env` file to a schema and reports differences.

**Input:**

```json
{
  "schemaPath": "envlock.config.mjs",
  "envFilePath": ".env"
}
```

**Parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `schemaPath` | string | yes | Path to schema file (relative to server cwd) |
| `envFilePath` | string | yes | Path to `.env` file (relative to server cwd) |

**Output:**

```json
{
  "ok": true,
  "source": ".env",
  "missing": [],
  "unknown": [],
  "invalid": []
}
```

On issues:

```json
{
  "ok": false,
  "source": ".env",
  "missing": ["DATABASE_URL"],
  "unknown": ["EXTRA_VAR"],
  "invalid": [
    {
      "key": "PORT",
      "code": "invalid",
      "message": "expected a finite number",
      "received": "abc"
    }
  ]
}
```

---

### `envlock_explain_issue`

Explains a validation issue with actionable guidance. This is a pure function with no file access; it only interprets issue codes and messages.

**Input:**

```json
{
  "code": "missing",
  "key": "DATABASE_URL",
  "message": "required variable is not set"
}
```

**Parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `code` | string | yes | Issue code: `"missing"`, `"invalid"`, or `"unknown"` |
| `key` | string | yes | Variable name |
| `message` | string | no | Validation message (provides context for `invalid`) |

**Output:**

```json
{
  "code": "missing",
  "key": "DATABASE_URL",
  "summary": "DATABASE_URL is required by the contract but the environment does not provide a non-empty value (required variable is not set).",
  "steps": [
    "Set DATABASE_URL in the environment or .env file; an empty value (`DATABASE_URL=`) still counts as missing.",
    "If DATABASE_URL should be allowed to be absent, mark it `.optional()` or give it a `.default(...)` in the contract.",
    "Run `envlock example` to see the expected format and description for DATABASE_URL."
  ]
}
```

When `message` is omitted from the input, the parenthetical suffix is dropped from the summary.

**Issue explanations:**

**Missing issue:**
- Summary: `"<KEY> is required by the contract but the environment does not provide a non-empty value (<message>)."` (message suffix omitted when not provided)
- Steps: Set the variable; mark `.optional()` or `.default()`; run `envlock example`

**Invalid issue:**
- Summary: `"<KEY> is set but its value does not satisfy the declared type: <message>."` (colon separator omitted when no message)
- Steps: Correct the value; adjust the builder; re-run `envlock check`

**Unknown issue:**
- Summary: `"<KEY> exists in the env file but the contract does not declare it (<message>)."` (message suffix omitted when not provided)
- Steps: Declare in schema; remove from env file; note about strict mode

---

## Resources

### Schema Resource Template

Schemas can be inspected as MCP resources via URL.

**Template:** `envlock://schema/{schemaPath}`

**Example:** `envlock://schema/envlock.config.mjs`

**Content:** Returns the result of `describeSchema()` as `application/json`.

Resources are read-only. Use `resources/templates/list` in the MCP client to discover available schema resources without hardcoding paths.

---

## Programmatic Usage

Use `createEnvlockServer` to integrate the MCP server into your own applications or testing.

```ts
import { createEnvlockServer } from "@envlock/mcp";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";

// Create the server
const server = createEnvlockServer({
  cwd: "/path/to/project",  // defaults to process.cwd()
});

// Connect on stdio
await server.connect(new StdioServerTransport());
```

**`EnvlockServerOptions` interface:**

```ts
interface EnvlockServerOptions {
  readonly cwd?: string;  // Working directory for file resolution (defaults to process.cwd())
}
```

**Server metadata:**

```ts
const SERVER_INFO = {
  name: "envlock",
  version: "0.1.0",
};
```

**Tool names:**

```ts
const TOOL_NAMES = {
  check: "envlock_check",
  inspect: "envlock_inspect",
  renderExample: "envlock_render_example",
  diff: "envlock_diff",
  explainIssue: "envlock_explain_issue",
};
```

---

## Security

The server enforces path sandboxing to prevent directory traversal attacks. All file paths are resolved relative to the server's working directory.

### Path Validation

Files must reside within the server's working directory. Paths that escape (via `..` traversal or absolute paths elsewhere) are rejected:

```
error: path ".." is outside the server working directory (/home/user/project); start envlock-mcp from the project root
```

**Key functions:**

- `resolveInsideCwd(cwd: string, filePath: string)`: Validates and resolves a file path relative to `cwd`. Returns `{ path: string }` on success or `{ error: string }` on failure.
- `loadSchemaFile(schemaPath: string, cwd?: string)`: Loads and parses a schema file with path validation.
- `loadEnvFile(envFilePath: string, cwd?: string)`: Loads and parses a `.env` file with path validation.

### Best Practices

1. **Run from project root:** Start `envlock-mcp` from your project's root directory
2. **Use relative paths:** All paths passed to tools should be relative (e.g., `envlock.config.mjs`, `.env`)
3. **Limit scope:** If integrating programmatically, pass the appropriate `cwd` to restrict file access
4. **Secrets:** Secret fields are masked in all outputs (shown as `"••••••"`)