Skip to main content
Glama

NextDNS MCP Server

A Model Context Protocol (MCP) server for the NextDNS API, built with FastMCP and generated from OpenAPI specifications.

Overview

This project provides an MCP server that exposes NextDNS API operations as tools that can be used by AI assistants and other MCP clients. The server is automatically generated from a comprehensive OpenAPI specification using the FastMCP library.

Related MCP server: Cloudflare Control

Features

  • Domain-grouped CRUD tools exposing the full NextDNS API surface through ~8 high-level tools

  • Profile Management: Full CRUD operations - create, read, update, and delete profiles

  • Profile Access Control: Fine-grained read/write restrictions per profile, with read-only mode support

  • DNS-over-HTTPS Testing: Perform DoH lookups to test DNS resolution through profiles

  • Settings Configuration: Comprehensive grouped settings management including logs, block page, and performance

  • Logs: Query log retrieval, download, and clearing

  • Analytics: Comprehensive DNS query analytics and statistics, including time-series and plotting

  • Content Lists: Manage denylist, allowlist, privacy blocklists, native tracking, security TLDs, and parental control

  • Security: Complete security settings and TLD blocking configuration

  • Privacy: Privacy settings, blocklists, and native tracking protection management

  • Parental Control: Settings management with safe search and YouTube restrictions

  • OpenAPI-backed: Tool behaviors are driven by nextdns-openapi.yaml

  • Docker MCP Gateway: Full integration with Docker's MCP Gateway for secure, isolated deployment

  • Docker Support: Containerized deployment with proper OCI labels

  • Safety Mechanisms: Write operation protections and validation

Documentation

Complete documentation can be found in docs/index.md.

Quick Start

Prerequisites

  • Python 3.12+

  • uv (for development)

  • Docker (for containerized deployment)

  • NextDNS API key (get one here)

Configuration

  1. Copy the .env.example file to .env:

    cp .env.example .env
  2. Edit .env and set your NextDNS API key:

    NEXTDNS_API_KEY=your_api_key_here
    NEXTDNS_DEFAULT_PROFILE=your_profile_id  # Optional
    NEXTDNS_TEST_PROFILE=test_profile_id     # For write operation tests
    
    # Optional: Profile access control (see Profile Access Control section)
    # NEXTDNS_READABLE_PROFILES=profile1,profile2
    # NEXTDNS_WRITABLE_PROFILES=test_profile
    # NEXTDNS_READ_ONLY=false

Running with Docker

  1. Build the Docker image:

    docker build -t nextdns-mcp:latest .
  2. Run the container with environment variables:

    Option A: Direct environment variables (simple)

    docker run -i --rm \
      -e NEXTDNS_API_KEY=your_api_key_here \
      -e NEXTDNS_DEFAULT_PROFILE=your_profile_id \
      nextdns-mcp:latest

    Option B: Docker secrets (recommended for production)

    # Create secret
    echo "your_api_key_here" | docker secret create nextdns_api_key -
    
    # Run with Docker Swarm
    docker service create \
      --name nextdns-mcp \
      --secret nextdns_api_key \
      -e NEXTDNS_API_KEY_FILE=/run/secrets/nextdns_api_key \
      nextdns-mcp:latest

    Or for non-swarm (using mounted file):

    # Create a secret file
    echo "your_api_key_here" > /tmp/api_key.txt
    chmod 600 /tmp/api_key.txt
    
    # Run with mounted secret
    docker run -i --rm \
      -v /tmp/api_key.txt:/run/secrets/nextdns_api_key:ro \
      -e NEXTDNS_API_KEY_FILE=/run/secrets/nextdns_api_key \
      nextdns-mcp:latest

    Option C: Environment file (development)

    docker run -i --rm \
      --env-file .env \
      nextdns-mcp:latest

    Note: MCP servers use stdio (standard input/output) for communication, not HTTP ports.

    Alpine variant

    An Alpine Linux image is also available. To build it locally, use Dockerfile.alpine:

    docker build -f Dockerfile.alpine -t nextdns-mcp:alpine .

    The published Alpine tags use the -alpine suffix (e.g. nextdns-mcp:alpine, nextdns-mcp:2.0-alpine). The python:3.14-slim image remains the recommended default.

Running Locally (Development)

  1. Install dependencies:

    uv sync
  2. Run the server:

    uv run python -m nextdns_mcp.server

