> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mainwp.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Configuration Reference

> Environment variables, settings.json options, connection diagnostics, and resource limits for the MainWP MCP Server.

The server accepts configuration through environment variables and a `settings.json` file. Environment variables take precedence, so you can keep a base file and override specific values at runtime.

## Environment variables

| Variable | Required | Default | Description |
| - | - | - | - |
| `MAINWP_URL` | Yes | | Base URL of your MainWP Dashboard |
| `MAINWP_USER` | Yes\* | | WordPress login name or email address of the user who owns the Application Password, not the display name |
| `MAINWP_APP_PASSWORD` | Yes\* | | WordPress Application Password |
| `MAINWP_TOKEN` | No | | MainWP REST API bearer token. **Not accepted by the Abilities API; see the note below** |
| `MAINWP_SKIP_SSL_VERIFY` | No | `false` | Skip SSL certificate verification (development only) |
| `MAINWP_ALLOW_HTTP` | No | `false` | Allow HTTP URLs (credentials sent in plain text) |
| `MAINWP_SAFE_MODE` | No | `false` | Block all destructive operations |
| `MAINWP_REQUIRE_USER_CONFIRMATION` | No | `true` | Require two-step confirmation for destructive operations |
| `MAINWP_ALLOWED_TOOLS` | No | | Comma-separated whitelist of tools |
| `MAINWP_BLOCKED_TOOLS` | No | | Comma-separated blacklist of tools |
| `MAINWP_SCHEMA_VERBOSITY` | No | `standard` | Schema detail level: `standard` or `compact` |
| `MAINWP_RESPONSE_FORMAT` | No | `compact` | Tool response JSON: `compact` or `pretty` |
| `MAINWP_RATE_LIMIT` | No | `60` | Maximum API requests per minute (`0` disables) |
| `MAINWP_REQUEST_TIMEOUT` | No | `30000` | Request timeout in milliseconds |
| `MAINWP_MAX_RESPONSE_SIZE` | No | `10485760` | Maximum single response size in bytes (10MB) |
| `MAINWP_MAX_SESSION_DATA` | No | `52428800` | Maximum cumulative session data in bytes (50MB) |
| `MAINWP_RETRY_ENABLED` | No | `true` | Enable automatic retry for transient errors |
| `MAINWP_MAX_RETRIES` | No | `2` | Total attempts including the initial request |
| `MAINWP_RETRY_BASE_DELAY` | No | `1000` | Base delay between retries in milliseconds |
| `MAINWP_RETRY_MAX_DELAY` | No | `2000` | Maximum delay between retries in milliseconds |
| `MAINWP_ABILITY_NAMESPACES` | No | `mainwp` | Comma-separated namespace allowlist |

\* Required as a pair. This is the authentication method.

<Warning>
  **Authentication is `MAINWP_USER` + `MAINWP_APP_PASSWORD`.** The Abilities API, which is the only API this server calls, authenticates through native WordPress and does not accept MainWP REST API bearer tokens. `MAINWP_TOKEN` is still read for compatibility and used when no Application Password credentials are present, but it will fail against the Abilities endpoints. Use an [Application Password](/mcp-server/quickstart).
</Warning>

## Configuration file

Create `settings.json` in one of these locations, checked in order:

