---
title: "Deploy Prompt Optimizer | Open Source PromptPerfect Alternative"
description: "AI prompt optimizer web app and MCP server, password and token protected"
category: "AI/ML"
url: https://railway.com/deploy/prompt-optimizer
---

# Deploy Prompt Optimizer | Open Source PromptPerfect Alternative

AI prompt optimizer web app and MCP server, password and token protected

**[Deploy Prompt Optimizer | Open Source PromptPerfect Alternative on Railway](https://railway.com/template/prompt-optimizer)**

Machine-readable deploy manifest (JSON, validated by TemplateCI): https://railway.com/deploy/prompt-optimizer/manifest.json

- **Creator:** katsuba.dev
- **Category:** AI/ML

## Template content

### prompt-optimizer https://cdn.jsdelivr.net/gh/linshenkx/prompt-optimizer@v2.11.10/images/logo/1024-1024.svg

- **Image:** linshen/prompt-optimizer:2.11.10
- **Start command:** `sh -c 'C=/etc/nginx/http.d/default.conf; A=/etc/nginx/http.d/00-mcp-token.conf; T=$(printf %s "$MCP_AUTH_TOKEN" | tr -cd "A-Za-z0-9"); printf "%s\n" "map \$request_method:\$http_authorization \$mcp_token_denied {" "    default 1;" "    \"~^OPTIONS:\" 0;" > $A; [ -n "$T" ] && printf "    \"~^[A-Z]+:Bearer %s\$\" 0;\n" "$T" >> $A; printf "%s\n" "}" >> $A; grep -q mcp_token_denied $C || sed -i -e "s|^    location /mcp {\$|&\n        if (\$mcp_token_denied) { return 401; }|" -e "s|^    location = /healthz {\$|    location = /livez {\n        auth_basic off;\n        default_type text/plain;\n        return 200 ok;\n    }\n\n&|" $C; grep -q "if (\$mcp_token_denied)" $C && grep -q "location = /livez" $C || { echo "prompt-optimizer: nginx.conf did not match, refusing to start with /mcp unauthenticated"; exit 1; }; [ -n "$T" ] || echo "prompt-optimizer: MCP_AUTH_TOKEN is empty, /mcp will answer 401 to everything"; exec sh /start-services.sh'`
- **Health check:** /livez
- **Public domain:** Yes

## Documentation

# Deploy and Host Prompt Optimizer on Railway

Prompt Optimizer is an open-source workbench for writing better prompts: paste a prompt, let a model rewrite it with a built-in optimisation template, compare the original and the result side by side, and iterate. This template runs the official web app together with its MCP server, so the same optimiser is available to Claude Desktop, Cursor and any other MCP client.

## About Hosting Prompt Optimizer

The template deploys the upstream `linshen/prompt-optimizer` image, pinned to an exact release rather than `latest`, as a single service. Inside it nginx serves the web app and a Node process serves the MCP server at `/mcp`.

It ships with both entrances locked:

- **Web app behind a password.** A random password is generated for the `admin` user on every deploy. This matters more than it looks: any provider key you set on the service is delivered to the browser inside `/config.js`, so without a password that key would be readable by anyone who finds the URL. Upstream's own compose file defaults the password to `123456`.
- **MCP endpoint behind a bearer token.** Upstream deliberately exempts `/mcp` from the password (MCP clients cannot do basic auth), and the MCP server has no authentication of its own, so a stock deployment lets anyone call the optimiser on your API key. This template puts an `Authorization: Bearer` check in front of `/mcp` using the generated `MCP_AUTH_TOKEN`. An empty token rejects every request instead of opening the endpoint.

There is no database and no volume. Model settings, history and favourites live in each user's browser (with an optional S3 or WebDAV backup you can configure in the app), and the MCP server is stateless.

## Common Use Cases

- **Prompt engineering for a team**: one shared, password-protected URL instead of everyone installing the desktop app or extension
- **Optimising system prompts**: rewrite and test system prompts for agents and assistants before shipping them
- **MCP tool for coding assistants**: call `optimize-user-prompt`, `optimize-system-prompt` and `iterate-prompt` from Claude Desktop or Cursor
- **Comparing models**: run the same prompt against OpenAI, Anthropic, Gemini, DeepSeek, OpenRouter or any OpenAI-compatible endpoint

## Dependencies for Prompt Optimizer Hosting

### Deployment Dependencies

- An API key for at least one model provider, if you want the MCP server or want the web app pre-configured. The web app alone works without one: users can enter their own keys in the browser.

### Implementation Details

**Signing in to the web app.** Open the public URL and sign in as `admin` with the value of `ACCESS_PASSWORD` from the service's Variables tab.

**Adding a provider key.** Set one of these variables on the service and redeploy:

- `VITE_OPENAI_API_KEY`
- `VITE_ANTHROPIC_API_KEY`
- `VITE_GEMINI_API_KEY`
- `VITE_DEEPSEEK_API_KEY`
- `VITE_OPENROUTER_API_KEY`
- `VITE_CUSTOM_API_KEY` together with `VITE_CUSTOM_API_BASE_URL` and `VITE_CUSTOM_API_MODEL` for any OpenAI-compatible endpoint (Ollama, vLLM, LiteLLM, Azure and so on)

Keys set here are shared with everyone who knows the web password, because the app runs in the browser and calls providers directly from it. If that is not what you want, leave them empty and let each user enter their own key in the app.

**The MCP server needs a key.** It picks its default model from the variables above and does not start when none is set. `MCP_DEFAULT_MODEL_PROVIDER` (for example `openai`, `anthropic` or `custom`) chooses between several.

**Connecting an MCP client.** Use the Streamable HTTP transport with the URL `https://YOUR-DOMAIN/mcp` and the header `Authorization: Bearer YOUR-MCP_AUTH_TOKEN`. For example, in Cursor's `mcp.json`:

```json
{
  "mcpServers": {
    "prompt-optimizer": {
      "url": "https://YOUR-DOMAIN/mcp",
      "headers": { "Authorization": "Bearer YOUR-MCP_AUTH_TOKEN" }
    }
  }
}
```

A request without the token, or with a wrong one, gets `401`. So does a correct token while the MCP server is not running, which means no provider key is set.

**Rotating credentials.** Change `ACCESS_PASSWORD` or `MCP_AUTH_TOKEN` in the Variables tab and redeploy. Nothing else stores them.

**Health.** Railway checks `/livez`, which nginx answers on its own, so a deployment with no provider key is still healthy.

**Resources and cost.** Measured on Railway: about 70 MB of RAM at idle and around 170 MB while handling MCP calls, with negligible CPU. Expect roughly $1–3 a month on usage-based pricing. Model calls are billed by your provider, not by Railway.

## Why Deploy Prompt Optimizer on Railway?

Railway is a singular platform to deploy your infrastructure stack. Railway will host your infrastructure so you don't have to deal with configuration, while allowing you to vertically and horizontally scale it.

By deploying Prompt Optimizer on Railway, you are one step closer to supporting a complete full-stack application with minimal burden. Host your servers, databases, AI agents, and more on Railway.


## Similar templates

- [Chat Chat](https://railway.com/deploy/-WWW5r) — Chat Chat, your own unified chat and search to AI platform.
- [stella](https://railway.com/deploy/stella) — Self-host stella with web, API, Postgres, Redis, and object storage.
- [Hermes Agent | OpenClaw Alternative with Dashboard](https://railway.com/deploy/hermes-agent-or-openclaw-alternative-wit) — Self-Hosted Hermes AI Agent for Telegram, Discord & Slack

Open this page in a browser: https://railway.com/deploy/prompt-optimizer