Architecture

This server uses a modern, declarative approach:

  1. OpenAPI Specification (nextdns-openapi.yaml): Complete NextDNS API documentation

  2. FastMCP Foundation: Server initialized using FastMCP.from_openapi(), with atomic tools removed and replaced by grouped CRUD tools

  3. HTTP Client: Authenticated httpx.AsyncClient with profile-level access control for NextDNS API calls

  4. MCP Protocol: Tools, resources, and prompts exposed via Model Context Protocol

Key Components

  • src/nextdns_mcp/nextdns-openapi.yaml: OpenAPI 3.0 specification for NextDNS API

  • src/nextdns_mcp/server.py: FastMCP server implementation

  • catalog.yaml: Docker MCP Gateway catalog entry with server metadata

  • Dockerfile: Container definition with OCI labels for MCP Gateway

  • AGENT.md: Development guidelines and safety rules

Docker Tags

This project publishes official Docker images with a standardized tagging policy. The default image is based on python:3.14-slim; an Alpine Linux variant is also available and tagged with an -alpine suffix.

Primary (python:3.14-slim) tags

  • :latest: Floating tag that tracks the most recent successful build from the main branch. This tag is rebuilt on changes to main and via scheduled rebuilds.

  • :<major>: Floating tag for the most recent build in a given major series (e.g., :2). This tag is updated whenever a new image for that major line is published and may include unreleased changes if the corresponding build comes from a branch head.

  • :<major>.<minor>: Floating tag for the most recent build in a given minor series (e.g., :2.0). Like :<major>, it is updated when new images are built for that series and may include unreleased changes.

  • :<major>.<minor>.<patch>: Tags for specific application releases (e.g., :2.0.3). These are intended to be immutable once published via the release workflow.

Alpine tags

  • :alpine: Floating tag for the most recent Alpine build from main.

  • :<major>-alpine: Floating tag for the most recent Alpine build in a major series (e.g., :2-alpine).

  • :<major>.<minor>-alpine: Floating tag for the most recent Alpine build in a minor series (e.g., :2.0-alpine).

  • :<major>.<minor>.<patch>-alpine: Specific Alpine release tag (e.g., :2.0.3-alpine).

All floating tags (:latest, :<major>, :<major>.<minor> and their -alpine counterparts) are rebuilt regularly to include the latest OS security updates and any application changes present in the source commit used for that build. Consumers who require strict version pinning should use the full :<major>.<minor>.<patch> or :<major>.<minor>.<patch>-alpine tags.

License

This project is released under the MIT License.

Contributing

  1. See AGENT.md for guidelines and architecture

  2. Note that NextDNS does not provide an OpenAPI specification. This is based on their documentation and may not reflect the current state of the API.

Available Tools

8 tools
dohLookupDohlookupC

Perform a DNS-over-HTTPS lookup using a NextDNS profile.

ParametersJSON Schema
NameRequiredDescriptionDefault
domainYesThe domain name to look up (e.g., "adwords.google.com")
profile_idNoNextDNS profile ID. If not provided, uses NEXTDNS_DEFAULT_PROFILE.
record_typeNoDNS record type to query (default "A").A

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

C2.9/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full behavioral burden. 'Lookup' implies a non-mutating read, which is useful, but nothing is said about authentication requirements, rate limits, whether the profile must pre-exist, or how the default-profile fallback behaves at runtime.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single, front-loaded sentence with no waste. It is efficient, though the brevity edges toward under-specification rather than optimal conciseness.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The output schema exists, so return-value explanation is not required, and the three parameters are fully covered by the schema. However, with no annotations and no usage or behavioral context, the definition is only minimally sufficient for an agent to invoke this confidently.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents domain, profile_id (including the NEXTDNS_DEFAULT_PROFILE fallback), and record_type. The description adds no parameter meaning beyond what the schema provides, so the baseline of 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (lookup) and resource (DNS-over-HTTPS via a NextDNS profile), which an agent can distinguish from the manage*/analytics siblings. It stops short of saying anything that would differentiate it from a hypothetical non-DoH DNS lookup, but the purpose is unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives no indication of when to use this tool versus the sibling tools (queryAnalytics, manageLogs) or when a DoH lookup is the right approach. There are no prerequisites or exclusion conditions stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

manageListsManagelistsA

