Skip to main content
Glama

audit.query

Read-onlyIdempotent

Query audit logs to view records of processing activities per GDPR Art.30. Filter by action, target type, and date range to monitor compliance.

Instructions

監査ログを検索します。GDPR Art.30に基づく処理活動記録の閲覧。Query audit logs. View records of processing activities per GDPR Art.30.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
actionNoアクションフィルタ(例: data.delete, page.analyze) / Action filter (e.g., data.delete, page.analyze)
target_typeNoターゲットタイプフィルタ(例: web_page, preference_profile) / Target type filter (e.g., web_page, preference_profile)
start_dateNo開始日時(ISO 8601形式) / Start date (ISO 8601 format)
end_dateNo終了日時(ISO 8601形式) / End date (ISO 8601 format)
limitNo結果上限(最大100、デフォルト20) / Result limit (max 100, default 20)

Implementation Reference

  • Main handler function for audit.query tool. Validates input via Zod schema, checks DI factory for AuditLogService, calls service.query() with filters, maps results to output format, and returns success/failure.
    export async function auditQueryHandler(input: unknown): Promise<AuditQueryOutput> {
      if (isDevelopment()) {
        logger.info("[MCP Tool] audit.query called");
      }
    
      // 入力バリデーション / Input validation
      let validated: AuditQueryInput;
      try {
        validated = auditQueryInputSchema.parse(input);
      } catch (error) {
        if (error instanceof ZodError) {
          const errorMessage = error.errors.map((e) => `${e.path.join(".")}: ${e.message}`).join(", ");
    
          logger.warn("[MCP Tool] audit.query validation error", {
            errors: error.errors,
          });
    
          return {
            success: false,
            error: {
              code: AUDIT_QUERY_ERROR_CODES.VALIDATION_ERROR,
              message: `Validation error: ${errorMessage}`,
            },
          };
        }
        throw error;
      }
    
      // サービスファクトリーチェック / Service factory check
      if (!auditLogServiceDI.get()) {
        logger.warn("[MCP Tool] audit.query service factory not set");
    
        return {
          success: false,
          error: {
            code: AUDIT_QUERY_ERROR_CODES.SERVICE_UNAVAILABLE,
            message: "Audit log service is not available",
          },
        };
      }
    
      const service = auditLogServiceDI.get()!();
    
      try {
        const records = await service.query({
          action: validated.action,
          targetType: validated.target_type,
          startDate: validated.start_date ? new Date(validated.start_date) : undefined,
          endDate: validated.end_date ? new Date(validated.end_date) : undefined,
          limit: validated.limit,
        });
    
        const logs = records.map(toOutputEntry);
    
        if (isDevelopment()) {
          logger.info("[MCP Tool] audit.query completed", {
            count: logs.length,
          });
        }
    
        return {
          success: true,
          data: {
            logs,
            count: logs.length,
          },
        };
      } catch (error) {
        const errorInstance = error instanceof Error ? error : new Error(String(error));
    
        logger.warn("[MCP Tool] audit.query error", {
          error: errorInstance.message,
        });
    
        return {
          success: false,
          error: {
            code: AUDIT_QUERY_ERROR_CODES.INTERNAL_ERROR,
            message: sanitizeErrorMessage(error),
          },
        };
      }
    }
  • Input schema (Zod) for audit.query: optional action, target_type, start_date, end_date (ISO 8601 strings), and limit (1-100).
    export const auditQueryInputSchema = z.object({
      /** アクションフィルタ / Action filter */
      action: z.string().max(100).optional(),
      /** ターゲットタイプフィルタ / Target type filter */
      target_type: z.string().max(100).optional(),
      /** 開始日時(ISO 8601) / Start date (ISO 8601) */
      start_date: isoDateStringSchema.optional(),
      /** 終了日時(ISO 8601) / End date (ISO 8601) */
      end_date: isoDateStringSchema.optional(),
      /** 結果上限(最大100、デフォルト20) / Result limit (max 100, default 20) */
      limit: z.number().int().min(1).max(100).optional(),
    });
  • Output type for audit.query: success with data.logs[] and data.count, or failure with error.code and error.message.
    export type AuditQueryOutput =
      | {
          success: true;
          data: {
            logs: AuditLogOutputEntry[];
            count: number;
          };
        }
      | {
          success: false;
          error: {
            code: string;
            message: string;
          };
        };
  • Tool definition object with name 'audit.query', description, annotations (readOnly, idempotent), and JSON Schema inputSchema matching Zod schema (5 optional fields).
    export const auditQueryToolDefinition = {
      name: "audit.query",
      description:
        "監査ログを検索します。GDPR Art.30に基づく処理活動記録の閲覧。" +
        "Query audit logs. View records of processing activities per GDPR Art.30.",
      annotations: {
        title: "Audit Log Query",
        readOnlyHint: true,
        idempotentHint: true,
        openWorldHint: false,
      },
      inputSchema: {
        type: "object" as const,
        properties: {
          action: {
            type: "string",
            description:
              "アクションフィルタ(例: data.delete, page.analyze) / " +
              "Action filter (e.g., data.delete, page.analyze)",
          },
          target_type: {
            type: "string",
            description:
              "ターゲットタイプフィルタ(例: web_page, preference_profile) / " +
              "Target type filter (e.g., web_page, preference_profile)",
          },
          start_date: {
            type: "string",
            format: "date-time",
            description: "開始日時(ISO 8601形式) / Start date (ISO 8601 format)",
          },
          end_date: {
            type: "string",
            format: "date-time",
            description: "終了日時(ISO 8601形式) / End date (ISO 8601 format)",
          },
          limit: {
            type: "number",
            description: "結果上限(最大100、デフォルト20) / Result limit (max 100, default 20)",
            minimum: 1,
            maximum: 100,
          },
        },
        required: [],
      },
    };
  • Registration of auditQueryHandler in the toolHandlers map under the key 'audit.query'.
    // audit.query(監査ログ検索、GDPR Art.30)
    "audit.query": auditQueryHandler,
  • auditQueryToolDefinition included in allToolDefinitions array for MCP server initialization.
    // audit.query(監査ログ検索、GDPR Art.30)
    auditQueryToolDefinition,
  • Helper function toOutputEntry: converts DB AuditLogRecord to MCP output format (maps camelCase fields to snake_case).
    function toOutputEntry(record: AuditLogRecord): AuditLogOutputEntry {
      return {
        id: record.id,
        timestamp:
          record.timestamp instanceof Date ? record.timestamp.toISOString() : String(record.timestamp),
        action: record.action,
        actor: record.actor,
        target_type: record.targetType,
        target_id: record.targetId,
        details: record.details,
        result: record.result,
      };
    }
  • Helper function truncateTargetId: truncates PII-sensitive target IDs for privacy (GDPR compliance).
    function truncateTargetId(id: string | undefined | null): string | null {
      if (!id) return null;
      if (id.length <= AUDIT_LOG_CONSTANTS.TARGET_ID_TRUNCATE_LENGTH) return id;
      return id.slice(0, AUDIT_LOG_CONSTANTS.TARGET_ID_TRUNCATE_LENGTH) + "...";
    }
  • Helper function sanitizeDetails: recursively removes sensitive keys (password, secret, token, etc.) from details objects.
    function sanitizeDetails(
      obj: Record<string, unknown> | null | undefined
    ): Record<string, unknown> | null {
      if (!obj || typeof obj !== "object") return null;
    
      const sanitized: Record<string, unknown> = {};
    
      for (const [key, value] of Object.entries(obj)) {
        // 機密キーはスキップ
        if (SENSITIVE_KEYS.has(key)) {
          continue;
        }
    
        // ネストされたオブジェクトは再帰処理
        if (value !== null && typeof value === "object" && !Array.isArray(value)) {
          sanitized[key] = sanitizeDetails(value as Record<string, unknown>);
        } else {
          sanitized[key] = value;
        }
      }
    
      return sanitized;
    }
  • AuditLogService.query() method: builds Prisma where clause from filters, applies limit clamping (1-100), orders by timestamp desc, and returns records.
    async query(filters: AuditLogFilters): Promise<AuditLogRecord[]> {
      if (!this.prismaClient) {
        logger.warn("[AuditLog] Prisma client not available for query");
        return [];
      }
    
      const where: Record<string, unknown> = {};
    
      if (filters.action) {
        where.action = filters.action;
      }
    
      if (filters.targetType) {
        where.targetType = filters.targetType;
      }
    
      if (filters.startDate || filters.endDate) {
        const timestampFilter: Record<string, Date> = {};
        if (filters.startDate) {
          timestampFilter.gte = filters.startDate;
        }
        if (filters.endDate) {
          timestampFilter.lte = filters.endDate;
        }
        where.timestamp = timestampFilter;
      }
    
      const limit = Math.min(
        Math.max(filters.limit ?? AUDIT_LOG_CONSTANTS.DEFAULT_QUERY_LIMIT, 1),
        AUDIT_LOG_CONSTANTS.MAX_QUERY_LIMIT
      );
    
      return this.prismaClient.auditLog.findMany({
        where,
        orderBy: { timestamp: "desc" },
        take: limit,
      });
    }
  • Auth permission mapping: audit.query requires SYSTEM_READ permission.
    // 監査系(v0.3.0 GDPR Art.30)
    "audit.query": [PERMISSIONS.SYSTEM_READ],
  • DI factory registration: setAuditQueryServiceFactory wires AuditLogService into the audit.query tool handler at service initialization.
      // audit.query ツールの DI ファクトリ登録
      setAuditQueryServiceFactory(() => getAuditLogService());
    
      result.registeredFactories.push("auditLogPrisma", "auditQueryService");
      result.categories.push("auditLog");
      logger.info("[ServiceInitializer] auditLog factories registered (prisma, queryService)");
    } catch (error) {
      recordInitError(result, "AuditLog", ["auditLogPrisma", "auditQueryService"], error);
    }
Behavior3/5

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

Annotations already declare readOnlyHint and idempotentHint, so the safety profile is clear. The description adds GDPR context but does not disclose other behaviors like pagination or rate limits. Given annotations, the description provides adequate additional 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 extremely concise (two sentences) and front-loaded with the purpose in both Japanese and English. Every sentence adds value with no waste.

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?

Given the tool is a query with 5 parameters, no output schema, and annotations covering safety, the description is minimally adequate but lacks details on return format or usage examples. It could be more complete for a query tool without output schema.

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?

All parameters have descriptions in the input schema (100% coverage), so the schema already explains parameter meaning. The description does not add extra value beyond what the schema provides, so baseline 3 is appropriate.

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 clearly identifies the tool as querying audit logs and references GDPR Art.30, which is specific. However, it does not strongly differentiate from sibling tools like search.unified, but the audit log domain is distinct enough.

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?

No guidance is provided on when to use this tool versus alternatives such as search.unified or data.delete. There is no mention of prerequisites or applicability.

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

Install Server

Other Tools

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/TKMD/ReftrixMCP'

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