Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

LDAP MCP Server

A Python-based Model Context Protocol (MCP) server that exposes LDAP directory operations to AI agents and coding assistants like Claude, Cursor, and OpenCode.

This is a Python port of the original trxo/ldap-mcp implementation written in Go by @trxo. Full credit to the original author for the design and concept.

Features

  • Full LDAP CRUD operations - Search, read, add, modify, and delete directory entries
  • Dual transport modes - stdio (local) and SSE (networked)
  • LDIF and JSON output - RFC 2849 compliant LDIF formatting or structured JSON
  • API key authentication - Secure Bearer token or X-API-Key header validation (SSE mode)
  • Read-only or read-write - Control write access via --read-write flag
  • TLS support - LDAPS and StartTLS with certificate validation
  • MCP resources - Expose Root DSE and individual entries as resources
  • Comprehensive tests - 50+ unit tests with full coverage

Installation

From PyPI (when published)

pip install kizano-ldap-mcp-server

From Source

git clone https://github.com/markizano/ldap-mcp-server.git
cd ldap-mcp-server
pip install -e .
git clone https://github.com/markizano/ldap-mcp-server.git
cd ldap-mcp-server
uv pip install -e .

Quick Start

1. Configuration

Create a .env file (copy from .env.example):

# LDAP connection
LDAP_URI=ldap://localhost:389
LDAP_BIND_DN=cn=admin,dc=example,dc=com
LDAP_BIND_PASSWORD=your_password_here

# MCP server (SSE mode)
MCP_HOST=0.0.0.0
MCP_PORT=9090
LDAP_MCP_SERVER_API_KEY=your-secure-api-key-here

# Logging
LOG_LEVEL=INFO

2. Start the Server

stdio mode (local development, no API key needed):

ldap-mcp-server --transport stdio --read-write

SSE mode (network server with authentication):

ldap-mcp-server --transport sse --host 0.0.0.0 --port 9090

3. Configure Your MCP Client

For stdio mode (Claude Desktop, Cursor, OpenCode):

Add to your MCP client configuration (e.g., ~/.config/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json):

{
  "mcpServers": {
    "ldap": {
      "command": "ldap-mcp-server",
      "args": ["--transport", "stdio", "--read-write"],
      "env": {
        "LDAP_URI": "ldap://localhost:389",
        "LDAP_BIND_DN": "cn=admin,dc=example,dc=com",
        "LDAP_BIND_PASSWORD": "your_password_here"
      }
    }
  }
}

For SSE mode (remote server):

{
  "mcpServers": {
    "ldap": {
      "url": "http://your-server:9090/sse",
      "headers": {
        "Authorization": "Bearer YOUR_LDAP_MCP_SERVER_API_KEY"
      }
    }
  }
}

Usage

Available Tools

The server exposes the following MCP tools:

search_entries

Search for LDAP entries matching a filter.

search_entries(
    base_dn="ou=users,dc=example,dc=com",
    filter="(objectClass=inetOrgPerson)",
    scope="sub",  # base, one, or sub
    attributes=["cn", "mail", "uid"],  # None for all attributes
    output_format="ldif"  # ldif or json
)

get_entry

Retrieve a single entry by DN.

get_entry(
    dn="uid=jsmith,ou=users,dc=example,dc=com",
    attributes=["cn", "mail"],
    output_format="ldif"
)

add_entry (requires --read-write)

Create a new LDAP entry.

add_entry(
    dn="uid=newuser,ou=users,dc=example,dc=com",
    attributes={
        "objectClass": ["inetOrgPerson", "organizationalPerson"],
        "cn": ["New User"],
        "sn": ["User"],
        "mail": ["newuser@example.com"]
    }
)

modify_entry (requires --read-write)

Modify an existing entry.

modify_entry(
    dn="uid=jsmith,ou=users,dc=example,dc=com",
    changes=[
        {
            "operation": "replace",
            "attribute": "mail",
            "values": ["newemail@example.com"]
        }
    ]
)

delete_entry (requires --read-write)

Delete an entry.

delete_entry(dn="uid=olduser,ou=users,dc=example,dc=com")

Available Resources

ldap://root-dse

Server metadata and capabilities (JSON format).

ldap://entry/{url-encoded-dn}

Individual entry by DN (LDIF format).

Example: ldap://entry/uid%3Djsmith%2Cou%3Dusers%2Cdc%3Dexample%2Cdc%3Dcom

Command-Line Options

usage: ldap-mcp-server [-h] [--transport {stdio,sse}] [--host HOST]
                       [--port PORT] [--url URL] [--bind-dn BIND_DN]
                       [--bind-password BIND_PASSWORD] [--starttls]
                       [--insecure] [--read-write] [--timeout TIMEOUT]
                       [--log-level {DEBUG,INFO,WARNING,ERROR,CRITICAL}]

