Skip to main content
Glama
ct9915

LDAP4Claude

by ct9915
README.md
# LDAP4Claude

An MCP (Model Context Protocol) server that connects Claude Code to LDAP / Active Directory.

## Features

- **User lookup** — search by name, email, username, or raw LDAP filter
- **Group management** — list groups, get members, check membership (supports nested groups)
- **Authentication** — verify user credentials via LDAP bind
- **Role mapping** — map AD groups to application roles (admin, editor, reader, etc.)

## Quick Start

```bash
npm install
npm run build
```

## Configuration

Set environment variables (see `.env.example`):

| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `LDAP_HOST` | Yes | — | Server hostname or IP |
| `LDAP_PORT` | No | `389` | Service port |
| `LDAP_BASE_DN` | Yes | — | Search base DN |
| `LDAP_BIND_DN` | Yes | — | Service account bind DN |
| `LDAP_BIND_PASSWORD` | Yes | — | Service account password |
| `LDAP_USE_TLS` | No | `false` | Use `ldaps://` |
| `LDAP_TLS_REJECT_UNAUTHORIZED` | No | `true` | Reject self-signed certs |
| `LDAP_TIMEOUT` | No | `5000` | Connection timeout (ms) |
| `ROLE_MAPPINGS_FILE` | No | `./config/role-mappings.json` | Role mapping file path |

## Register with Claude Code

Add to `~/.claude.json`:

```json
{
  "mcpServers": {
    "ldap4claude": {
      "command": "node",
      "args": ["/path/to/LDAP4Claude/build/index.js"],
      "env": {
        "LDAP_HOST": "dc.company.com",
        "LDAP_BASE_DN": "dc=company,dc=com",
        "LDAP_BIND_DN": "cn=service-account,cn=users,dc=company,dc=com",
        "LDAP_BIND_PASSWORD": "password"
      }
    }
  }
}
```

## Available Tools

### User Tools
| Tool | Description |
|------|-------------|
| `ldap_search_users` | Search users by name, email, username, or custom LDAP filter |
| `ldap_get_user` | Get detailed user info (title, department, groups, status) |
| `ldap_get_user_groups` | List all groups a user belongs to (supports recursive) |

### Group Tools
| Tool | Description |
|------|-------------|
| `ldap_list_groups` | List/search groups (security or distribution) |
| `ldap_get_group_members` | Get members of a group (supports nested) |
| `ldap_check_group_membership` | Check if a user is in a specific group |

### Authentication
| Tool | Description |
|------|-------------|
| `ldap_authenticate` | Verify username + password against AD |

### Role Management
| Tool | Description |
|------|-------------|
| `ldap_role_mapping_set` | Map AD groups to an application role |
| `ldap_role_mapping_get` | View current role mappings |
| `ldap_role_mapping_delete` | Delete a role mapping |
| `ldap_get_user_roles` | Get a user's application roles based on group membership |

## Role Mapping

Edit `config/role-mappings.json` or use the `ldap_role_mapping_set` tool:

```json
{
  "admin": ["Domain Admins", "IT Admins"],
  "editor": ["Content Team"],
  "reader": ["Domain Users"]
}
```

Then query a user's roles with `ldap_get_user_roles` — it checks the user's AD groups against these mappings and returns which roles apply.

## Architecture

![Architecture Diagram](docs/architecture.png)

```mermaid
graph TB
    subgraph Claude["Claude Code (Client)"]
        CC[Claude Code]
    end

    subgraph MCP["MCP Server (stdio transport)"]
        direction TB
        IDX[index.ts\nEntry Point]

        subgraph Tools["Tool Layer"]
            UT["user-tools.ts\nldap_search_users\nldap_get_user\nldap_get_user_groups"]
            GT["group-tools.ts\nldap_list_groups\nldap_get_group_members\nldap_check_group_membership"]
            AT["auth-tools.ts\nldap_authenticate"]
            RT["role-tools.ts\nldap_role_mapping_set/get/delete\nldap_get_user_roles"]
        end

        subgraph Core["Core Layer"]
            LC["ldap-client.ts\nLdapClient"]
            RM["role-manager.ts\nRoleManager"]
            CFG["config.ts\nZod validation"]
        end

        subgraph Utils["Utils"]
            ESC["ldap-escape.ts\nRFC 4515 filter escaping"]
        end
    end

    subgraph LDAP["Active Directory / LDAP Server"]
        SA["Service Account\nPersistent bind"]
        UA["User Auth\nTemporary bind"]
    end

    subgraph Storage["Local Storage"]
        JSON["role-mappings.json\nAtomic write"]
    end

    CC -- "JSON-RPC\n(stdin/stdout)" --> IDX
    IDX --> Tools
    IDX --> CFG
    IDX --> LC
    IDX --> RM

    UT --> LC
    GT --> LC
    AT --> LC
    RT --> LC
    RT --> RM

    LC --> ESC
    LC -- "ldap/ldaps bind\n(service account)" --> SA
    LC -- "separate Client\nper auth request" --> UA
    RM -- "read/write\n(tmp + rename)" --> JSON
```

## License

MIT