The DNA test for websites - URL intelligence and threat analysis platform with scanning, search, saved queries, and brand monitoring capabilities
The urlDNA MCP server demonstrates solid fundamentals across most tools with clear verb-based naming, meaningful descriptions, and structured input schemas. However, significant gaps in output schema documentation, limited error handling guidance, and missing parameter-level granularity prevent a higher score. Tool descriptions are generally well-written (averaging ~150-200 chars, within the 10-1024 baseline), and parameter types are defined. The server covers 14 tools across scanning, search, query management, and brand monitoring, a comprehensive domain. Main weaknesses: (1) output schemas are not documented anywhere in the provided source, forcing LLMs to infer result structure; (2) many parameters lack constraints (enums, ranges, patterns); (3) error recovery guidance is minimal; (4) no tool annotations (readOnlyHint, destructiveHint) visible despite clear risk levels declared.
Retrieve all scans associated with a specific brand. Returns scans linked to the brand, sorted by submission date (newest first). Optionally filter results further using CQL (Custom Query Language) syntax for more targeted threat analysis. Requires PREMIUM subscription.
Create a new saved query with one or more filter conditions. Saved queries allow reusable, complex searches across the urlDNA database. Requires a PREMIUM subscription.
Permanently delete a saved query by ID. Requires a PREMIUM subscription.
Quickly check if a URL has already been scanned in the urlDNA database. This is a lightweight lookup — it does not submit a new scan. Use this to avoid redundant scans and get instant results if the URL was previously analyzed. The URL is automatically normalized: if no scheme is provided (e.g., "example.com"), "https://" is prepended automatically.
Retrieve the full details of a specific brand by its ID. Returns complete brand metadata including configuration and visibility settings. Use list_brands first if you need to look up a brand ID by name. Requires PREMIUM subscription.
Output schemas completely undocumented across all tools. LLMs cannot infer result structure, field names, or types. This forces agents to guess or make incorrect assumptions about downstream data availability.
Complex parameter structures (query_filters array in create_query, update_query) documented as prose rather than formal JSON Schema. 'FIRST filter requires X, SUBSEQUENT filters require Y' is procedural pseudo-code, not a schema. LLMs cannot reliably construct correct nested structures.
Enums not declared as JSON Schema enums. 'filter' param in list_brands mentions 'one of: ALL, FREE, PREMIUM, USER_BRANDS' in description text, not as an enum constraint. LLMs may hallucinate invalid values.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-21 | C | 68 | 2026-07-28+ | v2 |
| 2026-03-09 | C | 65 | - | v1 |
Retrieve the full details of a specific saved query by its ID. Returns the query name and all filter conditions configured for it. Use list_queries first if you don't know the query ID.
Retrieve the full results of a previously submitted urlDNA scan by its ID. Use this tool when you already have a scan ID (e.g., from new_scan or search results) and want to fetch the detailed scan report.
List all brands available to the authenticated user for threat monitoring. Brands represent organizations or entities whose domains and assets are tracked in the urlDNA database. Use brands to monitor phishing attempts, brand impersonation, and suspicious lookalike domains. Requires PREMIUM subscription.
List all saved queries for the authenticated user. Saved queries are reusable filter combinations that can be executed against the urlDNA scan database. Each query has a name, a unique ID, and one or more filter conditions that are combined with logical AND.
Submit a URL to urlDNA for a full scan and wait for the result. This tool performs a complete website scan: it submits the URL, then polls the API until the scan finishes (status: DONE) or fails (status: ERROR). The result is automatically truncated to fit within the model's context window. The URL is automatically normalized: if no scheme is provided (e.g., "example.com"), "https://" is prepended automatically.
Execute a saved query and return all matching scans. Runs all filter conditions stored in the query against the urlDNA database and returns matching scans sorted by submission date (newest first). Pages beyond the first require a PREMIUM subscription.
Search urlDNA scans using CQL (Custom Query Language) syntax. Returns matching scans sorted by submission date descending (newest first). Page 1 is available to all users. Pages beyond the first require a PREMIUM subscription.
Search the official urlDNA documentation for integrations, API usage, and guides.
Update an existing saved query's name and filter conditions (full replacement). Requires a PREMIUM subscription.
CQL (Custom Query Language) syntax not formalized in tool definitions. search(), brand_scans(), and query_filters rely on LLMs understanding CQL syntax that is mentioned only in config strings. No schema or examples of valid attributes (domain, ip, technology, malicious, country_code, favicon, etc.) or operators (=, !=, LIKE, !LIKE).
No error recovery guidance. Tools do not document what errors can occur (404, 429, timeout, permission denied, rate limit) or how LLM should respond. E.g., delete_query has risk level DESTRUCTIVE but no confirmation or dry-run step documented.
Pagination not fully specified. search() and list_brands() mention 'page > 1 requires PREMIUM' but do not document default page size, maximum limit, or whether a total count is returned. LLMs cannot plan multi-page queries without knowing iteration bounds.
No tool annotations visible (readOnlyHint, destructiveHint, idempotentHint) despite clear risk levels declared (READ_ONLY, WRITE, DESTRUCTIVE). These hints help LLMs plan safely and decide whether to require user confirmation.
Vague output descriptions in some tool definitions. 'Returns matching scans' (search), 'returns complete brand metadata' (get_brand), 'returns all scans' (brand_scans) do not specify the fields, structure, or size of results.
Result truncation mentioned in new_scan ('The result is automatically truncated to fit within the model's context window') but truncation behavior is not documented: what is the byte limit? Are results lossy or complete? How does the LLM know if data was dropped?