Manage allow/deny/block lists for a NextDNS profile.

List types: - allowlist / denylist: Always-allow or always-block specific domains. - privacy_blocklists: Subscribed blocklists (e.g., nextdns-recommended). - privacy_natives: Native tracking blockers (e.g., apple, facebook). - security_tlds: Dangerous top-level domains to block (e.g., zip). - parental_categories: Content categories (e.g., gambling, porn). - parental_services: Specific apps/services (e.g., tiktok, youtube).

Operations: - get: Return the current list. - add: Append one entry (pass entry as {"id": "value"} or as a plain id string). - remove: Delete one entry by entry_id. - update: Toggle an existing entry by entry_id (pass entry={"active": True|False}). Only supported for allowlist, denylist, parental_categories, and parental_services. - replace: Replace the entire list with entries (list of dicts).

Examples: - get: manageLists(list_type="denylist", operation="get", profile_id="abc123") - add: manageLists(list_type="denylist", operation="add", profile_id="abc123", entry={"id": "example.com"}) - remove: manageLists(list_type="denylist", operation="remove", profile_id="abc123", entry_id="example.com") - replace: manageLists(list_type="privacy_blocklists", operation="replace", profile_id="abc123", entries=[{"id": "nextdns-recommended"}])

ParametersJSON Schema
NameRequiredDescriptionDefault
entryNo
entriesNo
entry_idNo
list_typeYes
operationYes
profile_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does well: it discloses that 'replace' overwrites the entire list (destructive), that 'remove' deletes one entry by entry_id, and that 'update' only toggles entries for a subset of list types. It omits auth/permission requirements and failure behavior, which keeps it below 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Content is well front-loaded with purpose, then list types, then operations, then examples. It is longer than typical, but the length is justified by 0% schema coverage and the examples are load-bearing; a small amount of redundancy exists between the operation prose and the examples.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex six-parameter, five-operation tool with an output schema already present, the description covers list taxonomy, per-operation argument shapes, and the update-support restriction. Nothing an agent needs to invoke it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate, and it does: it defines entry (id dict or plain string), entries (list of dicts for replace), entry_id (delete target), and the semantics of every operation enum. The four worked examples pin down exact argument shapes that the bare schema leaves ambiguous.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence states a specific verb and resource ('Manage allow/deny/block lists for a NextDNS profile') and the enumerated list types make the domain unmistakable versus siblings like manageRewrites or manageSettings. An agent can identify the tool's scope without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The Operations section maps each operation to its semantics and even states the condition where 'update' is invalid (only allowlist/denylist/parental_categories/parental_services), which is real when-to-use guidance. It does not, however, name alternative tools or state when not to use this tool at all.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

manageLogsManagelogsA

Manage query logs for a NextDNS profile.

Operations: - get: Return recent query log entries (use limit to cap results). Set raw=true to bypass deduplication/noise filtering. - clear: Delete all stored logs for the profile. - download: Download retained logs as CSV. from_time and to_time are ignored by the NextDNS download endpoint.

Time values can be Unix timestamps or relative strings like -1d or -7d. They are only used by get.

Examples: - get recent: manageLogs(operation="get", profile_id="abc123", limit=10) - get raw logs: manageLogs(operation="get", profile_id="abc123", raw=true) - download: manageLogs(operation="download", profile_id="abc123", from_time="-1d") - clear: manageLogs(operation="clear", profile_id="abc123")

ParametersJSON Schema
NameRequiredDescriptionDefault
rawNo
userNo
limitNo
deviceNo
to_timeNo
from_timeNo
operationYes
profile_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and mostly meets it: it warns that clear deletes all stored logs, that download ignores time filters, and that raw bypasses dedup/noise filtering. It omits any permission/auth requirements and return-volume or pagination behavior for get.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the one-line purpose, then operations, then time semantics, then examples. Well-structured with no filler, though the four copy-paste examples are somewhat repetitive with the operation bullets above them.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a multi-operation tool with an output schema present, the description covers operation semantics, filter interactions, and time formats adequately. The remaining gap is the unexplained user/device filters, which an agent would have to guess at.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It explains operation, limit, raw, from_time and to_time meaningfully, but the user and device parameters are never mentioned, leaving two of eight parameters undocumented in both schema and description.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The first line states the resource (query logs for a NextDNS profile) and the operation set (get/clear/download) is enumerated immediately after. 'Manage' alone is vague, but the bulleted operations make the tool's scope unambiguous and separable from siblings like queryAnalytics or manageProfiles.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Each operation's purpose is spelled out, and the description explicitly says from_time/to_time are ignored by the download endpoint and only used by get, which prevents a common misuse. It stops short of saying when to prefer this over queryAnalytics for log retrieval, so no exclusions or named alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

