Skip to main content
Glama
jstjep00

dehashed-mcp

by jstjep00

dehashed-mcp

An MCP (Model Context Protocol) server that wraps the DeHashed breach-data API and exposes every available endpoint as an MCP tool — with server-side API key management, structured Docker logging, and a pluggable RBAC/ABAC authorization engine that enforces access control at the individual tool call level.


Key design decisions

Concern

Decision

API key

Held exclusively in the server process (env var). Never passed to or returned by any tool.

Transport

Not decided here — wire stdio, HTTP/SSE, or a gRPC proxy on top.

MCP auth

Not decided here — add bearer token / OAuth / mTLS at the transport layer.

Tool-level authz

RBAC + ABAC via a hot-reloadable YAML policy file. Per-tool, per-tenant, per-domain-scope, per-page-size.

Logging

structlog → JSON → stdout/stderr → docker logs / any log driver.


Related MCP server: mcp-osint-server

Project layout

dehashed-mcp/
├── src/dehashed_mcp/
│   ├── __init__.py
│   ├── main.py            # FastMCP app + entrypoint
│   ├── config.py          # Pydantic Settings (reads env vars)
│   ├── client.py          # Async DeHashed HTTP client
│   ├── models.py          # Request/response Pydantic models
│   ├── tools.py           # All 17 MCP tool definitions
│   ├── authz.py           # RBAC/ABAC engine
│   └── logging_config.py  # structlog → Docker logs
├── config/
│   └── policy.yaml        # Default authorization policy
├── tests/
│   ├── conftest.py
│   ├── test_authz.py
│   ├── test_client.py
│   └── test_models.py
├── Dockerfile
├── docker-compose.yml
├── docker-entrypoint.sh
├── pyproject.toml
└── .env.example

Quick start

1. Configure

cp .env.example .env
# Edit .env — set DEHASHED_API_KEY at minimum

2. Build and run (stdio — Claude Desktop / any MCP host)

docker compose build
docker compose run --rm -i dehashed-mcp

3. Run with HTTP/SSE transport

MCP_TRANSPORT=http docker compose up
# Server listens on http://localhost:8000

4. View logs

docker logs -f dehashed-mcp
# Output is newline-delimited JSON

Environment variables

Variable

Required

Default

Description

DEHASHED_API_KEY

yes

Your DeHashed API key

DEHASHED_EMAIL

only for v1

Account email (V1 Basic Auth only)

DEHASHED_AUTH_MODE

no

v2_key

v2_key or v1_basic

DEHASHED_BASE_URL

no

https://api.dehashed.com

API base URL

LOG_LEVEL

no

INFO

DEBUG / INFO / WARNING / ERROR

MCP_TRANSPORT

no

stdio

stdio or http

PORT

no

8000

HTTP listen port (http transport only)

AUTHZ_POLICY_PATH

no

/config/policy.yaml

Path to policy file

AUTHZ_STRICT_TENANT

no

true

Reject unknown tenants when true


Available tools (17)

Tool

Description

Tags

search

Raw query string search

read, raw_query

search_by_field

Field + value + match mode

read

search_email

Email exact search

read

search_username

Username contains search

read

search_password

Plaintext password exact search

read, sensitive

search_hashed_password

Hash exact search

read, sensitive

search_ip

IP address exact search

read

search_name

Name contains search

read

search_vin

VIN exact search

read

search_address

Address contains search

read

search_phone

Phone contains search

read

search_domain

Domain contains search

read

search_database

Breach/database name search

read

search_license_plate

License plate exact search

read

search_crypto_address

Cryptocurrency address exact search

read

get_balance

Retrieve remaining API credits

read, account

paginate_all

Auto-paginate and aggregate

read, bulk, raw_query

Query match modes (search_by_field, search)

Mode

Syntax

Notes

contains

field:value

Default loose match

exact

field:"value"

Quoted exact match

regex

field:/pattern/

⚠ Reported broken in V2 (May 2025)

wildcard

field:"val*ue"

? = single char, * = multi ⚠ May be broken in V2


Authorization — RBAC/ABAC policy

Tool-level authorization is enforced before any DeHashed API call. The policy is a YAML file (config/policy.yaml) that can be hot-mounted into the container.

Policy structure

tenants:
  <tenant_id>:
    roles:
      <role_name>:
        allow: [<tool_name>, ...]   # or ["*"] for all tools
        deny:  [<tool_name>, ...]   # always wins over allow
        resource_scopes:
          domains: [acme.com, ...]  # restrict domain/email tools
    attributes:
      max_page_size: 500            # cap the `size` param
      max_pages: 3                  # cap paginate_all max_pages

default:                            # fallback (strict_tenant=false only)
  roles: ...

CallerContext injection

The MCP metadata dict passed with each tool call is the contract between your transport/auth layer and the authz engine:

# What your transport layer injects into _meta:
{
    "tenant": "acme",
    "roles": ["analyst"],
    "attributes": {}   # optional per-call ABAC overrides
}

At the transport layer (bearer token, OAuth, mTLS, API key validation), you decode the identity and populate this dict before the tool handler runs. The server enforces it on every call.

Hot-reload policy

Send SIGUSR1 or call authz.get_policy().reload() to reload the policy file without restarting the server.


Transport configuration

This server is transport-agnostic. Choose your transport at deploy time:

stdio (default)

Best for Claude Desktop integration:

{
  "mcpServers": {
    "dehashed": {
      "command": "docker",
      "args": ["run", "--rm", "-i",
               "-e", "DEHASHED_API_KEY=xxx",
               "dehashed-mcp:latest"]
    }
  }
}

HTTP / SSE

Run with MCP_TRANSPORT=http. The FastMCP app is also exported as an ASGI app object for direct uvicorn/gunicorn use:

uvicorn dehashed_mcp.main:app --host 0.0.0.0 --port 8000

Add your auth middleware (bearer token validation, OAuth introspection, etc.) as ASGI middleware on top.

gRPC

Put a gRPC-to-HTTP/2 transcoding proxy (e.g., Envoy, grpc-gateway) in front of the HTTP transport.


Development

# Install with dev extras
pip install -e ".[dev,http]"

# Run tests
pytest

# Lint
ruff check src tests
black --check src tests
mypy src

Logging

All log output is newline-delimited JSON sent to stdout. Docker captures it via the configured log driver (json-file by default in docker-compose.yml).

docker logs dehashed-mcp | jq .

Example log line:

{
  "event": "dehashed.search.ok",
  "total": 42,
  "returned": 100,
  "balance": 95,
  "service": "dehashed-mcp",
  "version": "0.1.0",
  "level": "info",
  "timestamp": "2025-03-09T12:00:00.000Z"
}

API keys, passwords, and tokens are automatically redacted from all log lines by the _redact_api_key processor in logging_config.py.


Credits and depletion

Each tool call that hits the DeHashed API costs 1 credit. paginate_all costs 1 credit per page. Monitor balance via get_balance or by watching the balance field in search results logged at INFO level. Policy max_pages attributes help prevent runaway credit consumption.


License

MIT

A
license - permissive license
-
quality - not tested
D
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/jstjep00/dehashed-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server