dns_query_logs
Retrieve DNS query logs with optional filters for domain, client IP, query type, and response code to analyze server activity.
Instructions
Query DNS server logs with optional filters. Returns recent DNS queries and their responses. Requires the Query Logs app to be installed.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| pageNumber | No | Page number (default: 1) | |
| entriesPerPage | No | Entries per page (default: 25, max: 100) | |
| domain | No | Filter by domain name (exact match, e.g. github.com) | |
| clientIp | No | Filter by client IP address | |
| queryType | No | Filter by DNS query type | |
| responseCode | No | Filter by response code |
Implementation Reference
- src/tools/logs.ts:66-107 (handler)The handler function that executes the dns_query_logs tool logic. It builds query parameters with optional filters (domain, clientIp, queryType, responseCode) and calls the /api/logs/query endpoint via the TechnitiumClient.
handler: async (args) => { const params: Record<string, string> = { name: "Query Logs (Sqlite)", classPath: "QueryLogsSqlite.App", pageNumber: String(args.pageNumber || 1), entriesPerPage: String( Math.min(Number(args.entriesPerPage) || 25, 100) ), }; if (args.domain) { // API uses 'qname' (exact match on the DNS question name column) params.qname = validateStringLength( args.domain as string, 253, "domain" ); } if (args.clientIp) { params.clientIpAddress = validateIp(args.clientIp as string); } if (args.queryType) { params.type = validateRecordType(args.queryType as string); } if (args.responseCode) { const valid = new Set([ "NoError", "ServerFailure", "NxDomain", "Refused", "FormatError", ]); const code = args.responseCode as string; if (!valid.has(code)) { throw new Error(`Invalid response code: ${code}`); } params.rcode = code; } const data = await client.callOrThrow("/api/logs/query", params); return JSON.stringify(data, null, 2); }, - src/tools/logs.ts:13-64 (schema)The input schema definition for dns_query_logs. Defines optional parameters: pageNumber, entriesPerPage, domain, clientIp, queryType (with enum of DNS record types), and responseCode (with enum of error codes).
definition: { name: "dns_query_logs", description: "Query DNS server logs with optional filters. Returns recent DNS queries and their responses. Requires the Query Logs app to be installed.", inputSchema: { type: "object", properties: { pageNumber: { type: "number", description: "Page number (default: 1)", }, entriesPerPage: { type: "number", description: "Entries per page (default: 25, max: 100)", }, domain: { type: "string", description: "Filter by domain name (exact match, e.g. github.com)", }, clientIp: { type: "string", description: "Filter by client IP address", }, queryType: { type: "string", enum: [ "A", "AAAA", "CNAME", "MX", "NS", "PTR", "SOA", "TXT", "ANY", ], description: "Filter by DNS query type", }, responseCode: { type: "string", enum: [ "NoError", "ServerFailure", "NxDomain", "Refused", "FormatError", ], description: "Filter by response code", }, }, }, }, - src/tools/index.ts:10-23 (registration)The tool is registered via the logTools function, imported from './logs.js' and included in the getAllTools array as ...logTools(client).
import { logTools } from "./logs.js"; import { appTools } from "./apps.js"; import { dnssecTools } from "./dnssec.js"; export function getAllTools(client: TechnitiumClient): ToolEntry[] { return [ ...dashboardTools(client), ...dnsClientTools(client), ...zoneTools(client), ...recordTools(client), ...blockingTools(client), ...cacheTools(client), ...settingsTools(client), ...logTools(client), - src/index.ts:35-35 (registration)The tool is registered in the MCP server's toolMap (line 35) and dispatched via CallToolRequestSchema (line 47-124). The definition (name, description, inputSchema) is sent via ListToolsRequestSchema (line 43-45).
const toolMap = new Map(tools.map((t) => [t.definition.name, t])); - src/validate.ts:91-99 (helper)The validateStringLength helper used to validate the domain filter length (max 253 chars). Also validateIp (line 19-28) and validateRecordType (line 51-60) are used for clientIp and queryType filters.
export function validateStringLength(value: string, maxLength: number, fieldName: string): string { if (typeof value !== "string") { throw new Error(`${fieldName} must be a string`); } if (value.length > maxLength) { throw new Error(`${fieldName} exceeds maximum length of ${maxLength}`); } return value; }