manageProfilesManageprofilesA

Manage NextDNS profiles.

NextDNS profiles are named configurations that contain DNS settings, blocklists, analytics, and logs. Most other tools require a profile_id from this tool.

Operations: - list: Return all profiles the API key can access. - create: Create a new profile (requires name). - get: Retrieve a single profile (requires profile_id). - update: Rename a profile (requires profile_id and name). - delete: Remove a profile (requires profile_id).

Examples: - list: manageProfiles(operation="list") - create: manageProfiles(operation="create", name="Home Network") - get: manageProfiles(operation="get", profile_id="abc123")

ParametersJSON Schema
NameRequiredDescriptionDefault
nameNo
operationYes
profile_idNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A3.9/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full behavioral burden but barely addresses it. It implies mutation for create/update/delete but never states that delete is destructive or irreversible, whether cascading effects occur, or what permissions/API-key scope is required beyond an incidental mention of 'the API key can access'.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The content is front-loaded with the resource overview, then a clean operation list, then examples. The examples are somewhat redundant with the operation list but do earn their place by showing parameter placement, so length is justified.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given an output schema exists, return values need not be explained, and the per-operation parameter requirements are covered. The main gap is behavioral disclosure around the destructive delete operation, which the absent annotations leave unaddressed.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate, and it largely does: it maps each operation to its required inputs (name for create/update, profile_id for get/update/delete) and shows them in examples. Only the exact format/constraints of profile_id and name are left unspecified.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific resource (NextDNS profiles) with a concrete verb (manage) and immediately enumerates the exact operations available (list, create, get, update, delete). It also distinguishes itself from siblings by noting other tools require a profile_id from this one, so an agent can place it in the workflow.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Each operation is scoped with its required parameters and concrete invocation examples, and the note that 'most other tools require a profile_id from this tool' gives real when-to-use context. However, there is no guidance on when NOT to use it or on alternatives for profile-like operations, so it falls short of explicit exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

manageRewritesManagerewritesA

Manage DNS rewrite entries for a NextDNS profile.

Rewrites let you return a custom answer for a hostname. Typical uses:

  • Point an internal hostname to a private IP.

  • Block a domain by rewriting it to 0.0.0.0.

Operations: - list: Show existing rewrites. - add: Create a rewrite (requires name and content). - delete: Remove a rewrite (requires entry_id from list).

Examples: - list: manageRewrites(operation="list", profile_id="abc123") - add: manageRewrites(operation="add", profile_id="abc123", name="router.home", content="192.168.1.1") - delete: manageRewrites(operation="delete", profile_id="abc123", entry_id="router.home")

ParametersJSON Schema
NameRequiredDescriptionDefault
nameNo
contentNo
entry_idNo
operationYes
profile_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.1/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full behavioral burden. It usefully discloses that delete consumes an entry_id obtained from list and that add requires name+content, but says nothing about whether delete/add are irreversible, what permissions the profile requires, or rate-limit behavior — a real gap for a mutating tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with a one-line purpose followed by scannable operation and example blocks; each line earns its place. The examples are somewhat repetitive of the operation list, which keeps it short of a 5.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, return values need no explanation, and the description covers purpose, operations, parameter roles, and concrete calls. It is nearly complete for a 5-param multi-operation tool, missing only mutability/safety context that no annotations supply.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate, and it largely does: it defines the enum values of operation, the meaning of name/content, and the provenance of entry_id ('from list'). profile_id is only shown by example rather than explained, leaving a small residual gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Manage DNS rewrite entries for a NextDNS profile') and explains what a rewrite actually is, so an agent can distinguish it from manageProfiles, manageSettings, and the other siblings without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Enumerates the three operations and states the required fields for each ('add' needs name+content, 'delete' needs entry_id from list), which is clear routing context. It does not say when to prefer this tool over a sibling or when not to use it, so it stops short of full when/when-not guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

