watchTowr Platform MCP Server
OfficialClick on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@watchTowr Platform MCP Serversummarize recent high-severity findings on my attack surface"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
watchTowr Platform MCP Server
A Model Context Protocol (MCP) server that connects AI assistants to the watchTowr Platform, providing real-time access to your external attack surface data, findings, hunts, and threat intelligence.
Features
116 tools covering the full watchTowr Platform API — assets, findings, hunts, certificates, suspicious domains, and more
Read and write — query your attack surface and take action (update statuses, trigger retests, submit seed assets)
Composite intelligence — built-in tools for attack surface summaries, change detection, executive scorecards, and compliance reporting
Secure — authenticates via API key with tenant isolation; credentials never leave your environment
Related MCP server: osint-mcp-server
Prerequisites
watchTowr Platform account with API access enabled
API Key — obtained from your watchTowr Platform dashboard under Settings → API Management
Platform Host — your watchTowr instance URL (e.g.
https://your-tenant.your-region.client.watchtowr.io)Python 3.10+ and uv (for local installation), or Docker
Quick Start
Local Installation
The watchtowr-api-sdk is included as a git submodule. Choose the path that matches your situation:
New installation
If you are setting up for the first time (or doing a fresh clone), use --recurse-submodules so Git fetches the SDK in one step. You do not need the migration steps below.
git clone --recurse-submodules https://github.com/watchtowr/watchtowr-mcp.git
cd watchtowr-mcp
# Install everything in one step (uv resolves the SDK from the submodule)
uv sync
cp .env.example .env
chmod 600 .envSet WATCHTOWR_API_KEY and WATCHTOWR_PLATFORM_HOST in .env (see API key handling), then run the server:
uv run --env-file .env watchtowr-mcpIf you already cloned without submodules, run git submodule update --init --recursive once, then uv sync.
Existing clone (old submodule URL only)
Skip this section if you used a fresh clone as shown above.
If your checkout predates the submodule move to watchtowr-api-sdk-python, Git still points at the old URL. Reset the submodule once:
cd watchtowr-mcp
git pull
git submodule sync
git submodule deinit -f watchtowr-api-sdk
rm -rf .git/modules/watchtowr-api-sdk
git submodule update --init --recursive
uv syncThis is a one-time migration. The SDK then stays pinned to the commit recorded in this repo; git submodule update --init --recursive always checks out that pinned commit.
Docker
The Docker image installs the SDK from the watchtowr-api-sdk submodule in your checkout (copied in at build time), so it uses the same pinned SDK commit as a local install. Make sure the submodule is checked out before building.
New installation
git clone --recurse-submodules https://github.com/watchtowr/watchtowr-mcp.git
cd watchtowr-mcp
docker build -t watchtowr-mcp .If you cloned without --recurse-submodules, run git submodule update --init --recursive first.
Existing clone (old submodule URL only)
If your checkout predates the SDK move to watchtowr-api-sdk-python, run the submodule migration under Local Installation first, then build:
docker build -t watchtowr-mcp .Then create .env in the checkout as for a local install: cp .env.example .env, chmod 600 .env, and set your API key and Platform host. docker run --env-file reads each line literally, so keep every line as KEY=value, with no export, no quotes and no trailing # comment.
stdio — for MCP clients
docker run -it --rm --env-file .env watchtowr-mcpHTTP — standalone service
docker run -d --rm \
--env-file .env \
-e MCP_TRANSPORT=streamable-http \
-p 127.0.0.1:8080:8080 \
watchtowr-mcpIn HTTP mode there is no server-wide API key: every request must send the caller's own watchTowr API key as Authorization: Bearer <api-key>, and requests with a Host or Origin outside the allow-lists are rejected. The container binds 0.0.0.0 only so Docker can forward the port; -p 127.0.0.1:8080:8080 keeps it reachable from this machine only. Exposing it further needs TLS in front and matching MCP_ALLOWED_HOSTS / MCP_ALLOWED_ORIGINS.
MCP Client Configuration
Claude Desktop / Cursor (local)
{
"mcpServers": {
"watchtowr": {
"command": "uv",
"args": [
"--directory", "/path/to/watchtowr-mcp",
"run", "--env-file", ".env", "watchtowr-mcp"
]
}
}
}.env is read from /path/to/watchtowr-mcp, so the key stays out of this config file.
Claude Code (local)
claude mcp add watchtowr -- uv --directory /path/to/watchtowr-mcp run --env-file .env watchtowr-mcpClaude Desktop / Cursor (Docker)
Build the
watchtowr-mcpimage first — see the Docker section above.
{
"mcpServers": {
"watchtowr": {
"command": "docker",
"args": [
"run", "--rm", "-i",
"--env-file", "/path/to/watchtowr-mcp/.env",
"watchtowr-mcp"
]
}
}
}HTTP (streamable-http)
Start the server first — see HTTP — standalone service.
In HTTP mode the MCP client sends the API key with each request, so the key has to be available to the client. Export WATCHTOWR_API_KEY in the shell that starts the client and reference it, so the key stays out of the config file.
Claude Code (.mcp.json):
{
"mcpServers": {
"watchtowr": {
"type": "http",
"url": "http://localhost:8080/mcp",
"headers": {
"Authorization": "Bearer ${WATCHTOWR_API_KEY}"
}
}
}
}Cursor (.cursor/mcp.json) uses the same config, with ${env:WATCHTOWR_API_KEY} in place of ${WATCHTOWR_API_KEY}.
Claude Desktop only launches local commands, so bridge to the HTTP server with mcp-remote (requires Node.js). Claude Desktop cannot read the key from your shell, so in this setup the key has to live in its config file. It goes through env because some platforms split an argument containing a space:
{
"mcpServers": {
"watchtowr": {
"command": "npx",
"args": ["-y", "mcp-remote", "http://localhost:8080/mcp", "--header", "Authorization:${WATCHTOWR_AUTH}"],
"env": {
"WATCHTOWR_AUTH": "Bearer your-api-key"
}
}
}
}Configuration
Set these in .env, starting from .env.example. Every setup above passes the file to the server with --env-file.
Variable | Required | Description |
| stdio only | Your watchTowr Platform API key. Ignored in |
| Yes | Your watchTowr Platform instance URL. The portal is served from the same host, so tools also use it to print links that open findings, assets, hunts, vulnerabilities, adversaries, compromised endpoints and business units in the portal |
| No | Transport mode: |
| No | HTTP bind address (default: |
| No | HTTP port when using |
| No | Comma-separated allowed |
| No | Comma-separated allowed |
| No | Set to |
| No | Seconds the watchTowr Platform may stay silent during a request before the tool returns a timeout error (default: |
API key handling
In stdio mode, keep the API key in
.envonly. Don't put it in your MCP client's config file, a chat or a screenshot. With--env-file, the key is not written into the client config and not shown in the process list. In HTTP mode the client sends the key instead, see HTTP (streamable-http).Configs that set
WATCHTOWR_API_KEYandWATCHTOWR_PLATFORM_HOSTin the client'senvblock, on the command line or withdocker run -estill work. The server reads the same variables however they are set; moving them to.envonly keeps the key out of those places.Git ignores
.env.chmod 600 .envstops other users on the machine from reading it.To rotate the key, change it in
.envand restart your MCP client.Leave
MCP_TRANSPORTandPORTout of.envwhen an MCP client starts the server: clients talk to it over stdio. Set them only when you run the HTTP service yourself.
Read-only mode
With WATCHTOWR_MCP_READ_ONLY set to true, 1 or yes, the server never changes anything on the watchTowr Platform. Unset, empty, false, 0 or no leaves every tool available. Any other value also turns read-only mode on, so a mistyped value never leaves write tools enabled, and is logged as a warning at startup.
Every non-GET request is refused. The API client rejects any POST, PUT, PATCH or DELETE before it is sent, so no tool can write, whatever the model calls.
Write-only tools are hidden from the tool list:
update_finding_status,retest_finding,update_finding_state,bulk_retest_findings,bulk_update_finding_status,set_asset_criticality,manage_asset_business_units,update_asset_status,add_seed_asset.Read/write tools stay listed but only read:
manage_engine_settings(get),manage_asset_custom_property(list) andmanage_asset_notes(list). Any other valid action returns an error namingWATCHTOWR_MCP_READ_ONLY.
Request Headers
Every request the server makes to the watchTowr Platform API identifies the MCP server, the tool and the MCP client:
User-Agent: watchtowr-mcp/<version>— the installed package version.X-Watchtowr-MCP-Tool: <tool name>— the tool that made the request. Omitted outside a tool call.X-Watchtowr-MCP-Client: <name>/<version>— theclientInfoyour MCP client sent when it connected, over stdio only. Always omitted overstreamable-http, because this server runs that transport stateless and keeps no client info afterinitialize. Also omitted when the client sent none, when its name or version is not printable ASCII, or when<name>/<version>is longer than 256 characters.
These headers carry no API key, tool arguments or other secrets; the API key is only ever sent in the Authorization header.
Available Tools
Findings (11 tools)
Tool | Description |
| List findings tagged as CISA Known Exploited Vulnerabilities |
| List findings filtered by severity (Critical, High, Medium, Low) |
| Get full finding detail — description, evidence, CVSS, CVE, EPSS |
| Search with filters: title, severity, status, asset, assignee, tags, date range, CVE (with an exposure verdict) |
| Change the status of a finding |
| Update the handling state of a finding (Uninvestigated, In Progress, Completed) |
| Trigger a retest to verify remediation |
| List available finding status values |
| Count breakdown of findings by severity level |
| List unresolved findings for a specific business unit |
| Export a finding report as PDF |
Assets (38 tools)
Tool | Description |
| List discovered IP addresses |
| Full detail for a specific IP address |
| List all ports discovered on a specific IP |
| Full detail for a port scoped to an IP address |
| List discovered root domains |
| Full detail for a specific domain |
| List discovered subdomains |
| Full detail for a specific subdomain |
| List open ports with service and banner info |
| Full detail for a specific port |
| List discovered IP ranges with ASN and country |
| Full detail for a specific IP range |
| List cloud storage buckets (S3, GCS, Azure) |
| Full detail for a specific cloud storage asset |
| List discovered code repositories |
| Full detail for a specific repository |
| List discovered container registry images |
| Full detail for a specific container image |
| List discovered SaaS platform instances |
| Full detail for a specific SaaS platform |
| List discovered mobile applications |
| Full detail for a specific mobile application |
| Update the status of any asset type |
| Submit a new seed asset for discovery |
| Get or update scan engine settings for domains, subdomains, and IPs |
| Set criticality for any supported asset type |
| Assign or unassign business units for any supported asset type |
| List, create, update, or delete custom properties on an asset |
| List, create, update, or delete notes on an asset |
| List discovered API documentation assets |
| Full detail for a specific API documentation asset |
| List discovered cloud assets (AWS, GCP, Azure, etc.) |
| Full detail for a specific cloud asset |
| List discovered package manager registry assets |
| Full detail for a specific package manager asset |
| Get change history for a specific asset |
| Get DNS records associated with a specific asset by name |
| Search DNS records across discovered assets |
Hunts (6 tools)
Tool | Description |
| List recent hunts with finding and affected-asset counts |
| Full hunt detail — description, hypothesis, references |
| List findings discovered by a specific hunt |
| List affected assets watchTowr linked to a specific hunt |
| Search hunts by keyword, status, type, priority, date |
| Combined summary: detail, severity breakdown, affected assets |
Threat Intelligence (7 tools)
Tool | Description |
| List domains flagged for typosquatting or brand impersonation |
| Full detail including WHOIS data |
| List leaked credentials, exposed configs, interesting endpoints |
| List SSL/TLS certificates with subject, issuer, and expiry |
| Full certificate detail including SANs and key info |
| List certificates expiring within N days |
| Search pending domains awaiting verification or discovery processing |
Intelligence (11 tools)
Tool | Description |
| List vulnerability intelligence entries (CVEs) |
| Get full details for a CVE/vulnerability |
| List adversary/threat actor profiles |
| Get full details for a threat actor |
| List compromised endpoints from stealer logs |
| List harvested credentials for an endpoint |
| List credential stuffing attempt logs |
| List retest history across all findings |
| Get retest history for a specific finding |
| Search active defense library rules by name, capability, or technique |
| Search hunts and TTP Library tactics by hunt title, CVE ID, or tactic name |
Services (2 tools)
Tool | Description |
| List exposed services with technology stack and country |
| List technology statistics for discovered services, ordered by count |
Organisation (5 tools)
Tool | Description |
| Get source IPs to whitelist for watchTowr scanning |
| Get recent platform activity logs |
| Search logs by type, user, keyword, and date range |
| List business units (useful for filtering other tools) |
| Full detail for a specific business unit |
Composite & Triage (13 tools)
Tool | Description |
| Asset counts by type and finding counts by severity |
| All newly discovered assets across every type within N days |
| Combined new assets + new findings within a time window |
| Full security posture for a BU: findings, assets, services, certs |
| Finding details enriched with the related asset's full details |
| Expiring certs cross-referenced with exposed services |
| Hunt findings expanded with details for remediation handoff |
| Executive headlines: critical/high counts, CISA-KEV, expiring certs, top findings |
| Search findings associated with a specific asset |
| Findings open longer than N days |
| Critical/high findings with no assignee |
| Unresolved findings heatmap by asset type |
| New assets not assigned to any business unit |
Reporting & Compliance (12 tools)
Tool | Description |
| Full asset inventory for a business unit |
| All assets marked as out of scope or excluded |
| Asset verification status breakdown across all types |
| Findings bucketed by age (0-7d, 7-30d, 30-90d, 90d+) and severity |
| Opened vs remediated findings per week (remediations placed by last update) |
| Most common open ports with service counts |
| Asset types with assets but zero findings — coverage gaps |
| Certificates grouped by health: expired, expiring, valid |
| Single-call executive dashboard: assets, findings, KEV, cert health |
| Weekly trend report: new assets and findings per week |
| Most frequently recurring finding titles — systemic issues |
| Security posture dashboard summary with executive risk metrics |
Incident Response (5 tools)
Tool | Description |
| Find all services in a specific country |
| Exposed services grouped by type with counts |
| Find all services running a specific technology |
| CISA-KEV findings grouped by remediation status |
| Blast radius mapping: subdomains, ports, services for an asset |
Workflow & Automation (6 tools)
Tool | Description |
| Remediated findings last updated within the last N days (no remediation-date filter) |
| 24-hour digest: new assets, new findings, activity log |
| Trigger retests for multiple findings at once (max 25 IDs per call) |
| Update the status of multiple findings at once (max 25 IDs per call) |
| Prioritized queue of open findings by severity and age |
| Unassigned open findings grouped by severity — triage inbox |
Example Prompts
"Give me an attack surface summary"
"Show all critical findings"
"What new assets were discovered this week?"
"List certificates expiring in the next 30 days"
"Show me suspicious domains flagged for typosquatting"
"Get the details for finding 1234 and trigger a retest"
"List all findings for business unit 5"
"What hunts have been completed recently?"
"Give me the executive risk scorecard"
"Show me stale findings older than 30 days"
"What critical findings are unassigned?"
"Run a daily digest"
"Bulk retest findings 101,102,103"
"Show me all assets in country CN"
"What services are running Apache?"
"Give me the CISA-KEV remediation status"
"Compare week-over-week changes for the last 4 weeks"Troubleshooting
HTTP 401: IP address not on an allow list
The watchTowr Platform can limit API access to listed IP addresses or ranges, in two places. A request has to pass both:
Client API allow list: the API Allow List on the Client API page (Integrations → Client API). It applies to API calls only.
Dashboard IP whitelist: the Dashboard IP Whitelisting page (Configure on the Dashboard IP Whitelist card of the Users page). It applies to the portal and to API calls.
A request from an address that is not listed gets HTTP 401, and the tool error names the list to update.
Add the public IP address of the machine running the MCP server, since that machine sends every request to the Platform:
stdio: the machine where your MCP client starts the server. With Docker, that is the Docker host.
streamable-http: the machine running the HTTP service, not the machines of the MCP clients that connect to it.
Behind NAT, a VPN or a proxy, the Platform sees the address traffic leaves from, so add that address. To find it, open a "what is my IP" service from the machine running the MCP server, or ask whoever runs its network.
This is not always the address the portal shows. "You are currently logged in from …" on the Dashboard IP Whitelisting page is the address of your browser, and it only matches when your browser and the MCP server reach the internet through the same address.
Development
Project Structure
watchtowr-mcp/
├── watchtowr_mcp_server/
│ ├── __init__.py
│ ├── mcp.py # Entry point
│ ├── client.py # API client and shared helpers
│ ├── middleware.py # Sets the tool and MCP client request headers
│ ├── http_security.py # streamable-http Host/Origin checks + bearer auth
│ └── tools/
│ ├── __init__.py # Tool registration
│ ├── findings.py # Finding tools
│ ├── assets.py # Asset tools
│ ├── hunts.py # Hunt tools
│ ├── threat_intel.py # Suspicious domains, POI, certificates
│ ├── services.py # Service listing tools
│ ├── organization.py # Business units, activity logs, source IPs
│ ├── composite.py # Cross-cutting intelligence, triage, and posture tools
│ ├── reporting.py # Compliance, audit, executive reporting tools
│ ├── incident.py # Incident response and threat hunting tools
│ └── workflow.py # Bulk operations, queues, and automation tools
├── pyproject.toml
├── Dockerfile
└── README.mdTests
A two-layer test suite lives under test/ — see test/README.md for details.
Unit tests (offline, no credentials): verify every SDK method the server imports actually exists, that
README.mdstays in sync with the@mcp.tool()registry, and thatsdk_compatpatches apply cleanly.Integration tests (live tenant): one test per tool across all 116 tools. Auto-skipped when
WATCHTOWR_API_KEY/WATCHTOWR_PLATFORM_HOSTare absent. Mutating tools are gated behind a separate--run-writesflag.
# Offline checks
uv run pytest test/unit
# Full read-only sweep against a tenant
uv run --env-file .env pytest test/integration -m live
# Include status flips, retests, seed asset submission
uv run --env-file .env pytest test/integration -m live --run-writesSupport
API Reference: watchTowr Platform API Documentation
Technical Support: Contact the watchTowr support team
Requires a valid watchTowr Platform subscription. For more information, visit watchtowr.com.
This server cannot be deployed
Maintenance
Related MCP Connectors
- mcpOAuthcom.vibgrate
Query your team's drift, vulnerability, and upgrade data from any AI assistant. OAuth 2.1, 51 tools.
Discover, inspect and run 63,000+ agent tools from one balance. Pay per call, no subscriptions.
Connect AI agents to 1000+ apps with managed authentication and tool-calling.
- SkilderOAuthai.skilder
One place to build, share, and govern the skills and tools your AI agents use at work.
Related MCP Servers
- AlicenseNot gradedqualityAmaintenanceConnects AI agents with the CrowdStrike Falcon platform to enable intelligent security analysis, providing programmatic access to detections, incidents, threat intelligence, vulnerabilities, and other security capabilities for advanced security operations and automation.273MIT
- AlicenseAqualityCmaintenanceProvides AI agents with 37 OSINT tools and 12 data sources to perform unified reconnaissance, domain analysis, and attack surface mapping. It enables agents to query, correlate, and reason across platforms like Shodan, VirusTotal, and Censys in parallel.37364 npm60MIT
- AlicenseNot gradedqualityCmaintenanceConnects AI agents with the CrowdStrike Falcon platform to programmatically access detections, threat intelligence, host management, and other security capabilities for intelligent security analysis and automation.1MIT
- AlicenseNot gradedqualityAmaintenanceEnables AI assistants to drive OWASP ZAP for authorized penetration testing and bug-bounty workflows, including authenticated scans and vulnerability triage through 67 curated safety-gated tools.1MIT