---
title: MCP Server
description: Set up and use the Envlock MCP server to expose environment-contract checks to coding agents over stdio.
url: https://pr-1-b9e16090e83d.thally.app/envlock/mcp
---

# MCP Server

Set up and use the Envlock MCP server to expose environment-contract checks to coding agents over stdio.

# MCP Server

The `@envlock/mcp` package provides a [Model Context Protocol](https://modelcontextprotocol.io/) server that exposes Envlock environment-contract operations to coding agents over stdio. Agents can check schemas, inspect contracts, diff `.env` files, render examples, and get fix suggestions -- all through five MCP tools and one resource template.

## Installation and configuration

Install the MCP server as a dev dependency:

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

### Claude Desktop

Add this block to your `claude_desktop_config.json`:

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

### Claude Code and Cursor

Add this block to your project's `.mcp.json`:

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

If `@envlock/mcp` is already installed in your project, you can skip the download step by using the binary name directly:

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

## Server info

| Field   | Value       |
| ------- | ----------- |
| name    | `envlock`   |
| version | `0.1.0`     |

## Tools

The server registers five tools. All tools are annotated with `readOnlyHint: true` and `idempotentHint: true`. JSON-returning tools provide both a text block and `structuredContent`. When a schema or file cannot be loaded, the result is returned with `isError: true` and a reason string rather than a thrown protocol error.

### `envlock_check`

Validates environment variables against a schema. Without `envFilePath`, validates the server's `process.env`. The `strict` flag only applies when checking a file.

**Input schema:**

| Parameter     | Type    | Required | Description                                            |
| ------------- | ------- | -------- | ------------------------------------------------------ |
| `schemaPath`  | string  | yes      | Path to the Envlock config file                        |
| `envFilePath` | string  | no       | Path to a `.env` file to validate instead of process.env |
| `strict`      | boolean | no       | Report undeclared keys (only applies when checking a file) |

**Returns:** `{ ok: boolean, issues: EnvIssue[], source: string }`

### `envlock_inspect`

Describes every variable declared in a schema, including type, default, constraints, and whether it is required or secret.

**Input schema:**

| Parameter    | Type   | Required | Description                     |
| ------------ | ------ | -------- | ------------------------------- |
| `schemaPath` | string | yes      | Path to the Envlock config file |

**Returns:** `{ schemaPath: string, variables: SchemaDescription[] }`

### `envlock_render_example`

Renders a `.env.example` file from the contract. The response is plain text, not JSON.

**Input schema:**

| Parameter    | Type   | Required | Description                     |
| ------------ | ------ | -------- | ------------------------------- |
| `schemaPath` | string | yes      | Path to the Envlock config file |

**Returns:** A text content block containing the rendered `.env.example` output.

### `envlock_diff`

Compares a dotenv file against the contract. Always runs in strict mode, reporting missing, unknown, and invalid variables.

**Input schema:**

| Parameter     | Type   | Required | Description                     |
| ------------- | ------ | -------- | ------------------------------- |
| `schemaPath`  | string | yes      | Path to the Envlock config file |
| `envFilePath` | string | yes      | Path to the `.env` file to diff |

**Returns:** `{ ok: boolean, missing: string[], unknown: string[], invalid: EnvIssue[], source: string }`

### `envlock_explain_issue`

Returns a human-readable explanation and fix steps for a validation issue code. This is a pure function that does not access any files.

**Input schema:**

| Parameter | Type   | Required | Description                                              |
| --------- | ------ | -------- | -------------------------------------------------------- |
| `code`    | string | yes      | One of `"missing"`, `"invalid"`, or `"unknown"`          |
| `key`     | string | yes      | The environment variable name                            |
| `message` | string | no       | The original issue message for additional context        |

**Returns:** `{ code: string, key: string, summary: string, steps: string[] }`

The explanations vary by code:

- **`missing`** -- summary notes the variable is required by the contract. Steps suggest setting the variable, marking it `.optional()` or `.default()`, and running `envlock example`.
- **`invalid`** -- summary notes the value does not satisfy the declared type. Steps suggest correcting the value, adjusting the builder, and re-running the check.
- **`unknown`** -- summary notes the variable is not declared in the contract. Steps suggest declaring it in the schema, removing it from the file, and note about strict mode.

## Resource template

The server exposes a single resource template:

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

URL-encode the `schemaPath` segment. The resource returns the output of `describeSchema()` as `application/json`. The same cwd confinement rules apply as with the tools.

There is no `list` callback registered for this template. Clients discover it via the `resources/templates/list` MCP method.

## Security

All tools are annotated with `readOnlyHint: true` and `idempotentHint: true` -- the server never writes to the filesystem or produces side effects.

**Path confinement:** every file path (schema files, `.env` files) is resolved against the server's working directory. Any path that would resolve outside the cwd is rejected with an error message. This prevents agents from reading arbitrary files on the host.

**Error handling:** loader failures (file not found, import errors, invalid schema exports) are returned as `isError: true` tool results with a descriptive reason string. They are not thrown as protocol-level errors.

## Programmatic usage

You can create and start the server programmatically:

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

const server = createEnvlockServer({ cwd: "/path/to/project" });
await server.connect(new StdioServerTransport());
```

The `createEnvlockServer` function accepts an optional `EnvlockServerOptions` object with a `cwd` property (defaults to `process.cwd()`). It returns a configured `McpServer` instance from `@modelcontextprotocol/sdk`.

### Exports

The `@envlock/mcp` package exports the following:

**Server setup:**

- `createEnvlockServer` -- creates a configured `McpServer` instance
- `EnvlockServerOptions` -- options type: `{ readonly cwd?: string }`
- `SERVER_INFO` -- `{ name: "envlock", version: "0.1.0" }`

**Tool and resource constants:**

- `TOOL_NAMES` -- object mapping logical names to MCP tool names (`check` to `"envlock_check"`, `inspect` to `"envlock_inspect"`, `renderExample` to `"envlock_render_example"`, `diff` to `"envlock_diff"`, `explainIssue` to `"envlock_explain_issue"`)
- `SCHEMA_RESOURCE_TEMPLATE` -- the URI template string `"envlock://schema/{schemaPath}"`

**Issue explanation:**

- `explainIssue` -- pure function that returns an `IssueExplanation` for a given issue code and key
- `ExplainIssueInput` -- input type: `{ readonly code: IssueCode; readonly key: string; readonly message?: string }`
- `IssueExplanation` -- return type: `{ readonly code: IssueCode; readonly key: string; readonly summary: string; readonly steps: readonly string[] }`

**File loading and path resolution:**

- `resolveInsideCwd` -- resolves a file path against a cwd, rejecting paths that escape it. Returns `PathResolution`.
- `loadSchemaFile` -- resolves, imports, and validates a schema file. Returns `Promise<SchemaLoadResult>`.
- `loadEnvFile` -- resolves and parses a dotenv file. Returns `Promise<EnvFileLoadResult>`.
- `PathResolution` -- `{ path: string } | { error: string }`
- `SchemaLoadResult` -- `{ schema: EnvSchema; path: string } | { error: string }`
- `EnvFileLoadResult` -- `{ source: EnvSource; path: string } | { error: string }`