manageSettingsManagesettingsA

Manage a settings category for a NextDNS profile.

Settings categories: - general: Core profile settings (e.g., name, web3 blocking). - privacy: Privacy features such as disguised-tracker blocking and affiliate links. - security: Threat intelligence, Google Safe Browsing, typosquatting protection. - parental: Parental control enablement (safe search, YouTube restricted mode). - performance: ECS, cache boost, and other performance options. - logs: Query-logging enablement and retention. - blockpage: Whether to show a custom block page for blocked queries.

Operations: - get: Retrieve current settings for the category. - update: Apply new settings (requires settings payload).

The settings argument can be a Python dict or a JSON string. For update, first call get to see the current schema, then send only the fields you want to change.

Examples: - get: manageSettings(operation="get", category="privacy", profile_id="abc123") - update: manageSettings(operation="update", category="privacy", profile_id="abc123", settings={"disguisedTrackers": True})

ParametersJSON Schema
NameRequiredDescriptionDefault
categoryYes
settingsNo
operationYes
profile_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden. It discloses that update requires a settings payload, that settings can be a dict or JSON string, and that you should retrieve first to see the schema. It doesn't describe permissions, reversibility, or rate limits, but for a settings-management tool, the get-before-update guidance and payload format are substantial behavioral context.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with a clear purpose statement, a bulleted category list, a bulleted operation list, and concrete examples. Every sentence earns its place; the formatting makes it easy to scan for the relevant category or operation.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the complexity (4 parameters, 2 enums, no annotations, but an output schema exists), the description is complete enough. It covers all categories, both operations, the settings payload format, and the recommended workflow. The output schema handles return values, so the description doesn't need to explain them.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It does: it enumerates all category values with meanings, lists the two operations with their effects, explains the settings argument format (dict or JSON string), and provides examples showing exact parameter usage. This fully compensates for the schema gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb+resource: managing a settings category within a NextDNS profile. It enumerates all categories and operations, so the agent understands the exact scope. It doesn't explicitly distinguish from siblings like manageProfiles or manageLogs, though the category list implicitly covers some overlap.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear when-to-use guidance: 'first call get to see the current schema, then send only the fields you want to change.' It explains the get-then-update workflow, which is a strong usage guideline. It doesn't state when not to use this tool or name alternatives, but the workflow guidance is explicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

plotAnalyticsPlotanalyticsA

Generate a PNG line chart for a NextDNS analytics time-series metric.

Use this to visualize query trends over time. The profile should have recent query history; otherwise the tool returns an error explaining that no data is available.

Supported metrics: status, devices, protocols, queryTypes, ipVersions, dnssec, encryption, reasons, ips.

Time values can be Unix timestamps or relative strings like -1d.

Examples: - plotAnalytics(metric="status", profile_id="abc123", from_time="-1d") - plotAnalytics(metric="devices", profile_id="abc123", from_time="-7d", interval=86400)

Returns: An MCP ImageContent PNG chart, or an error dict if data is unavailable.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
metricYes
to_timeNonow
intervalNo
partialsNonone
timezoneNoGMT
alignmentNoend
from_timeNo-1d
profile_idNo

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations present the description carries the full burden, and it does disclose the failure mode (error when no data is available) and the return shape (MCP ImageContent PNG or an error dict). It omits read-only/safety framing and any auth or rate-limit notes, which holds it below a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Well front-loaded: purpose, usage, metrics, time format, then two worked examples. The metric list and example block are useful rather than filler, though the Returns section partly duplicates what the opening sentence already implies.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 9-parameter tool with zero schema description coverage and no output schema, the description covers purpose, return type, and two of the trickier parameters, but leaves five parameters unexplained, which is a meaningful gap for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% across 9 parameters, so the description must compensate. It usefully documents the metric values and that time inputs accept Unix timestamps or relative strings like '-1d', but limit, interval, partials, timezone, and alignment remain undocumented anywhere.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

Specific verb+resource: 'Generate a PNG line chart for a NextDNS analytics time-series metric.' It is clearly a visualization tool, implicitly distinct from the sibling queryAnalytics, but it never names or contrasts with that sibling explicitly, so an agent must infer the boundary.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

States when to use it ('visualize query trends over time') and gives a concrete precondition that failure depends on ('the profile should have recent query history; otherwise the tool returns an error'). It does not name alternatives such as queryAnalytics for raw data, so selection guidance is incomplete but clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

