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

# User Management

## What Is User Management?

User Management allows enterprise applications to serve multiple users through a single MCP server instance. Instead of creating separate servers for each user, you can dynamically switch user context using the `x-alloy-userid` header.

Think of it as a multi-tenant system where:

* **One server** serves all your users
* **Each request** can specify which user it's for
* **Data and credentials** remain isolated per user
* **Permissions** are enforced at the user level

## How User Management Works

When you make a request with the `x-alloy-userid` header, the system switches context to that specific user:

```mermaid mermaid theme={null}
graph TD
    A[Client Request with x-alloy-userid] --> B{Validate Header}
    B -->|Valid User ID| C[Switch User Context]
    B -->|Invalid/Missing| D[Use Default Context]

    C --> E[Load User Credentials]
    C --> F[Apply User Permissions]
    C --> G[Access User Data]

    E --> H[Execute Request]
    F --> H
    G --> H

    H --> I[Return User-Specific Response]
    D --> J[Return Default Response]
```

The user management system operates at multiple levels:

1. **Authentication** - Validates the enterprise API key has permission to override users
2. **Context Switching** - Loads the specified user's context, credentials, and permissions
3. **Data Isolation** - Ensures each user only sees their own credentials and data
4. **Execution** - Runs the request in the user's context
5. **Response** - Returns results specific to that user

## Why Use User Management?

### Multi-Tenant SaaS Applications

* **Single Integration**: One MCP server for all your customers
* **Customer Isolation**: Each customer's data and credentials stay separate
* **Easy Scaling**: Add users without creating new servers

### Team Collaboration

* **Department Access**: Sales uses CRM tools, Marketing uses email tools
* **Individual Credentials**: Each team member has their own third-party logins
* **Centralized Control**: Manage all users from one place

### Enterprise Platforms

* **User Provisioning**: Automatically set up new users
* **Compliance**: Track actions per user for audit requirements
* **Cost Efficiency**: One server infrastructure for unlimited users

## Visualizing User Management

### Without User Management - Multiple Servers:

```mermaid mermaid theme={null}
graph LR
    U1[User Alice] --> S1[Alice's MCP Server]
    U2[User Bob] --> S2[Bob's MCP Server]
    U3[User Carol] --> S3[Carol's MCP Server]

    S1 --> C1[Alice's Credentials]
    S2 --> C2[Bob's Credentials]
    S3 --> C3[Carol's Credentials]
```

### With User Management - Single Server:

```mermaid mermaid theme={null}
graph LR
    U1[User Alice] --> H1[x-alloy-userid: alice]
    U2[User Bob] --> H2[x-alloy-userid: bob]
    U3[User Carol] --> H3[x-alloy-userid: carol]

    H1 --> S[Single MCP Server]
    H2 --> S
    H3 --> S

    S --> UC{User Context}
    UC -->|Alice| C1[Alice's Credentials]
    UC -->|Bob| C2[Bob's Credentials]
    UC -->|Carol| C3[Carol's Credentials]
```

## Quick Start

### Basic User Override

```bash expandable theme={null}
curl -X POST "https://mcp.runalloy.com/mcp/YOUR_SERVER_ID/YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "x-alloy-userid: user_abc123" \
  -d '{
    "jsonrpc": "2.0",
    "method": "tools/call",
    "params": {
      "name": "list_connectors_alloy",
      "arguments": {}
    },
    "id": "1"
  }'
```

## How to Implement User Management

### Step 1: Create an Enterprise MCP Server

Create a server with your enterprise API key:

```bash expandable theme={null}
curl -X POST https://mcp.runalloy.com/api/servers \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "enterprise-multi-user",
    "description": "Enterprise server for multiple users",
    "restrictions": {
      "permissions": [
        {
          "connector": "slack",
          "mode": "allow",
          "actions": ["*"]
        },
        {
          "connector": "notion",
          "mode": "allow",
          "actions": ["*"]
        }
      ]
    }
  }'
```

### Step 2: Execute Requests for Different Users

#### For User Alice:

```bash expandable theme={null}
curl -X POST "YOUR_MCP_SERVER_URL" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "x-alloy-userid: user_alice_123" \
  -d '{
    "jsonrpc": "2.0",
    "method": "tools/call",
    "params": {
      "name": "execute_action_alloy",
      "arguments": {
        "connectorId": "slack",
        "actionId": "chat_postMessage",
        "credentialId": "alice_slack_credential_id",
        "parameters": {
          "requestBody": {
            "channel": "C123456",
            "text": "Message from Alice"
          }
        }
      }
    },
    "id": "1"
  }'
```

