# How to Fix CORS Issues When Deploying Prompt-Optimizer as a Web App

> Resolve CORS issues deploying Prompt-Optimizer web app. Configure Express CORS middleware or Nginx reverse proxy to allow your origin and handle cross-origin requests.

- Repository: [且炼时光/prompt-optimizer](https://github.com/linshenkx/prompt-optimizer)
- Tags: troubleshooting
- Published: 2026-02-23

---

**Configure the Express MCP server with the `cors` middleware to explicitly allow your web app's origin, or use Nginx reverse proxy headers to handle cross-origin requests at the edge.**

When deploying the `linshenkx/prompt-optimizer` repository as a production web application, Cross-Origin Resource Sharing (CORS) errors frequently block API calls between the Vite frontend and the Express-based MCP server. These issues typically manifest when the `packages/web` frontend attempts to communicate with the `packages/mcp-server` backend across different origins, ports, or protocols.

## Understanding CORS in the Prompt-Optimizer Architecture

### The Separation of Frontend and Backend

The Prompt-Optimizer project is organized as a monorepo where `packages/web` contains the Vue.js frontend built with Vite, while `packages/mcp-server` houses the Express API that handles model context protocol operations. When you deploy these services separately—serving the web app from `https://app.example.com` and the API from `https://api.example.com`—the browser enforces CORS policies that require explicit permission from the server to complete cross-origin requests.

## Common CORS Issues When Deploying Prompt-Optimizer

### Missing or Mismatched Access-Control-Allow-Origin Headers

The most frequent error occurs when the MCP server returns responses without the `Access-Control-Allow-Origin` header, or returns a specific origin that doesn't match the browser's request. In [`packages/mcp-server/src/index.ts`](https://github.com/linshenkx/prompt-optimizer/blob/main/packages/mcp-server/src/index.ts), if the Express app doesn't configure CORS middleware, browsers will block all API responses with errors like "CORS header 'Access-Control-Allow-Origin' missing."

### Credentials and Wildcard Conflicts

When the frontend in `packages/web` sends requests with `credentials: 'include'` to pass authentication cookies or tokens, the server must respond with `Access-Control-Allow-Credentials: true`. However, CORS specifications forbid using the wildcard `*` for `Access-Control-Allow-Origin` when credentials are enabled. This creates a conflict if the Express server is configured with `origin: '*'` while `credentials: true` is also set.

### Pre-flight OPTIONS Request Failures

Complex requests—such as `POST` calls with `Content-Type: application/json` or custom headers like `Authorization`—trigger pre-flight `OPTIONS` requests. If the MCP server doesn't handle these OPTIONS requests properly in `packages/mcp-server`, the browser never sends the actual API call. This typically happens when the server lacks explicit handling for the `OPTIONS` method or doesn't return the required `Access-Control-Allow-Methods` and `Access-Control-Allow-Headers` headers.

### Protocol and Port Mismatches

Deploying the web app over HTTPS while the API remains on HTTP creates mixed-content blocks that appear similar to CORS errors. Similarly, using different ports in development—such as `localhost:5173` for the Vite dev server and `localhost:4000` for the MCP server—triggers origin mismatches unless properly configured.

## Resolving CORS Issues in Prompt-Optimizer

### Configure CORS in the Express MCP Server

The most direct solution involves adding the `cors` middleware to the Express application in `packages/mcp-server`. Install the package and configure it to allow your specific web app origin:

```ts
// File: packages/mcp-server/src/index.ts
import express from 'express';
import cors from 'cors';
import routes from './routes';

const app = express();

app.use(
  cors({
    origin: process.env.CORS_ORIGIN || '*', // replace '*' with your domain in prod
    credentials: true,
  })
);

app.use(express.json());
app.use('/api', routes);
export default app;

```

For production deployments, replace the wildcard `*` with the exact URL of your deployed web app (e.g., `https://prompt-optimizer.example.com`) and ensure `credentials: true` is only enabled when necessary.

### Set Up Nginx Reverse Proxy Headers

If you deploy Prompt-Optimizer using the included Docker setup with Nginx, you can handle CORS at the reverse proxy level in [`docker/nginx.conf`](https://github.com/linshenkx/prompt-optimizer/blob/main/docker/nginx.conf). This approach centralizes CORS handling and keeps application code clean:

```nginx

# File: docker/nginx.conf (inside the server block)

location /api/ {
    proxy_pass http://mcp-server:4000/;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;

    # CORS headers

    add_header Access-Control-Allow-Origin $http_origin always;
    add_header Access-Control-Allow-Methods 'GET,POST,PUT,DELETE,OPTIONS' always;
    add_header Access-Control-Allow-Headers 'Authorization,Content-Type' always;
    add_header Access-Control-Allow-Credentials 'true' always;

    # Handle pre‑flight

    if ($request_method = OPTIONS) {
        return 204;
    }
}

```

This configuration dynamically reads the requesting origin via `$http_origin`, allowing multiple domains while supporting credentials. The `OPTIONS` handler returns HTTP 204 for pre-flight requests without forwarding them to the backend.

### Use Vite Dev Server Proxy for Local Development

During development, you can bypass CORS entirely by configuring the Vite dev server in [`packages/web/vite.config.ts`](https://github.com/linshenkx/prompt-optimizer/blob/main/packages/web/vite.config.ts) to proxy API requests to the MCP server:

```ts
// File: packages/web/vite.config.ts
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';

export default defineConfig({
  plugins: [vue()],
  server: {
    proxy: {
      '/api': {
        target: 'http://localhost:4000',
        changeOrigin: true,
        secure: false,
      },
    },
  },
});

```

This setup makes the browser believe requests to `/api` originate from the same origin as the Vite dev server (typically `localhost:5173`), eliminating CORS errors during local testing. Note that this proxy only applies to the development server and does not affect production builds.

## Summary

- **CORS errors** in Prompt-Optimizer occur when the `packages/web` frontend attempts to call the `packages/mcp-server` API across different origins, ports, or protocols.
- **Missing headers** like `Access-Control-Allow-Origin` or improper handling of **pre-flight OPTIONS requests** are the most common root causes.
- **Resolution methods** include adding the `cors` middleware to [`packages/mcp-server/src/index.ts`](https://github.com/linshenkx/prompt-optimizer/blob/main/packages/mcp-server/src/index.ts), configuring [`docker/nginx.conf`](https://github.com/linshenkx/prompt-optimizer/blob/main/docker/nginx.conf) for reverse proxy header injection, or using the Vite proxy in [`packages/web/vite.config.ts`](https://github.com/linshenkx/prompt-optimizer/blob/main/packages/web/vite.config.ts) for development.
- **Production deployments** should specify exact allowed origins rather than wildcards when credentials are enabled, and ensure HTTPS protocols match between frontend and backend.

## Frequently Asked Questions

### Why do I get CORS errors only in production but not during local development?

Local development typically runs both the Vite frontend and Express backend on `localhost` with different ports, but browsers treat different ports as different origins. However, if you're using the Vite dev server proxy configured in [`packages/web/vite.config.ts`](https://github.com/linshenkx/prompt-optimizer/blob/main/packages/web/vite.config.ts), the browser sees all API requests as same-origin, masking CORS issues. In production, the frontend and backend usually reside on separate domains or subdomains without a proxy, exposing any missing CORS headers from the MCP server.

### Can I use wildcards for CORS origins when deploying Prompt-Optimizer?

You can use `origin: '*'` in the Express CORS configuration for development or public APIs, but this approach fails when your frontend sends requests with `credentials: 'include'` to pass authentication tokens or cookies. The CORS specification forbids combining wildcards with credentials. For production deployments of Prompt-Optimizer, specify the exact origin of your web app (e.g., `https://optimizer.example.com`) in the `CORS_ORIGIN` environment variable or Nginx configuration.

### How do I handle CORS for the MCP server API endpoints?

The MCP server in `packages/mcp-server` uses Express, so you should install the `cors` middleware (`npm install cors`) and apply it in the main entry file ([`src/index.ts`](https://github.com/linshenkx/prompt-optimizer/blob/main/src/index.ts)). Configure it to allow your web app's origin and handle pre-flight requests automatically. Alternatively, if you deploy behind the provided Nginx Docker setup, configure CORS headers in [`docker/nginx.conf`](https://github.com/linshenkx/prompt-optimizer/blob/main/docker/nginx.conf) to handle cross-origin requests at the reverse proxy layer before they reach the MCP server.

### Is it better to handle CORS in Nginx or in the Express application?

Handling CORS in Nginx via [`docker/nginx.conf`](https://github.com/linshenkx/prompt-optimizer/blob/main/docker/nginx.conf) is generally preferred for production deployments because it centralizes security policy, reduces load on the Express application, and handles pre-flight requests efficiently without hitting your backend server. However, configuring CORS directly in the Express app (`packages/mcp-server`) offers more granular control per route and easier debugging during development. Many deployments use both: strict origin validation in Express and broad header handling in Nginx for defense in depth.