queryAnalyticsQueryanalyticsA

Query NextDNS analytics metrics.

Metrics: - status: Query resolution status (default, blocked, allowed, relayed). - devices: Queries per device. - protocols: DNS transport protocol (DoH, DoT, Do53 UDP/TCP, DoQ). - queryTypes: DNS record types requested (A, AAAA, CNAME, etc.). - ipVersions: IPv4 vs IPv6 queries. - dnssec: DNSSEC validation results. - encryption: Encrypted vs unencrypted queries. - reasons: Why queries were blocked or allowed. - ips: Top source IPs. - destinations: Top destinations; requires destination_type such as countries or gafam.

Set series=true to fetch time-series data instead of aggregate totals. Time values can be Unix timestamps or relative strings like -1d. Note: series=true is not supported when metric="domains".

Optional filters: - cursor: Pagination cursor from a previous response. - device: Filter analytics to a single device id. - status: For the domains metric, filter by resolution status. - root: For the domains metric, group results by root domain (boolean).

Examples: - totals: queryAnalytics(metric="status", profile_id="abc123", from_time="-1d") - time series: queryAnalytics(metric="status", profile_id="abc123", from_time="-1d", series=true) - destinations: queryAnalytics(metric="destinations", profile_id="abc123", from_time="-1d", destination_type="countries")

