# Running Multiple Concurrent MCP Server Instances for Distinct OpenStack Projects: A Complete Guide

> Learn how to run multiple concurrent MCP server instances for distinct OpenStack projects. This guide details project-scoped isolation using unique OS PROJECT NAME variables.

- Repository: [JungJungIn/mcp-openstack-ops](https://github.com/call518/mcp-openstack-ops)
- Tags: how-to-guide
- Published: 2026-02-26

---

**You can safely run multiple concurrent MCP server instances for distinct OpenStack projects by launching separate processes with unique `OS_PROJECT_NAME` environment variables, as the call518/mcp-openstack-ops repository enforces strict project-scoped isolation at the connection level.**

The call518/mcp-openstack-ops repository provides a Model Context Protocol (MCP) server for OpenStack operations. When managing infrastructure across multiple tenants, running multiple concurrent MCP server instances for distinct OpenStack projects becomes essential for maintaining security boundaries and operational flexibility without risking cross-project data leakage.

## How Project Isolation Works in MCP-OpenStack-Ops

The repository implements project-scoped isolation through environment-variable-based connection management and runtime validation. Every tool validates that the resource it touches belongs to the project identified by the `OS_PROJECT_NAME` environment variable.

### Connection Caching and Environment Variables

In [`src/mcp_openstack_ops/connection.py`](https://github.com/call518/mcp-openstack-ops/blob/main/src/mcp_openstack_ops/connection.py), a single `openstack.connection.Connection` is created per process and cached for reuse. The connection is built from environment variables, including `OS_PROJECT_NAME`, ensuring that each process maintains its own distinct authentication context (lines 43-56).

### Project ID Resolution and Validation

The `get_current_project_id()` function (lines 43-72) reads the authentication token and falls back to a project-name lookup, guaranteeing the exact project ID is known for every request. Subsequently, every "find" or list helper calls `validate_resource_ownership()` (lines 78-112), which compares the resource's `project_id` with the current project ID, allowing only public or shared resources to be accessed outside the project boundary.

Because these checks are performed inside each process, running two processes with different environment variables creates two completely isolated execution contexts.

## Deployment Patterns for Concurrent MCP Server Instances

You can deploy multiple instances using three primary patterns, depending on your infrastructure requirements and client capabilities.

### Separate Local Processes

For quick testing or development environments, export distinct sets of `OS_…` variables for each project and start the server on different ports using the `--port` argument. This pattern requires minimal setup and works immediately on any host with Python installed.

### Docker Compose with Multiple Services

For production-grade, reproducible environments, duplicate the `mcp-server` service definition in your [`docker-compose.yml`](https://github.com/call518/mcp-openstack-ops/blob/main/docker-compose.yml), overriding `environment.OS_PROJECT_NAME` and mapping unique host ports for each service. This approach leverages container isolation while maintaining consistent deployment artifacts.

### Pre-Built Multi-Project JSON Configuration

When using Claude Desktop or any client that reads [`mcp_servers.json`](https://github.com/call518/mcp-openstack-ops/blob/main/mcp_servers.json), copy and edit `mcp-config.json.multi-project`. This file already contains three ready-to-use configurations (production, development, testing) with appropriate environment variable sets, eliminating manual configuration errors.

## Code Examples for Running Multiple Instances

### Running Two Processes Manually

Launch independent processes with distinct environment scopes and port bindings:

```bash

# Production – read-only

export OS_PROJECT_NAME=production
export OS_AUTH_HOST=192.168.35.2
export OS_AUTH_PORT=5555
export OS_USERNAME=admin
export OS_PASSWORD=changeme
export ALLOW_MODIFY_OPERATIONS=false
python -m mcp_openstack_ops --type stdio --port 8080 &

# Development – write-enabled

export OS_PROJECT_NAME=development
export ALLOW_MODIFY_OPERATIONS=true
python -m mcp_openstack_ops --type stdio --port 8081 &

```

Each process reads its own environment and therefore only sees resources belonging to the declared project.

### Docker Compose Configuration

Define three isolated services in [`docker-compose.yml`](https://github.com/call518/mcp-openstack-ops/blob/main/docker-compose.yml):

```yaml
version: "3.8"
services:
  mcp-server-production:
    build:
      context: .
      dockerfile: Dockerfile.MCP-Server
    environment:
      OS_PROJECT_NAME: production
      OS_AUTH_HOST: 192.168.35.2
      OS_AUTH_PORT: 5555
      ALLOW_MODIFY_OPERATIONS: "false"
    ports:
      - "18005:8080"

  mcp-server-development:
    build:
      context: .
      dockerfile: Dockerfile.MCP-Server
    environment:
      OS_PROJECT_NAME: development
      OS_AUTH_HOST: 192.168.35.2
      OS_AUTH_PORT: 5555
      ALLOW_MODIFY_OPERATIONS: "true"
    ports:
      - "18006:8080"

  mcp-server-testing:
    build:
      context: .
      dockerfile: Dockerfile.MCP-Server
    environment:
      OS_PROJECT_NAME: testing
      OS_AUTH_HOST: 192.168.35.2
      OS_AUTH_PORT: 5555
      ALLOW_MODIFY_OPERATIONS: "true"
      MCP_LOG_LEVEL: DEBUG
    ports:
      - "18007:8080"

```

All three containers share the same image but isolate themselves via `OS_PROJECT_NAME` and distinct host ports.

### Claude Desktop Multi-Project Setup

Configure `~/.config/claude-desktop/mcp_servers.json` using the provided multi-project template:

```json
{
  "mcpServers": {
    "openstack-production": {
      "command": "python",
      "args": ["-m", "mcp_openstack_ops"],
      "env": {
        "OS_PROJECT_NAME": "production",
        "ALLOW_MODIFY_OPERATIONS": "false"
      }
    },
    "openstack-development": {
      "command": "python",
      "args": ["-m", "mcp_openstack_ops"],
      "env": {
        "OS_PROJECT_NAME": "development",
        "ALLOW_MODIFY_OPERATIONS": "true"
      }
    },
    "openstack-testing": {
      "command": "python",
      "args": ["-m", "mcp_openstack_ops"],
      "env": {
        "OS_PROJECT_NAME": "testing",
        "ALLOW_MODIFY_OPERATIONS": "true",
        "MCP_LOG_LEVEL": "DEBUG"
      }
    }
  }
}

```

Place this file at the appropriate path for your MCP client, and the interface will expose three independent MCP servers, each locked to its specific project.

## Key Files Supporting Multi-Project Isolation

Understanding the source code structure helps verify the isolation guarantees when running multiple concurrent MCP server instances for distinct OpenStack projects.

- **[`src/mcp_openstack_ops/connection.py`](https://github.com/call518/mcp-openstack-ops/blob/main/src/mcp_openstack_ops/connection.py)** – Contains the core connection handling and project-isolation helpers including `get_current_project_id()` (lines 43-72) and `validate_resource_ownership()` (lines 78-112). These functions guarantee that each server process enforces project boundaries by comparing resource ownership against the current project ID derived from `OS_PROJECT_NAME`.

- **[`src/mcp_openstack_ops/mcp_main.py`](https://github.com/call518/mcp-openstack-ops/blob/main/src/mcp_openstack_ops/mcp_main.py)** – Registers tools based on the `ALLOW_MODIFY_OPERATIONS` environment flag, allowing you to configure specific instances as read-only or write-enabled per project.

- **`mcp-config.json.multi-project`** – Pre-filled JSON configuration defining three distinct server instances (production, development, testing) with appropriate environment variable sets, serving as a copy-and-paste template for MCP clients.

- **[`docker-compose.yml`](https://github.com/call518/mcp-openstack-ops/blob/main/docker-compose.yml)** – Example orchestration demonstrating how to expose each instance on a unique host port while reusing the same container image.

- **[`README.md`](https://github.com/call518/mcp-openstack-ops/blob/main/README.md)** – Documents the isolation model in the *Project Isolation & Security* and *Multi-Project Configuration* sections, providing additional context on the security architecture.

## Summary

Running multiple concurrent MCP server instances for distinct OpenStack projects relies on the built-in project-scoped isolation of the call518/mcp-openstack-ops repository.

- **Process-level isolation** is enforced through the `OS_PROJECT_NAME` environment variable, with each process maintaining its own cached `openstack.connection.Connection` in [`src/mcp_openstack_ops/connection.py`](https://github.com/call518/mcp-openstack-ops/blob/main/src/mcp_openstack_ops/connection.py).
- **Runtime validation** occurs via `validate_resource_ownership()` (lines 78-112), which compares resource project IDs against the current context, preventing cross-project access.
- **Deployment flexibility** supports local processes, Docker Compose services, or JSON configurations via `mcp-config.json.multi-project`, each binding to distinct ports with unique environment scopes.
- **Operational safety** is enhanced by the `ALLOW_MODIFY_OPERATIONS` flag, allowing read-only or write-enabled configurations per project instance.

## Frequently Asked Questions

### Can I run multiple MCP servers for the same OpenStack project?

Yes, you can run multiple instances targeting the same project if you require different operational modes. For example, you might run one instance with `ALLOW_MODIFY_OPERATIONS=false` for read-only operations and another with `ALLOW_MODIFY_OPERATIONS=true` for administrative tasks, both using the same `OS_PROJECT_NAME`. Each process maintains independent connection caches and validation contexts.

### How does the server prevent cross-project resource access?

The server prevents cross-project access through a three-layer validation system implemented in [`src/mcp_openstack_ops/connection.py`](https://github.com/call518/mcp-openstack-ops/blob/main/src/mcp_openstack_ops/connection.py). First, `get_current_project_id()` (lines 43-72) resolves the exact project ID from the `OS_PROJECT_NAME` environment variable. Second, every resource lookup calls `validate_resource_ownership()` (lines 78-112), which compares the resource's `project_id` field against the current project ID. Third, the connection cache ensures each process maintains its own authenticated session, preventing token leakage between instances.

### What happens if I change OS_PROJECT_NAME while the server is running?

Changing `OS_PROJECT_NAME` while the server is running does not affect the current process because the connection is cached at startup. In [`src/mcp_openstack_ops/connection.py`](https://github.com/call518/mcp-openstack-ops/blob/main/src/mcp_openstack_ops/connection.py) (lines 43-56), the `openstack.connection.Connection` is created once per process and reused for subsequent requests. To switch projects, you must restart the server process with the new environment variable values, ensuring the connection cache is rebuilt with the correct project scope.

### Is there a performance penalty for running multiple concurrent instances?

There is minimal performance penalty for running multiple concurrent instances because each process operates independently with its own connection cache. The `openstack.connection.Connection` object is cached per process (lines 43-56 in [`connection.py`](https://github.com/call518/mcp-openstack-ops/blob/main/connection.py)), eliminating redundant authentication overhead within each instance. Resource utilization scales linearly with the number of instances, similar to running multiple Python processes, with no shared locks or contention points between project-scoped servers.