1. `./settings.json` (the server's working directory)
2. `~/.config/mainwp-mcp/settings.json`

As of `@mainwp/mcp` 1.2.0, a working-directory `settings.json` cannot loosen security settings: `requireUserConfirmation: false`, `skipSslVerify: true`, and `allowHttp: true` are ignored there, with a warning on stderr. Set those through environment variables or the per-user file.

```json theme={null}
{
  "dashboardUrl": "https://your-dashboard.com",
  "username": "admin",
  "appPassword": "xxxx xxxx xxxx xxxx xxxx xxxx",
  "skipSslVerify": false,
  "safeMode": false,
  "schemaVerbosity": "standard",
  "rateLimit": 60
}
```

Restrict permissions on any file holding credentials:

```bash theme={null}
chmod 600 ~/.config/mainwp-mcp/settings.json
```

A JSON schema ships with the package as `settings.schema.json` for IDE autocompletion.

### Field mapping

| settings.json | Environment variable | Type |
| - | - | - |
| `dashboardUrl` | `MAINWP_URL` | string |
| `username` | `MAINWP_USER` | string |
| `appPassword` | `MAINWP_APP_PASSWORD` | string |
| `apiToken` | `MAINWP_TOKEN` | string |
| `skipSslVerify` | `MAINWP_SKIP_SSL_VERIFY` | boolean |
| `allowHttp` | `MAINWP_ALLOW_HTTP` | boolean |
| `safeMode` | `MAINWP_SAFE_MODE` | boolean |
| `requireUserConfirmation` | `MAINWP_REQUIRE_USER_CONFIRMATION` | boolean |
| `allowedTools` | `MAINWP_ALLOWED_TOOLS` | string\[] |
| `blockedTools` | `MAINWP_BLOCKED_TOOLS` | string\[] |
| `schemaVerbosity` | `MAINWP_SCHEMA_VERBOSITY` | string |
| `responseFormat` | `MAINWP_RESPONSE_FORMAT` | string |
| `rateLimit` | `MAINWP_RATE_LIMIT` | number |
| `requestTimeout` | `MAINWP_REQUEST_TIMEOUT` | number |
| `maxResponseSize` | `MAINWP_MAX_RESPONSE_SIZE` | number |
| `maxSessionData` | `MAINWP_MAX_SESSION_DATA` | number |
| `retryEnabled` | `MAINWP_RETRY_ENABLED` | boolean |
| `maxRetries` | `MAINWP_MAX_RETRIES` | number |
| `retryBaseDelay` | `MAINWP_RETRY_BASE_DELAY` | number |
| `retryMaxDelay` | `MAINWP_RETRY_MAX_DELAY` | number |
| `abilityNamespaces` | `MAINWP_ABILITY_NAMESPACES` | string\[] |

If both credential methods are present, the username plus Application Password pair takes precedence over `apiToken`.

### Multiple Dashboards

Give each Dashboard its own folder containing its own `settings.json`, then point each MCP server entry at the right folder with `cwd` in your AI client's configuration:

```json theme={null}
{
  "mcpServers": {
    "mainwp-staging": {
      "command": "npx",
      "args": ["-y", "@mainwp/mcp"],
      "cwd": "/path/to/staging-credentials"
    }
  }
}
```

Because `./settings.json` is checked first, each server instance picks up the credentials from its own working directory.

## First-run setup

As of `@mainwp/mcp` 1.3.0, a server started without a Dashboard URL or credentials does not fail to launch. It connects to your AI client in **setup mode**: the MainWP tools stay hidden and two setup tools take their place, so you can finish configuration in the conversation instead of hunting through stderr.

* `mainwp_get_setup_status` reports what is missing and returns setup instructions for your assistant to relay. If credentials are present but the Dashboard was unreachable at startup, calling it again retries the connection with the credentials already loaded.
* `mainwp_configure` takes a Dashboard URL, username, and Application Password, verifies them against the Dashboard, and saves them.

There are two ways to finish setup.

**Adding the credentials yourself is the recommended path.** Put `MAINWP_URL`, `MAINWP_USER`, and `MAINWP_APP_PASSWORD` in the `env` block of this server's entry in your MCP client config, or in `~/.config/mainwp-mcp/settings.json`, then restart the client. The password never passes through the conversation.

**Pasting them in chat is also fine.** Your assistant collects the three values and calls `mainwp_configure`. The server verifies them, writes them to `~/.config/mainwp-mcp/settings.json` with owner-only permissions (0600, in a 0700 directory), and scrubs the password from its own logs and from every response. An Application Password is separate from your WordPress login password and you can revoke it from your profile at any time.

<Note>
  Worth knowing before you choose: a password pasted in chat also becomes part of your chat history, which your AI client and provider may retain. If that bothers you later, revoke the password and create a new one.
</Note>

Once configuration succeeds, the full tool list appears in the same session for clients that honor MCP list-changed notifications. Clients that do not refresh on their own need a reconnect or restart.

`mainwp_configure` refuses rather than saving something that would be ignored or overridden:

* Any connection environment variable (`MAINWP_URL`, `MAINWP_USER`, `MAINWP_APP_PASSWORD`, `MAINWP_TOKEN`) is set. Environment variables outrank the file it writes, so finish setup there.
* A `settings.json` exists in the server's working directory. That file is loaded first and would permanently shadow the saved credentials.
* The server already has credentials loaded, whether or not they are currently working. See the next section.

It writes only those three connection fields, never security settings, and blocking `mainwp_configure` through `blockedTools` removes chat-based setup entirely while leaving the manual path available.

### Rejected credentials

If the Dashboard rejects the loaded credentials during startup or a setup connection check, the server enters `credentials_rejected` and keeps the MainWP tools hidden. Calling `mainwp_get_setup_status` reports the problem without resending those credentials. `mainwp_configure` cannot replace them from chat.

The setup status includes:

| Field | What to check |
| - | - |
| `username` | The configured WordPress login name or email address. A value that looks like an Application Password is withheld, with a warning that the username and password may be swapped. |
| `connectionSources` | Where each connection value came from: `env` or `settings.json`. Different values can come from different sources. |
| `overriddenSettingsKeys` | Settings-file values overridden by environment variables. Editing only the file will not change those effective values. |
| `problem` and `guidance` | The rejection details and recovery instructions. Passwords and tokens are not included. |

Correct the value at the source shown in `connectionSources`, using the [field mapping](#field-mapping) for settings-file names, then restart your MCP client. Use the WordPress login name or email address and an Application Password from that user's profile, not the display name or account login password. If the diagnostics report that Application Passwords are disabled, restore their availability on the Dashboard before reconnecting.

HTTP 401 is treated as a credential rejection. Other HTTP 4xx responses are treated this way only when WordPress reports `invalid_username`, `invalid_email`, `incorrect_password`, `application_passwords_disabled`, or `application_passwords_disabled_for_user`. Network failures, TLS errors, HTTP 5xx, and a bare HTTP 403 leave the server in `degraded`, where `mainwp_get_setup_status` can retry with the loaded credentials.

### Why setup will not replace credentials you already have

Chat-based setup can get you connected the first time, but it can never overwrite a connection you set up yourself. That line is deliberate, and it is worth knowing where it costs you something.

The reason is that an assistant acts on text, and text can come from places you did not intend. A page it read, a site name, or an ability description returned by a server could carry instructions aimed at the assistant rather than at you. If setup could overwrite a working configuration, that kind of injected instruction could quietly repoint your server at someone else's Dashboard, and every command you ran afterwards would go there. Restricting setup to the case where there is nothing to overwrite removes that possibility, because a server that has no credentials has nothing worth stealing.

A tempting middle ground is to allow it when the stored credentials are provably wrong, since the Dashboard rejected them with an authentication error. We do not do that, because it would let the remote side decide when your local configuration may be replaced: a Dashboard that had been compromised, or a connection someone was tampering with, could reject a valid login on purpose to unlock the replacement path, without ever knowing your password.

If you rotate the Application Password in WordPress, or the stored one is wrong for any other reason, the server stops resending it after a confirmed rejection. Follow the [rejected-credentials diagnostics](#rejected-credentials) to update the source that supplies the password, then restart the client.

## Behavior settings

* **`safeMode`** blocks every destructive operation at the server. Explained on [Safety & Permissions](/mcp-server/safety#safe-mode-block-deletions-entirely).
* **`requireUserConfirmation`** controls the two-step preview/confirm flow for destructive operations (default on). Also on [Safety & Permissions](/mcp-server/safety#deletions-require-your-approval).
* **`allowedTools` / `blockedTools`** filter the tool catalog. See [Restrict Available Tools](/mcp-server/guides/restrict-tools).
* **`schemaVerbosity`** trades tool-description detail for context tokens. See [Optimize Token Usage](/mcp-server/guides/token-usage).
* **`abilityNamespaces`** controls which plugins' abilities are exposed. See [Use Abilities from Other Plugins](/mcp-server/guides/other-plugin-abilities).
* **`responseFormat`** switches tool response JSON between `compact` (default) and `pretty`.

## Resource limits

These guard against runaway operations and oversized responses.

| Setting | Default | Behavior when exceeded |
| - | - | - |
| `rateLimit` | 60/min | Calls fail until the window passes; `0` disables |
| `requestTimeout` | 30000 ms | The request is aborted |
| `maxResponseSize` | 10 MB | The single response is rejected |
| `maxSessionData` | 50 MB | Subsequent calls fail with `RESOURCE_EXHAUSTED` until the server restarts |

### Input limits

Tool inputs have separate limits from response data. For each string, the called ability's input schema can declare a positive, safe-integer `maxLength`. That value replaces the default, including when it is smaller, up to the server ceiling below. A missing or invalid declaration keeps the default. The check follows nested `properties` and array `items` schemas.

| Input | Limit |
| - | - |
| String without a valid schema `maxLength` | 10,000 characters |
| String with a valid schema `maxLength` | The declared value, capped at 67,108,864 characters |
| Array | 1,000 elements per array |
| Nested objects and arrays | Maximum depth of 5 below the top-level arguments |

String lengths use JavaScript's UTF-16 code-unit count; ASCII and base64 characters each count as one. Over-limit values are rejected, not truncated. String-length errors identify the parameter, effective `maxLength`, and `limitSource` (`default`, `schema`, or `ceiling`).

Transport limits also apply:

* **Inbound stdio:** the buffer limit is 72 MiB of UTF-8 bytes for the incoming JSON-RPC data, including the request envelope and other arguments. Non-ASCII text, JSON escaping, or multiple large values can reach this limit before a per-string limit.
* **GET and DELETE:** inputs are encoded in the query string. The complete encoded URL must be at most 8,000 characters, even if the schema permits longer strings. Oversized URLs are rejected before sending.
* **POST:** inputs use a JSON body. The ability's schema and the Dashboard's PHP, web server, or proxy limits can impose additional constraints. A string limit is not a binary upload-size allowance; base64 encoding increases the payload size.

These input and transport limits are not changed by `maxResponseSize` or `maxSessionData`.

## Retry logic

Transient errors (HTTP 5xx, HTTP 429, network resets) are retried with exponential backoff and jitter. Only read-only operations are retried, which preserves idempotency; writes fail immediately. Permanent errors (4xx other than 429, authentication failures) are never retried. Total time across retries never exceeds `requestTimeout`, and retries bypass the rate limiter to avoid deadlocks.

Disable for automation or testing with `retryEnabled: false`.

## SSL

The server verifies certificates and refuses plain HTTP by default. `skipSslVerify` and `allowHttp` exist for local development against self-signed or HTTP-only environments.

<Warning>
  `skipSslVerify` disables certificate verification entirely and `allowHttp` sends credentials unencrypted. Use them only in isolated development environments, never in production or on untrusted networks.
</Warning>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.