diff --git a/src/oracle-db-mcp-java-toolkit/README.md b/src/oracle-db-mcp-java-toolkit/README.md index aebad4ba..bfbd8614 100644 --- a/src/oracle-db-mcp-java-toolkit/README.md +++ b/src/oracle-db-mcp-java-toolkit/README.md @@ -128,9 +128,7 @@ The server provides four built-in toolsets that can be enabled via `-Dtools`: log-analyzer JDBC and RDBMS log analysis - get-jdbc-stats, get-jdbc-queries, get-jdbc-errors, - get-jdbc-connection-events, list-log-files-from-directory, - jdbc-log-comparison, get-rdbms-errors, get-rdbms-packet-dumps + jdbc-analyzer, rdbms-analyzer @@ -153,7 +151,7 @@ _Note: Each tool belongs to exactly one built-in toolset. Enabling a toolset ena **Common Configurations:** - `-Dtools=mcp-admin` - Admin and runtime configuration tools -- `-Dtools=log-analyzer` - Log analysis only (no database required) +- `-Dtools=log-analyzer` - Oracle JDBC Log and RDBMS/SQLNet trace file analysis only (no database required) - `-Dtools=database-operator` - Database operations and SQL execution - `-Dtools=rag` – Vector similarity search - `-Dtools=mcp-admin,log-analyzer` - Admin + log analysis @@ -189,21 +187,25 @@ These tools help monitor database health and performance: ### 3.5. Oracle JDBC Log Analysis -These tools operate on Oracle JDBC thin client logs: +The `jdbc-analyzer` tool covers the Oracle JDBC thin client logs analysis using the `action` parameter, it supports the following values: -* **`get-jdbc-stats`**: Extracts performance statistics including error counts, sent/received packets and byte counts. -* **`get-jdbc-queries`**: Retrieves all executed SQL queries with timestamps and execution times. -* **`get-jdbc-errors`**: Extracts all errors reported by both server and client. -* **`get-jdbc-connection-events`**: Shows connection open/close events. -* **`list-log-files-from-directory`**: List all visible files from a specified directory, which helps the user analyze multiple files with one prompt. -* **`jdbc-log-comparison`**: Compares two log files for performance metrics, errors, and network information. +* **`action=stats`**: Extracts performance statistics including error counts, sent/received packets and byte counts. +* **`action=queries`**: Retrieves all executed SQL queries with timestamps and execution times. +* **`action=errors`**: Extracts all errors reported by both server and client. +* **`action=connection-events`**: Shows connection open/close events. +* **`action=compare`**: Compares two log files for performance metrics, errors, and network information. +* **`action=list-files`**: List all visible files from a specified directory, which helps the user analyze multiple files with one prompt. + +The tool returns results serialized in JSON format. ### 3.6. RDBMS/SQLNet Trace Analysis: -These tools operate on RDBMS/SQLNet trace files: +The `rdbms-analyzer` tool operate on RDBMS/SQLNet trace files based on the chosen `action`: + +* **`action=rdbms-errors`**: Extracts errors from RDBMS/SQLNet trace files. +* **`action=packet-dumps`**: Extracts packet dumps for a specific connection ID. -* **`get-rdbms-errors`**: Extracts errors from RDBMS/SQLNet trace files. -* **`get-rdbms-packet-dumps`**: Extracts packet dumps for a specific connection ID. +Each extracted record includes relevant details/context and is returned serialized in JSON format. ### 3.7. Vector Similarity Search (RAG) @@ -332,7 +334,7 @@ This is the mode used by tools like Claude Desktop, where the client directly la "-Ddb.url=jdbc:oracle:thin:@your-host:1521/your-service", "-Ddb.user=your_user", "-Ddb.password=your_password", - "-Dtools=get-jdbc-stats,get-jdbc-queries", + "-Dtools=jdbc-analyzer", "-Dojdbc.ext.dir=/path/to/extra-jars", "-jar", "/oracle-db-mcp-toolkit-1.0.0.jar" @@ -367,7 +369,7 @@ java \ -Ddb.url=jdbc:oracle:thin:@your-host:1521/your-service \ -Ddb.user=your_user \ -Ddb.password=your_password \ - -Dtools=get-jdbc-stats,get-jdbc-queries \ + -Dtools=jdbc-analyzer \ -jar /oracle-db-mcp-toolkit-1.0.0.jar ``` @@ -539,17 +541,17 @@ Ultimately, the token must be included in the http request header (e.g. `Authori No Comma-separated allow-list of tool or toolset names to enable (case-insensitive).
- You can pass individual tools (e.g. get-jdbc-stats, read-query) or any of the following built-in toolsets: + You can pass individual tools (e.g. jdbc-analyzer, read-query) or any of the following built-in toolsets: You can also define your own YAML toolsets: and reference them here. Use * or all to enable everything. If omitted, all tools are enabled by default. - mcp-admin,log-analyzer or reporting + mcp-admin, log-analyzer or reporting ojdbc.ext.dir @@ -681,7 +683,6 @@ podman run --rm \ -Dhttps.port=45451 \ -DcertificatePath=[path/to/certificate] \ -DcertificatePassword=[password] \ - -Dtools=get-jdbc-stats,get-jdbc-queries \ -Ddb.url=jdbc:oracle:thin:@your-host:1521/your-service \ -Ddb.user=your_user \ -Ddb.password=your_password" \ @@ -709,7 +710,6 @@ podman run --rm \ -e JAVA_TOOL_OPTIONS="\ -Dtransport=http \ -Dhttps.port=45451 \ - -Dtools=get-jdbc-stats,get-jdbc-queries \ -Ddb.url=jdbc:oracle:thin:@your-host:1521/your-service \ -Ddb.user=your_user \ -Ddb.password=your_password \ @@ -738,7 +738,7 @@ In this configuration, Claude Desktop runs `podman run --rm -i ...à and connect "-i", "-v", "/absolute/path/to/ext:/ext:ro", "-e", - "JAVA_TOOL_OPTIONS=-Dtools=get-jdbc-stats,get-jdbc-queries -Ddb.url=jdbc:oracle:thin:@your-host:1521/your-service -Ddb.user=your_user -Ddb.password=your_password -Dojdbc.ext.dir=/ext -DconfigFile=/config/config.yaml", + "JAVA_TOOL_OPTIONS=-Ddb.url=jdbc:oracle:thin:@your-host:1521/your-service -Ddb.user=your_user -Ddb.password=your_password -Dojdbc.ext.dir=/ext -DconfigFile=/config/config.yaml", "oracle-db-mcp-toolkit:1.0.0" ] } diff --git a/src/oracle-db-mcp-java-toolkit/src/main/java/com/oracle/database/mcptoolkit/ServerConfig.java b/src/oracle-db-mcp-java-toolkit/src/main/java/com/oracle/database/mcptoolkit/ServerConfig.java index 41d2b014..bfd66d52 100644 --- a/src/oracle-db-mcp-java-toolkit/src/main/java/com/oracle/database/mcptoolkit/ServerConfig.java +++ b/src/oracle-db-mcp-java-toolkit/src/main/java/com/oracle/database/mcptoolkit/ServerConfig.java @@ -67,16 +67,7 @@ private ServerConfig( /** Built-in toolsets covering predefined tools. Lowercase keys and members. */ private static final Map> BUILTIN_TOOLSETS = Map.of( - "log-analyzer", Set.of( - "get-jdbc-stats", - "get-jdbc-queries", - "get-jdbc-errors", - "list-log-files-from-directory", - "jdbc-log-comparison", - "get-jdbc-connection-events", - "get-rdbms-errors", - "get-rdbms-packet-dumps" - ), + "log-analyzer", Set.of("jdbc-analyzer", "rdbms-analyzer"), "rag", Set.of("similarity-search"), "database-operator", Set.of( "read-query", "write-query", "transaction", "table", "db-ping", "db-metrics-range", diff --git a/src/oracle-db-mcp-java-toolkit/src/main/java/com/oracle/database/mcptoolkit/tools/LogAnalyzerTools.java b/src/oracle-db-mcp-java-toolkit/src/main/java/com/oracle/database/mcptoolkit/tools/LogAnalyzerTools.java index b6373e59..7a47701f 100644 --- a/src/oracle-db-mcp-java-toolkit/src/main/java/com/oracle/database/mcptoolkit/tools/LogAnalyzerTools.java +++ b/src/oracle-db-mcp-java-toolkit/src/main/java/com/oracle/database/mcptoolkit/tools/LogAnalyzerTools.java @@ -38,284 +38,199 @@ public final class LogAnalyzerTools { private static final String FILE_PATH = "filePath"; private static final String SECOND_FILE_PATH = "secondFilePath"; private static final String CONNECTION_ID = "connectionId"; + private static final String JDBC_ANALYZER_DESCRIPTION = """ + Analyzes Oracle JDBC thin log files and directories. + Supports the following JDBC actions: + - stats (aggregated statistics such as errors, packets, bytes). + - queries (executed SQL queries with timestamp/execution info) + - errors (reported errors with stack trace/context) + - connection-events (opened/closed connection events) + - list-files (list visible files in a directory) + - compare (compare two JDBC logs and return a JSON report highlighting differences and similarities in performance metrics, encountered errors, and network-related information). + Returns results serialized in JSON format. + """; + private static final String RDBMS_ANALYZER_DESCRIPTION = """ + Analyzes Oracle RDBMS/SQLNet trace files. + Supports the following RDBMS actions: + - rdbms-errors (extract all reported errors from an RDBMS/SQLNet trace) + - packet-dumps (extract packet dump records that match a specified connectionId). + Each extracted record includes relevant details/context and is returned serialized in JSON format. + """; /** - *

- * Returns a list of available tools for Oracle JDBC Log Analyzer. - * The tools provided include: - *

    - *
  • {@code get-jdbc-stats}: Retrieves high-level statistics from an Oracle JDBC thin log file.
  • - *
  • {@code get-jdbc-queries}: Extracts all executed SQL queries from an Oracle JDBC thin log file.
  • - *
  • {@code get-jdbc-errors}: Processes a specified Oracle JDBC thin log file and extracts all reported errors.
  • - *
  • {@code list-log-files-from-directory}: Lists all Oracle JDBC log files present in the specified directory path.
  • - *
  • {@code jdbc-log-comparison}: Compares two Oracle JDBC log files and provides a JSON report highlighting differences and similarities.
  • - *
  • {@code get-jdbc-connection-events}: Retrieves opened and closed JDBC connection events from the log file.
  • - *
  • {@code get-rdbms-errors}: Processes a specified Oracle RDBMS/SQLNet trace file to extract all reported errors.
  • - *
  • {@code get-rdbms-packet-dumps}: Extracts packet dump information from a specified RDBMS/SQLNet trace file that matches a given connection ID.
  • - *
- *

+ * Returns the set of MCP tools exposed by the Oracle JDBC Log Analyzer server. + * + *

The returned {@link McpServerFeatures.SyncToolSpecification SyncToolSpecification} + * instances describe the following logical analyzers:

* - * @return a list of {@link McpServerFeatures.SyncToolSpecification SyncToolSpecification} instances representing the available tools. + *
    + *
  • JDBC analyzer ({@code jdbc-analyzer}): + *
      + *
    • {@code stats} – retrieves aggregated statistics (for example, errors, packets, bytes) + * from an Oracle JDBC thin log file.
    • + *
    • {@code queries} – extracts executed SQL statements together with timing/execution + * information.
    • + *
    • {@code errors} – extracts reported errors, including stack traces and contextual + * information.
    • + *
    • {@code connection-events} – returns opened and closed JDBC connection events + * from the log file.
    • + *
    • {@code list-files} – lists the visible log files in a given directory.
    • + *
    • {@code compare} – compares two JDBC log files and returns a JSON report that + * highlights differences and similarities in performance metrics, encountered errors, + * and network‑related information.
    • + *
    + *
  • + *
  • RDBMS/SQLNet analyzer ({@code rdbms-analyzer}): + *
      + *
    • {@code errors} – extracts all reported errors from an RDBMS/SQLNet trace file.
    • + *
    • {@code packet-dumps} – extracts packet dump records matching a specified + * {@code connectionId}.
    • + *
    + *
  • + *
+ * + *

All tool results are serialized in JSON format as defined by the individual tool + * implementations.

+ * + * @return an immutable list containing the JDBC and RDBMS/SQLNet analyzer tool specifications + * to be registered with an MCP server */ public static List getTools() { - return List.of( - getStatsTool(), - getQueriesTool(), - getErrorsTool(), - getListLogsDirectoryTool(), - getConnectionEventsTool(), - logComparisonTool(), - getRdbmsErrorsTool(), - getPacketDumpsTool()); + return List.of(getJDBCAnalyzerTool(), getRDBMSAnalyzerTool()); } - /** - *

- * Builds and returns a {@link SyncToolSpecification SyncToolSpecification} - * for the {@code get-jdbc-stats} tool, which retrieves high-level statistics from an Oracle JDBC thin log file. - * The tool gathers information such as error count, the number of sent and - * received packets, and byte counts from the specified log file. - *

- * - * @return a {@link SyncToolSpecification SyncToolSpecification} instance for the {@code get-jdbc-stats} tool. - */ - private static SyncToolSpecification getStatsTool() { + private static SyncToolSpecification getJDBCAnalyzerTool() { return SyncToolSpecification.builder() .tool(McpSchema.Tool.builder() - .name("get-jdbc-stats") - .title("Get JDBC Stats") - .description("Return aggregated stats (error count, packets, bytes) from an Oracle JDBC thin log.") - .inputSchema(ToolSchemas.FILE_PATH_SCHEMA) + .name("jdbc-analyzer") + .title("Oracle JDBC Log Analyzer") + .description(JDBC_ANALYZER_DESCRIPTION) + .inputSchema(ToolSchemas.JDBC_ANALYZER_SCHEMA) .build()) .callHandler((exchange, callReq) -> Utils.tryCall( () -> { - final var filePath = String.valueOf(callReq.arguments().get(FILE_PATH)); - final var stats = new JDBCLog(filePath).getStats(); - return McpSchema.CallToolResult.builder() - .addTextContent(stats.toJSONString()) - .isError(false) - .build(); - })) - .build(); - } + final var args = callReq.arguments(); + final var action = String.valueOf(args.get("action")); - /** - *

- * Builds and returns a {@link SyncToolSpecification SyncToolSpecification} for the {@code get-jdbc-queries} tool. - * This tool extracts all executed SQL queries from an Oracle JDBC thin log file. - * For each query, it provides the corresponding timestamp, execution time, connection id and tenant. - *

- * - * @return a {@link SyncToolSpecification SyncToolSpecification} instance for the {@code get-jdbc-queries} tool. - */ - private static SyncToolSpecification getQueriesTool() { - return SyncToolSpecification.builder() - .tool(Tool.builder() - .name("get-jdbc-queries") - .title("Get JDBC Queries") - .description("Get all executed queries from an Oracle JDBC thin log file, including the timestamp and execution time.") - .inputSchema(ToolSchemas.FILE_PATH_SCHEMA) - .build()) - .callHandler((exchange, callReq) -> Utils.tryCall(() -> { - final var filePath = String.valueOf(callReq.arguments().get(FILE_PATH)); - final var queries = new JDBCLog(filePath).getQueries(); - String results = queries.stream() - .map(JDBCExecutedQuery::toJSONString) - .collect(Collectors.joining(",", "[", "]")); - return McpSchema.CallToolResult.builder() - .addTextContent(results) - .isError(false) - .build(); - })) - .build(); - } + return switch (action) { + case "stats" -> { + final String filePath = String.valueOf(args.get(FILE_PATH)); + final var stats = new JDBCLog(filePath).getStats(); + yield McpSchema.CallToolResult.builder() + .addTextContent(stats.toJSONString()) + .isError(false) + .build(); + } + case "queries" -> { + final var filePath = String.valueOf(callReq.arguments().get(FILE_PATH)); + final var queries = new JDBCLog(filePath).getQueries(); + final var json = queries.stream() + .map(JDBCExecutedQuery::toJSONString) + .collect(Collectors.joining(",", "[", "]")); + yield McpSchema.CallToolResult.builder() + .addTextContent(json) + .isError(false) + .build(); + } + case "errors" -> { + final var filePath = String.valueOf(callReq.arguments().get(FILE_PATH)); + final var errors = new JDBCLog(filePath).getLogErrors(); + final var json = errors.stream() + .map(LogError::toJSONString) + .collect(Collectors.joining(",", "[", "]")); + yield McpSchema.CallToolResult.builder() + .addTextContent(json) + .isError(false) + .build(); + } + case "connection-events" -> { + final var filePath = String.valueOf(args.get(FILE_PATH)); + final var events = new JDBCLog(filePath).getConnectionEvents(); + final var json = events.stream() + .map(JDBCConnectionEvent::toJSONString) + .collect(Collectors.joining(",", "[", "]")); + yield McpSchema.CallToolResult.builder() + .addTextContent(json) + .isError(false) + .build(); + } + case "compare" -> { + final var filePath = String.valueOf(callReq.arguments().get(FILE_PATH)); + final var secondFilePath = String.valueOf(callReq.arguments().get(SECOND_FILE_PATH)); + final var comparison = new JDBCLog(filePath).compareTo(secondFilePath); + yield McpSchema.CallToolResult.builder() + .addTextContent(comparison.toJSONString()) + .isError(false) + .build(); + } + case "list-files" -> { + final var directoryPath = String.valueOf(args.get(FILE_PATH)); + final var directory = new File(directoryPath); + final var files = directory.listFiles(); + if (files == null || files.length == 0) + throw new IOException("No files found in the specified directory."); - /** - *

- * Builds and returns a {@link SyncToolSpecification SyncToolSpecification} for the get-jdbc-errors tool. - * This tool processes a specified Oracle JDBC thin log file and extracts all reported errors. - * Each error record includes details such as the stack trace and additional log context. - *

- * ` - * @return a {@link SyncToolSpecification SyncToolSpecification} representing the get-jdbc-errors tool. - */ - private static SyncToolSpecification getErrorsTool() { - return SyncToolSpecification.builder() - .tool(Tool.builder() - .name("get-jdbc-errors") - .title("Get JDBC Errors") - .description("Get all reported errors from an Oracle JDBC thin log file, including stacktrace and log context.") - .inputSchema(ToolSchemas.FILE_PATH_SCHEMA) - .build()) - .callHandler((exchange, callReq) -> Utils.tryCall(() -> { - final var filePath = String.valueOf(callReq.arguments().get(FILE_PATH)); - final var errors = new JDBCLog(filePath).getLogErrors(); - String results = errors.stream() - .map(LogError::toJSONString) - .collect(Collectors.joining(",", "[", "]")); - return McpSchema.CallToolResult.builder() - .addTextContent(results) - .isError(false) - .build(); - })) - .build(); - } - - - /** - *

- * Builds and returns a {@link SyncToolSpecification SyncToolSpecification} for the {@code list-log-files-from-directory} tool. - * This tool lists all Oracle JDBC log files present in the specified directory path. - *

- * - * @return a {@link SyncToolSpecification SyncToolSpecification} for the {@code list-log-files-from-directory} tool. - */ - private static SyncToolSpecification getListLogsDirectoryTool() { - return SyncToolSpecification.builder() - .tool(Tool.builder() - .name("list-log-files-from-directory") - .title("List Log Files From Directory") - .description("List all visible files from a specified directory, which helps the user analyze multiple files with one prompt.") - .inputSchema(ToolSchemas.FILE_PATH_SCHEMA) - .build()) - .callHandler((exchange, callReq) -> Utils.tryCall(() -> { - final var directoryPath = String.valueOf(callReq.arguments().get(FILE_PATH)); - final var directory = new File(directoryPath); - final var files = directory.listFiles(); - if (files == null || files.length == 0) { - throw new IOException("No files found in the specified directory."); - } - String results =Arrays.stream(files) - .filter(file -> !file.isHidden() && file.isFile()) - .map(File::getName) - .collect(Collectors.joining(",", "[", "]")); + final var json =Arrays.stream(files) + .filter(file -> !file.isHidden() && file.isFile()) + .map(File::getName) + .collect(Collectors.joining(",", "[", "]")); - return McpSchema.CallToolResult.builder() - .addTextContent(results) - .isError(false) + yield McpSchema.CallToolResult.builder() + .addTextContent(json) + .isError(false) + .build(); + } + default -> McpSchema.CallToolResult.builder() + .addTextContent("Unsupported action: " + action) + .isError(true) .build(); + }; })) .build(); } - /** - *

- * Builds and returns a {@link SyncToolSpecification SyncToolSpecification} for the {@code jdbc-log-comparison} tool. - * This tool enables comparison of two Oracle JDBC log files. It analyzes the specified log files and provides a JSON report - * highlighting differences and similarities in performance metrics, encountered errors, and network-related information. - *

- * - * @return a {@link SyncToolSpecification SyncToolSpecification} instance that defines the {@code jdbc-log-comparison} tool. - */ - private static SyncToolSpecification logComparisonTool() { - return SyncToolSpecification.builder() - .tool(Tool.builder() - .name("jdbc-log-comparison") - .title("JDBC Log Comparison") - .description("Compare two JDBC log files for performance metrics, errors, and network information.") - .inputSchema(ToolSchemas.FILE_COMPARISON_SCHEMA) - .build()) - .callHandler((exchange, callReq) -> Utils.tryCall(() -> { - final var filePath = String.valueOf(callReq.arguments().get(FILE_PATH)); - final var secondFilePath = String.valueOf(callReq.arguments().get(SECOND_FILE_PATH)); - final var comparison = new JDBCLog(filePath).compareTo(secondFilePath); - return McpSchema.CallToolResult.builder() - .addTextContent(comparison.toJSONString()) - .isError(false) - .build(); - })) - .build(); - } - /** - *

- * Builds and returns a {@link SyncToolSpecification SyncToolSpecification} for the {@code get-jdbc-connection-events} tool. - *

- * - * @return a {@link SyncToolSpecification SyncToolSpecification} instance for the {@code get-jdbc-connection-events} tool. - */ - private static SyncToolSpecification getConnectionEventsTool() { - return SyncToolSpecification.builder() - .tool(Tool.builder() - .name("get-jdbc-connection-events") - .title("Get JDBC Connection Events") - .description("Retrieve opened and closed JDBC connection events from the log file with timestamp and connection details.") - .inputSchema(ToolSchemas.FILE_PATH_SCHEMA) - .build()) - .callHandler((exchange, callReq) -> Utils.tryCall(() -> { - final var filePath = String.valueOf(callReq.arguments().get(FILE_PATH)); - final var events = new JDBCLog(filePath).getConnectionEvents(); - String results = events.stream() - .map(JDBCConnectionEvent::toJSONString) - .collect(Collectors.joining(",", "[", "]")); - return McpSchema.CallToolResult.builder() - .addTextContent(results) - .isError(false) - .build(); - })) - .build(); - } - /** - *

- * Builds and returns a {@link SyncToolSpecification SyncToolSpecification} for the get-rdbms-errors tool. - * This tool processes a specified Oracle RDBMS/SQLNet trace file to extract all reported errors. - * Each extracted error record includes relevant details, such as error messages and context information, - * and is serialized in JSON format. - *

- * - * @return a {@link SyncToolSpecification SyncToolSpecification} representing the {@code get-rdbms-errors} tool. - */ - private static SyncToolSpecification getRdbmsErrorsTool() { + private static SyncToolSpecification getRDBMSAnalyzerTool() { return SyncToolSpecification.builder() .tool(Tool.builder() - .name("get-rdbms-errors") - .title("Get RDBMS/SQLNet Errors") - .description("Retrieve errors from an RDBMS/SQLNet trace file.") - .inputSchema(ToolSchemas.RDBMS_TOOLS_SCHEMA) + .name("rdbms-analyzer") + .title("RDBMS/SQLNet Trace Analyzer") + .description(RDBMS_ANALYZER_DESCRIPTION) + .inputSchema(ToolSchemas.RDBMS_ANALYZER_SCHEMA) .build()) .callHandler((exchange, callReq) -> Utils.tryCall(() -> { - final var logFile = String.valueOf(callReq.arguments().get(FILE_PATH)); - final var errors = new RDBMSLog(logFile).getErrors(); - String results = errors.stream() - .map(RDBMSError::toJSONString) - .collect(Collectors.joining(",", "[", "]")); - return McpSchema.CallToolResult.builder() - .addTextContent(results) - .isError(false) - .build(); - })) - .build(); - } + final var args = callReq.arguments(); + final var filePath = String.valueOf(args.get(FILE_PATH)); + final var action = String.valueOf(args.get("action")); - /** - *

- * Builds and returns a {@link SyncToolSpecification SyncToolSpecification} for the get-rdbms-packet-dumps tool. - * This tool extracts packet dump information from a specified RDBMS/SQLNet trace file that matches a given connection ID. - * Each packet dump record includes its associated details and is serialized in JSON format. - *

- * - * @return a {@link SyncToolSpecification SyncToolSpecification} instance for the {@code get-rdbms-packet-dumps} tool. - */ - private static SyncToolSpecification getPacketDumpsTool() { - return SyncToolSpecification.builder() - .tool(Tool.builder() - .name("get-rdbms-packet-dumps") - .title("Get RDBMS/SQLNet Packet Dumps") - .description("Extract packet dumps from RDBMS/SQLNet trace file for given connection ID.") - .inputSchema(ToolSchemas.RDBMS_TOOLS_SCHEMA) - .build()) - .callHandler((exchange, callReq) -> Utils.tryCall(() -> { - final var filePath = String.valueOf(callReq.arguments().get(FILE_PATH)); - final var connId = String.valueOf(callReq.arguments().get(CONNECTION_ID)); - final var packetDumps = new RDBMSLog(filePath).getPacketDumps(connId); - String results = packetDumps.stream() - .map(RDBMSPacketDump::toJSONString) - .collect(Collectors.joining(",", "[", "]")); - return McpSchema.CallToolResult.builder() - .addTextContent(results) - .isError(false) + return switch (action) { + case "errors" -> { + final var errors = new RDBMSLog(filePath).getErrors(); + final var json = errors.stream() + .map(RDBMSError::toJSONString) + .collect(java.util.stream.Collectors.joining(",", "[", "]")); + yield McpSchema.CallToolResult.builder() + .addTextContent(json) + .isError(false) + .build(); + } + case "packet-dumps" -> { + final var connId = String.valueOf(args.get(CONNECTION_ID)); + final var dumps = new RDBMSLog(filePath).getPacketDumps(connId); + final var json = dumps.stream() + .map(RDBMSPacketDump::toJSONString) + .collect(java.util.stream.Collectors.joining(",", "[", "]")); + yield McpSchema.CallToolResult.builder() + .addTextContent(json) + .isError(false) + .build(); + } + default -> McpSchema.CallToolResult.builder() + .addTextContent("Unsupported action: " + action) + .isError(true) .build(); + }; })) .build(); } diff --git a/src/oracle-db-mcp-java-toolkit/src/main/java/com/oracle/database/mcptoolkit/tools/ToolSchemas.java b/src/oracle-db-mcp-java-toolkit/src/main/java/com/oracle/database/mcptoolkit/tools/ToolSchemas.java index dc06a2b7..fbcd81ab 100644 --- a/src/oracle-db-mcp-java-toolkit/src/main/java/com/oracle/database/mcptoolkit/tools/ToolSchemas.java +++ b/src/oracle-db-mcp-java-toolkit/src/main/java/com/oracle/database/mcptoolkit/tools/ToolSchemas.java @@ -81,67 +81,65 @@ public class ToolSchemas { "required":["sql"] }"""; - /** - * JSON schema for file path operations. - *

- * This schema requires a "filePath" property, which should be an absolute path or a URL to an Oracle JDBC log file. - */ - static final String FILE_PATH_SCHEMA = """ - { - "type": "object", - "properties": { - "filePath": { - "type": "string", - "description": "Absolute path or an URL to the Oracle JDBC log file." - } - }, - "required": ["filePath"] - } - """; - - /** - * JSON schema for file comparison operations. - *

- * This schema requires "filePath" and "secondFilePath" properties, which should be absolute paths or URLs to Oracle JDBC log files. - */ - static final String FILE_COMPARISON_SCHEMA = """ - { - "type": "object", - "properties": { - "filePath": { - "type": "string", - "description": "Absolute path or an URL to the 1st Oracle JDBC log file" - }, - "secondFilePath": { - "type": "string", - "description": "Absolute path or an URL to the 2nd Oracle JDBC log file" - } - }, - "required": ["filePath", "secondFilePath"] - } - """; + static final String JDBC_ANALYZER_SCHEMA = """ + { + "type": "object", + "properties": { + "action": { + "type": "string", + "enum": ["stats", "queries", "errors", "connection-events", "list-files", "compare"], + "description": "Operation to perform on JDBC logs." + }, + "filePath": { + "type": "string", + "description": "Absolute path or URL to an Oracle JDBC thin log file." + }, + "secondFilePath": { + "type": "string", + "description": "Absolute path or URL to the second Oracle JDBC thin log file (compare only)." + }, + "directoryPath": { + "type": "string", + "description": "Absolute path to a directory containing log files (list-files only)." + } + }, + "required": ["action"], + "oneOf": [ + { "properties": { "action": { "const": "compare" } }, "required": ["filePath", "secondFilePath"] }, + { "properties": { "action": { "const": "list-files" } }, "required": ["directoryPath"] }, + { "properties": { "action": { "const": "stats" } }, "required": ["filePath"] }, + { "properties": { "action": { "const": "queries" } }, "required": ["filePath"] }, + { "properties": { "action": { "const": "errors" } }, "required": ["filePath"] }, + { "properties": { "action": { "const": "connection-events" } }, "required": ["filePath"] } + ] + } + """; - /** - * JSON schema for RDBMS tools operations. - *

- * This schema requires "filePath" and "connectionId" properties, where "filePath" is an absolute path or a URL to an RDBMS/SQLNet trace file, and "connectionId" is a connection ID string. - */ - static final String RDBMS_TOOLS_SCHEMA = """ - { - "type": "object", - "properties": { - "filePath": { - "type": "string", - "description": "Absolute path or an URL to the RDBMS/SQLNet trace file" - }, - "connectionId": { - "type": "string", - "description": "Connection ID string" - } - }, - "required": ["filePath", "connectionId"] - } - """; + static final String RDBMS_ANALYZER_SCHEMA = """ + { + "type": "object", + "properties": { + "action": { + "type": "string", + "enum": ["errors", "packet-dumps"], + "description": "Operation to perform on an RDBMS/SQLNet trace file." + }, + "filePath": { + "type": "string", + "description": "Absolute path or URL to the RDBMS/SQLNet trace file." + }, + "connectionId": { + "type": "string", + "description": "Connection ID string (required for packet-dumps)." + } + }, + "required": ["action", "filePath"], + "oneOf": [ + { "properties": { "action": { "const": "packet-dumps" } }, "required": ["connectionId"] }, + { "properties": { "action": { "const": "errors" } } } + ] + } + """; /** * JSON schema for similarity search operations. diff --git a/src/oracle-db-mcp-java-toolkit/src/test/java/com/oracle/database/mcptoolkit/OracleJDBCLogAnalyzerTest.java b/src/oracle-db-mcp-java-toolkit/src/test/java/com/oracle/database/mcptoolkit/OracleJDBCLogAnalyzerTest.java index 1c2cc40b..e8b761c2 100644 --- a/src/oracle-db-mcp-java-toolkit/src/test/java/com/oracle/database/mcptoolkit/OracleJDBCLogAnalyzerTest.java +++ b/src/oracle-db-mcp-java-toolkit/src/test/java/com/oracle/database/mcptoolkit/OracleJDBCLogAnalyzerTest.java @@ -29,14 +29,8 @@ static void initializeTools(){ @ParameterizedTest @ValueSource(strings = { - "get-jdbc-stats", - "get-jdbc-queries", - "get-jdbc-errors", - "list-log-files-from-directory", - "get-jdbc-connection-events", - "jdbc-log-comparison", - "get-rdbms-errors", - "get-rdbms-packet-dumps" + "jdbc-analyzer", + "rdbms-analyzer" }) void testToolPresence(final String toolName) { final var isToolPresent = tools.containsKey(toolName); @@ -55,35 +49,4 @@ void testFilePathParameterInAllTools() { } } - @Test - void testSecondFilePathParameterInLogComparisonTool() { - final var toolProperties = tools.get("jdbc-log-comparison") - .inputSchema() - .properties(); - - final var isSecondFileParameterPresent = toolProperties.containsKey("filePath"); - assertTrue(isSecondFileParameterPresent, "log-comparison tool " + - "should have 'secondFilePath' parameter."); - - final var secondFilePathProperty = (Map) toolProperties.get("secondFilePath"); - - assertEquals("string", secondFilePathProperty.get("type"), - "The type of 'filePath' and 'secondFilePath' parameters should be 'string'"); - } - - @Test - void testConnectionIdParameterInGetPacketDumpsTool() { - final var toolProperties = tools.get("get-rdbms-packet-dumps") - .inputSchema() - .properties(); - - final var isConnectionIdPresent = toolProperties.containsKey("connectionId"); - assertTrue(isConnectionIdPresent, "log-comparison tool " + - "should have 'connectionId' parameter."); - - var connectionIdProperty = (Map) toolProperties.get("connectionId"); - - assertEquals("string", connectionIdProperty.get("type"), - "The type of 'filePath' and 'secondFilePath' parameters should be 'string'"); - } } \ No newline at end of file