ParametersJSON Schema
NameRequiredDescriptionDefault
rootNo
limitNo
cursorNo
deviceNo
metricYes
seriesNo
statusNo
to_timeNo
intervalNo
partialsNo
timezoneNo
alignmentNo
from_timeNo
profile_idYes
destination_typeNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A3.6/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries full burden. It discloses key behavioral constraints: series=true is unsupported for metric=domains, destinations requires destination_type, time values accept Unix timestamps or relative strings like '-1d'. These are useful non-obvious behaviors. However, it doesn't disclose rate limits, auth requirements, or the response shape.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core purpose, then structured sections (Metrics, Optional filters, Examples). The examples section adds real value. Some verbosity in per-metric explanations, but the structure makes it scannable.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Has an output schema so return value explanation isn't needed. For a 15-parameter tool, the description covers the semantic meaning of metric values and the important conditional constraints. Missing explanations for several parameters (interval, alignment, partials, timezone) is a gap, but overall adequate.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It explains meaning for many parameters: metric (with full enumeration of 11 values and their semantics), series, cursor, device, status (scoped to domains metric), root (scoped to domains metric), destination_type. Several parameters remain unexplained (limit, to_time, from_time, interval, partials, timezone, alignment) but the ones that matter most for correct invocation are covered.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (query) and resource (NextDNS analytics metrics), and clearly enumerates the available metrics. Doesn't differentiate from the sibling plotAnalytics, but the metric enumeration and emphasis on aggregate totals vs time-series gives an agent a clear sense of what this tool does.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explains usage context implicitly: series=true for time-series, cursor for pagination, device for filtering. However, it never explains when to use this versus plotAnalytics, which appears to be the natural alternative for visual analysis. No explicit when-not guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 2 tool updatesv3.1.5
    • AddeddohLookup
    • AddedmanageSettings
  2. 3 tool updatesv3.1.3
    • RemoveddohLookup
    • AddedmanageLists
    • AddedmanageRewrites
  3. 3 tool updatesv3.1.2
    • RemovedmanageLists
    • RemovedmanageRewrites
    • RemovedmanageSettings
  4. 82 tool updatesv3.0.1
    • RemovedaddPrivacyBlocklist
    • RemovedaddPrivacyNative
    • RemovedaddSecurityTLD
    • RemovedaddToAllowlist
    • RemovedaddToDenylist
    • RemovedaddToParentalControlCategories
    • RemovedaddToParentalControlServices
    • RemovedclearLogs
    • RemovedcreateProfile
    • RemoveddeleteProfile
    • ChangeddohLookup2 fields changed
      • changedInput schema / properties / profile_id / description
        Previous value: -"NextDNS profile ID (6-character alphanumeric). If not provided, uses NEXTDNS_DEFAULT_PROFILE"New value: +"NextDNS profile ID. If not provided, uses NEXTDNS_DEFAULT_PROFILE."
      • changedInput schema / properties / record_type / description
        Previous value: -"DNS record type to query. Common types:\n- A: IPv4 address (default)\n- AAAA: IPv6 address\n- CNAME: Canonical name\n- MX: Mail exchange\n- TXT: Text records\n- NS: Name servers\n- SOA: Start of authority\n- PTR: Pointer record"New value: +"DNS record type to query (default \"A\")."
    • RemovedgetAllowlist
    • RemovedgetAnalyticsDestinations
    • RemovedgetAnalyticsDestinationsSeries
    • RemovedgetAnalyticsDevices
    • RemovedgetAnalyticsDevicesSeries
    • RemovedgetAnalyticsDNSSEC
    • RemovedgetAnalyticsDNSSECSeries
    • RemovedgetAnalyticsDomains
    • RemovedgetAnalyticsEncryption
    • RemovedgetAnalyticsEncryptionSeries
    • RemovedgetAnalyticsIPs
    • RemovedgetAnalyticsIPsSeries
    • RemovedgetAnalyticsIPVersions
    • RemovedgetAnalyticsIPVersionsSeries
    • RemovedgetAnalyticsProtocols
    • RemovedgetAnalyticsProtocolsSeries
    • RemovedgetAnalyticsQueryTypes
    • RemovedgetAnalyticsQueryTypesSeries
    • RemovedgetAnalyticsReasons
    • RemovedgetAnalyticsReasonsSeries
    • RemovedgetAnalyticsStatus
    • RemovedgetAnalyticsStatusSeries
    • RemovedgetBlockPageSettings
    • RemovedgetDenylist
    • RemovedgetLogs
    • RemovedgetLogsSettings
    • RemovedgetParentalControlCategories
    • RemovedgetParentalControlServices
    • RemovedgetParentalControlSettings
    • RemovedgetPerformanceSettings
    • RemovedgetPrivacyBlocklists
    • RemovedgetPrivacyNatives
    • RemovedgetPrivacySettings
    • RemovedgetProfile
    • RemovedgetSecuritySettings
    • RemovedgetSecurityTLDs
    • RemovedgetSettings
    • RemovedlistProfiles
    • AddedmanageLists
    • AddedmanageLogs
    • AddedmanageProfiles
    • AddedmanageRewrites
    • AddedmanageSettings
    • AddedplotAnalytics
    • AddedqueryAnalytics
    • RemovedremoveFromAllowlist
    • RemovedremoveFromDenylist
    • RemovedremoveFromParentalControlCategories
    • RemovedremoveFromParentalControlServices
    • RemovedremovePrivacyBlocklist
    • RemovedremovePrivacyNative
    • RemovedremoveSecurityTLD
    • RemovedreplaceAllowlist
    • RemovedreplaceDenylist
    • RemovedreplaceParentalControlCategories
    • RemovedreplaceParentalControlServices
    • RemovedreplacePrivacyBlocklists
    • RemovedreplacePrivacyNatives
    • RemovedreplaceSecurityTLDs
    • RemovedupdateAllowlistEntry
    • RemovedupdateBlockPageSettings
    • RemovedupdateDenylistEntry
    • RemovedupdateLogsSettings
    • RemovedupdateParentalControlCategoryEntry
    • RemovedupdateParentalControlServiceEntry
    • RemovedupdateParentalControlSettings
    • RemovedupdatePerformanceSettings
    • RemovedupdatePrivacySettings
    • RemovedupdateProfile
    • RemovedupdateSecuritySettings
    • RemovedupdateSettings
  5. 75 tool updatesv2.0.16
    • First observedaddPrivacyBlocklist
    • First observedaddPrivacyNative
    • First observedaddSecurityTLD
    • First observedaddToAllowlist
    • First observedaddToDenylist
    • First observedaddToParentalControlCategories
    • First observedaddToParentalControlServices
    • First observedclearLogs
    • First observedcreateProfile
    • First observeddeleteProfile
    • First observeddohLookup
    • First observedgetAllowlist
    • First observedgetAnalyticsDestinations
    • First observedgetAnalyticsDestinationsSeries
    • First observedgetAnalyticsDevices
    • First observedgetAnalyticsDevicesSeries
    • First observedgetAnalyticsDNSSEC
    • First observedgetAnalyticsDNSSECSeries
    • First observedgetAnalyticsDomains
    • First observedgetAnalyticsEncryption
    • First observedgetAnalyticsEncryptionSeries
    • First observedgetAnalyticsIPs
    • First observedgetAnalyticsIPsSeries
    • First observedgetAnalyticsIPVersions
    • First observedgetAnalyticsIPVersionsSeries
    • First observedgetAnalyticsProtocols
    • First observedgetAnalyticsProtocolsSeries
    • First observedgetAnalyticsQueryTypes
    • First observedgetAnalyticsQueryTypesSeries
    • First observedgetAnalyticsReasons
    • First observedgetAnalyticsReasonsSeries
    • First observedgetAnalyticsStatus
    • First observedgetAnalyticsStatusSeries
    • First observedgetBlockPageSettings
    • First observedgetDenylist
    • First observedgetLogs
    • First observedgetLogsSettings
    • First observedgetParentalControlCategories
    • First observedgetParentalControlServices
    • First observedgetParentalControlSettings
    • First observedgetPerformanceSettings
    • First observedgetPrivacyBlocklists
    • First observedgetPrivacyNatives
    • First observedgetPrivacySettings
    • First observedgetProfile
    • First observedgetSecuritySettings
    • First observedgetSecurityTLDs
    • First observedgetSettings
    • First observedlistProfiles
    • First observedremoveFromAllowlist
    • First observedremoveFromDenylist
    • First observedremoveFromParentalControlCategories
    • First observedremoveFromParentalControlServices
    • First observedremovePrivacyBlocklist
    • First observedremovePrivacyNative
    • First observedremoveSecurityTLD
    • First observedreplaceAllowlist
    • First observedreplaceDenylist
    • First observedreplaceParentalControlCategories
    • First observedreplaceParentalControlServices
    • First observedreplacePrivacyBlocklists
    • First observedreplacePrivacyNatives
    • First observedreplaceSecurityTLDs
    • First observedupdateAllowlistEntry
    • First observedupdateBlockPageSettings
    • First observedupdateDenylistEntry
    • First observedupdateLogsSettings
    • First observedupdateParentalControlCategoryEntry
    • First observedupdateParentalControlServiceEntry
    • First observedupdateParentalControlSettings
    • First observedupdatePerformanceSettings
    • First observedupdatePrivacySettings
    • First observedupdateProfile
    • First observedupdateSecuritySettings
    • First observedupdateSettings