#### For User Bob:

```bash expandable theme={null}
curl -X POST "YOUR_MCP_SERVER_URL" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "x-alloy-userid: user_bob_456" \
  -d '{
    "jsonrpc": "2.0",
    "method": "tools/call",
    "params": {
      "name": "execute_action_alloy",
      "arguments": {
        "connectorId": "slack",
        "actionId": "chat_postMessage",
        "credentialId": "bob_slack_credential_id",
        "parameters": {
          "requestBody": {
            "channel": "C789012",
            "text": "Message from Bob"
          }
        }
      }
    },
    "id": "1"
  }'
```

## Understanding the User Flow

Here's how a typical user management request flows through the system:

```mermaid mermaid theme={null}
sequenceDiagram
    participant App as Your Application
    participant MCP as MCP Server
    participant Auth as Auth System
    participant Store as User Store
    participant Conn as Connector

    App->>MCP: Request with x-alloy-userid: user_123
    MCP->>Auth: Validate Enterprise API Key
    Auth-->>MCP: Valid Enterprise Key

    MCP->>Store: Load user_123 context
    Store-->>MCP: User credentials & permissions

    MCP->>Conn: Execute action with user_123 credentials
    Conn-->>MCP: Action result

    MCP-->>App: Response for user_123
```

Each step ensures:

1. **Authentication** - Only enterprise keys can override users
2. **Authorization** - User must exist and have permissions
3. **Isolation** - User gets only their data
4. **Execution** - Actions use user's specific credentials

## Integration Examples

### Node.js Client

```javascript expandable theme={null}
class MCPClient {
  constructor(serverUrl, token) {
    this.serverUrl = serverUrl;
    this.token = token;
  }

  async executeForUser(userId, method, params) {
    const response = await fetch(`${this.serverUrl}/${this.token}`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Accept': 'application/json, text/event-stream',
        'x-alloy-userid': userId  // Dynamic user override
      },
      body: JSON.stringify({
        jsonrpc: '2.0',
        method: 'tools/call',
        params: {
          name: method,
          arguments: params
        },
        id: '1'
      })
    });

    return response.json();
  }
}

// Usage
const mcp = new MCPClient(
  'https://mcp.runalloy.com/mcp/enterprise-123',
  'your_token_here'
);

// Execute for different users
await mcp.executeForUser('user_alice_123', 'list_connectors_alloy', {});
await mcp.executeForUser('user_bob_456', 'list_connectors_alloy', {});
```

### Python Client

```python expandable theme={null}
import requests

class MCPClient:
    def __init__(self, server_url, token):
        self.server_url = server_url
        self.token = token

    def execute_for_user(self, user_id, method, params):
        url = f"{self.server_url}/{self.token}"

        headers = {
            'Content-Type': 'application/json',
            'Accept': 'application/json, text/event-stream',
            'x-alloy-userid': user_id  # Dynamic user override
        }

        payload = {
            'jsonrpc': '2.0',
            'method': 'tools/call',
            'params': {
                'name': method,
                'arguments': params
            },
            'id': '1'
        }

        response = requests.post(url, json=payload, headers=headers)
        return response.json()

# Usage
mcp = MCPClient(
    'https://mcp.runalloy.com/mcp/enterprise-123',
    'your_token_here'
)

# Execute for different users
mcp.execute_for_user('user_alice_123', 'list_connectors_alloy', {})
mcp.execute_for_user('user_bob_456', 'list_connectors_alloy', {})
```

## Key Concepts

### User Context

Each user has their own isolated context containing:

* **Credentials** - OAuth tokens and API keys for third-party services
* **Permissions** - What actions they can perform
* **Data** - Their specific configurations and settings
* **History** - Their action logs and usage

### Enterprise Authentication

User management requires enterprise-level authentication:

* **Standard API Keys** - Cannot override user context
* **Enterprise API Keys** - Can specify any valid user ID
* **Security** - Prevents unauthorized user impersonation

## Common Use Cases

### 1. SaaS Platform Integration

Serve all your customers through one MCP server:

```javascript expandable theme={null}
// When customer Alice uses your platform
await mcpClient.executeForUser(alice.userId, 'execute_action_alloy', {
  connectorId: 'slack',
  actionId: 'chat_postMessage',
  // ... other params
});

// When customer Bob uses your platform
await mcpClient.executeForUser(bob.userId, 'execute_action_alloy', {
  connectorId: 'notion',
  actionId: 'pages_create',
  // ... other params
});
```

### 2. Multi-Tenant Applications

Isolate data and credentials per tenant:

```javascript expandable theme={null}
const tenantUserId = `tenant_${tenantId}_user_${userId}`;
await mcpClient.executeForUser(tenantUserId, method, params);
```

### 3. Team Collaboration Tools

Grant team members access to specific integrations:

```javascript expandable theme={null}
// Sales team member
await mcpClient.executeForUser('team_sales_john', 'execute_action_alloy', {
  connectorId: 'hubspot',
  actionId: 'contacts_create'
});

// Marketing team member
await mcpClient.executeForUser('team_marketing_jane', 'execute_action_alloy', {
  connectorId: 'mailchimp',
  actionId: 'campaigns_create'
});
```

### Security Features

1. **Enterprise-Only** - Only enterprise API keys can override users
2. **Validation** - User IDs are sanitized and validated
3. **Fallback** - Invalid users fall back to default context
4. **Logging** - All override attempts are logged
5. **Isolation** - Users cannot access each other's data

## Best Practices

### 1. User ID Format

Use a consistent format for user IDs:

```javascript theme={null}
// Good patterns
`${companyId}_${userId}`
`${environment}_${tenantId}_${userId}`
`team_${department}_${username}`
```

### 2. Error Handling

Always handle cases where user override might fail:

```javascript theme={null}
try {
  const result = await mcpClient.executeForUser(userId, method, params);
  return result;
} catch (error) {
  // Fallback logic or error reporting
  console.error(`Failed for user ${userId}:`, error);
}
```

### 3. Rate Limiting

Implement per-user rate limiting in your application:

```javascript expandable theme={null}
const userRateLimiter = new Map();

async function executeWithRateLimit(userId, method, params) {
  if (userRateLimiter.get(userId) > MAX_REQUESTS_PER_MINUTE) {
    throw new Error('Rate limit exceeded for user');
  }

  // Update rate limit counter
  userRateLimiter.set(userId, (userRateLimiter.get(userId) || 0) + 1);

  return mcpClient.executeForUser(userId, method, params);
}
```

### 4. Credential Management

Each user should have their own credentials:

```javascript theme={null}
// Store credentials per user
const userCredentials = {
  'user_alice_123': {
    slack: 'alice_slack_credential_id',
    notion: 'alice_notion_credential_id'
  },
  'user_bob_456': {
    slack: 'bob_slack_credential_id',
    hubspot: 'bob_hubspot_credential_id'
  }
};
```

## Important Considerations

### User Prerequisites

* Users must exist in Alloy before you can switch to their context
* Create users via Alloy API or dashboard first
* Invalid user IDs fall back to default context

### Permission Model

* Users inherit the server's restriction settings
* Cannot override server restrictions per user
* For different permissions, create separate servers

### Technical Limits

* HTTP header size limit (typically 8KB)
* User ID format restrictions (alphanumeric + limited special characters)
* Rate limits apply per user context

## Troubleshooting

### Common Issues

#### Invalid User ID

**Symptom**: User override is ignored

```json theme={null}
{
  "warning": "Invalid x-alloy-userid header",
  "attempted": "invalid-user-id",
  "fallback": "primary_account_id"
}
```

**Solution**: Ensure the user ID exists and is properly formatted.

#### Missing Credentials

**Symptom**: Actions fail with credential errors

```json theme={null}
{
  "error": "No credentials found for user_alice_123 on connector slack"
}
```

**Solution**: Each user needs their own credentials for each connector they use.

#### Permission Denied

**Symptom**: Actions blocked by restrictions

```json theme={null}
{
  "error": "Action chat_postMessage is not allowed for connector slack"
}
```

**Solution**: Check server restrictions - they apply to all users equally.

## Additional Resources

<CardGroup>
  <Card title="Restrictions Guide" href="/mcp/core-concepts/restrictions-guide" icon="code" iconType="solid" horizontal />

  <Card title="API Reference" href="/mcp/api-reference/api-endpoints-overview" icon="code" iconType="solid" horizontal />

  <Card title="Authentication" href="/mcp/api-reference/authentication" icon="code" iconType="solid" horizontal />
</CardGroup>