options:
  --transport {stdio,sse}    Transport mode (default: sse)
  --host HOST                Host to bind to (default: 0.0.0.0)
  --port PORT                Port to listen on (default: 9090)
  --url URL                  LDAP server URL
  --bind-dn BIND_DN          Bind DN for service account
  --bind-password BIND_PASSWORD
                             Bind password
  --starttls                 Use StartTLS (cannot be used with ldaps://)
  --insecure                 Skip TLS certificate verification (INSECURE)
  --read-write               Enable write operations
  --timeout TIMEOUT          LDAP operation timeout in seconds (default: 30)
  --log-level {DEBUG,INFO,WARNING,ERROR,CRITICAL}
                             Logging level (default: INFO)

CLI flags override environment variables.

Development

Running Tests

# Install test dependencies
pip install -e ".[test]"

# Run all tests
pytest tests/

# Run with coverage
pytest tests/ --cov=ldap_mcp_server --cov-report=html

Project Structure

ldap-mcp.py/
├── lib/ldap_mcp_server/
│   ├── __init__.py         # Entry point with dotenv loading
│   ├── __main__.py         # python -m support
│   ├── cli.py              # Argument parsing
│   ├── config.py           # Configuration dataclass
│   ├── ldap_client.py      # LDAP connection wrapper
│   ├── ldif.py             # LDIF formatter (RFC 2849)
│   ├── middleware.py       # API key authentication
│   ├── resources.py        # MCP resource registrations
│   ├── server.py           # Main serve() function
│   └── tools.py            # MCP tool registrations
├── tests/
│   ├── test_config.py      # Configuration tests
│   ├── test_ldif.py        # LDIF formatting tests
│   └── test_middleware.py  # Authentication tests
├── pyproject.toml          # Package metadata
└── pytest.ini              # Test configuration

Contributing

Contributions are welcome! Please follow these guidelines:

  1. Fork the repository and create a feature branch
  2. Write tests for new functionality (maintain >90% coverage)
  3. Follow the coding style:
    • Use type hints for all function signatures
    • All imports at the top of the module (no JIT imports)
    • Follow DRY principles (no copy-paste code)
    • Docstrings for all public functions
  4. Run the test suite before submitting:
    pytest tests/ -v
    
  5. Update documentation if adding features
  6. Submit a pull request with a clear description

Development Setup

# Clone the repo
git clone https://github.com/markizano/ldap-mcp-server.git
cd ldap-mcp-server

# Create virtual environment
python -m venv .venv
source .venv/bin/activate  # or `.venv\Scripts\activate` on Windows

# Install in editable mode with test dependencies
pip install -e ".[test]"

# Run tests
pytest tests/ -v

Security

  • API keys are read from environment variables only, never from CLI or config files
  • TLS certificate validation is enabled by default (use --insecure to disable for testing)
  • Write operations are disabled by default (requires explicit --read-write flag)
  • Bind credentials should use service accounts with minimal required privileges

Warning: Never commit .env files or hardcode credentials in code.

License

MIT License - see LICENSE file for details

Credits

Troubleshooting

"Failed to connect to LDAP"

  • Verify LDAP_URI is correct (ldap:// or ldaps://)
  • Check firewall rules allow connections to LDAP port (389 or 636)
  • Test with ldapsearch to verify credentials

"401 Unauthorized" (SSE mode)

  • Ensure LDAP_MCP_SERVER_API_KEY is set in environment
  • Verify client is sending Authorization: Bearer <key> or X-API-Key: <key> header
  • Check server logs for auth attempts

"405 Method Not Allowed"

  • Client may be POSTing to /sse instead of /messages
  • Client URL should be http://host:port/sse (not /messages)

Write operations fail

  • Ensure server started with --read-write flag
  • Verify bind DN has write permissions in LDAP directory
  • Check LDAP server logs for permission errors

Support

Roadmap

  • Connection pooling for high-traffic deployments
  • Schema introspection and validation
  • LDAP server discovery (DNS SRV records)
  • Prometheus metrics endpoint
  • Docker image and Kubernetes manifests
  • Interactive schema browser MCP resource

Made with ❤️ for the MCP community

Metadata

Release files for kizano-ldap-mcp-server 1.0.1.dev0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for kizano-ldap-mcp-server 1.0.1.dev0
File Size Uploaded
kizano_ldap_mcp_server-1.0.1.dev0.tar.gz 19.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for kizano-ldap-mcp-server 1.0.1.dev0
File Interpreter ABI Platform
kizano_ldap_mcp_server-1.0.1.dev0-py3-none-any.whl Python 3 none any Details

Total release size: 38.9 kB

Release files / kizano_ldap_mcp_server-1.0.1.dev0.tar.gz

Download URL kizano_ldap_mcp_server-1.0.1.dev0.tar.gz
Size 19.6 kB
Tags Source
SHA-256 checksum
How to use checksums
8ad661516f46e25c06f45dc5465c3b1494d732ad95141e939227878a1f5b3fc4
BLAKE2b-256 checksum
How to use checksums
bd008123f04a3d32f934c656e033361848e8ea3ba029a0c31f772da7b0673dd1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.2

Release files / kizano_ldap_mcp_server-1.0.1.dev0-py3-none-any.whl

Download URL kizano_ldap_mcp_server-1.0.1.dev0-py3-none-any.whl
Size 19.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ce8b7d1269f8556efc7f766c51dd3040205e9b67a9be8abb688134bb33148222
BLAKE2b-256 checksum
How to use checksums
470fc791fe1bc30a102408b582c91f5dc3a1d885b0be1bc5a970b057662fad3a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.2

Release history Release notifications | RSS feed

This release

1.0.1.dev0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page