TDQS

A3.8/5.0

Scored across 8 tools

Disambiguation4/5

Most tools target distinct resources: profiles, settings, lists, rewrites, logs, analytics, plotting, and DoH lookup. However, manageSettings(category='logs') overlaps conceptually with manageLogs, and both manageProfiles update and manageSettings(general) can alter profile name, creating minor ambiguity.

Naming Consistency4/5

All tools use camelCase consistently, with no mixing of snake_case or other conventions. The verb+noun pattern is mostly predictable, though dohLookup breaks the verb-first pattern slightly and manage* is reused across several resources.

Tool Count5/5

8 tools is well-scoped for a NextDNS management server. Each tool covers a distinct area of the API and none appears redundant or superfluous.

Completeness5/5

The surface covers the core NextDNS lifecycle: profile CRUD, settings categories, allow/deny/block lists, rewrites, query logs, analytics querying, visualization, and DoH lookup. No obvious operational gap prevents common workflows, though device-level management could be an extension.

Maintenance

ActivityActive
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    F
    maintenance
    Enables AI assistants to interact with Fastly's CDN API through the Model Context Protocol, allowing secure management of CDN services, caching, security settings, and performance monitoring without exposing API keys.
    2
    13 npm
    7
    MIT
  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables AI assistants to manage Cloudflare infrastructure including DNS records, cache purging, SSL settings, Workers, and analytics through the Cloudflare API. Eliminates dashboard context-switching by allowing natural language control of domain management and infrastructure operations.
    -
  • F
    license
    Not graded
    quality
    B
    maintenance
    Real-time DNS security analysis for AI assistants via MCP. Enables DNSSEC chain validation, email authentication posture, and registration intelligence directly from chat sessions.
    1
    -
  • A
    license
    B
    quality
    A
    maintenance
    Enables AI assistants to securely manage Bitwarden vault items, folders, attachments, and organization administration through the Model Context Protocol.
    59
    1,718 npm
    258
    GPL 3.0