From a4e92334c2cebbf2ed7da31776500a431af9388b Mon Sep 17 00:00:00 2001 From: Shyam N V Date: Fri, 19 Dec 2025 17:36:16 +0530 Subject: [PATCH 1/5] OCI DB Dynamic MCP Server --- src/oci-db-dynamic-mcp-server/LICENSE.txt | 35 + src/oci-db-dynamic-mcp-server/README.md | 453 + .../oracle/__init__.py | 5 + .../oci_db_dynamic_mcp_server/__init__.py | 8 + .../dynamic_tools_loader.py | 322 + .../oci_db_dynamic_mcp_server/server.py | 311 + .../tests/test_db_dynamic.py | 7843 +++++++++++++++++ src/oci-db-dynamic-mcp-server/pyproject.toml | 40 + src/oci-db-dynamic-mcp-server/uv.lock | 1075 +++ tox.ini | 3 +- 10 files changed, 10094 insertions(+), 1 deletion(-) create mode 100644 src/oci-db-dynamic-mcp-server/LICENSE.txt create mode 100644 src/oci-db-dynamic-mcp-server/README.md create mode 100644 src/oci-db-dynamic-mcp-server/oracle/__init__.py create mode 100644 src/oci-db-dynamic-mcp-server/oracle/oci_db_dynamic_mcp_server/__init__.py create mode 100644 src/oci-db-dynamic-mcp-server/oracle/oci_db_dynamic_mcp_server/dynamic_tools_loader.py create mode 100644 src/oci-db-dynamic-mcp-server/oracle/oci_db_dynamic_mcp_server/server.py create mode 100644 src/oci-db-dynamic-mcp-server/oracle/oci_db_dynamic_mcp_server/tests/test_db_dynamic.py create mode 100644 src/oci-db-dynamic-mcp-server/pyproject.toml create mode 100644 src/oci-db-dynamic-mcp-server/uv.lock diff --git a/src/oci-db-dynamic-mcp-server/LICENSE.txt b/src/oci-db-dynamic-mcp-server/LICENSE.txt new file mode 100644 index 00000000..8dc7c070 --- /dev/null +++ b/src/oci-db-dynamic-mcp-server/LICENSE.txt @@ -0,0 +1,35 @@ +Copyright (c) 2025 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/src/oci-db-dynamic-mcp-server/README.md b/src/oci-db-dynamic-mcp-server/README.md new file mode 100644 index 00000000..b041d0b4 --- /dev/null +++ b/src/oci-db-dynamic-mcp-server/README.md @@ -0,0 +1,453 @@ +# OCI Database Dynamic MCP Server + +## Overview + +This server provides tools to interact with the OCI Database service. +You can load the required tools using the `--resources` filter, and the server is designed to dynamically generate the, during runtime. + +## Running the server + +```sh +uv run oracle.oci-db-dynamic-mcp-server +``` + +## Environment Variables + +The server supports the following environment variables: + +- `OCI_CONFIG_PROFILE`: OCI configuration profile name (default: "DEFAULT") + +## Parameters + +The server accepts the following parameters to control which OCI resources are loaded. This helps reduce startup time and token usage by only loading the tools you need. + +| Parameter | Type | CLI Flag | Description | +| :--- | :--- |:--------------------|:---------------------- | +| **Resources** | String | `--resources or -r` | A comma-separated list of OCI resources to load (e.g., `database`, `db_system`). If omitted, all available tools are loaded. | + +## Configuration Example +This loads only the dbSystems and the databases resources (case-insensitive) +```json + "database-dynamic": { + "autoApprove": [], + "disabled": false, + "timeout": 30, + "type": "stdio", + "command": "uv", + "args": [ + "run", + "oracle.oci-db-dynamic-mcp-server", + "--resources", + "dbSystems, databases" + ], + "env": { + "VIRTUAL_ENV": "Documents/oci-mcp/.venv", + "OCI_CONFIG_PROFILE": "DEFAULT" + } +``` + +## Tools + +| Tool Name | Resource Name | Description +| --- |----------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| ListApplicationVips | applicationVip | Gets a list of application virtual IP (VIP) addresses on a cloud VM cluster | +| CreateApplicationVip | applicationVip | Creates a new application virtual IP (VIP) address in the specified cloud VM cluster based on the request parameters you provide | +| DeleteApplicationVip | applicationVip | Deletes and deregisters the specified application virtual IP (VIP) address | +| GetApplicationVip | applicationVip | Gets information about a specified application virtual IP (VIP) address | +| ListAutonomousContainerDatabaseBackups | autonomousContainerDatabaseBackups | Gets a list of Autonomous Container Database backups by using either the 'autonomousDatabaseId' or 'compartmentId' as your query parameter | +| ListAutonomousContainerDatabaseVersions | autonomousContainerDatabaseVersions | Gets a list of supported Autonomous Container Database versions | +| ListAutonomousContainerDatabases | autonomousContainerDatabases | Gets a list of the Autonomous Container Databases in the specified compartment | +| CreateAutonomousContainerDatabase | autonomousContainerDatabases | Creates an Autonomous Container Database in the specified Autonomous Exadata Infrastructure | +| TerminateAutonomousContainerDatabase | autonomousContainerDatabases | Terminates an Autonomous Container Database, which permanently deletes the container database and any databases within the container database | +| GetAutonomousContainerDatabase | autonomousContainerDatabases | Gets information about the specified Autonomous Container Database | +| UpdateAutonomousContainerDatabase | autonomousContainerDatabases | Updates the properties of an Autonomous Container Database, such as display name, maintenance preference, backup retention, and tags | +| AddStandbyAutonomousContainerDatabase | autonomousContainerDatabases | Add a standby Autonomous Container Database | +| ChangeAutonomousContainerDatabaseCompartment | autonomousContainerDatabases | Move the Autonomous Container Database and its dependent resources to the specified compartment | +| EditAutonomousContainerDatabaseDataguard | autonomousContainerDatabases | Modify Autonomous Container Database Data Guard settings such as protection mode, automatic failover, and fast start failover lag limit | +| FailoverAutonomousContainerDatabaseDataguard | autonomousContainerDatabases | Performs failover to a standby Autonomous Container Database (ACD) identified by the autonomousContainerDatabaseId parameter | +| ReinstateAutonomousContainerDatabaseDataguard | autonomousContainerDatabases | Reinstates a disabled standby Autonomous Container Database (ACD), identified by the autonomousContainerDatabaseId parameter to an active standby ACD | +| RestartAutonomousContainerDatabase | autonomousContainerDatabases | Rolling restarts the specified Autonomous Container Database | +| RotateAutonomousContainerDatabaseEncryptionKey | autonomousContainerDatabases | Creates a new version of an existing [Vault service](/iaas/Content/KeyManagement/Concepts/keyoverview | +| ConvertStandbyAutonomousContainerDatabase | autonomousContainerDatabases | Convert the standby Autonomous Container Database (ACD) between physical standby and snapshot standby ACD | +| SwitchoverAutonomousContainerDatabaseDataguard | autonomousContainerDatabases | Switchover an Autonomous Container Database (ACD), identified by the autonomousContainerDatabaseId parameter, to an active standby ACD | +| MigrateAutonomousContainerDatabaseDataguardAssociation | autonomousContainerDatabases | Migrate Autonomous Container Database, identified by the autonomousContainerDatabaseId parameter | +| ListContainerDatabasePatches | autonomousContainerDatabases | Lists the patches applicable to the requested container database | +| GetAutonomousContainerDatabaseResourceUsage | autonomousContainerDatabases | Get resource usage details for the specified Autonomous Container Database | +| ListAutonomousDatabaseBackups | autonomousDatabaseBackups | Gets a list of Autonomous AI Database backups based on either the `autonomousDatabaseId` or `compartmentId` specified as a query parameter | +| CreateAutonomousDatabaseBackup | autonomousDatabaseBackups | Creates a new Autonomous AI Database backup for the specified database based on the provided request parameters | +| DeleteAutonomousDatabaseBackup | autonomousDatabaseBackups | Deletes a long-term backup | +| GetAutonomousDatabaseBackup | autonomousDatabaseBackups | Gets information about the specified Autonomous AI Database backup | +| UpdateAutonomousDatabaseBackup | autonomousDatabaseBackups | Updates the Autonomous AI Database backup of the specified database based on the request parameters | +| ListAutonomousDatabaseCharacterSets | autonomousDatabaseCharacterSets | Gets a list of supported character sets | +| ListAutonomousDatabaseSoftwareImages | autonomousDatabaseSoftwareImages | Gets a list of the Autonomous AI Database Software Images in the specified compartment | +| CreateAutonomousDatabaseSoftwareImage | autonomousDatabaseSoftwareImages | create Autonomous AI Database Software Image in the specified compartment | +| DeleteAutonomousDatabaseSoftwareImage | autonomousDatabaseSoftwareImages | Delete an Autonomous AI Database Software Image | +| GetAutonomousDatabaseSoftwareImage | autonomousDatabaseSoftwareImages | Gets information about the specified Autonomous AI Database Software Image | +| UpdateAutonomousDatabaseSoftwareImage | autonomousDatabaseSoftwareImages | Updates the properties of an Autonomous AI Database Software Image, like add tags | +| ChangeAutonomousDatabaseSoftwareImageCompartment | autonomousDatabaseSoftwareImages | Move the Autonomous AI Database Software Image and its dependent resources to the specified compartment | +| ListAutonomousDatabases | autonomousDatabases | Gets a list of Autonomous AI Databases based on the query parameters specified | +| CreateAutonomousDatabase | autonomousDatabases | Creates a new Autonomous AI Database | +| ResourcePoolShapes | autonomousDatabases | Lists available resource pools shapes | +| GetAutonomousDatabaseRegionalWallet | autonomousDatabases | Gets the Autonomous AI Database regional wallet details | +| UpdateAutonomousDatabaseRegionalWallet | autonomousDatabases | Updates the Autonomous AI Database regional wallet | +| DeleteAutonomousDatabase | autonomousDatabases | Deletes the specified Autonomous AI Database | +| GetAutonomousDatabase | autonomousDatabases | Gets the details of the specified Autonomous AI Database | +| UpdateAutonomousDatabase | autonomousDatabases | Updates one or more attributes of the specified Autonomous AI Database | +| ChangeAutonomousDatabaseCompartment | autonomousDatabases | Move the Autonomous AI Database and its dependent resources to the specified compartment | +| ChangeDisasterRecoveryConfiguration | autonomousDatabases | This operation updates the cross-region disaster recovery (DR) details of the standby Autonomous AI Database Serverless database, and must be run on the standby side | +| ChangeAutonomousDatabaseSubscription | autonomousDatabases | Associate an Autonomous AI Database with a different subscription | +| ConfigureAutonomousDatabaseVaultKey | autonomousDatabases | Configures the Autonomous AI Database Vault service [key](/Content/KeyManagement/Concepts/keyoverview | +| ConfigureSaasAdminUser | autonomousDatabases | This operation updates SaaS administrative user configuration of the Autonomous AI Database | +| DeregisterAutonomousDatabaseDataSafe | autonomousDatabases | Asynchronously deregisters this Autonomous AI Database with Data Safe | +| DisableAutonomousDatabaseManagement | autonomousDatabases | Disables Database Management for the Autonomous AI Database resource | +| DisableAutonomousDatabaseOperationsInsights | autonomousDatabases | Disables Operations Insights for the Autonomous AI Database resource | +| EnableAutonomousDatabaseManagement | autonomousDatabases | Enables Database Management for Autonomous AI Database | +| EnableAutonomousDatabaseOperationsInsights | autonomousDatabases | Enables the specified Autonomous AI Database with Operations Insights | +| FailOverAutonomousDatabase | autonomousDatabases | Initiates a failover of the specified Autonomous AI Database to the associated peer database | +| GenerateAutonomousDatabaseWallet | autonomousDatabases | Creates and downloads a wallet for the specified Autonomous AI Database | +| SaasAdminUserStatus | autonomousDatabases | This operation gets SaaS administrative user status of the Autonomous AI Database | +| AutonomousDatabaseManualRefresh | autonomousDatabases | Initiates a data refresh for an Autonomous AI Database refreshable clone | +| RegisterAutonomousDatabaseDataSafe | autonomousDatabases | Asynchronously registers this Autonomous AI Database with Data Safe | +| RestartAutonomousDatabase | autonomousDatabases | Restarts the specified Autonomous AI Database | +| RestoreAutonomousDatabase | autonomousDatabases | Restores an Autonomous AI Database based on the provided request parameters | +| RotateAutonomousDatabaseEncryptionKey | autonomousDatabases | Rotate existing AutonomousDatabase [Vault service](/iaas/Content/KeyManagement/Concepts/keyoverview | +| ShrinkAutonomousDatabase | autonomousDatabases | This operation shrinks the current allocated storage down to the current actual used data storage (actualUsedDataStorageSizeInTBs) | +| StartAutonomousDatabase | autonomousDatabases | Starts the specified Autonomous AI Database | +| StopAutonomousDatabase | autonomousDatabases | Stops the specified Autonomous AI Database | +| SwitchoverAutonomousDatabase | autonomousDatabases | Initiates a switchover of the specified Autonomous AI Database to the associated peer database | +| ListAutonomousDatabaseDataguardAssociations | autonomousDatabases | *Deprecated | +| GetAutonomousDatabaseDataguardAssociation | autonomousDatabases | *Deprecated | +| ListAutonomousDatabaseClones | autonomousDatabases | Lists the Autonomous AI Database clones for the specified Autonomous AI Database | +| ListAutonomousDatabasePeers | autonomousDatabases | Lists the Autonomous AI Database peers for the specified Autonomous AI Database | +| ListAutonomousDatabaseRefreshableClones | autonomousDatabases | Lists the OCIDs of the Autonomous AI Database local and connected remote refreshable clones with the region where they exist for the specified source database | +| ListResourcePoolMembers | autonomousDatabases | Lists the OCIDs of the Autonomous AI Database resource pool members for the specified Autonomous AI Database leader | +| GetAutonomousDatabaseWallet | autonomousDatabases | Gets the wallet details for the specified Autonomous AI Database | +| UpdateAutonomousDatabaseWallet | autonomousDatabases | Updates the wallet for the specified Autonomous AI Database | +| ListAutonomousDbPreviewVersions | autonomousDbPreviewVersions | Gets a list of supported Autonomous AI Database versions | +| ListAutonomousDbVersions | autonomousDbVersions | Gets a list of supported Autonomous AI Database versions | +| GetExadataInfrastructureOcpus | autonomousExadataInfrastructures | Gets details of the available and consumed OCPUs for the specified Autonomous Exadata Infrastructure resource | +| GetAutonomousPatch | autonomousPatches | Gets information about a specific autonomous patch | +| ListAutonomousVirtualMachines | autonomousVirtualMachines | Lists the Autonomous Virtual Machines in the specified Autonomous VM Cluster and Compartment | +| GetAutonomousVirtualMachine | autonomousVirtualMachines | Gets the details of specific Autonomous Virtual Machine | +| ListAutonomousVmClusters | autonomousVmClusters | Gets a list of Exadata Cloud@Customer Autonomous VM clusters in the specified compartment | +| CreateAutonomousVmCluster | autonomousVmClusters | Creates an Autonomous VM cluster for Exadata Cloud@Customer | +| DeleteAutonomousVmCluster | autonomousVmClusters | Deletes the specified Autonomous VM cluster in an Exadata Cloud@Customer system | +| GetAutonomousVmCluster | autonomousVmClusters | Gets information about the specified Autonomous VM cluster for an Exadata Cloud@Customer system | +| UpdateAutonomousVmCluster | autonomousVmClusters | Updates the specified Autonomous VM cluster for the Exadata Cloud@Customer system | +| ListAutonomousVmClusterAcdResourceUsage | autonomousVmClusters | Gets the list of resource usage details for all the Autonomous Container Database in the specified Autonomous Exadata VM cluster | +| ChangeAutonomousVmClusterCompartment | autonomousVmClusters | Moves an Autonomous VM cluster and its dependent resources to another compartment | +| RotateAutonomousVmClusterOrdsCerts | autonomousVmClusters | Rotates the Oracle REST Data Services (ORDS) certificates for Autonomous Exadata VM cluster | +| RotateAutonomousVmClusterSslCerts | autonomousVmClusters | Rotates the SSL certificates for Autonomous Exadata VM cluster | +| GetAutonomousVmClusterResourceUsage | autonomousVmClusters | Get the resource usage details for the specified Autonomous Exadata VM cluster | +| ListBackupDestination | backupDestinations | Gets a list of backup destinations in the specified compartment | +| CreateBackupDestination | backupDestinations | Creates a backup destination in an Exadata Cloud@Customer system | +| DeleteBackupDestination | backupDestinations | Deletes a backup destination in an Exadata Cloud@Customer system | +| GetBackupDestination | backupDestinations | Gets information about the specified backup destination in an Exadata Cloud@Customer system | +| UpdateBackupDestination | backupDestinations | If no database is associated with the backup destination: - For a RECOVERY_APPLIANCE backup destination, updates the connection string and/or the list of VPC users | +| ChangeBackupDestinationCompartment | backupDestinations | Move the backup destination and its dependent resources to the specified compartment | +| ListBackups | backups | Gets a list of backups based on the `databaseId` or `compartmentId` specified | +| CreateBackup | backups | Creates a new backup in the specified database based on the request parameters you provide | +| DeleteBackup | backups | Deletes a full backup | +| GetBackup | backups | Gets information about the specified backup | +| ListCloudAutonomousVmClusters | cloudAutonomousVmClusters | Lists Autonomous Exadata VM clusters in the Oracle cloud | +| CreateCloudAutonomousVmCluster | cloudAutonomousVmClusters | Creates an Autonomous Exadata VM cluster in the Oracle cloud | +| DeleteCloudAutonomousVmCluster | cloudAutonomousVmClusters | Deletes the specified Autonomous Exadata VM cluster in the Oracle cloud | +| GetCloudAutonomousVmCluster | cloudAutonomousVmClusters | Gets information about the specified Autonomous Exadata VM cluster in the Oracle cloud | +| UpdateCloudAutonomousVmCluster | cloudAutonomousVmClusters | Updates the specified Autonomous Exadata VM cluster in the Oracle cloud | +| ListCloudAutonomousVmClusterAcdResourceUsage | cloudAutonomousVmClusters | Gets the list of resource usage details for all the Cloud Autonomous Container Database in the specified Cloud Autonomous Exadata VM cluster | +| ChangeCloudAutonomousVmClusterCompartment | cloudAutonomousVmClusters | Moves an Autonomous Exadata VM cluster in the Oracle cloud and its dependent resources to another compartment | +| RotateCloudAutonomousVmClusterOrdsCerts | cloudAutonomousVmClusters | Rotates the Oracle REST Data Services (ORDS) certificates for a cloud Autonomous Exadata VM cluster | +| RotateCloudAutonomousVmClusterSslCerts | cloudAutonomousVmClusters | Rotates the SSL certficates for a cloud Autonomous Exadata VM cluster | +| GetCloudAutonomousVmClusterResourceUsage | cloudAutonomousVmClusters | Get the resource usage details for the specified Cloud Autonomous Exadata VM cluster | +| ListCloudExadataInfrastructures | cloudExadataInfrastructures | Gets a list of the cloud Exadata infrastructure resources in the specified compartment | +| CreateCloudExadataInfrastructure | cloudExadataInfrastructures | Creates a cloud Exadata infrastructure resource | +| DeleteCloudExadataInfrastructure | cloudExadataInfrastructures | Deletes the cloud Exadata infrastructure resource | +| GetCloudExadataInfrastructure | cloudExadataInfrastructures | Gets information about the specified cloud Exadata infrastructure resource | +| UpdateCloudExadataInfrastructure | cloudExadataInfrastructures | Updates the Cloud Exadata infrastructure resource | +| AddStorageCapacityCloudExadataInfrastructure | cloudExadataInfrastructures | Makes the storage capacity from additional storage servers available for Cloud VM Cluster consumption | +| ChangeCloudExadataInfrastructureCompartment | cloudExadataInfrastructures | Moves a cloud Exadata infrastructure resource and its dependent resources to another compartment | +| ChangeCloudExadataInfrastructureSubscription | cloudExadataInfrastructures | Associate a cloud Exadata infrastructure with a different subscription | +| ConfigureExascaleCloudExadataInfrastructure | cloudExadataInfrastructures | Configures Exascale on Cloud exadata infrastructure resource | +| GetCloudExadataInfrastructureUnallocatedResources | cloudExadataInfrastructures | Gets unallocated resources information for the specified Cloud Exadata infrastructure | +| ListCloudVmClusters | cloudVmClusters | Gets a list of the cloud VM clusters in the specified compartment | +| CreateCloudVmCluster | cloudVmClusters | Creates a cloud VM cluster | +| DeleteCloudVmCluster | cloudVmClusters | Deletes the specified cloud VM cluster | +| GetCloudVmCluster | cloudVmClusters | Gets information about the specified cloud VM cluster | +| UpdateCloudVmCluster | cloudVmClusters | Updates the specified cloud VM cluster | +| GetCloudVmClusterIormConfig | cloudVmClusters | Gets the IORM configuration for the specified cloud VM cluster in an Exadata Cloud Service instance | +| UpdateCloudVmClusterIormConfig | cloudVmClusters | Updates the IORM settings for the specified cloud VM cluster in an Exadata Cloud Service instance | +| AddVirtualMachineToCloudVmCluster | cloudVmClusters | Add Virtual Machines to the Cloud VM cluster | +| ChangeCloudVmClusterCompartment | cloudVmClusters | Moves a cloud VM cluster and its dependent resources to another compartment | +| ChangeCloudVmClusterSubscription | cloudVmClusters | Associate a cloud VM cluster with a different subscription | +| RemoveVirtualMachineFromCloudVmCluster | cloudVmClusters | Remove Virtual Machines from the Cloud VM cluster | +| ListCloudVmClusterUpdateHistoryEntries | cloudVmClusters | Gets the history of the maintenance update actions performed on the specified cloud VM cluster | +| GetCloudVmClusterUpdateHistoryEntry | cloudVmClusters | Gets the maintenance update history details for the specified update history entry | +| ListCloudVmClusterUpdates | cloudVmClusters | Lists the maintenance updates that can be applied to the specified cloud VM cluster | +| GetCloudVmClusterUpdate | cloudVmClusters | Gets information about a specified maintenance update package for a cloud VM cluster | +| ListDatabaseSoftwareImages | databaseSoftwareImages | Gets a list of the database software images in the specified compartment | +| CreateDatabaseSoftwareImage | databaseSoftwareImages | create database software image in the specified compartment | +| DeleteDatabaseSoftwareImage | databaseSoftwareImages | Delete a database software image | +| GetDatabaseSoftwareImage | databaseSoftwareImages | Gets information about the specified database software image | +| UpdateDatabaseSoftwareImage | databaseSoftwareImages | Updates the properties of a Database Software Image, like Display Nmae | +| ChangeDatabaseSoftwareImageCompartment | databaseSoftwareImages | Move the Database Software Image and its dependent resources to the specified compartment | +| ListDatabases | databases | Gets a list of the databases in the specified Database Home | +| CreateDatabase | databases | Creates a new database in the specified Database Home | +| DeleteDatabase | databases | Deletes the specified database | +| GetDatabase | databases | Gets information about the specified database | +| UpdateDatabase | databases | Update the specified database based on the request parameters provided | +| ChangeEncryptionKeyLocation | databases | Update the encryption key management location for the database | +| ConvertToPdb | databases | Converts a non-container database to a pluggable database | +| DisableDatabaseManagement | databases | Disables the Database Management service for the database | +| EnableDatabaseManagement | databases | Enables the Database Management service for an Oracle Database located in Oracle Cloud Infrastructure | +| MigrateVaultKey | databases | Changes encryption key management from customer-managed, using the [Vault service](/iaas/Content/KeyManagement/Concepts/keyoverview | +| ModifyDatabaseManagement | databases | Updates one or more attributes of the Database Management service for the database | +| RestoreDatabase | databases | Restore a Database based on the request parameters you provide | +| RotateVaultKey | databases | Creates a new version of an existing [Vault service](/iaas/Content/KeyManagement/Concepts/keyoverview | +| UpgradeDatabase | databases | Upgrades the specified Oracle Database instance | +| ConvertToStandalone | databases | Disassociate the standby database identified by the `databaseId` parameter from existing Data Guard group | +| FailoverDataGuard | databases | Performs a failover to transition the standby database identified by the `databaseId` path parameter into the primary role after the existing primary database fails or becomes unreachable | +| ReinstateDataGuard | databases | Reinstates the database identified by the `databaseId` parameter into the standby role in a Data Guard association | +| SwitchOverDataGuard | databases | Performs a switchover to transition primary database of this Data Guard association into a standby role | +| UpdateDataGuard | databases | Update an existing Data Guard member | +| ListDataGuardAssociations | databases | Lists all Data Guard associations for the specified database | +| CreateDataGuardAssociation | databases | Creates a new Data Guard association | +| GetDataGuardAssociation | databases | Gets the specified Data Guard association's configuration information | +| UpdateDataGuardAssociation | databases | Updates the Data Guard association the specified database | +| FailoverDataGuardAssociation | databases | Performs a failover to transition the standby database identified by the `databaseId` parameter into the specified Data Guard association's primary role after the existing primary database fails or becomes unreachable | +| MigrateDataGuardAssociationToMultiDataGuards | databases | Migrates the existing Data Guard association to new Data Guard model to support multiple standby databases functionality | +| ReinstateDataGuardAssociation | databases | Reinstates the database identified by the `databaseId` parameter into the standby role in a Data Guard association | +| SwitchoverDataGuardAssociation | databases | Performs a switchover to transition the primary database of a Data Guard association into a standby role | +| ListPdbConversionHistoryEntries | databases | Gets the pluggable database conversion history for a specified database in a bare metal or virtual machine DB system | +| GetPdbConversionHistoryEntry | databases | Gets the details of operations performed to convert the specified database from non-container (non-CDB) to pluggable (PDB) | +| ListDatabaseUpgradeHistoryEntries | databases | Gets the upgrade history for a specified database in a bare metal or virtual machine DB system | +| GetDatabaseUpgradeHistoryEntry | databases | gets the upgrade history for a specified database | +| ListDbHomes | dbHomes | Lists the Database Homes in the specified DB system and compartment | +| CreateDbHome | dbHomes | Creates a new Database Home in the specified database system based on the request parameters you provide | +| DeleteDbHome | dbHomes | Deletes a Database Home | +| GetDbHome | dbHomes | Gets information about the specified Database Home | +| UpdateDbHome | dbHomes | Patches the specified Database Home | +| ListDbHomePatchHistoryEntries | dbHomes | Lists the history of patch operations on the specified Database Home | +| GetDbHomePatchHistoryEntry | dbHomes | Gets the patch history details for the specified patchHistoryEntryId | +| ListDbHomePatches | dbHomes | Lists patches applicable to the requested Database Home | +| GetDbHomePatch | dbHomes | Gets information about a specified patch package | +| ListDbNodes | dbNodes | Lists the database nodes in the specified DB system and compartment | +| GetDbNode | dbNodes | Gets information about the specified database node | +| DbNodeAction | dbNodes | Performs one of the following power actions on the specified DB node: - start - power on - stop - power off gracefully - softreset - ACPI shutdown and power on - reset - power off and power on **Note:** Stopping a node affects billing differently, depending on the type of DB system: *Bare metal and Exadata systems* - The _stop_ state has no effect on the resources you consume | +| ListConsoleConnections | dbNodes | Lists the console connections for the specified database node | +| CreateConsoleConnection | dbNodes | Creates a new console connection to the specified database node | +| DeleteConsoleConnection | dbNodes | Deletes the specified database node console connection | +| GetConsoleConnection | dbNodes | Gets the specified database node console connection's information | +| ListConsoleHistories | dbNodes | Lists the console histories for the specified database node | +| CreateConsoleHistory | dbNodes | Captures the most recent serial console data (up to a megabyte) for the specified database node | +| DeleteConsoleHistory | dbNodes | Deletes the specified database node console history | +| GetConsoleHistory | dbNodes | Gets information about the specified database node console history | +| UpdateConsoleHistory | dbNodes | Updates the specified database node console history | +| GetConsoleHistoryContent | dbNodes | Retrieves the specified database node console history contents upto a megabyte | +| ListDbServers | dbServers | Lists the Exadata DB servers in the ExadataInfrastructureId and specified compartment | +| GetDbServer | dbServers | Gets information about the Exadata Db server | +| ListDbSystemComputePerformances | dbSystemComputePerformance | Gets a list of expected compute performance parameters for a virtual machine DB system based on system configuration | +| ListDbSystemShapes | dbSystemShapes | Gets a list of the shapes that can be used to launch a new DB system | +| ListFlexComponents | dbSystemShapes | Gets a list of the flex components that can be used to launch a new DB system | +| ListDbSystemStoragePerformances | dbSystemStoragePerformance | Gets a list of possible expected storage performance parameters of a VMDB System based on Configuration | +| ListDbSystems | dbSystems | Lists the DB systems in the specified compartment | +| LaunchDbSystem | dbSystems | Creates a new DB system in the specified compartment and availability domain | +| TerminateDbSystem | dbSystems | Terminates a DB system and permanently deletes it and any databases running on it, and any storage volumes attached to it | +| GetDbSystem | dbSystems | Gets information about the specified DB system | +| UpdateDbSystem | dbSystems | Updates the properties of the specified DB system | +| GetExadataIormConfig | dbSystems | Gets the IORM configuration settings for the specified cloud Exadata DB system | +| UpdateExadataIormConfig | dbSystems | Updates IORM settings for the specified Exadata DB system | +| ChangeDbSystemCompartment | dbSystems | Moves the DB system and its dependent resources to the specified compartment | +| MigrateExadataDbSystemResourceModel | dbSystems | Migrates the Exadata DB system to the new [Exadata resource model](/iaas/Content/Database/Concepts/exaflexsystem | +| UpgradeDbSystem | dbSystems | Upgrades the operating system and grid infrastructure of the DB system | +| ListDbSystemPatchHistoryEntries | dbSystems | Gets the history of the patch actions performed on the specified DB system | +| GetDbSystemPatchHistoryEntry | dbSystems | Gets the details of the specified patch operation on the specified DB system | +| ListDbSystemPatches | dbSystems | Lists the patches applicable to the specified DB system | +| GetDbSystemPatch | dbSystems | Gets information the specified patch | +| ListDbSystemUpgradeHistoryEntries | dbSystems | Gets the history of the upgrade actions performed on the specified DB system | +| GetDbSystemUpgradeHistoryEntry | dbSystems | Gets the details of the specified operating system upgrade operation for the specified DB system | +| ListDbVersions | dbVersions | Gets a list of supported Oracle Database versions | +| ListExadataInfrastructures | exadataInfrastructures | Lists the Exadata infrastructure resources in the specified compartment | +| CreateExadataInfrastructure | exadataInfrastructures | Creates an Exadata infrastructure resource | +| DeleteExadataInfrastructure | exadataInfrastructures | Deletes the Exadata Cloud@Customer infrastructure | +| GetExadataInfrastructure | exadataInfrastructures | Gets information about the specified Exadata infrastructure | +| UpdateExadataInfrastructure | exadataInfrastructures | Updates the Exadata infrastructure resource | +| ActivateExadataInfrastructure | exadataInfrastructures | Activates the specified Exadata infrastructure resource | +| AddStorageCapacityExadataInfrastructure | exadataInfrastructures | Makes the storage capacity from additional storage servers available for VM Cluster consumption | +| ChangeExadataInfrastructureCompartment | exadataInfrastructures | Moves an Exadata infrastructure resource and its dependent resources to another compartment | +| DownloadExadataInfrastructureConfigFile | exadataInfrastructures | Downloads the configuration file for the specified Exadata Cloud@Customer infrastructure | +| GetExadataInfrastructureUnAllocatedResources | exadataInfrastructures | Gets un allocated resources information for the specified Exadata infrastructure | +| ListVmClusterNetworks | exadataInfrastructures | Gets a list of the VM cluster networks in the specified compartment | +| CreateVmClusterNetwork | exadataInfrastructures | Creates the VM cluster network | +| GenerateRecommendedVmClusterNetwork | exadataInfrastructures | Generates a recommended Cloud@Customer VM cluster network configuration | +| DeleteVmClusterNetwork | exadataInfrastructures | Deletes the specified VM cluster network | +| GetVmClusterNetwork | exadataInfrastructures | Gets information about the specified VM cluster network | +| UpdateVmClusterNetwork | exadataInfrastructures | Updates the specified VM cluster network | +| DownloadVmClusterNetworkConfigFile | exadataInfrastructures | Downloads the configuration file for the specified VM cluster network | +| ResizeVmClusterNetwork | exadataInfrastructures | Adds or removes Db server network nodes to extend or shrink the existing VM cluster network | +| ValidateVmClusterNetwork | exadataInfrastructures | Validates the specified VM cluster network | +| ListExadbVmClusters | exadbVmClusters | Gets a list of the Exadata VM clusters on Exascale Infrastructure in the specified compartment | +| CreateExadbVmCluster | exadbVmClusters | Creates an Exadata VM cluster on Exascale Infrastructure | +| DeleteExadbVmCluster | exadbVmClusters | Deletes the specified Exadata VM cluster on Exascale Infrastructure | +| GetExadbVmCluster | exadbVmClusters | Gets information about the specified Exadata VM cluster on Exascale Infrastructure | +| UpdateExadbVmCluster | exadbVmClusters | Updates the specified Exadata VM cluster on Exascale Infrastructure | +| ChangeExadbVmClusterCompartment | exadbVmClusters | Moves a Exadata VM cluster on Exascale Infrastructure and its dependent resources to another compartment | +| ChangeExadbVmClusterSubscription | exadbVmClusters | Associate a Exadata VM cluster on Exascale Infrastructure with a different subscription | +| RemoveVirtualMachineFromExadbVmCluster | exadbVmClusters | Remove Virtual Machines from the Exadata VM cluster on Exascale Infrastructure | +| ListExadbVmClusterUpdateHistoryEntries | exadbVmClusters | Gets the history of the maintenance update actions performed on the specified Exadata VM cluster on Exascale Infrastructure | +| GetExadbVmClusterUpdateHistoryEntry | exadbVmClusters | Gets the maintenance update history details for the specified update history entry | +| ListExadbVmClusterUpdates | exadbVmClusters | Lists the maintenance updates that can be applied to the specified Exadata VM cluster on Exascale Infrastructure | +| GetExadbVmClusterUpdate | exadbVmClusters | Gets information about a specified maintenance update package for a Exadata VM cluster on Exascale Infrastructure | +| ListExascaleDbStorageVaults | exascaleDbStorageVaults | Gets a list of the Exadata Database Storage Vaults in the specified compartment | +| CreateExascaleDbStorageVault | exascaleDbStorageVaults | Creates an Exadata Database Storage Vault | +| DeleteExascaleDbStorageVault | exascaleDbStorageVaults | Deletes the specified Exadata Database Storage Vault | +| GetExascaleDbStorageVault | exascaleDbStorageVaults | Gets information about the specified Exadata Database Storage Vaults in the specified compartment | +| UpdateExascaleDbStorageVault | exascaleDbStorageVaults | Updates the specified Exadata Database Storage Vault | +| ChangeExascaleDbStorageVaultCompartment | exascaleDbStorageVaults | Moves a Exadata Database Storage Vault to another compartment | +| ChangeExascaleDbStorageVaultSubscription | exascaleDbStorageVaults | Associate a Exadata Database Storage Vault with a different subscription | +| ListExecutionActions | executionActions | Lists the execution action resources in the specified compartment | +| CreateExecutionAction | executionActions | Creates an execution action resource | +| DeleteExecutionAction | executionActions | Deletes the execution action | +| GetExecutionAction | executionActions | Gets information about the specified execution action | +| UpdateExecutionAction | executionActions | Updates the execution action resource | +| MoveExecutionActionMember | executionActions | Moves an execution action member to this execution action resource from another | +| ListExecutionWindows | executionWindows | Lists the execution window resources in the specified compartment | +| CreateExecutionWindow | executionWindows | Creates an execution window resource | +| DeleteExecutionWindow | executionWindows | Deletes the execution window | +| GetExecutionWindow | executionWindows | Gets information about the specified execution window | +| UpdateExecutionWindow | executionWindows | Updates the execution window resource | +| ReorderExecutionActions | executionWindows | Reorders the execution actions under this execution window resource | +| CreateExternalBackupJob | externalBackupJobs | Creates a new backup resource and returns the information the caller needs to back up an on-premises Oracle Database to Oracle Cloud Infrastructure | +| GetExternalBackupJob | externalBackupJobs | Gets information about the specified external backup job | +| CompleteExternalBackupJob | externalBackupJobs | Changes the status of the standalone backup resource to `ACTIVE` after the backup is created from the on-premises database and placed in Oracle Cloud Infrastructure Object Storage | +| ListExternalContainerDatabases | externalcontainerdatabases | Gets a list of the external container databases in the specified compartment | +| CreateExternalContainerDatabase | externalcontainerdatabases | Creates a new external container database resource | +| DeleteExternalContainerDatabase | externalcontainerdatabases | Deletes the [external container database](#/en/database/latest/datatypes/CreateExternalContainerDatabaseDetails) resource | +| GetExternalContainerDatabase | externalcontainerdatabases | Gets information about the specified external container database | +| UpdateExternalContainerDatabase | externalcontainerdatabases | Updates the properties of an [ExternalContainerDatabase](#/en/database/latest/datatypes/CreateExternalContainerDatabaseDetails) resource, such as the display name | +| ChangeExternalContainerDatabaseCompartment | externalcontainerdatabases | Move the [external container database](#/en/database/latest/datatypes/CreateExternalContainerDatabaseDetails) and its dependent resources to the specified compartment | +| DisableExternalContainerDatabaseDatabaseManagement | externalcontainerdatabases | Disable Database Management service for the external container database | +| DisableExternalContainerDatabaseStackMonitoring | externalcontainerdatabases | Disable Stack Monitoring for the external container database | +| EnableExternalContainerDatabaseDatabaseManagement | externalcontainerdatabases | Enables Database Management Service for the external container database | +| EnableExternalContainerDatabaseStackMonitoring | externalcontainerdatabases | Enable Stack Monitoring for the external container database | +| ScanExternalContainerDatabasePluggableDatabases | externalcontainerdatabases | Scans for pluggable databases in the specified external container database | +| ListExternalDatabaseConnectors | externaldatabaseconnectors | Gets a list of the external database connectors in the specified compartment | +| CreateExternalDatabaseConnector | externaldatabaseconnectors | Creates a new external database connector | +| DeleteExternalDatabaseConnector | externaldatabaseconnectors | Deletes an external database connector | +| GetExternalDatabaseConnector | externaldatabaseconnectors | Gets information about the specified external database connector | +| UpdateExternalDatabaseConnector | externaldatabaseconnectors | Updates the properties of an external database connector, such as the display name | +| CheckExternalDatabaseConnectorConnectionStatus | externaldatabaseconnectors | Check the status of the external database connection specified in this connector | +| ListExternalNonContainerDatabases | externalnoncontainerdatabases | Gets a list of the ExternalNonContainerDatabases in the specified compartment | +| CreateExternalNonContainerDatabase | externalnoncontainerdatabases | Creates a new ExternalNonContainerDatabase resource | +| DeleteExternalNonContainerDatabase | externalnoncontainerdatabases | Deletes the Oracle Cloud Infrastructure resource representing an external non-container database | +| GetExternalNonContainerDatabase | externalnoncontainerdatabases | Gets information about a specific external non-container database | +| UpdateExternalNonContainerDatabase | externalnoncontainerdatabases | Updates the properties of an external non-container database, such as the display name | +| ChangeExternalNonContainerDatabaseCompartment | externalnoncontainerdatabases | Move the external non-container database and its dependent resources to the specified compartment | +| DisableExternalNonContainerDatabaseDatabaseManagement | externalnoncontainerdatabases | Disable Database Management Service for the external non-container database | +| DisableExternalNonContainerDatabaseOperationsInsights | externalnoncontainerdatabases | Disable Operations Insights for the external non-container database | +| DisableExternalNonContainerDatabaseStackMonitoring | externalnoncontainerdatabases | Disable Stack Monitoring for the external non-container database | +| EnableExternalNonContainerDatabaseDatabaseManagement | externalnoncontainerdatabases | Enable Database Management Service for the external non-container database | +| EnableExternalNonContainerDatabaseOperationsInsights | externalnoncontainerdatabases | Enable Operations Insights for the external non-container database | +| EnableExternalNonContainerDatabaseStackMonitoring | externalnoncontainerdatabases | Enable Stack Monitoring for the external non-container database | +| ListExternalPluggableDatabases | externalpluggabledatabases | Gets a list of the [ExternalPluggableDatabase](#/en/database/latest/datatypes/CreateExternalPluggableDatabaseDetails) resources in the specified compartment | +| CreateExternalPluggableDatabase | externalpluggabledatabases | Registers a new [ExternalPluggableDatabase](#/en/database/latest/datatypes/CreateExternalPluggableDatabaseDetails) resource | +| DeleteExternalPluggableDatabase | externalpluggabledatabases | Deletes the [external pluggable database](#/en/database/latest/datatypes/CreateExternalPluggableDatabaseDetails) | +| GetExternalPluggableDatabase | externalpluggabledatabases | Gets information about a specific [external pluggable database](#/en/database/latest/datatypes/CreateExternalPluggableDatabaseDetails) resource | +| UpdateExternalPluggableDatabase | externalpluggabledatabases | Updates the properties of an [external pluggable database](#/en/database/latest/datatypes/CreateExternalPluggableDatabaseDetails) resource, such as the display name | +| ChangeExternalPluggableDatabaseCompartment | externalpluggabledatabases | Move the [external pluggable database](#/en/database/latest/datatypes/CreateExternalPluggableDatabaseDetails) and its dependent resources to the specified compartment | +| DisableExternalPluggableDatabaseDatabaseManagement | externalpluggabledatabases | Disable Database Management Service for the external pluggable database | +| DisableExternalPluggableDatabaseOperationsInsights | externalpluggabledatabases | Disable Operations Insights for the external pluggable database | +| DisableExternalPluggableDatabaseStackMonitoring | externalpluggabledatabases | Disable Stack Monitoring for the external pluggable database | +| EnableExternalPluggableDatabaseDatabaseManagement | externalpluggabledatabases | Enable Database Management Service for the external pluggable database | +| EnableExternalPluggableDatabaseOperationsInsights | externalpluggabledatabases | Enable Operations Insights for the external pluggable database | +| EnableExternalPluggableDatabaseStackMonitoring | externalpluggabledatabases | Enable Stack Monitoring for the external pluggable database | +| ListGiVersions | giVersions | Gets a list of supported GI versions | +| ListGiVersionMinorVersions | giVersions | Gets a list of supported Oracle Grid Infrastructure minor versions for the given major version and shape family | +| ListKeyStores | keyStores | Gets a list of key stores in the specified compartment | +| CreateKeyStore | keyStores | Creates a Key Store | +| DeleteKeyStore | keyStores | Deletes a key store | +| GetKeyStore | keyStores | Gets information about the specified key store | +| UpdateKeyStore | keyStores | Edit the key store | +| ChangeKeyStoreCompartment | keyStores | Move the key store resource to the specified compartment | +| ListMaintenanceRunHistory | maintenanceRunHistory | Gets a list of the maintenance run histories in the specified compartment | +| GetMaintenanceRunHistory | maintenanceRunHistory | Gets information about the specified maintenance run history | +| ListMaintenanceRuns | maintenanceRuns | Gets a list of the maintenance runs in the specified compartment | +| CreateMaintenanceRun | maintenanceRuns | Creates a maintenance run with one of the following: 1 | +| GetMaintenanceRun | maintenanceRuns | Gets information about the specified maintenance run | +| UpdateMaintenanceRun | maintenanceRuns | Updates the properties of a maintenance run, such as the state of a maintenance run | +| ListOneoffPatches | oneoffPatches | Lists one-off patches in the specified compartment | +| CreateOneoffPatch | oneoffPatches | Creates one-off patch for specified database version to download | +| DeleteOneoffPatch | oneoffPatches | Deletes a one-off patch | +| GetOneoffPatch | oneoffPatches | Gets information about the specified one-off patch | +| UpdateOneoffPatch | oneoffPatches | Updates the properties of the specified one-off patch | +| ChangeOneoffPatchCompartment | oneoffPatches | Move the one-off patch to the specified compartment | +| DownloadOneoffPatch | oneoffPatches | Download one-off patch | +| ListPluggableDatabases | pluggableDatabases | Gets a list of the pluggable databases in a database or compartment | +| CreatePluggableDatabase | pluggableDatabases | Creates and starts a pluggable database in the specified container database | +| DeletePluggableDatabase | pluggableDatabases | Deletes the specified pluggable database | +| GetPluggableDatabase | pluggableDatabases | Gets information about the specified pluggable database | +| UpdatePluggableDatabase | pluggableDatabases | Updates the specified pluggable database | +| ConvertToRegularPluggableDatabase | pluggableDatabases | Converts a Refreshable clone to Regular pluggable database (PDB) | +| RefreshPluggableDatabase | pluggableDatabases | Refreshes a pluggable database (PDB) Refreshable clone | +| StartPluggableDatabase | pluggableDatabases | Starts a stopped pluggable database | +| StopPluggableDatabase | pluggableDatabases | Stops a pluggable database | +| GetResourcePrincipalToken | resourcePrincipalToken | Gets a resource principal intermediate token that contains mapping information between the instance prinicpal and resource | +| ListParamsForActionType | scheduledActionParams | List all the action params and their possible values for a given action type | +| ListScheduledActions | scheduledActions | Lists the Scheduled Action resources in the specified compartment | +| CreateScheduledAction | scheduledActions | Creates a Scheduled Action resource | +| DeleteScheduledAction | scheduledActions | Deletes the scheduled action | +| GetScheduledAction | scheduledActions | Gets information about the specified Scheduled Action | +| UpdateScheduledAction | scheduledActions | Updates the Scheduled Action resource | +| ListSchedulingPlans | schedulingPlans | Lists the Scheduling Plan resources in the specified compartment | +| CreateSchedulingPlan | schedulingPlans | Creates a Scheduling Plan resource | +| DeleteSchedulingPlan | schedulingPlans | Deletes the scheduling plan | +| GetSchedulingPlan | schedulingPlans | Gets information about the specified Scheduling Plan | +| ChangeSchedulingPlanCompartment | schedulingPlans | Moves an scheduling plan resource to another compartment | +| ReorderScheduledActions | schedulingPlans | Re-order the scheduled actions under this scheduling plan resource | +| ListSchedulingPolicies | schedulingPolicies | Lists the Scheduling Policy resources in the specified compartment | +| CreateSchedulingPolicy | schedulingPolicies | Creates a Scheduling Policy resource | +| DeleteSchedulingPolicy | schedulingPolicies | Deletes the scheduling policy | +| GetSchedulingPolicy | schedulingPolicies | Gets information about the specified Scheduling Policy | +| UpdateSchedulingPolicy | schedulingPolicies | Updates the Scheduling Policy resource | +| ChangeSchedulingPolicyCompartment | schedulingPolicies | Moves an scheduling policy resource to another compartment | +| ListRecommendedScheduledActions | schedulingPolicies | Returns a recommended Scheduled Actions configuration for a given resource, plan intent and scheduling policy | +| ListSchedulingWindows | schedulingPolicies | Lists the Scheduling Window resources in the specified compartment | +| CreateSchedulingWindow | schedulingPolicies | Creates a Scheduling Window resource | +| DeleteSchedulingWindow | schedulingPolicies | Deletes the scheduling window | +| GetSchedulingWindow | schedulingPolicies | Gets information about the specified Scheduling Window | +| UpdateSchedulingWindow | schedulingPolicies | Updates the Scheduling Window resource | +| ListSystemVersions | systemVersions | Gets a list of supported Exadata system versions for a given shape and GI version | +| ListVmClusters | vmClusters | Lists the VM clusters in the specified compartment | +| CreateVmCluster | vmClusters | Creates an Exadata Cloud@Customer VM cluster | +| DeleteVmCluster | vmClusters | Deletes the specified VM cluster | +| GetVmCluster | vmClusters | Gets information about the VM cluster | +| UpdateVmCluster | vmClusters | Updates the specified VM cluster | +| AddVirtualMachineToVmCluster | vmClusters | Add Virtual Machines to the VM cluster | +| ChangeVmClusterCompartment | vmClusters | Moves a VM cluster and its dependent resources to another compartment | +| RemoveVirtualMachineFromVmCluster | vmClusters | Remove Virtual Machines from the VM cluster | +| ListVmClusterPatchHistoryEntries | vmClusters | Gets the history of the patch actions performed on the specified VM cluster in an Exadata Cloud@Customer system | +| GetVmClusterPatchHistoryEntry | vmClusters | Gets the patch history details for the specified patch history entry | +| ListVmClusterPatches | vmClusters | Lists the patches applicable to the specified VM cluster in an Exadata Cloud@Customer system | +| GetVmClusterPatch | vmClusters | Gets information about a specified patch package | +| ListVmClusterUpdateHistoryEntries | vmClusters | Gets the history of the maintenance update actions performed on the specified VM cluster | +| GetVmClusterUpdateHistoryEntry | vmClusters | Gets the maintenance update history details for the specified update history entry | +| ListVmClusterUpdates | vmClusters | Lists the maintenance updates that can be applied to the specified VM cluster | +| GetVmClusterUpdate | vmClusters | Gets information about a specified maintenance update package for a VM cluster | + + +⚠️ **NOTE**: All actions are performed with the permissions of the configured OCI CLI profile. We advise least-privilege IAM setup, secure credential management, safe network practices, secure logging, and warn against exposing secrets. + +## Third-Party APIs + +Developers choosing to distribute a binary implementation of this project are responsible for obtaining and providing all required licenses and copyright notices for the third-party code used in order to ensure compliance with their respective open source licenses. + +## Disclaimer + +Users are responsible for their local environment and credential safety. Different language model selections may yield different results and performance. + +## License + +Copyright (c) 2025 Oracle and/or its affiliates. + +Released under the Universal Permissive License v1.0 as shown at +. + diff --git a/src/oci-db-dynamic-mcp-server/oracle/__init__.py b/src/oci-db-dynamic-mcp-server/oracle/__init__.py new file mode 100644 index 00000000..d9dff098 --- /dev/null +++ b/src/oci-db-dynamic-mcp-server/oracle/__init__.py @@ -0,0 +1,5 @@ +""" +Copyright (c) 2025, Oracle and/or its affiliates. +Licensed under the Universal Permissive License v1.0 as shown at +https://oss.oracle.com/licenses/upl. +""" diff --git a/src/oci-db-dynamic-mcp-server/oracle/oci_db_dynamic_mcp_server/__init__.py b/src/oci-db-dynamic-mcp-server/oracle/oci_db_dynamic_mcp_server/__init__.py new file mode 100644 index 00000000..8d062ba9 --- /dev/null +++ b/src/oci-db-dynamic-mcp-server/oracle/oci_db_dynamic_mcp_server/__init__.py @@ -0,0 +1,8 @@ +""" +Copyright (c) 2025, Oracle and/or its affiliates. +Licensed under the Universal Permissive License v1.0 as shown at +https://oss.oracle.com/licenses/upl. +""" + +__project__ = "oracle.oci-db-dynamic-mcp-server" +__version__ = "1.0.1" diff --git a/src/oci-db-dynamic-mcp-server/oracle/oci_db_dynamic_mcp_server/dynamic_tools_loader.py b/src/oci-db-dynamic-mcp-server/oracle/oci_db_dynamic_mcp_server/dynamic_tools_loader.py new file mode 100644 index 00000000..85677697 --- /dev/null +++ b/src/oci-db-dynamic-mcp-server/oracle/oci_db_dynamic_mcp_server/dynamic_tools_loader.py @@ -0,0 +1,322 @@ +from dataclasses import dataclass, field +from typing import Any, Dict, List, Optional + +import requests +import yaml + +SPEC_INDEX_JSON = "https://docs.oracle.com/en-us/iaas/api/specs/index.json" +BASE_SPEC_URL = "https://docs.oracle.com/en-us/iaas/api/specs/" +HTTP_METHODS = {"get", "post", "put", "delete", "patch"} + + +@dataclass +class OperationMeta: + operationId: str + httpMethod: str + path: str + summary: str + description: str + parameters: List[Dict[str, Any]] = field(default_factory=list) + requestBodySchema: Dict[str, Any] = field(default_factory=dict) + responseSchema: Dict[str, Any] = field(default_factory=dict) + relatedResource: str = "other" + + +def load_yaml_from_url(url: str): + resp = requests.get(url, timeout=15) + resp.raise_for_status() + return yaml.safe_load(resp.text) + + +def load_yaml_from_public_docs(): + try: + resp = requests.get(SPEC_INDEX_JSON, timeout=15) + resp.raise_for_status() + index_json = resp.json() + specs_node = index_json.get("database", {}).get("specs", []) + if specs_node: + full_url = BASE_SPEC_URL + specs_node[0].split("/")[-1] + print(f"Loading OCI Spec from: {full_url}") + return load_yaml_from_url(full_url) + return {} + except Exception as e: + print(f"Spec load failed: {e}") + return {} + + +def resolve_schema(schema: Dict[str, Any], spec: Dict[str, Any]) -> Dict[str, Any]: + """ + Recursively resolve $ref AND merge 'allOf' inheritance. + """ + if not isinstance(schema, dict): + return schema + + # 1. Resolve $ref + if "$ref" in schema: + ref = schema["$ref"] + # Handle both root-based (#/definitions/...) and relative refs + if ref.startswith("#/"): + parts = ref[2:].split("/") + node = spec + for p in parts: + node = node.get(p, {}) + return resolve_schema(node, spec) + else: + parts = ref.split("/") + node = spec + for p in parts: + node = node.get(p, {}) + return resolve_schema(node, spec) + + # 2. Handle 'allOf' (Merge properties from parents) + if "allOf" in schema: + merged = {"type": "object", "properties": {}, "required": []} + + for part in schema["allOf"]: + resolved_part = resolve_schema(part, spec) + + if "properties" in resolved_part: + merged["properties"].update(resolved_part["properties"]) + + if "required" in resolved_part: + merged["required"].extend(resolved_part["required"]) + + if "type" in resolved_part and "type" not in merged: + merged["type"] = resolved_part["type"] + + if "properties" in schema: + merged["properties"].update(schema["properties"]) + if "required" in schema: + merged["required"].extend(schema["required"]) + + merged["required"] = list(set(merged["required"])) + return merged + + # 3. Recurse + result = {} + for k, v in schema.items(): + if isinstance(v, dict): + result[k] = resolve_schema(v, spec) + elif isinstance(v, list): + result[k] = [ + resolve_schema(i, spec) if isinstance(i, dict) else i for i in v + ] + else: + result[k] = v + return result + + +def flatten_schema( + schema: Dict[str, Any], spec: Optional[Dict[str, Any]] = None +) -> Dict[str, Dict[str, Any]]: + flat: Dict[str, Dict[str, Any]] = {} + if not schema or not isinstance(schema, dict): + return flat + + def _walk(obj_schema: Dict[str, Any], path: List[str]): + if not isinstance(obj_schema, dict): + return + + props = obj_schema.get("properties", {}) + required_props = set(obj_schema.get("required", []) or []) + + for prop_name, prop_schema in props.items(): + prop_path = path + [prop_name] + prop_type = prop_schema.get("type") + + if not prop_type: + if "items" in prop_schema: + prop_type = "array" + elif "properties" in prop_schema: + prop_type = "object" + else: + prop_type = "string" + + flat_key = "_".join(prop_path) + + if prop_type == "array": + flat[flat_key] = { + "path": prop_path, + "type": "array", + "required": prop_name in required_props, + } + continue + + if prop_type == "object" and "properties" in prop_schema: + _walk(prop_schema, prop_path) + continue + + flat[flat_key] = { + "path": prop_path, + "type": prop_type, + "required": prop_name in required_props, + "raw_schema": prop_schema, + } + + if schema.get("type") == "object" or "properties" in schema: + _walk(schema, []) + return flat + + +def infer_resource_from_path_or_tags(path: str, tags: list) -> str: + if not path: + return "unknown" + parts = path.strip("/").split("/") + return parts[0] if parts else "unknown" + + +def extract_required_output_fields(schema: Dict[str, Any]) -> Dict[str, Any]: + """ + Given a resolved schema, return a simplified schema containing + ONLY the 'required' fields. Handles Arrays and Objects. + """ + if not schema or not isinstance(schema, dict): + return {} + + prop_type = schema.get("type") + + # CASE A: ARRAY (e.g. ListDbSystems returns [DbSystem]) + if prop_type == "array" and "items" in schema: + item_schema = schema["items"] + # Recurse into the item definition + simplified_item = extract_required_output_fields(item_schema) + return {"type": "array", "items": simplified_item} + + # CASE B: OBJECT (e.g. GetDbSystem returns DbSystem) + if prop_type == "object" or "properties" in schema: + required_keys = schema.get("required", []) + all_props = schema.get("properties", {}) + + simplified_props = {} + for key in required_keys: + if key in all_props: + simplified_props[key] = all_props[key] + + return { + "type": "object", + "properties": simplified_props, + "required": required_keys, + } + + # Fallback for scalars + return schema + + +def build_registry(api_spec: Dict[str, Any]) -> Dict[str, OperationMeta]: + paths = api_spec.get("paths", {}) + registry = {} + + for path, path_item in paths.items(): + if not isinstance(path_item, dict): + continue + path_params = path_item.get("parameters", []) + + for method, op in path_item.items(): + if method.lower() not in HTTP_METHODS or not isinstance(op, dict): + continue + + op_id = op.get("operationId", f"{method}_{path}") + + # 1. Parameters + params = [] + all_raw_params = path_params + op.get("parameters", []) + for p in all_raw_params: + params.append(resolve_schema(p, api_spec)) + + # 2. Request Body + req_schema = {} + if "requestBody" in op: # OpenAPI 3 + content = op["requestBody"].get("content", {}) + if "application/json" in content: + req_schema = resolve_schema( + content["application/json"].get("schema", {}), api_spec + ) + for p in params: # Swagger 2 + if p.get("in") == "body" and "schema" in p: + req_schema = resolve_schema(p["schema"], api_spec) + + # 3. Response Schema + resp_schema = {} + responses = op.get("responses", {}) + success_code = next( + (c for c in ["200", "201", "202", "204"] if c in responses), None + ) + + if success_code: + resp_obj = responses[success_code] + if "schema" in resp_obj: + resp_schema = resolve_schema(resp_obj["schema"], api_spec) + elif "content" in resp_obj: + content = resp_obj["content"] + if "application/json" in content: + resp_schema = resolve_schema( + content["application/json"].get("schema", {}), api_spec + ) + + registry[op_id] = OperationMeta( + operationId=op_id, + httpMethod=method.upper(), + path=path, + summary=op.get("summary", ""), + description=op.get("description", ""), + parameters=params, + requestBodySchema=req_schema, + responseSchema=resp_schema, + relatedResource=infer_resource_from_path_or_tags( + path, op.get("tags", []) + ), + ) + return registry + + +def build_tools_from_latest_spec( + allowed_resources: List[str] = None, +) -> List[Dict[str, Any]]: + api_spec = load_yaml_from_public_docs() + if not api_spec: + return [] + registry = build_registry(api_spec) + exposed_tools = [] + + allowed_set = {r.lower() for r in allowed_resources} if allowed_resources else None + + for op_id, meta in registry.items(): + + if allowed_set and meta.relatedResource.lower() not in allowed_set: + continue + if meta.description.startswith("**Deprecated"): + continue + + flat_schema = ( + flatten_schema(meta.requestBodySchema) if meta.requestBodySchema else {} + ) + + final_params = [] + for p in meta.parameters: + if p.get("in") == "body": + continue + if p.get("name") in flat_schema: + continue + final_params.append(p) + + filtered_output_schema = extract_required_output_fields(meta.responseSchema) + + exposed_tools.append( + { + "name": meta.operationId, + "description": meta.description, + "method": meta.httpMethod, + "path": meta.path, + "schema": meta.requestBodySchema, + "flatSchema": flat_schema, + "output_schema": filtered_output_schema, + "parameters": final_params, + "resource": meta.relatedResource, + } + ) + return exposed_tools + + +if __name__ == "__main__": + tools = build_tools_from_latest_spec() + print(f"Loaded {len(tools)} tools.") diff --git a/src/oci-db-dynamic-mcp-server/oracle/oci_db_dynamic_mcp_server/server.py b/src/oci-db-dynamic-mcp-server/oracle/oci_db_dynamic_mcp_server/server.py new file mode 100644 index 00000000..9b505aad --- /dev/null +++ b/src/oci-db-dynamic-mcp-server/oracle/oci_db_dynamic_mcp_server/server.py @@ -0,0 +1,311 @@ +""" +Copyright (c) 2025, Oracle and/or its affiliates. +Licensed under the Universal Permissive License v1.0. +""" + +import argparse +import os +import re +from typing import Annotated, Any, Dict, List, Optional + +import oci +import requests +from fastmcp import FastMCP +from oci.auth.signers import security_token_signer +from pydantic import Field + +from . import __project__ +from .dynamic_tools_loader import build_tools_from_latest_spec + +mcp = FastMCP(name=__project__) + +DEFAULT_ENDPOINT = "https://database.us-ashburn-1.oraclecloud.com/20160918/" + +# ---------------- TYPE MAPPING ---------------- +TYPE_MAP = { + "integer": "int", + "boolean": "bool", + "number": "float", + "array": "list", + "object": "dict", + "string": "str", +} + + +# ---------------- OCI API INVOKER ---------------- +def invoke_oci_api(method, path, params=None, payload=None, headers=None): + config = oci.config.from_file( + profile_name=os.getenv("OCI_CONFIG_PROFILE", oci.config.DEFAULT_PROFILE) + ) + + # Load security token + with open(config["security_token_file"], "r") as f: + security_token = f.read().strip() + + # Create signer + signer = security_token_signer.SecurityTokenSigner( + token=security_token, + private_key=oci.signer.load_private_key_from_file( + config["key_file"], pass_phrase=config.get("pass_phrase") + ), + ) + + endpoint = f"https://database.{config['region']}.oraclecloud.com/20160918/" + url = endpoint.rstrip("/") + "/" + path.lstrip("/") + user_agent_name = __project__.split("oracle.", 1)[1].split("-server", 1)[0] + + headers = headers or {"Content-Type": "application/json"} + headers["authorization"] = f"Bearer {security_token}" + headers["x-oci-secondary-auth"] = "true" + headers["User-Agent"] = user_agent_name + + with requests.Session() as session: + + req = requests.Request( + method=method.upper(), + url=url, + headers=headers, + json=payload, + params=params or {}, + auth=signer, + ) + + prepared = req.prepare() + + response = session.send(prepared) + return response + + +# ---------------- UNFLATTENER ---------------- +def unflatten_payload(flat_input: dict, flat_schema: dict): + root = {} + for flat_key, meta in flat_schema.items(): + if flat_key not in flat_input: + continue + + value = flat_input[flat_key] + path = meta.get("path", []) + if not path: + root[flat_key] = value + continue + + cursor = root + for p in path[:-1]: + if p not in cursor or not isinstance(cursor[p], dict): + cursor[p] = {} + cursor = cursor[p] + cursor[path[-1]] = value + return root + + +# ---------------- Utilities ---------------- +def escape_string(s: str) -> str: + if not s: + return "" + return ( + s.replace("\\", "\\\\") + .replace('"', '\\"') + .replace("\n", "\\n") + .replace("\r", "\\r") + ) + + +def clean_description_text(text: str) -> str: + if not text: + return "" + text = text.strip() + text = re.sub(r"(?i)^Parameters\s*$", "", text) + text = re.sub(r"<[^>]+>", "", text) + text = re.sub(r"(?m)^\s*`[^`]+`.*$", "", text) + text = re.sub(r"\n{3,}", "\n\n", text) + return text.strip() + + +def build_collapsed_parent_notes(resolved_schema: dict, flat_schema: dict) -> str: + """ + Identify top-level objects that were 'collapsed' during flattening + and append their descriptions to the tool context. + These usually contain high-level logic (e.g., which subtype to use). + """ + if not resolved_schema or "properties" not in resolved_schema: + return "" + + lines = [] + # Iterate over the ORIGINAL schema properties + for name, prop in resolved_schema["properties"].items(): + + # If this top-level name is NOT in the flattened list, it means it was + # a container object that got flattened away. + if name not in flat_schema: + desc_raw = prop.get("description", "").strip() + if desc_raw: + desc_clean = " ".join(desc_raw.splitlines()).strip() + # Add it as a context note + lines.append(f"\n* **{name} (Context)**: {desc_clean}") + + if not lines: + return "" + + return "\n\n### Important Context" + "".join(lines) + + +def register_tools(allowed_resources: Optional[List[str]] = None): + """ + Load tools dynamically. + allowed_resources: List of strings (e.g. ['database', 'dbsystem']) or None for ALL. + """ + print(f"Loading OCI Specs (Filter: {allowed_resources})...") + tools = build_tools_from_latest_spec(allowed_resources=allowed_resources) + print(f"Loaded {len(tools)} tools.") + + for t in tools: + tool_name = t.get("name") + flat_schema = t.get("flatSchema", {}) + resolved_schema = t.get("schema", {}) + + param_map = {} + required_args = [] + optional_args = [] + + # --- A. Process Query/Path Params --- + flat_top_names = {k.split("_", 1)[0] for k in flat_schema.keys()} + + for p in t.get("parameters", []): + pname = p.get("name") + if not pname: + continue + if p.get("in") == "body": + continue + if pname in flat_top_names: + continue + if pname in flat_schema: + continue + + sanitized = pname.replace("-", "_") + desc = escape_string(p.get("description", "No description").strip()) + + raw_type = p.get("type") or p.get("schema", {}).get("type", "string") + py_type = TYPE_MAP.get(raw_type, "str") + + param_map[sanitized] = { + "orig_name": pname, + "location": p.get("in", "query"), + "type": py_type, + } + + if p.get("required"): + required_args.append( + f'{sanitized}: Annotated[{py_type}, Field(description="{desc}")]' + ) + else: + optional_args.append( + f'{sanitized}: Annotated[{py_type}, Field(description="{desc}")] = None' + ) + + # --- B. Process Flattened Body Fields --- + for flat_key, meta in flat_schema.items(): + sanitized = flat_key.replace("-", "_") + desc_raw = ( + meta.get("description") + or (meta.get("raw_schema") or {}).get("description") + or "Body field" + ) + desc = escape_string(desc_raw.strip()) + + raw_type = meta.get("type") or (meta.get("raw_schema") or {}).get( + "type", "string" + ) + py_type = TYPE_MAP.get(raw_type, "str") + + param_map[sanitized] = { + "orig_name": flat_key, + "location": "body_flat", + "type": py_type, + } + + if meta.get("required"): + required_args.append( + f'{sanitized}: Annotated[{py_type}, Field(description="{desc}")]' + ) + else: + optional_args.append( + f'{sanitized}: Annotated[{py_type}, Field(description="{desc}")] = None' + ) + + # --- C. Build Docstring --- + top_desc = clean_description_text(t.get("description", "")) + context_notes = build_collapsed_parent_notes(resolved_schema, flat_schema) + docstring = escape_string(top_desc + context_notes) + + # --- D. Generate Function Code --- + args_sig = ", ".join(required_args + optional_args) + + func_code = f''' +async def {tool_name}({args_sig}): + """ + {docstring} + """ + from oracle.oci_db_dynamic_mcp_server.server import invoke_oci_api, unflatten_payload + args = locals() + params = {{}} + flat_body = {{}} + path = "{t.get('path', '')}" + for sanitized, info in param_map.items(): + val = args.get(sanitized) + if val is None: continue + # Remove 'args' from locals if it exists to avoid polluting param map + if sanitized == "args": continue + + if info["location"] == "body_flat": + flat_body[info["orig_name"]] = val + else: + placeholder = "{{" + info['orig_name'] + "}}" + if placeholder in path: + path = path.replace(placeholder, str(val)) + else: + params[info['orig_name']] = val + payload = unflatten_payload(flat_body, flat_schema) + return invoke_oci_api( + method="{t.get('method', 'GET')}", + path=path, + params=params, + payload=payload + ) +''' + exec_globals = { + "Annotated": Annotated, + "Field": Field, + "List": List, + "Dict": Dict, + "Any": Any, + "Optional": Optional, + "param_map": param_map, + "flat_schema": flat_schema, + } + + try: + exec(func_code, exec_globals) + tool_func = exec_globals[tool_name] + mcp.tool(tool_func) + except Exception as e: + print(f"Failed to register tool {tool_name}: {e}") + + +def main(): + parser = argparse.ArgumentParser(description="OCI DBaaS MCP Server") + parser.add_argument( + "--resources", "-r", type=str, help="Comma-separated resources (e.g. databases)" + ) + args = parser.parse_args() + + allowed = [r.strip() for r in args.resources.split(",")] if args.resources else None + register_tools(allowed) + + print("Server running...") + mcp.run(transport="stdio") + + +if __name__ == "__main__": + main() +else: + register_tools() diff --git a/src/oci-db-dynamic-mcp-server/oracle/oci_db_dynamic_mcp_server/tests/test_db_dynamic.py b/src/oci-db-dynamic-mcp-server/oracle/oci_db_dynamic_mcp_server/tests/test_db_dynamic.py new file mode 100644 index 00000000..8ba0dda5 --- /dev/null +++ b/src/oci-db-dynamic-mcp-server/oracle/oci_db_dynamic_mcp_server/tests/test_db_dynamic.py @@ -0,0 +1,7843 @@ +from unittest.mock import patch + +import pytest +from fastmcp import Client +from oracle.oci_db_dynamic_mcp_server.server import mcp + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListApplicationVips(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListApplicationVips", + arguments={ + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "cloudVmClusterId": "ocid1.cloudvmcluster.oc1..mockcloudvmclusterid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateApplicationVip(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateApplicationVip", + arguments={ + "cloudVmClusterId": "ocid1.cloudvmcluster.oc1..mockcloudvmclusterid", + "hostnameLabel": "mockhost", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteApplicationVip(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteApplicationVip", + arguments={ + "applicationVipId": "ocid1.applicationvip.oc1..mockapplicationvipid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetApplicationVip(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetApplicationVip", + arguments={ + "applicationVipId": "ocid1.applicationvip.oc1..mockapplicationvipid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListAutonomousContainerDatabaseBackups(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListAutonomousContainerDatabaseBackups", arguments={} + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListAutonomousContainerDatabaseVersions(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListAutonomousContainerDatabaseVersions", + arguments={ + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "serviceComponent": "DATABASE", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListAutonomousContainerDatabases(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListAutonomousContainerDatabases", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateAutonomousContainerDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateAutonomousContainerDatabase", + arguments={ + "displayName": "Mock_Display_Name", + "patchModel": "RELEASE_UPDATE", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_TerminateAutonomousContainerDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "TerminateAutonomousContainerDatabase", + arguments={ + "autonomousContainerDatabaseId": "ocid1.autonomouscontainerdatabase.oc1..mockacdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetAutonomousContainerDatabase(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetAutonomousContainerDatabase", + arguments={ + "autonomousContainerDatabaseId": "ocid1.autonomouscontainerdatabase.oc1..mockacdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateAutonomousContainerDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateAutonomousContainerDatabase", + arguments={ + "autonomousContainerDatabaseId": "ocid1.autonomouscontainerdatabase.oc1..mockacdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_AddStandbyAutonomousContainerDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "AddStandbyAutonomousContainerDatabase", + arguments={ + "autonomousContainerDatabaseId": "ocid1.autonomouscontainerdatabase.oc1..mockacdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeAutonomousContainerDatabaseCompartment(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeAutonomousContainerDatabaseCompartment", + arguments={ + "autonomousContainerDatabaseId": "ocid1.autonomouscontainerdatabase.oc1..mockacdbid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_EditAutonomousContainerDatabaseDataguard(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "EditAutonomousContainerDatabaseDataguard", + arguments={ + "autonomousContainerDatabaseId": "ocid1.autonomouscontainerdatabase.oc1..mockacdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_FailoverAutonomousContainerDatabaseDataguard(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "FailoverAutonomousContainerDatabaseDataguard", + arguments={ + "autonomousContainerDatabaseId": "ocid1.autonomouscontainerdatabase.oc1..mockacdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ReinstateAutonomousContainerDatabaseDataguard(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ReinstateAutonomousContainerDatabaseDataguard", + arguments={ + "autonomousContainerDatabaseId": "ocid1.autonomouscontainerdatabase.oc1..mockacdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_RestartAutonomousContainerDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "RestartAutonomousContainerDatabase", + arguments={ + "autonomousContainerDatabaseId": "ocid1.autonomouscontainerdatabase.oc1..mockacdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_RotateAutonomousContainerDatabaseEncryptionKey(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "RotateAutonomousContainerDatabaseEncryptionKey", + arguments={ + "autonomousContainerDatabaseId": "ocid1.autonomouscontainerdatabase.oc1..mockacdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ConvertStandbyAutonomousContainerDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ConvertStandbyAutonomousContainerDatabase", + arguments={ + "autonomousContainerDatabaseId": "ocid1.autonomouscontainerdatabase.oc1..mockacdbid", + "role": "PRIMARY", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_SwitchoverAutonomousContainerDatabaseDataguard(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "SwitchoverAutonomousContainerDatabaseDataguard", + arguments={ + "autonomousContainerDatabaseId": "ocid1.autonomouscontainerdatabase.oc1..mockacdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_MigrateAutonomousContainerDatabaseDataguardAssociation(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "MigrateAutonomousContainerDatabaseDataguardAssociation", + arguments={ + "autonomousContainerDatabaseId": "ocid1.autonomouscontainerdatabase.oc1..mockacdbid", + "autonomousContainerDatabaseDataguardAssociationId": "ocid1.autonomouscontainerdatabasedataguardassociation.oc1..mockacddgassocid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListContainerDatabasePatches(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListContainerDatabasePatches", + arguments={ + "autonomousContainerDatabaseId": "ocid1.autonomouscontainerdatabase.oc1..mockacdbid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetAutonomousContainerDatabaseResourceUsage(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetAutonomousContainerDatabaseResourceUsage", + arguments={ + "autonomousContainerDatabaseId": "ocid1.autonomouscontainerdatabase.oc1..mockacdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListAutonomousDatabaseBackups(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool("ListAutonomousDatabaseBackups", arguments={}) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateAutonomousDatabaseBackup(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateAutonomousDatabaseBackup", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid", + "backupDestinationDetails_type": "NFS", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteAutonomousDatabaseBackup(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteAutonomousDatabaseBackup", + arguments={ + "autonomousDatabaseBackupId": "ocid1.autonomousdatabasebackup.oc1..mockadbbackupid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetAutonomousDatabaseBackup(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetAutonomousDatabaseBackup", + arguments={ + "autonomousDatabaseBackupId": "ocid1.autonomousdatabasebackup.oc1..mockadbbackupid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateAutonomousDatabaseBackup(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateAutonomousDatabaseBackup", + arguments={ + "autonomousDatabaseBackupId": "ocid1.autonomousdatabasebackup.oc1..mockadbbackupid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListAutonomousDatabaseCharacterSets(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListAutonomousDatabaseCharacterSets", arguments={} + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListAutonomousDatabaseSoftwareImages(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListAutonomousDatabaseSoftwareImages", + arguments={ + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "imageShapeFamily": "VM.Standard", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateAutonomousDatabaseSoftwareImage(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateAutonomousDatabaseSoftwareImage", + arguments={ + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "displayName": "Mock_Display_Name", + "imageShapeFamily": "VM.Standard", + "sourceCdbId": "ocid1.database.oc1..mocksourcecdbid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteAutonomousDatabaseSoftwareImage(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteAutonomousDatabaseSoftwareImage", + arguments={ + "autonomousDatabaseSoftwareImageId": "ocid1.autonomousdatabasesoftwareimage.oc1..mockadbimageid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetAutonomousDatabaseSoftwareImage(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetAutonomousDatabaseSoftwareImage", + arguments={ + "autonomousDatabaseSoftwareImageId": "ocid1.autonomousdatabasesoftwareimage.oc1..mockadbimageid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateAutonomousDatabaseSoftwareImage(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateAutonomousDatabaseSoftwareImage", + arguments={ + "autonomousDatabaseSoftwareImageId": "ocid1.autonomousdatabasesoftwareimage.oc1..mockadbimageid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeAutonomousDatabaseSoftwareImageCompartment(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeAutonomousDatabaseSoftwareImageCompartment", + arguments={ + "autonomousDatabaseSoftwareImageId": "ocid1.autonomousdatabasesoftwareimage.oc1..mockadbimageid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListAutonomousDatabases(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListAutonomousDatabases", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateAutonomousDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateAutonomousDatabase", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ResourcePoolShapes(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool("ResourcePoolShapes", arguments={}) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetAutonomousDatabaseRegionalWallet(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetAutonomousDatabaseRegionalWallet", arguments={} + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateAutonomousDatabaseRegionalWallet(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateAutonomousDatabaseRegionalWallet", arguments={} + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteAutonomousDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteAutonomousDatabase", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetAutonomousDatabase(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetAutonomousDatabase", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateAutonomousDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateAutonomousDatabase", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeAutonomousDatabaseCompartment(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeAutonomousDatabaseCompartment", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeDisasterRecoveryConfiguration(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeDisasterRecoveryConfiguration", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeAutonomousDatabaseSubscription(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeAutonomousDatabaseSubscription", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ConfigureAutonomousDatabaseVaultKey(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ConfigureAutonomousDatabaseVaultKey", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ConfigureSaasAdminUser(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ConfigureSaasAdminUser", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeregisterAutonomousDatabaseDataSafe(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeregisterAutonomousDatabaseDataSafe", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid", + "pdbAdminPassword": "MockPdbPassword123!", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DisableAutonomousDatabaseManagement(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DisableAutonomousDatabaseManagement", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DisableAutonomousDatabaseOperationsInsights(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DisableAutonomousDatabaseOperationsInsights", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_EnableAutonomousDatabaseManagement(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "EnableAutonomousDatabaseManagement", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_EnableAutonomousDatabaseOperationsInsights(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "EnableAutonomousDatabaseOperationsInsights", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_FailOverAutonomousDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "FailOverAutonomousDatabase", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GenerateAutonomousDatabaseWallet(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GenerateAutonomousDatabaseWallet", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid", + "password": "MockPassword!", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_SaasAdminUserStatus(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "SaasAdminUserStatus", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_AutonomousDatabaseManualRefresh(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "AutonomousDatabaseManualRefresh", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_RegisterAutonomousDatabaseDataSafe(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "RegisterAutonomousDatabaseDataSafe", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid", + "pdbAdminPassword": "MockPdbPassword123!", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_RestartAutonomousDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "RestartAutonomousDatabase", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_RestoreAutonomousDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "RestoreAutonomousDatabase", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_RotateAutonomousDatabaseEncryptionKey(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "RotateAutonomousDatabaseEncryptionKey", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ShrinkAutonomousDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ShrinkAutonomousDatabase", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_StartAutonomousDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "StartAutonomousDatabase", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_StopAutonomousDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "StopAutonomousDatabase", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_SwitchoverAutonomousDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "SwitchoverAutonomousDatabase", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListAutonomousDatabaseDataguardAssociations(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListAutonomousDatabaseDataguardAssociations", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetAutonomousDatabaseDataguardAssociation(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetAutonomousDatabaseDataguardAssociation", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid", + "autonomousDatabaseDataguardAssociationId": "ocid1.autonomousdatabasedataguardassociation.oc1..mockadbdgassocid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListAutonomousDatabaseClones(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListAutonomousDatabaseClones", + arguments={ + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListAutonomousDatabasePeers(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListAutonomousDatabasePeers", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListAutonomousDatabaseRefreshableClones(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListAutonomousDatabaseRefreshableClones", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListResourcePoolMembers(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListResourcePoolMembers", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetAutonomousDatabaseWallet(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetAutonomousDatabaseWallet", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateAutonomousDatabaseWallet(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateAutonomousDatabaseWallet", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListAutonomousDbPreviewVersions(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListAutonomousDbPreviewVersions", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListAutonomousDbVersions(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListAutonomousDbVersions", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetExadataInfrastructureOcpus(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetExadataInfrastructureOcpus", + arguments={ + "autonomousExadataInfrastructureId": "ocid1.autonomousexadatainfrastructure.oc1..mockaxid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetAutonomousPatch(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetAutonomousPatch", + arguments={ + "autonomousPatchId": "ocid1.autonomouspatch.oc1..mockautonomouspatchid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListAutonomousVirtualMachines(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListAutonomousVirtualMachines", + arguments={ + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "autonomousVmClusterId": "ocid1.autonomousvmcluster.oc1..mockavmclusterid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetAutonomousVirtualMachine(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetAutonomousVirtualMachine", + arguments={ + "autonomousVirtualMachineId": "ocid1.autonomousvirtualmachine.oc1..mockavmid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListAutonomousVmClusters(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListAutonomousVmClusters", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateAutonomousVmCluster(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateAutonomousVmCluster", + arguments={ + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "displayName": "Mock_Display_Name", + "exadataInfrastructureId": "ocid1.exadatainfrastructure.oc1..mockexadatainfraid", + "vmClusterNetworkId": "ocid1.vmclusternetwork.oc1..mockvmclusternetworkid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteAutonomousVmCluster(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteAutonomousVmCluster", + arguments={ + "autonomousVmClusterId": "ocid1.autonomousvmcluster.oc1..mockavmclusterid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetAutonomousVmCluster(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetAutonomousVmCluster", + arguments={ + "autonomousVmClusterId": "ocid1.autonomousvmcluster.oc1..mockavmclusterid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateAutonomousVmCluster(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateAutonomousVmCluster", + arguments={ + "autonomousVmClusterId": "ocid1.autonomousvmcluster.oc1..mockavmclusterid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListAutonomousVmClusterAcdResourceUsage(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListAutonomousVmClusterAcdResourceUsage", + arguments={ + "autonomousVmClusterId": "ocid1.autonomousvmcluster.oc1..mockavmclusterid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeAutonomousVmClusterCompartment(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeAutonomousVmClusterCompartment", + arguments={ + "autonomousVmClusterId": "ocid1.autonomousvmcluster.oc1..mockavmclusterid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_RotateAutonomousVmClusterOrdsCerts(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "RotateAutonomousVmClusterOrdsCerts", + arguments={ + "autonomousVmClusterId": "ocid1.autonomousvmcluster.oc1..mockavmclusterid", + "certificateGenerationType": "BYOC", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_RotateAutonomousVmClusterSslCerts(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "RotateAutonomousVmClusterSslCerts", + arguments={ + "autonomousVmClusterId": "ocid1.autonomousvmcluster.oc1..mockavmclusterid", + "certificateGenerationType": "BYOC", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetAutonomousVmClusterResourceUsage(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetAutonomousVmClusterResourceUsage", + arguments={ + "autonomousVmClusterId": "ocid1.autonomousvmcluster.oc1..mockavmclusterid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListBackupDestination(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListBackupDestination", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateBackupDestination(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateBackupDestination", + arguments={ + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "displayName": "Mock_Display_Name", + "type": "FULL", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteBackupDestination(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteBackupDestination", + arguments={ + "backupDestinationId": "ocid1.backupdestination.oc1..mockbackupdestinationid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetBackupDestination(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetBackupDestination", + arguments={ + "backupDestinationId": "ocid1.backupdestination.oc1..mockbackupdestinationid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateBackupDestination(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateBackupDestination", + arguments={ + "backupDestinationId": "ocid1.backupdestination.oc1..mockbackupdestinationid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeBackupDestinationCompartment(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeBackupDestinationCompartment", + arguments={ + "backupDestinationId": "ocid1.backupdestination.oc1..mockbackupdestinationid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListBackups(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool("ListBackups", arguments={}) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateBackup(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateBackup", + arguments={ + "databaseId": "ocid1.database.oc1..mockdatabaseid", + "displayName": "Mock_Display_Name", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteBackup(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteBackup", arguments={"backupId": "ocid1.backup.oc1..mockbackupid"} + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetBackup(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetBackup", arguments={"backupId": "ocid1.backup.oc1..mockbackupid"} + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListCloudAutonomousVmClusters(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListCloudAutonomousVmClusters", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateCloudAutonomousVmCluster(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateCloudAutonomousVmCluster", + arguments={ + "cloudExadataInfrastructureId": "ocid1.cloudexadatainfrastructure.oc1..mockcloudexadataid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "displayName": "Mock_Display_Name", + "subnetId": "ocid1.subnet.oc1..mocksubnetid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteCloudAutonomousVmCluster(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteCloudAutonomousVmCluster", + arguments={ + "cloudAutonomousVmClusterId": "ocid1.cloudautonomousvmcluster.oc1..mockcloudavmclusterid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetCloudAutonomousVmCluster(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetCloudAutonomousVmCluster", + arguments={ + "cloudAutonomousVmClusterId": "ocid1.cloudautonomousvmcluster.oc1..mockcloudavmclusterid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateCloudAutonomousVmCluster(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateCloudAutonomousVmCluster", + arguments={ + "cloudAutonomousVmClusterId": "ocid1.cloudautonomousvmcluster.oc1..mockcloudavmclusterid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListCloudAutonomousVmClusterAcdResourceUsage(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListCloudAutonomousVmClusterAcdResourceUsage", + arguments={ + "cloudAutonomousVmClusterId": "ocid1.cloudautonomousvmcluster.oc1..mockcloudavmclusterid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeCloudAutonomousVmClusterCompartment(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeCloudAutonomousVmClusterCompartment", + arguments={ + "cloudAutonomousVmClusterId": "ocid1.cloudautonomousvmcluster.oc1..mockcloudavmclusterid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_RotateCloudAutonomousVmClusterOrdsCerts(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "RotateCloudAutonomousVmClusterOrdsCerts", + arguments={ + "cloudAutonomousVmClusterId": "ocid1.cloudautonomousvmcluster.oc1..mockcloudavmclusterid", + "certificateGenerationType": "BYOC", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_RotateCloudAutonomousVmClusterSslCerts(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "RotateCloudAutonomousVmClusterSslCerts", + arguments={ + "cloudAutonomousVmClusterId": "ocid1.cloudautonomousvmcluster.oc1..mockcloudavmclusterid", + "certificateGenerationType": "BYOC", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetCloudAutonomousVmClusterResourceUsage(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetCloudAutonomousVmClusterResourceUsage", + arguments={ + "cloudAutonomousVmClusterId": "ocid1.cloudautonomousvmcluster.oc1..mockcloudavmclusterid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListCloudExadataInfrastructures(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListCloudExadataInfrastructures", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateCloudExadataInfrastructure(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateCloudExadataInfrastructure", + arguments={ + "availabilityDomain": "Uocm:US-ASHBURN-AD-1", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "displayName": "Mock_Display_Name", + "shape": "Exadata.X8M", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteCloudExadataInfrastructure(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteCloudExadataInfrastructure", + arguments={ + "cloudExadataInfrastructureId": "ocid1.cloudexadatainfrastructure.oc1..mockcloudexadataid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetCloudExadataInfrastructure(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetCloudExadataInfrastructure", + arguments={ + "cloudExadataInfrastructureId": "ocid1.cloudexadatainfrastructure.oc1..mockcloudexadataid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateCloudExadataInfrastructure(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateCloudExadataInfrastructure", + arguments={ + "cloudExadataInfrastructureId": "ocid1.cloudexadatainfrastructure.oc1..mockcloudexadataid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_AddStorageCapacityCloudExadataInfrastructure(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "AddStorageCapacityCloudExadataInfrastructure", + arguments={ + "cloudExadataInfrastructureId": "ocid1.cloudexadatainfrastructure.oc1..mockcloudexadataid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeCloudExadataInfrastructureCompartment(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeCloudExadataInfrastructureCompartment", + arguments={ + "cloudExadataInfrastructureId": "ocid1.cloudexadatainfrastructure.oc1..mockcloudexadataid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeCloudExadataInfrastructureSubscription(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeCloudExadataInfrastructureSubscription", + arguments={ + "cloudExadataInfrastructureId": "ocid1.cloudexadatainfrastructure.oc1..mockcloudexadataid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ConfigureExascaleCloudExadataInfrastructure(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ConfigureExascaleCloudExadataInfrastructure", + arguments={ + "cloudExadataInfrastructureId": "ocid1.cloudexadatainfrastructure.oc1..mockcloudexadataid", + "totalStorageInGBs": 5000, + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetCloudExadataInfrastructureUnallocatedResources(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetCloudExadataInfrastructureUnallocatedResources", + arguments={ + "cloudExadataInfrastructureId": "ocid1.cloudexadatainfrastructure.oc1..mockcloudexadataid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListCloudVmClusters(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListCloudVmClusters", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateCloudVmCluster(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateCloudVmCluster", + arguments={ + "backupSubnetId": "ocid1.subnet.oc1..mockbackupsubnetid", + "cloudExadataInfrastructureId": "ocid1.cloudexadatainfrastructure.oc1..mockcloudexadataid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "cpuCoreCount": 16, + "displayName": "Mock_Display_Name", + "giVersion": "19.0.0.0", + "hostname": "mock-host-1", + "sshPublicKeys": ["ssh-rsa AAAAB3Nza... mockKey1"], + "subnetId": "ocid1.subnet.oc1..mocksubnetid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteCloudVmCluster(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteCloudVmCluster", + arguments={ + "cloudVmClusterId": "ocid1.cloudvmcluster.oc1..mockcloudvmclusterid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetCloudVmCluster(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetCloudVmCluster", + arguments={ + "cloudVmClusterId": "ocid1.cloudvmcluster.oc1..mockcloudvmclusterid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateCloudVmCluster(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateCloudVmCluster", + arguments={ + "cloudVmClusterId": "ocid1.cloudvmcluster.oc1..mockcloudvmclusterid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetCloudVmClusterIormConfig(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetCloudVmClusterIormConfig", + arguments={ + "cloudVmClusterId": "ocid1.cloudvmcluster.oc1..mockcloudvmclusterid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateCloudVmClusterIormConfig(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateCloudVmClusterIormConfig", + arguments={ + "cloudVmClusterId": "ocid1.cloudvmcluster.oc1..mockcloudvmclusterid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_AddVirtualMachineToCloudVmCluster(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "AddVirtualMachineToCloudVmCluster", + arguments={ + "cloudVmClusterId": "ocid1.cloudvmcluster.oc1..mockcloudvmclusterid", + "dbServers": [ + "ocid1.dbserver.oc1..server1", + "ocid1.dbserver.oc1..server2", + ], + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeCloudVmClusterCompartment(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeCloudVmClusterCompartment", + arguments={ + "cloudVmClusterId": "ocid1.cloudvmcluster.oc1..mockcloudvmclusterid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeCloudVmClusterSubscription(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeCloudVmClusterSubscription", + arguments={ + "cloudVmClusterId": "ocid1.cloudvmcluster.oc1..mockcloudvmclusterid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_RemoveVirtualMachineFromCloudVmCluster(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "RemoveVirtualMachineFromCloudVmCluster", + arguments={ + "cloudVmClusterId": "ocid1.cloudvmcluster.oc1..mockcloudvmclusterid", + "dbServers": [ + "ocid1.dbserver.oc1..server1", + "ocid1.dbserver.oc1..server2", + ], + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListCloudVmClusterUpdateHistoryEntries(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListCloudVmClusterUpdateHistoryEntries", + arguments={ + "cloudVmClusterId": "ocid1.cloudvmcluster.oc1..mockcloudvmclusterid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetCloudVmClusterUpdateHistoryEntry(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetCloudVmClusterUpdateHistoryEntry", + arguments={ + "cloudVmClusterId": "ocid1.cloudvmcluster.oc1..mockcloudvmclusterid", + "updateHistoryEntryId": "ocid1.updatehistory.oc1..mockupdatehistoryid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListCloudVmClusterUpdates(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListCloudVmClusterUpdates", + arguments={ + "cloudVmClusterId": "ocid1.cloudvmcluster.oc1..mockcloudvmclusterid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetCloudVmClusterUpdate(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetCloudVmClusterUpdate", + arguments={ + "cloudVmClusterId": "ocid1.cloudvmcluster.oc1..mockcloudvmclusterid", + "updateId": "ocid1.update.oc1..mockupdateid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListDatabaseSoftwareImages(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListDatabaseSoftwareImages", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateDatabaseSoftwareImage(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateDatabaseSoftwareImage", + arguments={ + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "displayName": "Mock_Display_Name", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteDatabaseSoftwareImage(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteDatabaseSoftwareImage", + arguments={ + "databaseSoftwareImageId": "ocid1.databasesoftwareimage.oc1..mockdbsoftwareimageid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetDatabaseSoftwareImage(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetDatabaseSoftwareImage", + arguments={ + "databaseSoftwareImageId": "ocid1.databasesoftwareimage.oc1..mockdbsoftwareimageid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateDatabaseSoftwareImage(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateDatabaseSoftwareImage", + arguments={ + "databaseSoftwareImageId": "ocid1.databasesoftwareimage.oc1..mockdbsoftwareimageid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeDatabaseSoftwareImageCompartment(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeDatabaseSoftwareImageCompartment", + arguments={ + "databaseSoftwareImageId": "ocid1.databasesoftwareimage.oc1..mockdbsoftwareimageid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListDatabases(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListDatabases", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateDatabase", + arguments={ + "dbHomeId": "ocid1.dbhome.oc1..mockdbhomeid", + "source": "DB_SYSTEM", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteDatabase", + arguments={"databaseId": "ocid1.database.oc1..mockdatabaseid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetDatabase(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetDatabase", + arguments={"databaseId": "ocid1.database.oc1..mockdatabaseid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateDatabase", + arguments={ + "databaseId": "ocid1.database.oc1..mockdatabaseid", + "storageSizeDetails_dataStorageSizeInGBs": 1024, + "storageSizeDetails_recoStorageSizeInGBs": 256, + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeEncryptionKeyLocation(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeEncryptionKeyLocation", + arguments={ + "databaseId": "ocid1.database.oc1..mockdatabaseid", + "providerType": "OCI", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ConvertToPdb(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ConvertToPdb", + arguments={ + "databaseId": "ocid1.database.oc1..mockdatabaseid", + "action": "STOP", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DisableDatabaseManagement(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DisableDatabaseManagement", + arguments={"databaseId": "ocid1.database.oc1..mockdatabaseid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_EnableDatabaseManagement(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "EnableDatabaseManagement", + arguments={ + "databaseId": "ocid1.database.oc1..mockdatabaseid", + "credentialDetails_passwordSecretId": "ocid1.vaultsecret.oc1..mockpasswordsecretid", + "credentialDetails_userName": "db_admin", + "privateEndPointId": "ocid1.privateendpoint.oc1..mockprivateendpointid", + "serviceName": "mockservice.example.com", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_MigrateVaultKey(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "MigrateVaultKey", + arguments={ + "databaseId": "ocid1.database.oc1..mockdatabaseid", + "kmsKeyId": "ocid1.key.oc1..mockkmskeyid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ModifyDatabaseManagement(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ModifyDatabaseManagement", + arguments={ + "databaseId": "ocid1.database.oc1..mockdatabaseid", + "credentialDetails_passwordSecretId": "ocid1.vaultsecret.oc1..mockpasswordsecretid", + "credentialDetails_userName": "db_admin", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_RestoreDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "RestoreDatabase", + arguments={"databaseId": "ocid1.database.oc1..mockdatabaseid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_RotateVaultKey(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "RotateVaultKey", + arguments={"databaseId": "ocid1.database.oc1..mockdatabaseid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpgradeDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpgradeDatabase", + arguments={ + "databaseId": "ocid1.database.oc1..mockdatabaseid", + "action": "STOP", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ConvertToStandalone(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ConvertToStandalone", + arguments={ + "databaseId": "ocid1.database.oc1..mockdatabaseid", + "databaseAdminPassword": "MockDbPassword123!", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_FailoverDataGuard(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "FailoverDataGuard", + arguments={ + "databaseId": "ocid1.database.oc1..mockdatabaseid", + "databaseAdminPassword": "MockDbPassword123!", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ReinstateDataGuard(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ReinstateDataGuard", + arguments={ + "databaseId": "ocid1.database.oc1..mockdatabaseid", + "databaseAdminPassword": "MockDbPassword123!", + "sourceDatabaseId": "ocid1.database.oc1..mocksourcedbid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_SwitchOverDataGuard(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "SwitchOverDataGuard", + arguments={ + "databaseId": "ocid1.database.oc1..mockdatabaseid", + "databaseAdminPassword": "MockDbPassword123!", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateDataGuard(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateDataGuard", + arguments={"databaseId": "ocid1.database.oc1..mockdatabaseid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListDataGuardAssociations(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListDataGuardAssociations", + arguments={"databaseId": "ocid1.database.oc1..mockdatabaseid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateDataGuardAssociation(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateDataGuardAssociation", + arguments={ + "databaseId": "ocid1.database.oc1..mockdatabaseid", + "creationType": "CLONE", + "databaseAdminPassword": "MockDbPassword123!", + "protectionMode": "MAXIMUM_PERFORMANCE", + "sourceEncryptionKeyLocationDetails_providerType": "OCI_VAULT", + "transportType": "TCP", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetDataGuardAssociation(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetDataGuardAssociation", + arguments={ + "databaseId": "ocid1.database.oc1..mockdatabaseid", + "dataGuardAssociationId": "ocid1.dataguardassociation.oc1..mockdgassocid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateDataGuardAssociation(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateDataGuardAssociation", + arguments={ + "databaseId": "ocid1.database.oc1..mockdatabaseid", + "dataGuardAssociationId": "ocid1.dataguardassociation.oc1..mockdgassocid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_FailoverDataGuardAssociation(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "FailoverDataGuardAssociation", + arguments={ + "databaseId": "ocid1.database.oc1..mockdatabaseid", + "dataGuardAssociationId": "ocid1.dataguardassociation.oc1..mockdgassocid", + "databaseAdminPassword": "MockDbPassword123!", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_MigrateDataGuardAssociationToMultiDataGuards(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "MigrateDataGuardAssociationToMultiDataGuards", + arguments={ + "databaseId": "ocid1.database.oc1..mockdatabaseid", + "dataGuardAssociationId": "ocid1.dataguardassociation.oc1..mockdgassocid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ReinstateDataGuardAssociation(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ReinstateDataGuardAssociation", + arguments={ + "databaseId": "ocid1.database.oc1..mockdatabaseid", + "dataGuardAssociationId": "ocid1.dataguardassociation.oc1..mockdgassocid", + "databaseAdminPassword": "MockDbPassword123!", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_SwitchoverDataGuardAssociation(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "SwitchoverDataGuardAssociation", + arguments={ + "databaseId": "ocid1.database.oc1..mockdatabaseid", + "dataGuardAssociationId": "ocid1.dataguardassociation.oc1..mockdgassocid", + "databaseAdminPassword": "MockDbPassword123!", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListPdbConversionHistoryEntries(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListPdbConversionHistoryEntries", + arguments={"databaseId": "ocid1.database.oc1..mockdatabaseid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetPdbConversionHistoryEntry(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetPdbConversionHistoryEntry", + arguments={ + "databaseId": "ocid1.database.oc1..mockdatabaseid", + "pdbConversionHistoryEntryId": "ocid1.pdbconversionhistory.oc1..mockpdbhistoryid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListDatabaseUpgradeHistoryEntries(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListDatabaseUpgradeHistoryEntries", + arguments={"databaseId": "ocid1.database.oc1..mockdatabaseid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetDatabaseUpgradeHistoryEntry(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetDatabaseUpgradeHistoryEntry", + arguments={ + "databaseId": "ocid1.database.oc1..mockdatabaseid", + "upgradeHistoryEntryId": "ocid1.upgradehistory.oc1..mockupgradehistoryid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListDbHomes(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListDbHomes", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateDbHome(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool("CreateDbHome", arguments={}) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteDbHome(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteDbHome", arguments={"dbHomeId": "ocid1.dbhome.oc1..mockdbhomeid"} + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetDbHome(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetDbHome", arguments={"dbHomeId": "ocid1.dbhome.oc1..mockdbhomeid"} + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateDbHome(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateDbHome", arguments={"dbHomeId": "ocid1.dbhome.oc1..mockdbhomeid"} + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListDbHomePatchHistoryEntries(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListDbHomePatchHistoryEntries", + arguments={"dbHomeId": "ocid1.dbhome.oc1..mockdbhomeid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetDbHomePatchHistoryEntry(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetDbHomePatchHistoryEntry", + arguments={ + "dbHomeId": "ocid1.dbhome.oc1..mockdbhomeid", + "patchHistoryEntryId": "ocid1.patchhistory.oc1..mockpatchhistoryid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListDbHomePatches(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListDbHomePatches", + arguments={"dbHomeId": "ocid1.dbhome.oc1..mockdbhomeid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetDbHomePatch(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetDbHomePatch", + arguments={ + "dbHomeId": "ocid1.dbhome.oc1..mockdbhomeid", + "patchId": "ocid1.patch.oc1..mockpatchid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListDbNodes(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListDbNodes", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetDbNode(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetDbNode", arguments={"dbNodeId": "ocid1.dbnode.oc1..mockdbnodeid"} + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DbNodeAction(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DbNodeAction", + arguments={"dbNodeId": "ocid1.dbnode.oc1..mockdbnodeid", "action": "STOP"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListConsoleConnections(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListConsoleConnections", + arguments={"dbNodeId": "ocid1.dbnode.oc1..mockdbnodeid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateConsoleConnection(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateConsoleConnection", + arguments={ + "dbNodeId": "ocid1.dbnode.oc1..mockdbnodeid", + "publicKey": "ssh-rsa AAAAB3Nza... mockPublicKey", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteConsoleConnection(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteConsoleConnection", + arguments={ + "dbNodeId": "ocid1.dbnode.oc1..mockdbnodeid", + "consoleConnectionId": "ocid1.consoleconnection.oc1..mockconsoleconnid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetConsoleConnection(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetConsoleConnection", + arguments={ + "dbNodeId": "ocid1.dbnode.oc1..mockdbnodeid", + "consoleConnectionId": "ocid1.consoleconnection.oc1..mockconsoleconnid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListConsoleHistories(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListConsoleHistories", + arguments={"dbNodeId": "ocid1.dbnode.oc1..mockdbnodeid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateConsoleHistory(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateConsoleHistory", + arguments={ + "dbNodeId": "ocid1.dbnode.oc1..mockdbnodeid", + "displayName": "Mock_Display_Name", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteConsoleHistory(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteConsoleHistory", + arguments={ + "dbNodeId": "ocid1.dbnode.oc1..mockdbnodeid", + "consoleHistoryId": "ocid1.consolehistory.oc1..mockconsolehistoryid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetConsoleHistory(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetConsoleHistory", + arguments={ + "dbNodeId": "ocid1.dbnode.oc1..mockdbnodeid", + "consoleHistoryId": "ocid1.consolehistory.oc1..mockconsolehistoryid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateConsoleHistory(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateConsoleHistory", + arguments={ + "dbNodeId": "ocid1.dbnode.oc1..mockdbnodeid", + "consoleHistoryId": "ocid1.consolehistory.oc1..mockconsolehistoryid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetConsoleHistoryContent(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetConsoleHistoryContent", + arguments={ + "dbNodeId": "ocid1.dbnode.oc1..mockdbnodeid", + "consoleHistoryId": "ocid1.consolehistory.oc1..mockconsolehistoryid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListDbServers(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListDbServers", + arguments={ + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "exadataInfrastructureId": "ocid1.exadatainfrastructure.oc1..mockexadatainfraid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetDbServer(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetDbServer", + arguments={ + "exadataInfrastructureId": "ocid1.exadatainfrastructure.oc1..mockexadatainfraid", + "dbServerId": "ocid1.dbserver.oc1..mockdbserverid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListDbSystemComputePerformances(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListDbSystemComputePerformances", arguments={} + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListDbSystemShapes(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListDbSystemShapes", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListFlexComponents(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListFlexComponents", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListDbSystemStoragePerformances(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListDbSystemStoragePerformances", arguments={"storageManagement": "ASM"} + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListDbSystems(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListDbSystems", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_LaunchDbSystem(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "LaunchDbSystem", + arguments={ + "availabilityDomain": "Uocm:US-ASHBURN-AD-1", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "hostname": "mock-host-1", + "shape": "Exadata.X8M", + "sshPublicKeys": ["ssh-rsa AAAAB3Nza... mockKey1"], + "subnetId": "ocid1.subnet.oc1..mocksubnetid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_TerminateDbSystem(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "TerminateDbSystem", + arguments={"dbSystemId": "ocid1.dbsystem.oc1..mockdbsystemid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetDbSystem(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetDbSystem", + arguments={"dbSystemId": "ocid1.dbsystem.oc1..mockdbsystemid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateDbSystem(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateDbSystem", + arguments={"dbSystemId": "ocid1.dbsystem.oc1..mockdbsystemid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetExadataIormConfig(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetExadataIormConfig", + arguments={"dbSystemId": "ocid1.dbsystem.oc1..mockdbsystemid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateExadataIormConfig(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateExadataIormConfig", + arguments={"dbSystemId": "ocid1.dbsystem.oc1..mockdbsystemid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeDbSystemCompartment(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeDbSystemCompartment", + arguments={ + "dbSystemId": "ocid1.dbsystem.oc1..mockdbsystemid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_MigrateExadataDbSystemResourceModel(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "MigrateExadataDbSystemResourceModel", + arguments={"dbSystemId": "ocid1.dbsystem.oc1..mockdbsystemid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpgradeDbSystem(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpgradeDbSystem", + arguments={ + "dbSystemId": "ocid1.dbsystem.oc1..mockdbsystemid", + "action": "STOP", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListDbSystemPatchHistoryEntries(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListDbSystemPatchHistoryEntries", + arguments={"dbSystemId": "ocid1.dbsystem.oc1..mockdbsystemid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetDbSystemPatchHistoryEntry(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetDbSystemPatchHistoryEntry", + arguments={ + "dbSystemId": "ocid1.dbsystem.oc1..mockdbsystemid", + "patchHistoryEntryId": "ocid1.patchhistory.oc1..mockpatchhistoryid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListDbSystemPatches(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListDbSystemPatches", + arguments={"dbSystemId": "ocid1.dbsystem.oc1..mockdbsystemid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetDbSystemPatch(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetDbSystemPatch", + arguments={ + "dbSystemId": "ocid1.dbsystem.oc1..mockdbsystemid", + "patchId": "ocid1.patch.oc1..mockpatchid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListDbSystemUpgradeHistoryEntries(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListDbSystemUpgradeHistoryEntries", + arguments={"dbSystemId": "ocid1.dbsystem.oc1..mockdbsystemid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetDbSystemUpgradeHistoryEntry(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetDbSystemUpgradeHistoryEntry", + arguments={ + "dbSystemId": "ocid1.dbsystem.oc1..mockdbsystemid", + "upgradeHistoryEntryId": "ocid1.upgradehistory.oc1..mockupgradehistoryid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListDbVersions(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListDbVersions", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListExadataInfrastructures(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListExadataInfrastructures", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateExadataInfrastructure(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateExadataInfrastructure", + arguments={ + "adminNetworkCIDR": "192.168.1.0/24", + "cloudControlPlaneServer1": "10.0.0.5", + "cloudControlPlaneServer2": "10.0.0.6", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "corporateProxy": "http://corp-proxy:8080", + "displayName": "Mock_Display_Name", + "dnsServer": ["169.254.169.254"], + "gateway": "10.0.0.1", + "infiniBandNetworkCIDR": "192.168.0.0/24", + "netmask": "255.255.255.0", + "ntpServer": ["169.254.169.254"], + "shape": "Exadata.X8M", + "timeZone": "UTC", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteExadataInfrastructure(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteExadataInfrastructure", + arguments={ + "exadataInfrastructureId": "ocid1.exadatainfrastructure.oc1..mockexadatainfraid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetExadataInfrastructure(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetExadataInfrastructure", + arguments={ + "exadataInfrastructureId": "ocid1.exadatainfrastructure.oc1..mockexadatainfraid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateExadataInfrastructure(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateExadataInfrastructure", + arguments={ + "exadataInfrastructureId": "ocid1.exadatainfrastructure.oc1..mockexadatainfraid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ActivateExadataInfrastructure(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ActivateExadataInfrastructure", + arguments={ + "exadataInfrastructureId": "ocid1.exadatainfrastructure.oc1..mockexadatainfraid", + "activationFile": "mock_activation_file_path_or_content", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_AddStorageCapacityExadataInfrastructure(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "AddStorageCapacityExadataInfrastructure", + arguments={ + "exadataInfrastructureId": "ocid1.exadatainfrastructure.oc1..mockexadatainfraid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeExadataInfrastructureCompartment(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeExadataInfrastructureCompartment", + arguments={ + "exadataInfrastructureId": "ocid1.exadatainfrastructure.oc1..mockexadatainfraid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DownloadExadataInfrastructureConfigFile(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DownloadExadataInfrastructureConfigFile", + arguments={ + "exadataInfrastructureId": "ocid1.exadatainfrastructure.oc1..mockexadatainfraid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetExadataInfrastructureUnAllocatedResources(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetExadataInfrastructureUnAllocatedResources", + arguments={ + "exadataInfrastructureId": "ocid1.exadatainfrastructure.oc1..mockexadatainfraid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListVmClusterNetworks(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListVmClusterNetworks", + arguments={ + "exadataInfrastructureId": "ocid1.exadatainfrastructure.oc1..mockexadatainfraid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateVmClusterNetwork(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateVmClusterNetwork", + arguments={ + "exadataInfrastructureId": "ocid1.exadatainfrastructure.oc1..mockexadatainfraid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "displayName": "Mock_Display_Name", + "scans": [{"hostname": "scan1", "port": 1521}], + "vmNetworks": [ + { + "networkType": "CLIENT", + "netmask": "255.255.255.0", + "gateway": "10.0.0.1", + } + ], + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GenerateRecommendedVmClusterNetwork(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GenerateRecommendedVmClusterNetwork", + arguments={ + "exadataInfrastructureId": "ocid1.exadatainfrastructure.oc1..mockexadatainfraid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "displayName": "Mock_Display_Name", + "networks": [{"id": "ocid1.network.oc1..mocknetworkid"}], + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteVmClusterNetwork(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteVmClusterNetwork", + arguments={ + "exadataInfrastructureId": "ocid1.exadatainfrastructure.oc1..mockexadatainfraid", + "vmClusterNetworkId": "ocid1.vmclusternetwork.oc1..mockvmclusternetworkid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetVmClusterNetwork(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetVmClusterNetwork", + arguments={ + "exadataInfrastructureId": "ocid1.exadatainfrastructure.oc1..mockexadatainfraid", + "vmClusterNetworkId": "ocid1.vmclusternetwork.oc1..mockvmclusternetworkid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateVmClusterNetwork(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateVmClusterNetwork", + arguments={ + "exadataInfrastructureId": "ocid1.exadatainfrastructure.oc1..mockexadatainfraid", + "vmClusterNetworkId": "ocid1.vmclusternetwork.oc1..mockvmclusternetworkid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DownloadVmClusterNetworkConfigFile(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DownloadVmClusterNetworkConfigFile", + arguments={ + "exadataInfrastructureId": "ocid1.exadatainfrastructure.oc1..mockexadatainfraid", + "vmClusterNetworkId": "ocid1.vmclusternetwork.oc1..mockvmclusternetworkid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ResizeVmClusterNetwork(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ResizeVmClusterNetwork", + arguments={ + "exadataInfrastructureId": "ocid1.exadatainfrastructure.oc1..mockexadatainfraid", + "vmClusterNetworkId": "ocid1.vmclusternetwork.oc1..mockvmclusternetworkid", + "action": "STOP", + "vmNetworks": [ + { + "networkType": "CLIENT", + "netmask": "255.255.255.0", + "gateway": "10.0.0.1", + } + ], + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ValidateVmClusterNetwork(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ValidateVmClusterNetwork", + arguments={ + "exadataInfrastructureId": "ocid1.exadatainfrastructure.oc1..mockexadatainfraid", + "vmClusterNetworkId": "ocid1.vmclusternetwork.oc1..mockvmclusternetworkid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListExadbVmClusters(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListExadbVmClusters", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateExadbVmCluster(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateExadbVmCluster", + arguments={ + "availabilityDomain": "Uocm:US-ASHBURN-AD-1", + "backupSubnetId": "ocid1.subnet.oc1..mockbackupsubnetid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "displayName": "Mock_Display_Name", + "enabledECpuCount": 8, + "exascaleDbStorageVaultId": "ocid1.exascaledbstoragevault.oc1..mockexascalevaultid", + "gridImageId": "ocid1.gridimage.oc1..mockgridimageid", + "hostname": "mock-host-1", + "nodeCount": 3, + "shape": "Exadata.X8M", + "sshPublicKeys": ["ssh-rsa AAAAB3Nza... mockKey1"], + "subnetId": "ocid1.subnet.oc1..mocksubnetid", + "totalECpuCount": 32, + "vmFileSystemStorage_totalSizeInGbs": 500, + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteExadbVmCluster(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteExadbVmCluster", + arguments={ + "exadbVmClusterId": "ocid1.exadbvmcluster.oc1..mockexadbvmclusterid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetExadbVmCluster(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetExadbVmCluster", + arguments={ + "exadbVmClusterId": "ocid1.exadbvmcluster.oc1..mockexadbvmclusterid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateExadbVmCluster(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateExadbVmCluster", + arguments={ + "exadbVmClusterId": "ocid1.exadbvmcluster.oc1..mockexadbvmclusterid", + "vmFileSystemStorage_totalSizeInGbs": 500, + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeExadbVmClusterCompartment(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeExadbVmClusterCompartment", + arguments={ + "exadbVmClusterId": "ocid1.exadbvmcluster.oc1..mockexadbvmclusterid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeExadbVmClusterSubscription(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeExadbVmClusterSubscription", + arguments={ + "exadbVmClusterId": "ocid1.exadbvmcluster.oc1..mockexadbvmclusterid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_RemoveVirtualMachineFromExadbVmCluster(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "RemoveVirtualMachineFromExadbVmCluster", + arguments={ + "exadbVmClusterId": "ocid1.exadbvmcluster.oc1..mockexadbvmclusterid", + "dbNodes": [ + {"id": "ocid1.dbnode.oc1..node1"}, + {"id": "ocid1.dbnode.oc1..node2"}, + ], + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListExadbVmClusterUpdateHistoryEntries(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListExadbVmClusterUpdateHistoryEntries", + arguments={ + "exadbVmClusterId": "ocid1.exadbvmcluster.oc1..mockexadbvmclusterid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetExadbVmClusterUpdateHistoryEntry(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetExadbVmClusterUpdateHistoryEntry", + arguments={ + "exadbVmClusterId": "ocid1.exadbvmcluster.oc1..mockexadbvmclusterid", + "updateHistoryEntryId": "ocid1.updatehistory.oc1..mockupdatehistoryid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListExadbVmClusterUpdates(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListExadbVmClusterUpdates", + arguments={ + "exadbVmClusterId": "ocid1.exadbvmcluster.oc1..mockexadbvmclusterid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetExadbVmClusterUpdate(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetExadbVmClusterUpdate", + arguments={ + "exadbVmClusterId": "ocid1.exadbvmcluster.oc1..mockexadbvmclusterid", + "updateId": "ocid1.update.oc1..mockupdateid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListExascaleDbStorageVaults(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListExascaleDbStorageVaults", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateExascaleDbStorageVault(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateExascaleDbStorageVault", + arguments={ + "availabilityDomain": "Uocm:US-ASHBURN-AD-1", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "displayName": "Mock_Display_Name", + "highCapacityDatabaseStorage_totalSizeInGbs": 4096, + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteExascaleDbStorageVault(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteExascaleDbStorageVault", + arguments={ + "exascaleDbStorageVaultId": "ocid1.exascaledbstoragevault.oc1..mockexascalevaultid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetExascaleDbStorageVault(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetExascaleDbStorageVault", + arguments={ + "exascaleDbStorageVaultId": "ocid1.exascaledbstoragevault.oc1..mockexascalevaultid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateExascaleDbStorageVault(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateExascaleDbStorageVault", + arguments={ + "exascaleDbStorageVaultId": "ocid1.exascaledbstoragevault.oc1..mockexascalevaultid", + "highCapacityDatabaseStorage_totalSizeInGbs": 4096, + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeExascaleDbStorageVaultCompartment(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeExascaleDbStorageVaultCompartment", + arguments={ + "exascaleDbStorageVaultId": "ocid1.exascaledbstoragevault.oc1..mockexascalevaultid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeExascaleDbStorageVaultSubscription(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeExascaleDbStorageVaultSubscription", + arguments={ + "exascaleDbStorageVaultId": "ocid1.exascaledbstoragevault.oc1..mockexascalevaultid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListExecutionActions(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListExecutionActions", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateExecutionAction(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateExecutionAction", + arguments={ + "actionType": "DB_Server_Patching", + "executionWindowId": "ocid1.executionwindow.oc1..mockexecutionwindowid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteExecutionAction(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteExecutionAction", + arguments={ + "executionActionId": "ocid1.executionaction.oc1..mockexecutionactionid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetExecutionAction(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetExecutionAction", + arguments={ + "executionActionId": "ocid1.executionaction.oc1..mockexecutionactionid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateExecutionAction(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateExecutionAction", + arguments={ + "executionActionId": "ocid1.executionaction.oc1..mockexecutionactionid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_MoveExecutionActionMember(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "MoveExecutionActionMember", + arguments={ + "executionActionId": "ocid1.executionaction.oc1..mockexecutionactionid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListExecutionWindows(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListExecutionWindows", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateExecutionWindow(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateExecutionWindow", + arguments={ + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "executionResourceId": "ocid1.executionresource.oc1..mockexecutionresourceid", + "timeScheduled": "2025-01-01T00:00:00.000Z", + "windowDurationInMins": 240, + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteExecutionWindow(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteExecutionWindow", + arguments={ + "executionWindowId": "ocid1.executionwindow.oc1..mockexecutionwindowid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetExecutionWindow(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetExecutionWindow", + arguments={ + "executionWindowId": "ocid1.executionwindow.oc1..mockexecutionwindowid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateExecutionWindow(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateExecutionWindow", + arguments={ + "executionWindowId": "ocid1.executionwindow.oc1..mockexecutionwindowid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ReorderExecutionActions(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ReorderExecutionActions", + arguments={ + "executionWindowId": "ocid1.executionwindow.oc1..mockexecutionwindowid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateExternalBackupJob(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateExternalBackupJob", + arguments={ + "availabilityDomain": "Uocm:US-ASHBURN-AD-1", + "characterSet": "AL32UTF8", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "databaseEdition": "ENTERPRISE_EDITION_EXTREME_PERFORMANCE", + "databaseMode": "READ_WRITE", + "dbName": "MOCKDB", + "dbVersion": "19.0.0.0", + "displayName": "Mock_Display_Name", + "externalDatabaseIdentifier": 1, + "ncharacterSet": "AL16UTF16", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetExternalBackupJob(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetExternalBackupJob", + arguments={"backupId": "ocid1.backup.oc1..mockbackupid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CompleteExternalBackupJob(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CompleteExternalBackupJob", + arguments={"backupId": "ocid1.backup.oc1..mockbackupid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListExternalContainerDatabases(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListExternalContainerDatabases", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateExternalContainerDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateExternalContainerDatabase", + arguments={ + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "displayName": "Mock_Display_Name", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteExternalContainerDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteExternalContainerDatabase", + arguments={ + "externalContainerDatabaseId": "ocid1.externalcontainerdatabase.oc1..mockextcdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetExternalContainerDatabase(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetExternalContainerDatabase", + arguments={ + "externalContainerDatabaseId": "ocid1.externalcontainerdatabase.oc1..mockextcdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateExternalContainerDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateExternalContainerDatabase", + arguments={ + "externalContainerDatabaseId": "ocid1.externalcontainerdatabase.oc1..mockextcdbid", + "displayName": "Mock_Display_Name", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeExternalContainerDatabaseCompartment(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeExternalContainerDatabaseCompartment", + arguments={ + "externalContainerDatabaseId": "ocid1.externalcontainerdatabase.oc1..mockextcdbid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DisableExternalContainerDatabaseDatabaseManagement(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DisableExternalContainerDatabaseDatabaseManagement", + arguments={ + "externalContainerDatabaseId": "ocid1.externalcontainerdatabase.oc1..mockextcdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DisableExternalContainerDatabaseStackMonitoring(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DisableExternalContainerDatabaseStackMonitoring", + arguments={ + "externalContainerDatabaseId": "ocid1.externalcontainerdatabase.oc1..mockextcdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_EnableExternalContainerDatabaseDatabaseManagement(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "EnableExternalContainerDatabaseDatabaseManagement", + arguments={ + "externalContainerDatabaseId": "ocid1.externalcontainerdatabase.oc1..mockextcdbid", + "externalDatabaseConnectorId": "ocid1.externaldatabaseconnector.oc1..mockextdbconnectorid", + "licenseModel": "BRING_YOUR_OWN_LICENSE", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_EnableExternalContainerDatabaseStackMonitoring(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "EnableExternalContainerDatabaseStackMonitoring", + arguments={ + "externalContainerDatabaseId": "ocid1.externalcontainerdatabase.oc1..mockextcdbid", + "externalDatabaseConnectorId": "ocid1.externaldatabaseconnector.oc1..mockextdbconnectorid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ScanExternalContainerDatabasePluggableDatabases(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ScanExternalContainerDatabasePluggableDatabases", + arguments={ + "externalContainerDatabaseId": "ocid1.externalcontainerdatabase.oc1..mockextcdbid", + "externalDatabaseConnectorId": "ocid1.externaldatabaseconnector.oc1..mockextdbconnectorid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListExternalDatabaseConnectors(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListExternalDatabaseConnectors", + arguments={ + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "externalDatabaseId": "ocid1.externaldatabase.oc1..mockexternaldatabaseid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateExternalDatabaseConnector(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateExternalDatabaseConnector", + arguments={ + "displayName": "Mock_Display_Name", + "externalDatabaseId": "ocid1.externaldatabase.oc1..mockexternaldatabaseid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteExternalDatabaseConnector(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteExternalDatabaseConnector", + arguments={ + "externalDatabaseConnectorId": "ocid1.externaldatabaseconnector.oc1..mockextdbconnectorid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetExternalDatabaseConnector(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetExternalDatabaseConnector", + arguments={ + "externalDatabaseConnectorId": "ocid1.externaldatabaseconnector.oc1..mockextdbconnectorid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateExternalDatabaseConnector(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateExternalDatabaseConnector", + arguments={ + "externalDatabaseConnectorId": "ocid1.externaldatabaseconnector.oc1..mockextdbconnectorid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CheckExternalDatabaseConnectorConnectionStatus(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CheckExternalDatabaseConnectorConnectionStatus", + arguments={ + "externalDatabaseConnectorId": "ocid1.externaldatabaseconnector.oc1..mockextdbconnectorid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListExternalNonContainerDatabases(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListExternalNonContainerDatabases", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateExternalNonContainerDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateExternalNonContainerDatabase", + arguments={ + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "displayName": "Mock_Display_Name", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteExternalNonContainerDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteExternalNonContainerDatabase", + arguments={ + "externalNonContainerDatabaseId": "ocid1.externalnoncontainerdatabase.oc1..mockextnoncdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetExternalNonContainerDatabase(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetExternalNonContainerDatabase", + arguments={ + "externalNonContainerDatabaseId": "ocid1.externalnoncontainerdatabase.oc1..mockextnoncdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateExternalNonContainerDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateExternalNonContainerDatabase", + arguments={ + "externalNonContainerDatabaseId": "ocid1.externalnoncontainerdatabase.oc1..mockextnoncdbid", + "displayName": "Mock_Display_Name", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeExternalNonContainerDatabaseCompartment(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeExternalNonContainerDatabaseCompartment", + arguments={ + "externalNonContainerDatabaseId": "ocid1.externalnoncontainerdatabase.oc1..mockextnoncdbid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DisableExternalNonContainerDatabaseDatabaseManagement(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DisableExternalNonContainerDatabaseDatabaseManagement", + arguments={ + "externalNonContainerDatabaseId": "ocid1.externalnoncontainerdatabase.oc1..mockextnoncdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DisableExternalNonContainerDatabaseOperationsInsights(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DisableExternalNonContainerDatabaseOperationsInsights", + arguments={ + "externalNonContainerDatabaseId": "ocid1.externalnoncontainerdatabase.oc1..mockextnoncdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DisableExternalNonContainerDatabaseStackMonitoring(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DisableExternalNonContainerDatabaseStackMonitoring", + arguments={ + "externalNonContainerDatabaseId": "ocid1.externalnoncontainerdatabase.oc1..mockextnoncdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_EnableExternalNonContainerDatabaseDatabaseManagement(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "EnableExternalNonContainerDatabaseDatabaseManagement", + arguments={ + "externalNonContainerDatabaseId": "ocid1.externalnoncontainerdatabase.oc1..mockextnoncdbid", + "externalDatabaseConnectorId": "ocid1.externaldatabaseconnector.oc1..mockextdbconnectorid", + "licenseModel": "BRING_YOUR_OWN_LICENSE", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_EnableExternalNonContainerDatabaseOperationsInsights(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "EnableExternalNonContainerDatabaseOperationsInsights", + arguments={ + "externalNonContainerDatabaseId": "ocid1.externalnoncontainerdatabase.oc1..mockextnoncdbid", + "externalDatabaseConnectorId": "ocid1.externaldatabaseconnector.oc1..mockextdbconnectorid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_EnableExternalNonContainerDatabaseStackMonitoring(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "EnableExternalNonContainerDatabaseStackMonitoring", + arguments={ + "externalNonContainerDatabaseId": "ocid1.externalnoncontainerdatabase.oc1..mockextnoncdbid", + "externalDatabaseConnectorId": "ocid1.externaldatabaseconnector.oc1..mockextdbconnectorid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListExternalPluggableDatabases(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListExternalPluggableDatabases", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateExternalPluggableDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateExternalPluggableDatabase", + arguments={ + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "displayName": "Mock_Display_Name", + "externalContainerDatabaseId": "ocid1.externalcontainerdatabase.oc1..mockextcdbid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteExternalPluggableDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteExternalPluggableDatabase", + arguments={ + "externalPluggableDatabaseId": "ocid1.externalpluggabledatabase.oc1..mockextpdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetExternalPluggableDatabase(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetExternalPluggableDatabase", + arguments={ + "externalPluggableDatabaseId": "ocid1.externalpluggabledatabase.oc1..mockextpdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateExternalPluggableDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateExternalPluggableDatabase", + arguments={ + "externalPluggableDatabaseId": "ocid1.externalpluggabledatabase.oc1..mockextpdbid", + "displayName": "Mock_Display_Name", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeExternalPluggableDatabaseCompartment(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeExternalPluggableDatabaseCompartment", + arguments={ + "externalPluggableDatabaseId": "ocid1.externalpluggabledatabase.oc1..mockextpdbid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DisableExternalPluggableDatabaseDatabaseManagement(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DisableExternalPluggableDatabaseDatabaseManagement", + arguments={ + "externalPluggableDatabaseId": "ocid1.externalpluggabledatabase.oc1..mockextpdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DisableExternalPluggableDatabaseOperationsInsights(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DisableExternalPluggableDatabaseOperationsInsights", + arguments={ + "externalPluggableDatabaseId": "ocid1.externalpluggabledatabase.oc1..mockextpdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DisableExternalPluggableDatabaseStackMonitoring(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DisableExternalPluggableDatabaseStackMonitoring", + arguments={ + "externalPluggableDatabaseId": "ocid1.externalpluggabledatabase.oc1..mockextpdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_EnableExternalPluggableDatabaseDatabaseManagement(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "EnableExternalPluggableDatabaseDatabaseManagement", + arguments={ + "externalPluggableDatabaseId": "ocid1.externalpluggabledatabase.oc1..mockextpdbid", + "externalDatabaseConnectorId": "ocid1.externaldatabaseconnector.oc1..mockextdbconnectorid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_EnableExternalPluggableDatabaseOperationsInsights(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "EnableExternalPluggableDatabaseOperationsInsights", + arguments={ + "externalPluggableDatabaseId": "ocid1.externalpluggabledatabase.oc1..mockextpdbid", + "externalDatabaseConnectorId": "ocid1.externaldatabaseconnector.oc1..mockextdbconnectorid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_EnableExternalPluggableDatabaseStackMonitoring(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "EnableExternalPluggableDatabaseStackMonitoring", + arguments={ + "externalPluggableDatabaseId": "ocid1.externalpluggabledatabase.oc1..mockextpdbid", + "externalDatabaseConnectorId": "ocid1.externaldatabaseconnector.oc1..mockextdbconnectorid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListGiVersions(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListGiVersions", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListGiVersionMinorVersions(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListGiVersionMinorVersions", arguments={"version": "1.0"} + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListKeyStores(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListKeyStores", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateKeyStore(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateKeyStore", + arguments={ + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "displayName": "Mock_Display_Name", + "typeDetails_type": "VM_CLUSTER", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteKeyStore(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteKeyStore", + arguments={"keyStoreId": "ocid1.keystore.oc1..mockkeystoreid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetKeyStore(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetKeyStore", + arguments={"keyStoreId": "ocid1.keystore.oc1..mockkeystoreid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateKeyStore(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateKeyStore", + arguments={ + "keyStoreId": "ocid1.keystore.oc1..mockkeystoreid", + "typeDetails_type": "VM_CLUSTER", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeKeyStoreCompartment(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeKeyStoreCompartment", + arguments={ + "keyStoreId": "ocid1.keystore.oc1..mockkeystoreid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListMaintenanceRunHistory(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListMaintenanceRunHistory", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetMaintenanceRunHistory(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetMaintenanceRunHistory", + arguments={ + "maintenanceRunHistoryId": "ocid1.maintenancerunhistory.oc1..mockmrhistoryid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListMaintenanceRuns(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListMaintenanceRuns", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateMaintenanceRun(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateMaintenanceRun", + arguments={ + "patchType": "GI", + "targetResourceId": "ocid1.resource.oc1..mocktargetresourceid", + "timeScheduled": "2025-01-01T00:00:00.000Z", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetMaintenanceRun(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetMaintenanceRun", + arguments={"maintenanceRunId": "ocid1.maintenancerun.oc1..mockmrid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateMaintenanceRun(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateMaintenanceRun", + arguments={"maintenanceRunId": "ocid1.maintenancerun.oc1..mockmrid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListOneoffPatches(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListOneoffPatches", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateOneoffPatch(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateOneoffPatch", + arguments={ + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "dbVersion": "19.0.0.0", + "displayName": "Mock_Display_Name", + "releaseUpdate": "19.15", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteOneoffPatch(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteOneoffPatch", + arguments={"oneoffPatchId": "ocid1.oneoffpatch.oc1..mockoneoffpatchid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetOneoffPatch(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetOneoffPatch", + arguments={"oneoffPatchId": "ocid1.oneoffpatch.oc1..mockoneoffpatchid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateOneoffPatch(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateOneoffPatch", + arguments={"oneoffPatchId": "ocid1.oneoffpatch.oc1..mockoneoffpatchid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeOneoffPatchCompartment(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeOneoffPatchCompartment", + arguments={ + "oneoffPatchId": "ocid1.oneoffpatch.oc1..mockoneoffpatchid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DownloadOneoffPatch(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DownloadOneoffPatch", + arguments={"oneoffPatchId": "ocid1.oneoffpatch.oc1..mockoneoffpatchid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListPluggableDatabases(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool("ListPluggableDatabases", arguments={}) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreatePluggableDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreatePluggableDatabase", + arguments={ + "containerDatabaseId": "ocid1.database.oc1..mockcontainerdatabaseid", + "pdbCreationTypeDetails_creationType": "LOCAL_CLONE", + "pdbName": "PDB1", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeletePluggableDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeletePluggableDatabase", + arguments={"pluggableDatabaseId": "ocid1.pluggabledatabase.oc1..mockpdbid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetPluggableDatabase(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetPluggableDatabase", + arguments={"pluggableDatabaseId": "ocid1.pluggabledatabase.oc1..mockpdbid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdatePluggableDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdatePluggableDatabase", + arguments={"pluggableDatabaseId": "ocid1.pluggabledatabase.oc1..mockpdbid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ConvertToRegularPluggableDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ConvertToRegularPluggableDatabase", + arguments={"pluggableDatabaseId": "ocid1.pluggabledatabase.oc1..mockpdbid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_RefreshPluggableDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "RefreshPluggableDatabase", + arguments={"pluggableDatabaseId": "ocid1.pluggabledatabase.oc1..mockpdbid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_StartPluggableDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "StartPluggableDatabase", + arguments={"pluggableDatabaseId": "ocid1.pluggabledatabase.oc1..mockpdbid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_StopPluggableDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "StopPluggableDatabase", + arguments={"pluggableDatabaseId": "ocid1.pluggabledatabase.oc1..mockpdbid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetResourcePrincipalToken(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetResourcePrincipalToken", + arguments={"instanceId": "ocid1.instance.oc1..mockinstanceid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListParamsForActionType(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListParamsForActionType", arguments={"type": "FULL"} + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListScheduledActions(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListScheduledActions", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateScheduledAction(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateScheduledAction", + arguments={ + "actionOrder": [1], + "actionType": "DB_Server_Patching", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "schedulingPlanId": "ocid1.schedulingplan.oc1..mockschedulingplanid", + "schedulingWindowId": "ocid1.schedulingwindow.oc1..mockschedulingwindowid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteScheduledAction(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteScheduledAction", + arguments={ + "scheduledActionId": "ocid1.scheduledaction.oc1..mockscheduledactionid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetScheduledAction(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetScheduledAction", + arguments={ + "scheduledActionId": "ocid1.scheduledaction.oc1..mockscheduledactionid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateScheduledAction(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateScheduledAction", + arguments={ + "scheduledActionId": "ocid1.scheduledaction.oc1..mockscheduledactionid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListSchedulingPlans(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListSchedulingPlans", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateSchedulingPlan(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateSchedulingPlan", + arguments={ + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "resourceId": "ocid1.resource.oc1..mockresourceid", + "schedulingPolicyId": "ocid1.schedulingpolicy.oc1..mockschedulingpolicyid", + "serviceType": "EXADATA", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteSchedulingPlan(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteSchedulingPlan", + arguments={ + "schedulingPlanId": "ocid1.schedulingplan.oc1..mockschedulingplanid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetSchedulingPlan(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetSchedulingPlan", + arguments={ + "schedulingPlanId": "ocid1.schedulingplan.oc1..mockschedulingplanid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeSchedulingPlanCompartment(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeSchedulingPlanCompartment", + arguments={ + "schedulingPlanId": "ocid1.schedulingplan.oc1..mockschedulingplanid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ReorderScheduledActions(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ReorderScheduledActions", + arguments={ + "schedulingPlanId": "ocid1.schedulingplan.oc1..mockschedulingplanid", + "scheduledActionIdOrders": [ + {"actionId": "ocid1.scheduledaction.oc1..id1", "order": 1} + ], + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListSchedulingPolicies(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListSchedulingPolicies", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateSchedulingPolicy(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateSchedulingPolicy", + arguments={ + "cadence": "MONTHLY", + "cadenceStartMonth_name": "JANUARY", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "displayName": "Mock_Display_Name", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteSchedulingPolicy(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteSchedulingPolicy", + arguments={ + "schedulingPolicyId": "ocid1.schedulingpolicy.oc1..mockschedulingpolicyid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetSchedulingPolicy(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetSchedulingPolicy", + arguments={ + "schedulingPolicyId": "ocid1.schedulingpolicy.oc1..mockschedulingpolicyid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateSchedulingPolicy(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateSchedulingPolicy", + arguments={ + "schedulingPolicyId": "ocid1.schedulingpolicy.oc1..mockschedulingpolicyid", + "cadenceStartMonth_name": "JANUARY", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeSchedulingPolicyCompartment(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeSchedulingPolicyCompartment", + arguments={ + "schedulingPolicyId": "ocid1.schedulingpolicy.oc1..mockschedulingpolicyid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListRecommendedScheduledActions(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListRecommendedScheduledActions", + arguments={ + "schedulingPolicyId": "ocid1.schedulingpolicy.oc1..mockschedulingpolicyid", + "schedulingPolicyTargetResourceId": "ocid1.resource.oc1..mockpolicytargetid", + "planIntent": "EXADATA", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListSchedulingWindows(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListSchedulingWindows", + arguments={ + "schedulingPolicyId": "ocid1.schedulingpolicy.oc1..mockschedulingpolicyid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateSchedulingWindow(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateSchedulingWindow", + arguments={ + "schedulingPolicyId": "ocid1.schedulingpolicy.oc1..mockschedulingpolicyid", + "windowPreference_daysOfWeek": [{"name": "SUNDAY"}], + "windowPreference_duration": 4, + "windowPreference_isEnforcedDuration": True, + "windowPreference_startTime": "02:00", + "windowPreference_weeksOfMonth": [1, 3], + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteSchedulingWindow(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteSchedulingWindow", + arguments={ + "schedulingPolicyId": "ocid1.schedulingpolicy.oc1..mockschedulingpolicyid", + "schedulingWindowId": "ocid1.schedulingwindow.oc1..mockschedulingwindowid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetSchedulingWindow(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetSchedulingWindow", + arguments={ + "schedulingPolicyId": "ocid1.schedulingpolicy.oc1..mockschedulingpolicyid", + "schedulingWindowId": "ocid1.schedulingwindow.oc1..mockschedulingwindowid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateSchedulingWindow(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateSchedulingWindow", + arguments={ + "schedulingPolicyId": "ocid1.schedulingpolicy.oc1..mockschedulingpolicyid", + "schedulingWindowId": "ocid1.schedulingwindow.oc1..mockschedulingwindowid", + "windowPreference_daysOfWeek": [{"name": "SUNDAY"}], + "windowPreference_duration": 4, + "windowPreference_isEnforcedDuration": True, + "windowPreference_startTime": "02:00", + "windowPreference_weeksOfMonth": [1, 3], + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListSystemVersions(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListSystemVersions", + arguments={ + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "shape": "Exadata.X8M", + "giVersion": "19.0.0.0", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListVmClusters(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListVmClusters", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateVmCluster(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateVmCluster", + arguments={ + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "cpuCoreCount": 16, + "displayName": "Mock_Display_Name", + "exadataInfrastructureId": "ocid1.exadatainfrastructure.oc1..mockexadatainfraid", + "giVersion": "19.0.0.0", + "sshPublicKeys": ["ssh-rsa AAAAB3Nza... mockKey1"], + "vmClusterNetworkId": "ocid1.vmclusternetwork.oc1..mockvmclusternetworkid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteVmCluster(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteVmCluster", + arguments={"vmClusterId": "ocid1.vmcluster.oc1..mockvmclusterid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetVmCluster(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetVmCluster", + arguments={"vmClusterId": "ocid1.vmcluster.oc1..mockvmclusterid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateVmCluster(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateVmCluster", + arguments={"vmClusterId": "ocid1.vmcluster.oc1..mockvmclusterid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_AddVirtualMachineToVmCluster(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "AddVirtualMachineToVmCluster", + arguments={ + "vmClusterId": "ocid1.vmcluster.oc1..mockvmclusterid", + "dbServers": [ + "ocid1.dbserver.oc1..server1", + "ocid1.dbserver.oc1..server2", + ], + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeVmClusterCompartment(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeVmClusterCompartment", + arguments={ + "vmClusterId": "ocid1.vmcluster.oc1..mockvmclusterid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_RemoveVirtualMachineFromVmCluster(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "RemoveVirtualMachineFromVmCluster", + arguments={ + "vmClusterId": "ocid1.vmcluster.oc1..mockvmclusterid", + "dbServers": [ + "ocid1.dbserver.oc1..server1", + "ocid1.dbserver.oc1..server2", + ], + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListVmClusterPatchHistoryEntries(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListVmClusterPatchHistoryEntries", + arguments={"vmClusterId": "ocid1.vmcluster.oc1..mockvmclusterid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetVmClusterPatchHistoryEntry(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetVmClusterPatchHistoryEntry", + arguments={ + "vmClusterId": "ocid1.vmcluster.oc1..mockvmclusterid", + "patchHistoryEntryId": "ocid1.patchhistory.oc1..mockpatchhistoryid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListVmClusterPatches(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListVmClusterPatches", + arguments={"vmClusterId": "ocid1.vmcluster.oc1..mockvmclusterid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetVmClusterPatch(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetVmClusterPatch", + arguments={ + "vmClusterId": "ocid1.vmcluster.oc1..mockvmclusterid", + "patchId": "ocid1.patch.oc1..mockpatchid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListVmClusterUpdateHistoryEntries(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListVmClusterUpdateHistoryEntries", + arguments={"vmClusterId": "ocid1.vmcluster.oc1..mockvmclusterid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetVmClusterUpdateHistoryEntry(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetVmClusterUpdateHistoryEntry", + arguments={ + "vmClusterId": "ocid1.vmcluster.oc1..mockvmclusterid", + "updateHistoryEntryId": "ocid1.updatehistory.oc1..mockupdatehistoryid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListVmClusterUpdates(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListVmClusterUpdates", + arguments={"vmClusterId": "ocid1.vmcluster.oc1..mockvmclusterid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetVmClusterUpdate(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetVmClusterUpdate", + arguments={ + "vmClusterId": "ocid1.vmcluster.oc1..mockvmclusterid", + "updateId": "ocid1.update.oc1..mockupdateid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() diff --git a/src/oci-db-dynamic-mcp-server/pyproject.toml b/src/oci-db-dynamic-mcp-server/pyproject.toml new file mode 100644 index 00000000..acdc96b1 --- /dev/null +++ b/src/oci-db-dynamic-mcp-server/pyproject.toml @@ -0,0 +1,40 @@ +[project] +name = "oracle.oci-db-dynamic-mcp-server" +version = "1.0.1" +description = "OCI Database Service Dynamic MCP server" +readme = "README.md" +requires-python = ">=3.13" +license = "UPL-1.0" +license-files = ["LICENSE.txt"] +authors = [ + {name = "Oracle MCP", email = "237432095+oracle-mcp@users.noreply.github.com"}, +] +dependencies = [ + "fastmcp==2.12.2", + "oci==2.160.0", + "mcp>=1.0.0", + "requests", +] + +classifiers = [ + "License :: OSI Approved :: Universal Permissive License (UPL)", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3.13", +] + +[project.scripts] +"oracle.oci-db-dynamic-mcp-server" = "oracle.oci_db_dynamic_mcp_server.server:main" + +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[tool.hatch.build.targets.wheel] +packages = ["oracle"] + +[dependency-groups] +dev = [ + "pytest>=8.4.2", + "pytest-asyncio>=1.2.0", +] diff --git a/src/oci-db-dynamic-mcp-server/uv.lock b/src/oci-db-dynamic-mcp-server/uv.lock new file mode 100644 index 00000000..9ba159fb --- /dev/null +++ b/src/oci-db-dynamic-mcp-server/uv.lock @@ -0,0 +1,1075 @@ +version = 1 +revision = 3 +requires-python = ">=3.13" + +[[package]] +name = "annotated-types" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, +] + +[[package]] +name = "anyio" +version = "4.10.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "sniffio" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f1/b4/636b3b65173d3ce9a38ef5f0522789614e590dab6a8d505340a4efe4c567/anyio-4.10.0.tar.gz", hash = "sha256:3f3fae35c96039744587aa5b8371e7e8e603c0702999535961dd336026973ba6", size = 213252, upload-time = "2025-08-04T08:54:26.451Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6f/12/e5e0282d673bb9746bacfb6e2dba8719989d3660cdb2ea79aee9a9651afb/anyio-4.10.0-py3-none-any.whl", hash = "sha256:60e474ac86736bbfd6f210f7a61218939c318f43f9972497381f1c5e930ed3d1", size = 107213, upload-time = "2025-08-04T08:54:24.882Z" }, +] + +[[package]] +name = "attrs" +version = "25.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/1367933a8532ee6ff8d63537de4f1177af4bff9f3e829baf7331f595bb24/attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b", size = 812032, upload-time = "2025-03-13T11:10:22.779Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", size = 63815, upload-time = "2025-03-13T11:10:21.14Z" }, +] + +[[package]] +name = "authlib" +version = "1.6.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cryptography" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ce/bb/73a1f1c64ee527877f64122422dafe5b87a846ccf4ac933fe21bcbb8fee8/authlib-1.6.4.tar.gz", hash = "sha256:104b0442a43061dc8bc23b133d1d06a2b0a9c2e3e33f34c4338929e816287649", size = 164046, upload-time = "2025-09-17T09:59:23.897Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0e/aa/91355b5f539caf1b94f0e66ff1e4ee39373b757fce08204981f7829ede51/authlib-1.6.4-py2.py3-none-any.whl", hash = "sha256:39313d2a2caac3ecf6d8f95fbebdfd30ae6ea6ae6a6db794d976405fdd9aa796", size = 243076, upload-time = "2025-09-17T09:59:22.259Z" }, +] + +[[package]] +name = "certifi" +version = "2025.8.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/dc/67/960ebe6bf230a96cda2e0abcf73af550ec4f090005363542f0765df162e0/certifi-2025.8.3.tar.gz", hash = "sha256:e564105f78ded564e3ae7c923924435e1daa7463faeab5bb932bc53ffae63407", size = 162386, upload-time = "2025-08-03T03:07:47.08Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/48/1549795ba7742c948d2ad169c1c8cdbae65bc450d6cd753d124b17c8cd32/certifi-2025.8.3-py3-none-any.whl", hash = "sha256:f6c12493cfb1b06ba2ff328595af9350c65d6644968e5d3a2ffd78699af217a5", size = 161216, upload-time = "2025-08-03T03:07:45.777Z" }, +] + +[[package]] +name = "cffi" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser", marker = "implementation_name != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" }, + { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" }, + { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" }, + { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" }, + { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" }, + { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" }, + { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" }, + { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" }, + { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" }, + { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" }, + { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" }, + { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" }, + { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" }, + { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" }, + { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" }, + { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" }, + { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" }, + { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" }, + { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" }, + { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" }, + { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" }, + { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" }, + { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" }, + { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" }, + { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" }, + { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" }, + { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" }, + { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" }, + { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" }, + { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" }, + { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" }, + { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" }, + { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" }, + { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/83/2d/5fd176ceb9b2fc619e63405525573493ca23441330fcdaee6bef9460e924/charset_normalizer-3.4.3.tar.gz", hash = "sha256:6fce4b8500244f6fcb71465d4a4930d132ba9ab8e71a7859e6a5d59851068d14", size = 122371, upload-time = "2025-08-09T07:57:28.46Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/65/ca/2135ac97709b400c7654b4b764daf5c5567c2da45a30cdd20f9eefe2d658/charset_normalizer-3.4.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:14c2a87c65b351109f6abfc424cab3927b3bdece6f706e4d12faaf3d52ee5efe", size = 205326, upload-time = "2025-08-09T07:56:24.721Z" }, + { url = "https://files.pythonhosted.org/packages/71/11/98a04c3c97dd34e49c7d247083af03645ca3730809a5509443f3c37f7c99/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41d1fc408ff5fdfb910200ec0e74abc40387bccb3252f3f27c0676731df2b2c8", size = 146008, upload-time = "2025-08-09T07:56:26.004Z" }, + { url = "https://files.pythonhosted.org/packages/60/f5/4659a4cb3c4ec146bec80c32d8bb16033752574c20b1252ee842a95d1a1e/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1bb60174149316da1c35fa5233681f7c0f9f514509b8e399ab70fea5f17e45c9", size = 159196, upload-time = "2025-08-09T07:56:27.25Z" }, + { url = "https://files.pythonhosted.org/packages/86/9e/f552f7a00611f168b9a5865a1414179b2c6de8235a4fa40189f6f79a1753/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:30d006f98569de3459c2fc1f2acde170b7b2bd265dc1943e87e1a4efe1b67c31", size = 156819, upload-time = "2025-08-09T07:56:28.515Z" }, + { url = "https://files.pythonhosted.org/packages/7e/95/42aa2156235cbc8fa61208aded06ef46111c4d3f0de233107b3f38631803/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:416175faf02e4b0810f1f38bcb54682878a4af94059a1cd63b8747244420801f", size = 151350, upload-time = "2025-08-09T07:56:29.716Z" }, + { url = "https://files.pythonhosted.org/packages/c2/a9/3865b02c56f300a6f94fc631ef54f0a8a29da74fb45a773dfd3dcd380af7/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6aab0f181c486f973bc7262a97f5aca3ee7e1437011ef0c2ec04b5a11d16c927", size = 148644, upload-time = "2025-08-09T07:56:30.984Z" }, + { url = "https://files.pythonhosted.org/packages/77/d9/cbcf1a2a5c7d7856f11e7ac2d782aec12bdfea60d104e60e0aa1c97849dc/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabf8315679312cfa71302f9bd509ded4f2f263fb5b765cf1433b39106c3cc9", size = 160468, upload-time = "2025-08-09T07:56:32.252Z" }, + { url = "https://files.pythonhosted.org/packages/f6/42/6f45efee8697b89fda4d50580f292b8f7f9306cb2971d4b53f8914e4d890/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:bd28b817ea8c70215401f657edef3a8aa83c29d447fb0b622c35403780ba11d5", size = 158187, upload-time = "2025-08-09T07:56:33.481Z" }, + { url = "https://files.pythonhosted.org/packages/70/99/f1c3bdcfaa9c45b3ce96f70b14f070411366fa19549c1d4832c935d8e2c3/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:18343b2d246dc6761a249ba1fb13f9ee9a2bcd95decc767319506056ea4ad4dc", size = 152699, upload-time = "2025-08-09T07:56:34.739Z" }, + { url = "https://files.pythonhosted.org/packages/a3/ad/b0081f2f99a4b194bcbb1934ef3b12aa4d9702ced80a37026b7607c72e58/charset_normalizer-3.4.3-cp313-cp313-win32.whl", hash = "sha256:6fb70de56f1859a3f71261cbe41005f56a7842cc348d3aeb26237560bfa5e0ce", size = 99580, upload-time = "2025-08-09T07:56:35.981Z" }, + { url = "https://files.pythonhosted.org/packages/9a/8f/ae790790c7b64f925e5c953b924aaa42a243fb778fed9e41f147b2a5715a/charset_normalizer-3.4.3-cp313-cp313-win_amd64.whl", hash = "sha256:cf1ebb7d78e1ad8ec2a8c4732c7be2e736f6e5123a4146c5b89c9d1f585f8cef", size = 107366, upload-time = "2025-08-09T07:56:37.339Z" }, + { url = "https://files.pythonhosted.org/packages/8e/91/b5a06ad970ddc7a0e513112d40113e834638f4ca1120eb727a249fb2715e/charset_normalizer-3.4.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3cd35b7e8aedeb9e34c41385fda4f73ba609e561faedfae0a9e75e44ac558a15", size = 204342, upload-time = "2025-08-09T07:56:38.687Z" }, + { url = "https://files.pythonhosted.org/packages/ce/ec/1edc30a377f0a02689342f214455c3f6c2fbedd896a1d2f856c002fc3062/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b89bc04de1d83006373429975f8ef9e7932534b8cc9ca582e4db7d20d91816db", size = 145995, upload-time = "2025-08-09T07:56:40.048Z" }, + { url = "https://files.pythonhosted.org/packages/17/e5/5e67ab85e6d22b04641acb5399c8684f4d37caf7558a53859f0283a650e9/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2001a39612b241dae17b4687898843f254f8748b796a2e16f1051a17078d991d", size = 158640, upload-time = "2025-08-09T07:56:41.311Z" }, + { url = "https://files.pythonhosted.org/packages/f1/e5/38421987f6c697ee3722981289d554957c4be652f963d71c5e46a262e135/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8dcfc373f888e4fb39a7bc57e93e3b845e7f462dacc008d9749568b1c4ece096", size = 156636, upload-time = "2025-08-09T07:56:43.195Z" }, + { url = "https://files.pythonhosted.org/packages/a0/e4/5a075de8daa3ec0745a9a3b54467e0c2967daaaf2cec04c845f73493e9a1/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18b97b8404387b96cdbd30ad660f6407799126d26a39ca65729162fd810a99aa", size = 150939, upload-time = "2025-08-09T07:56:44.819Z" }, + { url = "https://files.pythonhosted.org/packages/02/f7/3611b32318b30974131db62b4043f335861d4d9b49adc6d57c1149cc49d4/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ccf600859c183d70eb47e05a44cd80a4ce77394d1ac0f79dbd2dd90a69a3a049", size = 148580, upload-time = "2025-08-09T07:56:46.684Z" }, + { url = "https://files.pythonhosted.org/packages/7e/61/19b36f4bd67f2793ab6a99b979b4e4f3d8fc754cbdffb805335df4337126/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:53cd68b185d98dde4ad8990e56a58dea83a4162161b1ea9272e5c9182ce415e0", size = 159870, upload-time = "2025-08-09T07:56:47.941Z" }, + { url = "https://files.pythonhosted.org/packages/06/57/84722eefdd338c04cf3030ada66889298eaedf3e7a30a624201e0cbe424a/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:30a96e1e1f865f78b030d65241c1ee850cdf422d869e9028e2fc1d5e4db73b92", size = 157797, upload-time = "2025-08-09T07:56:49.756Z" }, + { url = "https://files.pythonhosted.org/packages/72/2a/aff5dd112b2f14bcc3462c312dce5445806bfc8ab3a7328555da95330e4b/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d716a916938e03231e86e43782ca7878fb602a125a91e7acb8b5112e2e96ac16", size = 152224, upload-time = "2025-08-09T07:56:51.369Z" }, + { url = "https://files.pythonhosted.org/packages/b7/8c/9839225320046ed279c6e839d51f028342eb77c91c89b8ef2549f951f3ec/charset_normalizer-3.4.3-cp314-cp314-win32.whl", hash = "sha256:c6dbd0ccdda3a2ba7c2ecd9d77b37f3b5831687d8dc1b6ca5f56a4880cc7b7ce", size = 100086, upload-time = "2025-08-09T07:56:52.722Z" }, + { url = "https://files.pythonhosted.org/packages/ee/7a/36fbcf646e41f710ce0a563c1c9a343c6edf9be80786edeb15b6f62e17db/charset_normalizer-3.4.3-cp314-cp314-win_amd64.whl", hash = "sha256:73dc19b562516fc9bcf6e5d6e596df0b4eb98d87e4f79f3ae71840e6ed21361c", size = 107400, upload-time = "2025-08-09T07:56:55.172Z" }, + { url = "https://files.pythonhosted.org/packages/8a/1f/f041989e93b001bc4e44bb1669ccdcf54d3f00e628229a85b08d330615c5/charset_normalizer-3.4.3-py3-none-any.whl", hash = "sha256:ce571ab16d890d23b5c278547ba694193a45011ff86a9162a71307ed9f86759a", size = 53175, upload-time = "2025-08-09T07:57:26.864Z" }, +] + +[[package]] +name = "circuitbreaker" +version = "2.1.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/df/ac/de7a92c4ed39cba31fe5ad9203b76a25ca67c530797f6bb420fff5f65ccb/circuitbreaker-2.1.3.tar.gz", hash = "sha256:1a4baee510f7bea3c91b194dcce7c07805fe96c4423ed5594b75af438531d084", size = 10787, upload-time = "2025-03-31T08:12:08.963Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ae/34/15f08edd4628f65217de1fc3c1a27c82e46fe357d60c217fc9881e12ebcc/circuitbreaker-2.1.3-py3-none-any.whl", hash = "sha256:87ba6a3ed03fdc7032bc175561c2b04d52ade9d5faf94ca2b035fbdc5e6b1dd1", size = 7737, upload-time = "2025-03-31T08:12:07.802Z" }, +] + +[[package]] +name = "click" +version = "8.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/46/61/de6cd827efad202d7057d93e0fed9294b96952e188f7384832791c7b2254/click-8.3.0.tar.gz", hash = "sha256:e7b8232224eba16f4ebe410c25ced9f7875cb5f3263ffc93cc3e8da705e229c4", size = 276943, upload-time = "2025-09-18T17:32:23.696Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/d3/9dcc0f5797f070ec8edf30fbadfb200e71d9db6b84d211e3b2085a7589a0/click-8.3.0-py3-none-any.whl", hash = "sha256:9b9f285302c6e3064f4330c05f05b81945b2a39544279343e6e7c5f27a9baddc", size = 107295, upload-time = "2025-09-18T17:32:22.42Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "cryptography" +version = "44.0.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/53/d6/1411ab4d6108ab167d06254c5be517681f1e331f90edf1379895bcb87020/cryptography-44.0.3.tar.gz", hash = "sha256:fe19d8bc5536a91a24a8133328880a41831b6c5df54599a8417b62fe015d3053", size = 711096, upload-time = "2025-05-02T19:36:04.667Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/08/53/c776d80e9d26441bb3868457909b4e74dd9ccabd182e10b2b0ae7a07e265/cryptography-44.0.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:962bc30480a08d133e631e8dfd4783ab71cc9e33d5d7c1e192f0b7c06397bb88", size = 6670281, upload-time = "2025-05-02T19:34:50.665Z" }, + { url = "https://files.pythonhosted.org/packages/6a/06/af2cf8d56ef87c77319e9086601bef621bedf40f6f59069e1b6d1ec498c5/cryptography-44.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ffc61e8f3bf5b60346d89cd3d37231019c17a081208dfbbd6e1605ba03fa137", size = 3959305, upload-time = "2025-05-02T19:34:53.042Z" }, + { url = "https://files.pythonhosted.org/packages/ae/01/80de3bec64627207d030f47bf3536889efee8913cd363e78ca9a09b13c8e/cryptography-44.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58968d331425a6f9eedcee087f77fd3c927c88f55368f43ff7e0a19891f2642c", size = 4171040, upload-time = "2025-05-02T19:34:54.675Z" }, + { url = "https://files.pythonhosted.org/packages/bd/48/bb16b7541d207a19d9ae8b541c70037a05e473ddc72ccb1386524d4f023c/cryptography-44.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:e28d62e59a4dbd1d22e747f57d4f00c459af22181f0b2f787ea83f5a876d7c76", size = 3963411, upload-time = "2025-05-02T19:34:56.61Z" }, + { url = "https://files.pythonhosted.org/packages/42/b2/7d31f2af5591d217d71d37d044ef5412945a8a8e98d5a2a8ae4fd9cd4489/cryptography-44.0.3-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:af653022a0c25ef2e3ffb2c673a50e5a0d02fecc41608f4954176f1933b12359", size = 3689263, upload-time = "2025-05-02T19:34:58.591Z" }, + { url = "https://files.pythonhosted.org/packages/25/50/c0dfb9d87ae88ccc01aad8eb93e23cfbcea6a6a106a9b63a7b14c1f93c75/cryptography-44.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:157f1f3b8d941c2bd8f3ffee0af9b049c9665c39d3da9db2dc338feca5e98a43", size = 4196198, upload-time = "2025-05-02T19:35:00.988Z" }, + { url = "https://files.pythonhosted.org/packages/66/c9/55c6b8794a74da652690c898cb43906310a3e4e4f6ee0b5f8b3b3e70c441/cryptography-44.0.3-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:c6cd67722619e4d55fdb42ead64ed8843d64638e9c07f4011163e46bc512cf01", size = 3966502, upload-time = "2025-05-02T19:35:03.091Z" }, + { url = "https://files.pythonhosted.org/packages/b6/f7/7cb5488c682ca59a02a32ec5f975074084db4c983f849d47b7b67cc8697a/cryptography-44.0.3-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:b424563394c369a804ecbee9b06dfb34997f19d00b3518e39f83a5642618397d", size = 4196173, upload-time = "2025-05-02T19:35:05.018Z" }, + { url = "https://files.pythonhosted.org/packages/d2/0b/2f789a8403ae089b0b121f8f54f4a3e5228df756e2146efdf4a09a3d5083/cryptography-44.0.3-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c91fc8e8fd78af553f98bc7f2a1d8db977334e4eea302a4bfd75b9461c2d8904", size = 4087713, upload-time = "2025-05-02T19:35:07.187Z" }, + { url = "https://files.pythonhosted.org/packages/1d/aa/330c13655f1af398fc154089295cf259252f0ba5df93b4bc9d9c7d7f843e/cryptography-44.0.3-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:25cd194c39fa5a0aa4169125ee27d1172097857b27109a45fadc59653ec06f44", size = 4299064, upload-time = "2025-05-02T19:35:08.879Z" }, + { url = "https://files.pythonhosted.org/packages/10/a8/8c540a421b44fd267a7d58a1fd5f072a552d72204a3f08194f98889de76d/cryptography-44.0.3-cp37-abi3-win32.whl", hash = "sha256:3be3f649d91cb182c3a6bd336de8b61a0a71965bd13d1a04a0e15b39c3d5809d", size = 2773887, upload-time = "2025-05-02T19:35:10.41Z" }, + { url = "https://files.pythonhosted.org/packages/b9/0d/c4b1657c39ead18d76bbd122da86bd95bdc4095413460d09544000a17d56/cryptography-44.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:3883076d5c4cc56dbef0b898a74eb6992fdac29a7b9013870b34efe4ddb39a0d", size = 3209737, upload-time = "2025-05-02T19:35:12.12Z" }, + { url = "https://files.pythonhosted.org/packages/34/a3/ad08e0bcc34ad436013458d7528e83ac29910943cea42ad7dd4141a27bbb/cryptography-44.0.3-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:5639c2b16764c6f76eedf722dbad9a0914960d3489c0cc38694ddf9464f1bb2f", size = 6673501, upload-time = "2025-05-02T19:35:13.775Z" }, + { url = "https://files.pythonhosted.org/packages/b1/f0/7491d44bba8d28b464a5bc8cc709f25a51e3eac54c0a4444cf2473a57c37/cryptography-44.0.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3ffef566ac88f75967d7abd852ed5f182da252d23fac11b4766da3957766759", size = 3960307, upload-time = "2025-05-02T19:35:15.917Z" }, + { url = "https://files.pythonhosted.org/packages/f7/c8/e5c5d0e1364d3346a5747cdcd7ecbb23ca87e6dea4f942a44e88be349f06/cryptography-44.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:192ed30fac1728f7587c6f4613c29c584abdc565d7417c13904708db10206645", size = 4170876, upload-time = "2025-05-02T19:35:18.138Z" }, + { url = "https://files.pythonhosted.org/packages/73/96/025cb26fc351d8c7d3a1c44e20cf9a01e9f7cf740353c9c7a17072e4b264/cryptography-44.0.3-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:7d5fe7195c27c32a64955740b949070f21cba664604291c298518d2e255931d2", size = 3964127, upload-time = "2025-05-02T19:35:19.864Z" }, + { url = "https://files.pythonhosted.org/packages/01/44/eb6522db7d9f84e8833ba3bf63313f8e257729cf3a8917379473fcfd6601/cryptography-44.0.3-cp39-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3f07943aa4d7dad689e3bb1638ddc4944cc5e0921e3c227486daae0e31a05e54", size = 3689164, upload-time = "2025-05-02T19:35:21.449Z" }, + { url = "https://files.pythonhosted.org/packages/68/fb/d61a4defd0d6cee20b1b8a1ea8f5e25007e26aeb413ca53835f0cae2bcd1/cryptography-44.0.3-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:cb90f60e03d563ca2445099edf605c16ed1d5b15182d21831f58460c48bffb93", size = 4198081, upload-time = "2025-05-02T19:35:23.187Z" }, + { url = "https://files.pythonhosted.org/packages/1b/50/457f6911d36432a8811c3ab8bd5a6090e8d18ce655c22820994913dd06ea/cryptography-44.0.3-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:ab0b005721cc0039e885ac3503825661bd9810b15d4f374e473f8c89b7d5460c", size = 3967716, upload-time = "2025-05-02T19:35:25.426Z" }, + { url = "https://files.pythonhosted.org/packages/35/6e/dca39d553075980ccb631955c47b93d87d27f3596da8d48b1ae81463d915/cryptography-44.0.3-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:3bb0847e6363c037df8f6ede57d88eaf3410ca2267fb12275370a76f85786a6f", size = 4197398, upload-time = "2025-05-02T19:35:27.678Z" }, + { url = "https://files.pythonhosted.org/packages/9b/9d/d1f2fe681eabc682067c66a74addd46c887ebacf39038ba01f8860338d3d/cryptography-44.0.3-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:b0cc66c74c797e1db750aaa842ad5b8b78e14805a9b5d1348dc603612d3e3ff5", size = 4087900, upload-time = "2025-05-02T19:35:29.312Z" }, + { url = "https://files.pythonhosted.org/packages/c4/f5/3599e48c5464580b73b236aafb20973b953cd2e7b44c7c2533de1d888446/cryptography-44.0.3-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6866df152b581f9429020320e5eb9794c8780e90f7ccb021940d7f50ee00ae0b", size = 4301067, upload-time = "2025-05-02T19:35:31.547Z" }, + { url = "https://files.pythonhosted.org/packages/a7/6c/d2c48c8137eb39d0c193274db5c04a75dab20d2f7c3f81a7dcc3a8897701/cryptography-44.0.3-cp39-abi3-win32.whl", hash = "sha256:c138abae3a12a94c75c10499f1cbae81294a6f983b3af066390adee73f433028", size = 2775467, upload-time = "2025-05-02T19:35:33.805Z" }, + { url = "https://files.pythonhosted.org/packages/c9/ad/51f212198681ea7b0deaaf8846ee10af99fba4e894f67b353524eab2bbe5/cryptography-44.0.3-cp39-abi3-win_amd64.whl", hash = "sha256:5d186f32e52e66994dce4f766884bcb9c68b8da62d61d9d215bfe5fb56d21334", size = 3210375, upload-time = "2025-05-02T19:35:35.369Z" }, +] + +[[package]] +name = "cyclopts" +version = "3.24.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "docstring-parser", marker = "python_full_version < '4'" }, + { name = "rich" }, + { name = "rich-rst" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/30/ca/7782da3b03242d5f0a16c20371dff99d4bd1fedafe26bc48ff82e42be8c9/cyclopts-3.24.0.tar.gz", hash = "sha256:de6964a041dfb3c57bf043b41e68c43548227a17de1bad246e3a0bfc5c4b7417", size = 76131, upload-time = "2025-09-08T15:40:57.75Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f0/8b/2c95f0645c6f40211896375e6fa51f504b8ccb29c21f6ae661fe87ab044e/cyclopts-3.24.0-py3-none-any.whl", hash = "sha256:809d04cde9108617106091140c3964ee6fceb33cecdd537f7ffa360bde13ed71", size = 86154, upload-time = "2025-09-08T15:40:56.41Z" }, +] + +[[package]] +name = "dnspython" +version = "2.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8c/8b/57666417c0f90f08bcafa776861060426765fdb422eb10212086fb811d26/dnspython-2.8.0.tar.gz", hash = "sha256:181d3c6996452cb1189c4046c61599b84a5a86e099562ffde77d26984ff26d0f", size = 368251, upload-time = "2025-09-07T18:58:00.022Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", size = 331094, upload-time = "2025-09-07T18:57:58.071Z" }, +] + +[[package]] +name = "docstring-parser" +version = "0.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/9d/c3b43da9515bd270df0f80548d9944e389870713cc1fe2b8fb35fe2bcefd/docstring_parser-0.17.0.tar.gz", hash = "sha256:583de4a309722b3315439bb31d64ba3eebada841f2e2cee23b99df001434c912", size = 27442, upload-time = "2025-07-21T07:35:01.868Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/55/e2/2537ebcff11c1ee1ff17d8d0b6f4db75873e3b0fb32c2d4a2ee31ecb310a/docstring_parser-0.17.0-py3-none-any.whl", hash = "sha256:cf2569abd23dce8099b300f9b4fa8191e9582dda731fd533daf54c4551658708", size = 36896, upload-time = "2025-07-21T07:35:00.684Z" }, +] + +[[package]] +name = "docutils" +version = "0.22.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e4/47/d869000fb74438584858acc628a364b277fc012695f0dfd513cb10f99768/docutils-0.22.1.tar.gz", hash = "sha256:d2fb50923a313532b6d41a77776d24cb459a594be9b7e4afa1fbcb5bda1893e6", size = 2291655, upload-time = "2025-09-17T17:58:45.409Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8c/dc/1948b90c5d9dbfa4d1fd3991013a042ba3ac62ebd3afdcb3fac08366e755/docutils-0.22.1-py3-none-any.whl", hash = "sha256:806e896f256a17466426544038f30cb860a99f5d4af640e36c284bfcb1824512", size = 638455, upload-time = "2025-09-17T17:58:42.498Z" }, +] + +[[package]] +name = "email-validator" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "dnspython" }, + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f5/22/900cb125c76b7aaa450ce02fd727f452243f2e91a61af068b40adba60ea9/email_validator-2.3.0.tar.gz", hash = "sha256:9fc05c37f2f6cf439ff414f8fc46d917929974a82244c20eb10231ba60c54426", size = 51238, upload-time = "2025-08-26T13:09:06.831Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl", hash = "sha256:80f13f623413e6b197ae73bb10bf4eb0908faf509ad8362c5edeb0be7fd450b4", size = 35604, upload-time = "2025-08-26T13:09:05.858Z" }, +] + +[[package]] +name = "exceptiongroup" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0b/9f/a65090624ecf468cdca03533906e7c69ed7588582240cfe7cc9e770b50eb/exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88", size = 29749, upload-time = "2025-05-10T17:42:51.123Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/36/f4/c6e662dade71f56cd2f3735141b265c3c79293c109549c1e6933b0651ffc/exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10", size = 16674, upload-time = "2025-05-10T17:42:49.33Z" }, +] + +[[package]] +name = "fastmcp" +version = "2.12.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "authlib" }, + { name = "cyclopts" }, + { name = "exceptiongroup" }, + { name = "httpx" }, + { name = "mcp" }, + { name = "openapi-core" }, + { name = "openapi-pydantic" }, + { name = "pydantic", extra = ["email"] }, + { name = "pyperclip" }, + { name = "python-dotenv" }, + { name = "rich" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/35/8a/c46759bb41a53187191e5b3d963c0bde54783ecc89186a93c4947607b8e4/fastmcp-2.12.2.tar.gz", hash = "sha256:6d13e2f9be57b99763fc22485f9f603daa23bfbca35a8172baa43b283d6fc1ff", size = 5244547, upload-time = "2025-09-03T21:28:09.869Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5c/0a/7a8d564b1b9909dbfc36eb93d76410a4acfada6b1e13ee451a753bb6dbc2/fastmcp-2.12.2-py3-none-any.whl", hash = "sha256:0b58d68e819c82078d1fd51989d3d81f2be7382d527308b06df55f4d0a4ec94f", size = 312029, upload-time = "2025-09-03T21:28:08.62Z" }, +] + +[[package]] +name = "h11" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, +] + +[[package]] +name = "httpcore" +version = "1.0.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, +] + +[[package]] +name = "httpx" +version = "0.28.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "certifi" }, + { name = "httpcore" }, + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, +] + +[[package]] +name = "httpx-sse" +version = "0.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6e/fa/66bd985dd0b7c109a3bcb89272ee0bfb7e2b4d06309ad7b38ff866734b2a/httpx_sse-0.4.1.tar.gz", hash = "sha256:8f44d34414bc7b21bf3602713005c5df4917884f76072479b21f68befa4ea26e", size = 12998, upload-time = "2025-06-24T13:21:05.71Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/25/0a/6269e3473b09aed2dab8aa1a600c70f31f00ae1349bee30658f7e358a159/httpx_sse-0.4.1-py3-none-any.whl", hash = "sha256:cba42174344c3a5b06f255ce65b350880f962d99ead85e776f23c6618a377a37", size = 8054, upload-time = "2025-06-24T13:21:04.772Z" }, +] + +[[package]] +name = "idna" +version = "3.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, +] + +[[package]] +name = "iniconfig" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793, upload-time = "2025-03-19T20:09:59.721Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050, upload-time = "2025-03-19T20:10:01.071Z" }, +] + +[[package]] +name = "isodate" +version = "0.7.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/54/4d/e940025e2ce31a8ce1202635910747e5a87cc3a6a6bb2d00973375014749/isodate-0.7.2.tar.gz", hash = "sha256:4cd1aa0f43ca76f4a6c6c0292a85f40b35ec2e43e315b59f06e6d32171a953e6", size = 29705, upload-time = "2024-10-08T23:04:11.5Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/15/aa/0aca39a37d3c7eb941ba736ede56d689e7be91cab5d9ca846bde3999eba6/isodate-0.7.2-py3-none-any.whl", hash = "sha256:28009937d8031054830160fce6d409ed342816b543597cece116d966c6d99e15", size = 22320, upload-time = "2024-10-08T23:04:09.501Z" }, +] + +[[package]] +name = "jsonschema" +version = "4.25.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "jsonschema-specifications" }, + { name = "referencing" }, + { name = "rpds-py" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/74/69/f7185de793a29082a9f3c7728268ffb31cb5095131a9c139a74078e27336/jsonschema-4.25.1.tar.gz", hash = "sha256:e4a9655ce0da0c0b67a085847e00a3a51449e1157f4f75e9fb5aa545e122eb85", size = 357342, upload-time = "2025-08-18T17:03:50.038Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bf/9c/8c95d856233c1f82500c2450b8c68576b4cf1c871db3afac5c34ff84e6fd/jsonschema-4.25.1-py3-none-any.whl", hash = "sha256:3fba0169e345c7175110351d456342c364814cfcf3b964ba4587f22915230a63", size = 90040, upload-time = "2025-08-18T17:03:48.373Z" }, +] + +[[package]] +name = "jsonschema-path" +version = "0.3.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pathable" }, + { name = "pyyaml" }, + { name = "referencing" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6e/45/41ebc679c2a4fced6a722f624c18d658dee42612b83ea24c1caf7c0eb3a8/jsonschema_path-0.3.4.tar.gz", hash = "sha256:8365356039f16cc65fddffafda5f58766e34bebab7d6d105616ab52bc4297001", size = 11159, upload-time = "2025-01-24T14:33:16.547Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/58/3485da8cb93d2f393bce453adeef16896751f14ba3e2024bc21dc9597646/jsonschema_path-0.3.4-py3-none-any.whl", hash = "sha256:f502191fdc2b22050f9a81c9237be9d27145b9001c55842bece5e94e382e52f8", size = 14810, upload-time = "2025-01-24T14:33:14.652Z" }, +] + +[[package]] +name = "jsonschema-specifications" +version = "2025.9.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "referencing" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/19/74/a633ee74eb36c44aa6d1095e7cc5569bebf04342ee146178e2d36600708b/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d", size = 32855, upload-time = "2025-09-08T01:34:59.186Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437, upload-time = "2025-09-08T01:34:57.871Z" }, +] + +[[package]] +name = "lazy-object-proxy" +version = "1.12.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/08/a2/69df9c6ba6d316cfd81fe2381e464db3e6de5db45f8c43c6a23504abf8cb/lazy_object_proxy-1.12.0.tar.gz", hash = "sha256:1f5a462d92fd0cfb82f1fab28b51bfb209fabbe6aabf7f0d51472c0c124c0c61", size = 43681, upload-time = "2025-08-22T13:50:06.783Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/26/b74c791008841f8ad896c7f293415136c66cc27e7c7577de4ee68040c110/lazy_object_proxy-1.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:86fd61cb2ba249b9f436d789d1356deae69ad3231dc3c0f17293ac535162672e", size = 26745, upload-time = "2025-08-22T13:42:44.982Z" }, + { url = "https://files.pythonhosted.org/packages/9b/52/641870d309e5d1fb1ea7d462a818ca727e43bfa431d8c34b173eb090348c/lazy_object_proxy-1.12.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:81d1852fb30fab81696f93db1b1e55a5d1ff7940838191062f5f56987d5fcc3e", size = 71537, upload-time = "2025-08-22T13:42:46.141Z" }, + { url = "https://files.pythonhosted.org/packages/47/b6/919118e99d51c5e76e8bf5a27df406884921c0acf2c7b8a3b38d847ab3e9/lazy_object_proxy-1.12.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:be9045646d83f6c2664c1330904b245ae2371b5c57a3195e4028aedc9f999655", size = 71141, upload-time = "2025-08-22T13:42:47.375Z" }, + { url = "https://files.pythonhosted.org/packages/e5/47/1d20e626567b41de085cf4d4fb3661a56c159feaa73c825917b3b4d4f806/lazy_object_proxy-1.12.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:67f07ab742f1adfb3966c40f630baaa7902be4222a17941f3d85fd1dae5565ff", size = 69449, upload-time = "2025-08-22T13:42:48.49Z" }, + { url = "https://files.pythonhosted.org/packages/58/8d/25c20ff1a1a8426d9af2d0b6f29f6388005fc8cd10d6ee71f48bff86fdd0/lazy_object_proxy-1.12.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:75ba769017b944fcacbf6a80c18b2761a1795b03f8899acdad1f1c39db4409be", size = 70744, upload-time = "2025-08-22T13:42:49.608Z" }, + { url = "https://files.pythonhosted.org/packages/c0/67/8ec9abe15c4f8a4bcc6e65160a2c667240d025cbb6591b879bea55625263/lazy_object_proxy-1.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:7b22c2bbfb155706b928ac4d74c1a63ac8552a55ba7fff4445155523ea4067e1", size = 26568, upload-time = "2025-08-22T13:42:57.719Z" }, + { url = "https://files.pythonhosted.org/packages/23/12/cd2235463f3469fd6c62d41d92b7f120e8134f76e52421413a0ad16d493e/lazy_object_proxy-1.12.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4a79b909aa16bde8ae606f06e6bbc9d3219d2e57fb3e0076e17879072b742c65", size = 27391, upload-time = "2025-08-22T13:42:50.62Z" }, + { url = "https://files.pythonhosted.org/packages/60/9e/f1c53e39bbebad2e8609c67d0830cc275f694d0ea23d78e8f6db526c12d3/lazy_object_proxy-1.12.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:338ab2f132276203e404951205fe80c3fd59429b3a724e7b662b2eb539bb1be9", size = 80552, upload-time = "2025-08-22T13:42:51.731Z" }, + { url = "https://files.pythonhosted.org/packages/4c/b6/6c513693448dcb317d9d8c91d91f47addc09553613379e504435b4cc8b3e/lazy_object_proxy-1.12.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8c40b3c9faee2e32bfce0df4ae63f4e73529766893258eca78548bac801c8f66", size = 82857, upload-time = "2025-08-22T13:42:53.225Z" }, + { url = "https://files.pythonhosted.org/packages/12/1c/d9c4aaa4c75da11eb7c22c43d7c90a53b4fca0e27784a5ab207768debea7/lazy_object_proxy-1.12.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:717484c309df78cedf48396e420fa57fc8a2b1f06ea889df7248fdd156e58847", size = 80833, upload-time = "2025-08-22T13:42:54.391Z" }, + { url = "https://files.pythonhosted.org/packages/0b/ae/29117275aac7d7d78ae4f5a4787f36ff33262499d486ac0bf3e0b97889f6/lazy_object_proxy-1.12.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a6b7ea5ea1ffe15059eb44bcbcb258f97bcb40e139b88152c40d07b1a1dfc9ac", size = 79516, upload-time = "2025-08-22T13:42:55.812Z" }, + { url = "https://files.pythonhosted.org/packages/19/40/b4e48b2c38c69392ae702ae7afa7b6551e0ca5d38263198b7c79de8b3bdf/lazy_object_proxy-1.12.0-cp313-cp313t-win_amd64.whl", hash = "sha256:08c465fb5cd23527512f9bd7b4c7ba6cec33e28aad36fbbe46bf7b858f9f3f7f", size = 27656, upload-time = "2025-08-22T13:42:56.793Z" }, + { url = "https://files.pythonhosted.org/packages/ef/3a/277857b51ae419a1574557c0b12e0d06bf327b758ba94cafc664cb1e2f66/lazy_object_proxy-1.12.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c9defba70ab943f1df98a656247966d7729da2fe9c2d5d85346464bf320820a3", size = 26582, upload-time = "2025-08-22T13:49:49.366Z" }, + { url = "https://files.pythonhosted.org/packages/1a/b6/c5e0fa43535bb9c87880e0ba037cdb1c50e01850b0831e80eb4f4762f270/lazy_object_proxy-1.12.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6763941dbf97eea6b90f5b06eb4da9418cc088fce0e3883f5816090f9afcde4a", size = 71059, upload-time = "2025-08-22T13:49:50.488Z" }, + { url = "https://files.pythonhosted.org/packages/06/8a/7dcad19c685963c652624702f1a968ff10220b16bfcc442257038216bf55/lazy_object_proxy-1.12.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fdc70d81235fc586b9e3d1aeef7d1553259b62ecaae9db2167a5d2550dcc391a", size = 71034, upload-time = "2025-08-22T13:49:54.224Z" }, + { url = "https://files.pythonhosted.org/packages/12/ac/34cbfb433a10e28c7fd830f91c5a348462ba748413cbb950c7f259e67aa7/lazy_object_proxy-1.12.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:0a83c6f7a6b2bfc11ef3ed67f8cbe99f8ff500b05655d8e7df9aab993a6abc95", size = 69529, upload-time = "2025-08-22T13:49:55.29Z" }, + { url = "https://files.pythonhosted.org/packages/6f/6a/11ad7e349307c3ca4c0175db7a77d60ce42a41c60bcb11800aabd6a8acb8/lazy_object_proxy-1.12.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:256262384ebd2a77b023ad02fbcc9326282bcfd16484d5531154b02bc304f4c5", size = 70391, upload-time = "2025-08-22T13:49:56.35Z" }, + { url = "https://files.pythonhosted.org/packages/59/97/9b410ed8fbc6e79c1ee8b13f8777a80137d4bc189caf2c6202358e66192c/lazy_object_proxy-1.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:7601ec171c7e8584f8ff3f4e440aa2eebf93e854f04639263875b8c2971f819f", size = 26988, upload-time = "2025-08-22T13:49:57.302Z" }, +] + +[[package]] +name = "markdown-it-py" +version = "4.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mdurl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" }, +] + +[[package]] +name = "markupsafe" +version = "3.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537, upload-time = "2024-10-18T15:21:54.129Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274, upload-time = "2024-10-18T15:21:24.577Z" }, + { url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352, upload-time = "2024-10-18T15:21:25.382Z" }, + { url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122, upload-time = "2024-10-18T15:21:26.199Z" }, + { url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085, upload-time = "2024-10-18T15:21:27.029Z" }, + { url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978, upload-time = "2024-10-18T15:21:27.846Z" }, + { url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208, upload-time = "2024-10-18T15:21:28.744Z" }, + { url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357, upload-time = "2024-10-18T15:21:29.545Z" }, + { url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344, upload-time = "2024-10-18T15:21:30.366Z" }, + { url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101, upload-time = "2024-10-18T15:21:31.207Z" }, + { url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603, upload-time = "2024-10-18T15:21:32.032Z" }, + { url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510, upload-time = "2024-10-18T15:21:33.625Z" }, + { url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486, upload-time = "2024-10-18T15:21:34.611Z" }, + { url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480, upload-time = "2024-10-18T15:21:35.398Z" }, + { url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914, upload-time = "2024-10-18T15:21:36.231Z" }, + { url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796, upload-time = "2024-10-18T15:21:37.073Z" }, + { url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473, upload-time = "2024-10-18T15:21:37.932Z" }, + { url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114, upload-time = "2024-10-18T15:21:39.799Z" }, + { url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098, upload-time = "2024-10-18T15:21:40.813Z" }, + { url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208, upload-time = "2024-10-18T15:21:41.814Z" }, + { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739, upload-time = "2024-10-18T15:21:42.784Z" }, +] + +[[package]] +name = "mcp" +version = "1.14.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "httpx" }, + { name = "httpx-sse" }, + { name = "jsonschema" }, + { name = "pydantic" }, + { name = "pydantic-settings" }, + { name = "python-multipart" }, + { name = "pywin32", marker = "sys_platform == 'win32'" }, + { name = "sse-starlette" }, + { name = "starlette" }, + { name = "uvicorn", marker = "sys_platform != 'emscripten'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/48/e9/242096400d702924b49f8d202c6ded7efb8841cacba826b5d2e6183aef7b/mcp-1.14.1.tar.gz", hash = "sha256:31c4406182ba15e8f30a513042719c3f0a38c615e76188ee5a736aaa89e20134", size = 454944, upload-time = "2025-09-18T13:37:19.971Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8e/11/d334fbb7c2aeddd2e762b86d7a619acffae012643a5738e698f975a2a9e2/mcp-1.14.1-py3-none-any.whl", hash = "sha256:3b7a479e8e5cbf5361bdc1da8bc6d500d795dc3aff44b44077a363a7f7e945a4", size = 163809, upload-time = "2025-09-18T13:37:18.165Z" }, +] + +[[package]] +name = "mdurl" +version = "0.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, +] + +[[package]] +name = "more-itertools" +version = "10.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ea/5d/38b681d3fce7a266dd9ab73c66959406d565b3e85f21d5e66e1181d93721/more_itertools-10.8.0.tar.gz", hash = "sha256:f638ddf8a1a0d134181275fb5d58b086ead7c6a72429ad725c67503f13ba30bd", size = 137431, upload-time = "2025-09-02T15:23:11.018Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a4/8e/469e5a4a2f5855992e425f3cb33804cc07bf18d48f2db061aec61ce50270/more_itertools-10.8.0-py3-none-any.whl", hash = "sha256:52d4362373dcf7c52546bc4af9a86ee7c4579df9a8dc268be0a2f949d376cc9b", size = 69667, upload-time = "2025-09-02T15:23:09.635Z" }, +] + +[[package]] +name = "oci" +version = "2.160.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "circuitbreaker" }, + { name = "cryptography" }, + { name = "pyopenssl" }, + { name = "python-dateutil" }, + { name = "pytz" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f3/7b/c9d7fc28f11c25c7875db3584eab5d52ccb2d7df553d07ac47f19a14d075/oci-2.160.0.tar.gz", hash = "sha256:f8e3410204c1405b40247179550cf74f5145a8e17025c4f2a92f2b9ffdc7d26b", size = 15601606, upload-time = "2025-09-09T04:17:43.728Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/51/752375a4e0d2de371c2788414157eda337417010d2ef7383cd7140388f1e/oci-2.160.0-py3-none-any.whl", hash = "sha256:3dba1ec671ebea23f255fabf836cb0fd08aea0913a8df85610fccaa5a4344ee9", size = 31715365, upload-time = "2025-09-09T04:17:34.998Z" }, +] + +[[package]] +name = "openapi-core" +version = "0.19.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "isodate" }, + { name = "jsonschema" }, + { name = "jsonschema-path" }, + { name = "more-itertools" }, + { name = "openapi-schema-validator" }, + { name = "openapi-spec-validator" }, + { name = "parse" }, + { name = "typing-extensions" }, + { name = "werkzeug" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/35/1acaa5f2fcc6e54eded34a2ec74b479439c4e469fc4e8d0e803fda0234db/openapi_core-0.19.5.tar.gz", hash = "sha256:421e753da56c391704454e66afe4803a290108590ac8fa6f4a4487f4ec11f2d3", size = 103264, upload-time = "2025-03-20T20:17:28.193Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/27/6f/83ead0e2e30a90445ee4fc0135f43741aebc30cca5b43f20968b603e30b6/openapi_core-0.19.5-py3-none-any.whl", hash = "sha256:ef7210e83a59394f46ce282639d8d26ad6fc8094aa904c9c16eb1bac8908911f", size = 106595, upload-time = "2025-03-20T20:17:26.77Z" }, +] + +[[package]] +name = "openapi-pydantic" +version = "0.5.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pydantic" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/02/2e/58d83848dd1a79cb92ed8e63f6ba901ca282c5f09d04af9423ec26c56fd7/openapi_pydantic-0.5.1.tar.gz", hash = "sha256:ff6835af6bde7a459fb93eb93bb92b8749b754fc6e51b2f1590a19dc3005ee0d", size = 60892, upload-time = "2025-01-08T19:29:27.083Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/cf/03675d8bd8ecbf4445504d8071adab19f5f993676795708e36402ab38263/openapi_pydantic-0.5.1-py3-none-any.whl", hash = "sha256:a3a09ef4586f5bd760a8df7f43028b60cafb6d9f61de2acba9574766255ab146", size = 96381, upload-time = "2025-01-08T19:29:25.275Z" }, +] + +[[package]] +name = "openapi-schema-validator" +version = "0.6.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jsonschema" }, + { name = "jsonschema-specifications" }, + { name = "rfc3339-validator" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8b/f3/5507ad3325169347cd8ced61c232ff3df70e2b250c49f0fe140edb4973c6/openapi_schema_validator-0.6.3.tar.gz", hash = "sha256:f37bace4fc2a5d96692f4f8b31dc0f8d7400fd04f3a937798eaf880d425de6ee", size = 11550, upload-time = "2025-01-10T18:08:22.268Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/21/c6/ad0fba32775ae749016829dace42ed80f4407b171da41313d1a3a5f102e4/openapi_schema_validator-0.6.3-py3-none-any.whl", hash = "sha256:f3b9870f4e556b5a62a1c39da72a6b4b16f3ad9c73dc80084b1b11e74ba148a3", size = 8755, upload-time = "2025-01-10T18:08:19.758Z" }, +] + +[[package]] +name = "openapi-spec-validator" +version = "0.7.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jsonschema" }, + { name = "jsonschema-path" }, + { name = "lazy-object-proxy" }, + { name = "openapi-schema-validator" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/82/af/fe2d7618d6eae6fb3a82766a44ed87cd8d6d82b4564ed1c7cfb0f6378e91/openapi_spec_validator-0.7.2.tar.gz", hash = "sha256:cc029309b5c5dbc7859df0372d55e9d1ff43e96d678b9ba087f7c56fc586f734", size = 36855, upload-time = "2025-06-07T14:48:56.299Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/27/dd/b3fd642260cb17532f66cc1e8250f3507d1e580483e209dc1e9d13bd980d/openapi_spec_validator-0.7.2-py3-none-any.whl", hash = "sha256:4bbdc0894ec85f1d1bea1d6d9c8b2c3c8d7ccaa13577ef40da9c006c9fd0eb60", size = 39713, upload-time = "2025-06-07T14:48:54.077Z" }, +] + +[[package]] +name = "oracle-oci-db-dynamic-mcp-server" +version = "1.0.1" +source = { editable = "." } +dependencies = [ + { name = "fastmcp" }, + { name = "mcp" }, + { name = "oci" }, + { name = "requests" }, +] + +[package.dev-dependencies] +dev = [ + { name = "pytest" }, + { name = "pytest-asyncio" }, +] + +[package.metadata] +requires-dist = [ + { name = "fastmcp", specifier = "==2.12.2" }, + { name = "mcp", specifier = ">=1.0.0" }, + { name = "oci", specifier = "==2.160.0" }, + { name = "requests" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "pytest", specifier = ">=8.4.2" }, + { name = "pytest-asyncio", specifier = ">=1.2.0" }, +] + +[[package]] +name = "packaging" +version = "25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, +] + +[[package]] +name = "parse" +version = "1.20.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4f/78/d9b09ba24bb36ef8b83b71be547e118d46214735b6dfb39e4bfde0e9b9dd/parse-1.20.2.tar.gz", hash = "sha256:b41d604d16503c79d81af5165155c0b20f6c8d6c559efa66b4b695c3e5a0a0ce", size = 29391, upload-time = "2024-06-11T04:41:57.34Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d0/31/ba45bf0b2aa7898d81cbbfac0e88c267befb59ad91a19e36e1bc5578ddb1/parse-1.20.2-py2.py3-none-any.whl", hash = "sha256:967095588cb802add9177d0c0b6133b5ba33b1ea9007ca800e526f42a85af558", size = 20126, upload-time = "2024-06-11T04:41:55.057Z" }, +] + +[[package]] +name = "pathable" +version = "0.4.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/67/93/8f2c2075b180c12c1e9f6a09d1a985bc2036906b13dff1d8917e395f2048/pathable-0.4.4.tar.gz", hash = "sha256:6905a3cd17804edfac7875b5f6c9142a218c7caef78693c2dbbbfbac186d88b2", size = 8124, upload-time = "2025-01-10T18:43:13.247Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7d/eb/b6260b31b1a96386c0a880edebe26f89669098acea8e0318bff6adb378fd/pathable-0.4.4-py3-none-any.whl", hash = "sha256:5ae9e94793b6ef5a4cbe0a7ce9dbbefc1eec38df253763fd0aeeacf2762dbbc2", size = 9592, upload-time = "2025-01-10T18:43:11.88Z" }, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + +[[package]] +name = "pycparser" +version = "2.23" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/cf/d2d3b9f5699fb1e4615c8e32ff220203e43b248e1dfcc6736ad9057731ca/pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2", size = 173734, upload-time = "2025-09-09T13:23:47.91Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140, upload-time = "2025-09-09T13:23:46.651Z" }, +] + +[[package]] +name = "pydantic" +version = "2.11.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-types" }, + { name = "pydantic-core" }, + { name = "typing-extensions" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ff/5d/09a551ba512d7ca404d785072700d3f6727a02f6f3c24ecfd081c7cf0aa8/pydantic-2.11.9.tar.gz", hash = "sha256:6b8ffda597a14812a7975c90b82a8a2e777d9257aba3453f973acd3c032a18e2", size = 788495, upload-time = "2025-09-13T11:26:39.325Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3e/d3/108f2006987c58e76691d5ae5d200dd3e0f532cb4e5fa3560751c3a1feba/pydantic-2.11.9-py3-none-any.whl", hash = "sha256:c42dd626f5cfc1c6950ce6205ea58c93efa406da65f479dcb4029d5934857da2", size = 444855, upload-time = "2025-09-13T11:26:36.909Z" }, +] + +[package.optional-dependencies] +email = [ + { name = "email-validator" }, +] + +[[package]] +name = "pydantic-core" +version = "2.33.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ad/88/5f2260bdfae97aabf98f1778d43f69574390ad787afb646292a638c923d4/pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc", size = 435195, upload-time = "2025-04-23T18:33:52.104Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/46/8c/99040727b41f56616573a28771b1bfa08a3d3fe74d3d513f01251f79f172/pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f", size = 2015688, upload-time = "2025-04-23T18:31:53.175Z" }, + { url = "https://files.pythonhosted.org/packages/3a/cc/5999d1eb705a6cefc31f0b4a90e9f7fc400539b1a1030529700cc1b51838/pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6", size = 1844808, upload-time = "2025-04-23T18:31:54.79Z" }, + { url = "https://files.pythonhosted.org/packages/6f/5e/a0a7b8885c98889a18b6e376f344da1ef323d270b44edf8174d6bce4d622/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef", size = 1885580, upload-time = "2025-04-23T18:31:57.393Z" }, + { url = "https://files.pythonhosted.org/packages/3b/2a/953581f343c7d11a304581156618c3f592435523dd9d79865903272c256a/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a", size = 1973859, upload-time = "2025-04-23T18:31:59.065Z" }, + { url = "https://files.pythonhosted.org/packages/e6/55/f1a813904771c03a3f97f676c62cca0c0a4138654107c1b61f19c644868b/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916", size = 2120810, upload-time = "2025-04-23T18:32:00.78Z" }, + { url = "https://files.pythonhosted.org/packages/aa/c3/053389835a996e18853ba107a63caae0b9deb4a276c6b472931ea9ae6e48/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a", size = 2676498, upload-time = "2025-04-23T18:32:02.418Z" }, + { url = "https://files.pythonhosted.org/packages/eb/3c/f4abd740877a35abade05e437245b192f9d0ffb48bbbbd708df33d3cda37/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d", size = 2000611, upload-time = "2025-04-23T18:32:04.152Z" }, + { url = "https://files.pythonhosted.org/packages/59/a7/63ef2fed1837d1121a894d0ce88439fe3e3b3e48c7543b2a4479eb99c2bd/pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56", size = 2107924, upload-time = "2025-04-23T18:32:06.129Z" }, + { url = "https://files.pythonhosted.org/packages/04/8f/2551964ef045669801675f1cfc3b0d74147f4901c3ffa42be2ddb1f0efc4/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5", size = 2063196, upload-time = "2025-04-23T18:32:08.178Z" }, + { url = "https://files.pythonhosted.org/packages/26/bd/d9602777e77fc6dbb0c7db9ad356e9a985825547dce5ad1d30ee04903918/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e", size = 2236389, upload-time = "2025-04-23T18:32:10.242Z" }, + { url = "https://files.pythonhosted.org/packages/42/db/0e950daa7e2230423ab342ae918a794964b053bec24ba8af013fc7c94846/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162", size = 2239223, upload-time = "2025-04-23T18:32:12.382Z" }, + { url = "https://files.pythonhosted.org/packages/58/4d/4f937099c545a8a17eb52cb67fe0447fd9a373b348ccfa9a87f141eeb00f/pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849", size = 1900473, upload-time = "2025-04-23T18:32:14.034Z" }, + { url = "https://files.pythonhosted.org/packages/a0/75/4a0a9bac998d78d889def5e4ef2b065acba8cae8c93696906c3a91f310ca/pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9", size = 1955269, upload-time = "2025-04-23T18:32:15.783Z" }, + { url = "https://files.pythonhosted.org/packages/f9/86/1beda0576969592f1497b4ce8e7bc8cbdf614c352426271b1b10d5f0aa64/pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9", size = 1893921, upload-time = "2025-04-23T18:32:18.473Z" }, + { url = "https://files.pythonhosted.org/packages/a4/7d/e09391c2eebeab681df2b74bfe6c43422fffede8dc74187b2b0bf6fd7571/pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac", size = 1806162, upload-time = "2025-04-23T18:32:20.188Z" }, + { url = "https://files.pythonhosted.org/packages/f1/3d/847b6b1fed9f8ed3bb95a9ad04fbd0b212e832d4f0f50ff4d9ee5a9f15cf/pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5", size = 1981560, upload-time = "2025-04-23T18:32:22.354Z" }, + { url = "https://files.pythonhosted.org/packages/6f/9a/e73262f6c6656262b5fdd723ad90f518f579b7bc8622e43a942eec53c938/pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9", size = 1935777, upload-time = "2025-04-23T18:32:25.088Z" }, +] + +[[package]] +name = "pydantic-settings" +version = "2.10.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pydantic" }, + { name = "python-dotenv" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/68/85/1ea668bbab3c50071ca613c6ab30047fb36ab0da1b92fa8f17bbc38fd36c/pydantic_settings-2.10.1.tar.gz", hash = "sha256:06f0062169818d0f5524420a360d632d5857b83cffd4d42fe29597807a1614ee", size = 172583, upload-time = "2025-06-24T13:26:46.841Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/58/f0/427018098906416f580e3cf1366d3b1abfb408a0652e9f31600c24a1903c/pydantic_settings-2.10.1-py3-none-any.whl", hash = "sha256:a60952460b99cf661dc25c29c0ef171721f98bfcb52ef8d9ea4c943d7c8cc796", size = 45235, upload-time = "2025-06-24T13:26:45.485Z" }, +] + +[[package]] +name = "pygments" +version = "2.19.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, +] + +[[package]] +name = "pyopenssl" +version = "24.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cryptography" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c1/d4/1067b82c4fc674d6f6e9e8d26b3dff978da46d351ca3bac171544693e085/pyopenssl-24.3.0.tar.gz", hash = "sha256:49f7a019577d834746bc55c5fce6ecbcec0f2b4ec5ce1cf43a9a173b8138bb36", size = 178944, upload-time = "2024-11-27T20:43:12.755Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/42/22/40f9162e943f86f0fc927ebc648078be87def360d9d8db346619fb97df2b/pyOpenSSL-24.3.0-py3-none-any.whl", hash = "sha256:e474f5a473cd7f92221cc04976e48f4d11502804657a08a989fb3be5514c904a", size = 56111, upload-time = "2024-11-27T20:43:21.112Z" }, +] + +[[package]] +name = "pyperclip" +version = "1.10.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/15/99/25f4898cf420efb6f45f519de018f4faea5391114a8618b16736ef3029f1/pyperclip-1.10.0.tar.gz", hash = "sha256:180c8346b1186921c75dfd14d9048a6b5d46bfc499778811952c6dd6eb1ca6be", size = 12193, upload-time = "2025-09-18T00:54:00.384Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/bc/22540e73c5f5ae18f02924cd3954a6c9a4aa6b713c841a94c98335d333a1/pyperclip-1.10.0-py3-none-any.whl", hash = "sha256:596fbe55dc59263bff26e61d2afbe10223e2fccb5210c9c96a28d6887cfcc7ec", size = 11062, upload-time = "2025-09-18T00:53:59.252Z" }, +] + +[[package]] +name = "pytest" +version = "8.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a3/5c/00a0e072241553e1a7496d638deababa67c5058571567b92a7eaa258397c/pytest-8.4.2.tar.gz", hash = "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01", size = 1519618, upload-time = "2025-09-04T14:34:22.711Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79", size = 365750, upload-time = "2025-09-04T14:34:20.226Z" }, +] + +[[package]] +name = "pytest-asyncio" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/86/9e3c5f48f7b7b638b216e4b9e645f54d199d7abbbab7a64a13b4e12ba10f/pytest_asyncio-1.2.0.tar.gz", hash = "sha256:c609a64a2a8768462d0c99811ddb8bd2583c33fd33cf7f21af1c142e824ffb57", size = 50119, upload-time = "2025-09-12T07:33:53.816Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/93/2fa34714b7a4ae72f2f8dad66ba17dd9a2c793220719e736dda28b7aec27/pytest_asyncio-1.2.0-py3-none-any.whl", hash = "sha256:8e17ae5e46d8e7efe51ab6494dd2010f4ca8dae51652aa3c8d55acf50bfb2e99", size = 15095, upload-time = "2025-09-12T07:33:52.639Z" }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + +[[package]] +name = "python-dotenv" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/b0/4bc07ccd3572a2f9df7e6782f52b0c6c90dcbb803ac4a167702d7d0dfe1e/python_dotenv-1.1.1.tar.gz", hash = "sha256:a8a6399716257f45be6a007360200409fce5cda2661e3dec71d23dc15f6189ab", size = 41978, upload-time = "2025-06-24T04:21:07.341Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5f/ed/539768cf28c661b5b068d66d96a2f155c4971a5d55684a514c1a0e0dec2f/python_dotenv-1.1.1-py3-none-any.whl", hash = "sha256:31f23644fe2602f88ff55e1f5c79ba497e01224ee7737937930c448e4d0e24dc", size = 20556, upload-time = "2025-06-24T04:21:06.073Z" }, +] + +[[package]] +name = "python-multipart" +version = "0.0.20" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/87/f44d7c9f274c7ee665a29b885ec97089ec5dc034c7f3fafa03da9e39a09e/python_multipart-0.0.20.tar.gz", hash = "sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13", size = 37158, upload-time = "2024-12-16T19:45:46.972Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl", hash = "sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104", size = 24546, upload-time = "2024-12-16T19:45:44.423Z" }, +] + +[[package]] +name = "pytz" +version = "2025.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884, upload-time = "2025-03-25T02:25:00.538Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" }, +] + +[[package]] +name = "pywin32" +version = "311" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a5/be/3fd5de0979fcb3994bfee0d65ed8ca9506a8a1260651b86174f6a86f52b3/pywin32-311-cp313-cp313-win32.whl", hash = "sha256:f95ba5a847cba10dd8c4d8fefa9f2a6cf283b8b88ed6178fa8a6c1ab16054d0d", size = 8705700, upload-time = "2025-07-14T20:13:26.471Z" }, + { url = "https://files.pythonhosted.org/packages/e3/28/e0a1909523c6890208295a29e05c2adb2126364e289826c0a8bc7297bd5c/pywin32-311-cp313-cp313-win_amd64.whl", hash = "sha256:718a38f7e5b058e76aee1c56ddd06908116d35147e133427e59a3983f703a20d", size = 9494700, upload-time = "2025-07-14T20:13:28.243Z" }, + { url = "https://files.pythonhosted.org/packages/04/bf/90339ac0f55726dce7d794e6d79a18a91265bdf3aa70b6b9ca52f35e022a/pywin32-311-cp313-cp313-win_arm64.whl", hash = "sha256:7b4075d959648406202d92a2310cb990fea19b535c7f4a78d3f5e10b926eeb8a", size = 8709318, upload-time = "2025-07-14T20:13:30.348Z" }, + { url = "https://files.pythonhosted.org/packages/c9/31/097f2e132c4f16d99a22bfb777e0fd88bd8e1c634304e102f313af69ace5/pywin32-311-cp314-cp314-win32.whl", hash = "sha256:b7a2c10b93f8986666d0c803ee19b5990885872a7de910fc460f9b0c2fbf92ee", size = 8840714, upload-time = "2025-07-14T20:13:32.449Z" }, + { url = "https://files.pythonhosted.org/packages/90/4b/07c77d8ba0e01349358082713400435347df8426208171ce297da32c313d/pywin32-311-cp314-cp314-win_amd64.whl", hash = "sha256:3aca44c046bd2ed8c90de9cb8427f581c479e594e99b5c0bb19b29c10fd6cb87", size = 9656800, upload-time = "2025-07-14T20:13:34.312Z" }, + { url = "https://files.pythonhosted.org/packages/c0/d2/21af5c535501a7233e734b8af901574572da66fcc254cb35d0609c9080dd/pywin32-311-cp314-cp314-win_arm64.whl", hash = "sha256:a508e2d9025764a8270f93111a970e1d0fbfc33f4153b388bb649b7eec4f9b42", size = 8932540, upload-time = "2025-07-14T20:13:36.379Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631, upload-time = "2024-08-06T20:33:50.674Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309, upload-time = "2024-08-06T20:32:43.4Z" }, + { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679, upload-time = "2024-08-06T20:32:44.801Z" }, + { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428, upload-time = "2024-08-06T20:32:46.432Z" }, + { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361, upload-time = "2024-08-06T20:32:51.188Z" }, + { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523, upload-time = "2024-08-06T20:32:53.019Z" }, + { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660, upload-time = "2024-08-06T20:32:54.708Z" }, + { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597, upload-time = "2024-08-06T20:32:56.985Z" }, + { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527, upload-time = "2024-08-06T20:33:03.001Z" }, + { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446, upload-time = "2024-08-06T20:33:04.33Z" }, +] + +[[package]] +name = "referencing" +version = "0.36.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "rpds-py" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2f/db/98b5c277be99dd18bfd91dd04e1b759cad18d1a338188c936e92f921c7e2/referencing-0.36.2.tar.gz", hash = "sha256:df2e89862cd09deabbdba16944cc3f10feb6b3e6f18e902f7cc25609a34775aa", size = 74744, upload-time = "2025-01-25T08:48:16.138Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/b1/3baf80dc6d2b7bc27a95a67752d0208e410351e3feb4eb78de5f77454d8d/referencing-0.36.2-py3-none-any.whl", hash = "sha256:e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0", size = 26775, upload-time = "2025-01-25T08:48:14.241Z" }, +] + +[[package]] +name = "requests" +version = "2.32.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, +] + +[[package]] +name = "rfc3339-validator" +version = "0.1.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/28/ea/a9387748e2d111c3c2b275ba970b735e04e15cdb1eb30693b6b5708c4dbd/rfc3339_validator-0.1.4.tar.gz", hash = "sha256:138a2abdf93304ad60530167e51d2dfb9549521a836871b88d7f4695d0022f6b", size = 5513, upload-time = "2021-05-12T16:37:54.178Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7b/44/4e421b96b67b2daff264473f7465db72fbdf36a07e05494f50300cc7b0c6/rfc3339_validator-0.1.4-py2.py3-none-any.whl", hash = "sha256:24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa", size = 3490, upload-time = "2021-05-12T16:37:52.536Z" }, +] + +[[package]] +name = "rich" +version = "14.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown-it-py" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fe/75/af448d8e52bf1d8fa6a9d089ca6c07ff4453d86c65c145d0a300bb073b9b/rich-14.1.0.tar.gz", hash = "sha256:e497a48b844b0320d45007cdebfeaeed8db2a4f4bcf49f15e455cfc4af11eaa8", size = 224441, upload-time = "2025-07-25T07:32:58.125Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e3/30/3c4d035596d3cf444529e0b2953ad0466f6049528a879d27534700580395/rich-14.1.0-py3-none-any.whl", hash = "sha256:536f5f1785986d6dbdea3c75205c473f970777b4a0d6c6dd1b696aa05a3fa04f", size = 243368, upload-time = "2025-07-25T07:32:56.73Z" }, +] + +[[package]] +name = "rich-rst" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "docutils" }, + { name = "rich" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b0/69/5514c3a87b5f10f09a34bb011bc0927bc12c596c8dae5915604e71abc386/rich_rst-1.3.1.tar.gz", hash = "sha256:fad46e3ba42785ea8c1785e2ceaa56e0ffa32dbe5410dec432f37e4107c4f383", size = 13839, upload-time = "2024-04-30T04:40:38.125Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fd/bc/cc4e3dbc5e7992398dcb7a8eda0cbcf4fb792a0cdb93f857b478bf3cf884/rich_rst-1.3.1-py3-none-any.whl", hash = "sha256:498a74e3896507ab04492d326e794c3ef76e7cda078703aa592d1853d91098c1", size = 11621, upload-time = "2024-04-30T04:40:32.619Z" }, +] + +[[package]] +name = "rpds-py" +version = "0.27.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e9/dd/2c0cbe774744272b0ae725f44032c77bdcab6e8bcf544bffa3b6e70c8dba/rpds_py-0.27.1.tar.gz", hash = "sha256:26a1c73171d10b7acccbded82bf6a586ab8203601e565badc74bbbf8bc5a10f8", size = 27479, upload-time = "2025-08-27T12:16:36.024Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cc/77/610aeee8d41e39080c7e14afa5387138e3c9fa9756ab893d09d99e7d8e98/rpds_py-0.27.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:e4b9fcfbc021633863a37e92571d6f91851fa656f0180246e84cbd8b3f6b329b", size = 361741, upload-time = "2025-08-27T12:13:31.039Z" }, + { url = "https://files.pythonhosted.org/packages/3a/fc/c43765f201c6a1c60be2043cbdb664013def52460a4c7adace89d6682bf4/rpds_py-0.27.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1441811a96eadca93c517d08df75de45e5ffe68aa3089924f963c782c4b898cf", size = 345574, upload-time = "2025-08-27T12:13:32.902Z" }, + { url = "https://files.pythonhosted.org/packages/20/42/ee2b2ca114294cd9847d0ef9c26d2b0851b2e7e00bf14cc4c0b581df0fc3/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55266dafa22e672f5a4f65019015f90336ed31c6383bd53f5e7826d21a0e0b83", size = 385051, upload-time = "2025-08-27T12:13:34.228Z" }, + { url = "https://files.pythonhosted.org/packages/fd/e8/1e430fe311e4799e02e2d1af7c765f024e95e17d651612425b226705f910/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d78827d7ac08627ea2c8e02c9e5b41180ea5ea1f747e9db0915e3adf36b62dcf", size = 398395, upload-time = "2025-08-27T12:13:36.132Z" }, + { url = "https://files.pythonhosted.org/packages/82/95/9dc227d441ff2670651c27a739acb2535ccaf8b351a88d78c088965e5996/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae92443798a40a92dc5f0b01d8a7c93adde0c4dc965310a29ae7c64d72b9fad2", size = 524334, upload-time = "2025-08-27T12:13:37.562Z" }, + { url = "https://files.pythonhosted.org/packages/87/01/a670c232f401d9ad461d9a332aa4080cd3cb1d1df18213dbd0d2a6a7ab51/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c46c9dd2403b66a2a3b9720ec4b74d4ab49d4fabf9f03dfdce2d42af913fe8d0", size = 407691, upload-time = "2025-08-27T12:13:38.94Z" }, + { url = "https://files.pythonhosted.org/packages/03/36/0a14aebbaa26fe7fab4780c76f2239e76cc95a0090bdb25e31d95c492fcd/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2efe4eb1d01b7f5f1939f4ef30ecea6c6b3521eec451fb93191bf84b2a522418", size = 386868, upload-time = "2025-08-27T12:13:40.192Z" }, + { url = "https://files.pythonhosted.org/packages/3b/03/8c897fb8b5347ff6c1cc31239b9611c5bf79d78c984430887a353e1409a1/rpds_py-0.27.1-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:15d3b4d83582d10c601f481eca29c3f138d44c92187d197aff663a269197c02d", size = 405469, upload-time = "2025-08-27T12:13:41.496Z" }, + { url = "https://files.pythonhosted.org/packages/da/07/88c60edc2df74850d496d78a1fdcdc7b54360a7f610a4d50008309d41b94/rpds_py-0.27.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4ed2e16abbc982a169d30d1a420274a709949e2cbdef119fe2ec9d870b42f274", size = 422125, upload-time = "2025-08-27T12:13:42.802Z" }, + { url = "https://files.pythonhosted.org/packages/6b/86/5f4c707603e41b05f191a749984f390dabcbc467cf833769b47bf14ba04f/rpds_py-0.27.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a75f305c9b013289121ec0f1181931975df78738cdf650093e6b86d74aa7d8dd", size = 562341, upload-time = "2025-08-27T12:13:44.472Z" }, + { url = "https://files.pythonhosted.org/packages/b2/92/3c0cb2492094e3cd9baf9e49bbb7befeceb584ea0c1a8b5939dca4da12e5/rpds_py-0.27.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:67ce7620704745881a3d4b0ada80ab4d99df390838839921f99e63c474f82cf2", size = 592511, upload-time = "2025-08-27T12:13:45.898Z" }, + { url = "https://files.pythonhosted.org/packages/10/bb/82e64fbb0047c46a168faa28d0d45a7851cd0582f850b966811d30f67ad8/rpds_py-0.27.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9d992ac10eb86d9b6f369647b6a3f412fc0075cfd5d799530e84d335e440a002", size = 557736, upload-time = "2025-08-27T12:13:47.408Z" }, + { url = "https://files.pythonhosted.org/packages/00/95/3c863973d409210da7fb41958172c6b7dbe7fc34e04d3cc1f10bb85e979f/rpds_py-0.27.1-cp313-cp313-win32.whl", hash = "sha256:4f75e4bd8ab8db624e02c8e2fc4063021b58becdbe6df793a8111d9343aec1e3", size = 221462, upload-time = "2025-08-27T12:13:48.742Z" }, + { url = "https://files.pythonhosted.org/packages/ce/2c/5867b14a81dc217b56d95a9f2a40fdbc56a1ab0181b80132beeecbd4b2d6/rpds_py-0.27.1-cp313-cp313-win_amd64.whl", hash = "sha256:f9025faafc62ed0b75a53e541895ca272815bec18abe2249ff6501c8f2e12b83", size = 232034, upload-time = "2025-08-27T12:13:50.11Z" }, + { url = "https://files.pythonhosted.org/packages/c7/78/3958f3f018c01923823f1e47f1cc338e398814b92d83cd278364446fac66/rpds_py-0.27.1-cp313-cp313-win_arm64.whl", hash = "sha256:ed10dc32829e7d222b7d3b93136d25a406ba9788f6a7ebf6809092da1f4d279d", size = 222392, upload-time = "2025-08-27T12:13:52.587Z" }, + { url = "https://files.pythonhosted.org/packages/01/76/1cdf1f91aed5c3a7bf2eba1f1c4e4d6f57832d73003919a20118870ea659/rpds_py-0.27.1-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:92022bbbad0d4426e616815b16bc4127f83c9a74940e1ccf3cfe0b387aba0228", size = 358355, upload-time = "2025-08-27T12:13:54.012Z" }, + { url = "https://files.pythonhosted.org/packages/c3/6f/bf142541229374287604caf3bb2a4ae17f0a580798fd72d3b009b532db4e/rpds_py-0.27.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:47162fdab9407ec3f160805ac3e154df042e577dd53341745fc7fb3f625e6d92", size = 342138, upload-time = "2025-08-27T12:13:55.791Z" }, + { url = "https://files.pythonhosted.org/packages/1a/77/355b1c041d6be40886c44ff5e798b4e2769e497b790f0f7fd1e78d17e9a8/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb89bec23fddc489e5d78b550a7b773557c9ab58b7946154a10a6f7a214a48b2", size = 380247, upload-time = "2025-08-27T12:13:57.683Z" }, + { url = "https://files.pythonhosted.org/packages/d6/a4/d9cef5c3946ea271ce2243c51481971cd6e34f21925af2783dd17b26e815/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e48af21883ded2b3e9eb48cb7880ad8598b31ab752ff3be6457001d78f416723", size = 390699, upload-time = "2025-08-27T12:13:59.137Z" }, + { url = "https://files.pythonhosted.org/packages/3a/06/005106a7b8c6c1a7e91b73169e49870f4af5256119d34a361ae5240a0c1d/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6f5b7bd8e219ed50299e58551a410b64daafb5017d54bbe822e003856f06a802", size = 521852, upload-time = "2025-08-27T12:14:00.583Z" }, + { url = "https://files.pythonhosted.org/packages/e5/3e/50fb1dac0948e17a02eb05c24510a8fe12d5ce8561c6b7b7d1339ab7ab9c/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08f1e20bccf73b08d12d804d6e1c22ca5530e71659e6673bce31a6bb71c1e73f", size = 402582, upload-time = "2025-08-27T12:14:02.034Z" }, + { url = "https://files.pythonhosted.org/packages/cb/b0/f4e224090dc5b0ec15f31a02d746ab24101dd430847c4d99123798661bfc/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0dc5dceeaefcc96dc192e3a80bbe1d6c410c469e97bdd47494a7d930987f18b2", size = 384126, upload-time = "2025-08-27T12:14:03.437Z" }, + { url = "https://files.pythonhosted.org/packages/54/77/ac339d5f82b6afff1df8f0fe0d2145cc827992cb5f8eeb90fc9f31ef7a63/rpds_py-0.27.1-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:d76f9cc8665acdc0c9177043746775aa7babbf479b5520b78ae4002d889f5c21", size = 399486, upload-time = "2025-08-27T12:14:05.443Z" }, + { url = "https://files.pythonhosted.org/packages/d6/29/3e1c255eee6ac358c056a57d6d6869baa00a62fa32eea5ee0632039c50a3/rpds_py-0.27.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:134fae0e36022edad8290a6661edf40c023562964efea0cc0ec7f5d392d2aaef", size = 414832, upload-time = "2025-08-27T12:14:06.902Z" }, + { url = "https://files.pythonhosted.org/packages/3f/db/6d498b844342deb3fa1d030598db93937a9964fcf5cb4da4feb5f17be34b/rpds_py-0.27.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:eb11a4f1b2b63337cfd3b4d110af778a59aae51c81d195768e353d8b52f88081", size = 557249, upload-time = "2025-08-27T12:14:08.37Z" }, + { url = "https://files.pythonhosted.org/packages/60/f3/690dd38e2310b6f68858a331399b4d6dbb9132c3e8ef8b4333b96caf403d/rpds_py-0.27.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:13e608ac9f50a0ed4faec0e90ece76ae33b34c0e8656e3dceb9a7db994c692cd", size = 587356, upload-time = "2025-08-27T12:14:10.034Z" }, + { url = "https://files.pythonhosted.org/packages/86/e3/84507781cccd0145f35b1dc32c72675200c5ce8d5b30f813e49424ef68fc/rpds_py-0.27.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dd2135527aa40f061350c3f8f89da2644de26cd73e4de458e79606384f4f68e7", size = 555300, upload-time = "2025-08-27T12:14:11.783Z" }, + { url = "https://files.pythonhosted.org/packages/e5/ee/375469849e6b429b3516206b4580a79e9ef3eb12920ddbd4492b56eaacbe/rpds_py-0.27.1-cp313-cp313t-win32.whl", hash = "sha256:3020724ade63fe320a972e2ffd93b5623227e684315adce194941167fee02688", size = 216714, upload-time = "2025-08-27T12:14:13.629Z" }, + { url = "https://files.pythonhosted.org/packages/21/87/3fc94e47c9bd0742660e84706c311a860dcae4374cf4a03c477e23ce605a/rpds_py-0.27.1-cp313-cp313t-win_amd64.whl", hash = "sha256:8ee50c3e41739886606388ba3ab3ee2aae9f35fb23f833091833255a31740797", size = 228943, upload-time = "2025-08-27T12:14:14.937Z" }, + { url = "https://files.pythonhosted.org/packages/70/36/b6e6066520a07cf029d385de869729a895917b411e777ab1cde878100a1d/rpds_py-0.27.1-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:acb9aafccaae278f449d9c713b64a9e68662e7799dbd5859e2c6b3c67b56d334", size = 362472, upload-time = "2025-08-27T12:14:16.333Z" }, + { url = "https://files.pythonhosted.org/packages/af/07/b4646032e0dcec0df9c73a3bd52f63bc6c5f9cda992f06bd0e73fe3fbebd/rpds_py-0.27.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:b7fb801aa7f845ddf601c49630deeeccde7ce10065561d92729bfe81bd21fb33", size = 345676, upload-time = "2025-08-27T12:14:17.764Z" }, + { url = "https://files.pythonhosted.org/packages/b0/16/2f1003ee5d0af4bcb13c0cf894957984c32a6751ed7206db2aee7379a55e/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe0dd05afb46597b9a2e11c351e5e4283c741237e7f617ffb3252780cca9336a", size = 385313, upload-time = "2025-08-27T12:14:19.829Z" }, + { url = "https://files.pythonhosted.org/packages/05/cd/7eb6dd7b232e7f2654d03fa07f1414d7dfc980e82ba71e40a7c46fd95484/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b6dfb0e058adb12d8b1d1b25f686e94ffa65d9995a5157afe99743bf7369d62b", size = 399080, upload-time = "2025-08-27T12:14:21.531Z" }, + { url = "https://files.pythonhosted.org/packages/20/51/5829afd5000ec1cb60f304711f02572d619040aa3ec033d8226817d1e571/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ed090ccd235f6fa8bb5861684567f0a83e04f52dfc2e5c05f2e4b1309fcf85e7", size = 523868, upload-time = "2025-08-27T12:14:23.485Z" }, + { url = "https://files.pythonhosted.org/packages/05/2c/30eebca20d5db95720ab4d2faec1b5e4c1025c473f703738c371241476a2/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf876e79763eecf3e7356f157540d6a093cef395b65514f17a356f62af6cc136", size = 408750, upload-time = "2025-08-27T12:14:24.924Z" }, + { url = "https://files.pythonhosted.org/packages/90/1a/cdb5083f043597c4d4276eae4e4c70c55ab5accec078da8611f24575a367/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:12ed005216a51b1d6e2b02a7bd31885fe317e45897de81d86dcce7d74618ffff", size = 387688, upload-time = "2025-08-27T12:14:27.537Z" }, + { url = "https://files.pythonhosted.org/packages/7c/92/cf786a15320e173f945d205ab31585cc43969743bb1a48b6888f7a2b0a2d/rpds_py-0.27.1-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:ee4308f409a40e50593c7e3bb8cbe0b4d4c66d1674a316324f0c2f5383b486f9", size = 407225, upload-time = "2025-08-27T12:14:28.981Z" }, + { url = "https://files.pythonhosted.org/packages/33/5c/85ee16df5b65063ef26017bef33096557a4c83fbe56218ac7cd8c235f16d/rpds_py-0.27.1-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0b08d152555acf1f455154d498ca855618c1378ec810646fcd7c76416ac6dc60", size = 423361, upload-time = "2025-08-27T12:14:30.469Z" }, + { url = "https://files.pythonhosted.org/packages/4b/8e/1c2741307fcabd1a334ecf008e92c4f47bb6f848712cf15c923becfe82bb/rpds_py-0.27.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:dce51c828941973a5684d458214d3a36fcd28da3e1875d659388f4f9f12cc33e", size = 562493, upload-time = "2025-08-27T12:14:31.987Z" }, + { url = "https://files.pythonhosted.org/packages/04/03/5159321baae9b2222442a70c1f988cbbd66b9be0675dd3936461269be360/rpds_py-0.27.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:c1476d6f29eb81aa4151c9a31219b03f1f798dc43d8af1250a870735516a1212", size = 592623, upload-time = "2025-08-27T12:14:33.543Z" }, + { url = "https://files.pythonhosted.org/packages/ff/39/c09fd1ad28b85bc1d4554a8710233c9f4cefd03d7717a1b8fbfd171d1167/rpds_py-0.27.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:3ce0cac322b0d69b63c9cdb895ee1b65805ec9ffad37639f291dd79467bee675", size = 558800, upload-time = "2025-08-27T12:14:35.436Z" }, + { url = "https://files.pythonhosted.org/packages/c5/d6/99228e6bbcf4baa764b18258f519a9035131d91b538d4e0e294313462a98/rpds_py-0.27.1-cp314-cp314-win32.whl", hash = "sha256:dfbfac137d2a3d0725758cd141f878bf4329ba25e34979797c89474a89a8a3a3", size = 221943, upload-time = "2025-08-27T12:14:36.898Z" }, + { url = "https://files.pythonhosted.org/packages/be/07/c802bc6b8e95be83b79bdf23d1aa61d68324cb1006e245d6c58e959e314d/rpds_py-0.27.1-cp314-cp314-win_amd64.whl", hash = "sha256:a6e57b0abfe7cc513450fcf529eb486b6e4d3f8aee83e92eb5f1ef848218d456", size = 233739, upload-time = "2025-08-27T12:14:38.386Z" }, + { url = "https://files.pythonhosted.org/packages/c8/89/3e1b1c16d4c2d547c5717377a8df99aee8099ff050f87c45cb4d5fa70891/rpds_py-0.27.1-cp314-cp314-win_arm64.whl", hash = "sha256:faf8d146f3d476abfee026c4ae3bdd9ca14236ae4e4c310cbd1cf75ba33d24a3", size = 223120, upload-time = "2025-08-27T12:14:39.82Z" }, + { url = "https://files.pythonhosted.org/packages/62/7e/dc7931dc2fa4a6e46b2a4fa744a9fe5c548efd70e0ba74f40b39fa4a8c10/rpds_py-0.27.1-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:ba81d2b56b6d4911ce735aad0a1d4495e808b8ee4dc58715998741a26874e7c2", size = 358944, upload-time = "2025-08-27T12:14:41.199Z" }, + { url = "https://files.pythonhosted.org/packages/e6/22/4af76ac4e9f336bfb1a5f240d18a33c6b2fcaadb7472ac7680576512b49a/rpds_py-0.27.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:84f7d509870098de0e864cad0102711c1e24e9b1a50ee713b65928adb22269e4", size = 342283, upload-time = "2025-08-27T12:14:42.699Z" }, + { url = "https://files.pythonhosted.org/packages/1c/15/2a7c619b3c2272ea9feb9ade67a45c40b3eeb500d503ad4c28c395dc51b4/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9e960fc78fecd1100539f14132425e1d5fe44ecb9239f8f27f079962021523e", size = 380320, upload-time = "2025-08-27T12:14:44.157Z" }, + { url = "https://files.pythonhosted.org/packages/a2/7d/4c6d243ba4a3057e994bb5bedd01b5c963c12fe38dde707a52acdb3849e7/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:62f85b665cedab1a503747617393573995dac4600ff51869d69ad2f39eb5e817", size = 391760, upload-time = "2025-08-27T12:14:45.845Z" }, + { url = "https://files.pythonhosted.org/packages/b4/71/b19401a909b83bcd67f90221330bc1ef11bc486fe4e04c24388d28a618ae/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fed467af29776f6556250c9ed85ea5a4dd121ab56a5f8b206e3e7a4c551e48ec", size = 522476, upload-time = "2025-08-27T12:14:47.364Z" }, + { url = "https://files.pythonhosted.org/packages/e4/44/1a3b9715c0455d2e2f0f6df5ee6d6f5afdc423d0773a8a682ed2b43c566c/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2729615f9d430af0ae6b36cf042cb55c0936408d543fb691e1a9e36648fd35a", size = 403418, upload-time = "2025-08-27T12:14:49.991Z" }, + { url = "https://files.pythonhosted.org/packages/1c/4b/fb6c4f14984eb56673bc868a66536f53417ddb13ed44b391998100a06a96/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b207d881a9aef7ba753d69c123a35d96ca7cb808056998f6b9e8747321f03b8", size = 384771, upload-time = "2025-08-27T12:14:52.159Z" }, + { url = "https://files.pythonhosted.org/packages/c0/56/d5265d2d28b7420d7b4d4d85cad8ef891760f5135102e60d5c970b976e41/rpds_py-0.27.1-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:639fd5efec029f99b79ae47e5d7e00ad8a773da899b6309f6786ecaf22948c48", size = 400022, upload-time = "2025-08-27T12:14:53.859Z" }, + { url = "https://files.pythonhosted.org/packages/8f/e9/9f5fc70164a569bdd6ed9046486c3568d6926e3a49bdefeeccfb18655875/rpds_py-0.27.1-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fecc80cb2a90e28af8a9b366edacf33d7a91cbfe4c2c4544ea1246e949cfebeb", size = 416787, upload-time = "2025-08-27T12:14:55.673Z" }, + { url = "https://files.pythonhosted.org/packages/d4/64/56dd03430ba491db943a81dcdef115a985aac5f44f565cd39a00c766d45c/rpds_py-0.27.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:42a89282d711711d0a62d6f57d81aa43a1368686c45bc1c46b7f079d55692734", size = 557538, upload-time = "2025-08-27T12:14:57.245Z" }, + { url = "https://files.pythonhosted.org/packages/3f/36/92cc885a3129993b1d963a2a42ecf64e6a8e129d2c7cc980dbeba84e55fb/rpds_py-0.27.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:cf9931f14223de59551ab9d38ed18d92f14f055a5f78c1d8ad6493f735021bbb", size = 588512, upload-time = "2025-08-27T12:14:58.728Z" }, + { url = "https://files.pythonhosted.org/packages/dd/10/6b283707780a81919f71625351182b4f98932ac89a09023cb61865136244/rpds_py-0.27.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f39f58a27cc6e59f432b568ed8429c7e1641324fbe38131de852cd77b2d534b0", size = 555813, upload-time = "2025-08-27T12:15:00.334Z" }, + { url = "https://files.pythonhosted.org/packages/04/2e/30b5ea18c01379da6272a92825dd7e53dc9d15c88a19e97932d35d430ef7/rpds_py-0.27.1-cp314-cp314t-win32.whl", hash = "sha256:d5fa0ee122dc09e23607a28e6d7b150da16c662e66409bbe85230e4c85bb528a", size = 217385, upload-time = "2025-08-27T12:15:01.937Z" }, + { url = "https://files.pythonhosted.org/packages/32/7d/97119da51cb1dd3f2f3c0805f155a3aa4a95fa44fe7d78ae15e69edf4f34/rpds_py-0.27.1-cp314-cp314t-win_amd64.whl", hash = "sha256:6567d2bb951e21232c2f660c24cf3470bb96de56cdcb3f071a83feeaff8a2772", size = 230097, upload-time = "2025-08-27T12:15:03.961Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + +[[package]] +name = "sniffio" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, +] + +[[package]] +name = "sse-starlette" +version = "3.0.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/6f/22ed6e33f8a9e76ca0a412405f31abb844b779d52c5f96660766edcd737c/sse_starlette-3.0.2.tar.gz", hash = "sha256:ccd60b5765ebb3584d0de2d7a6e4f745672581de4f5005ab31c3a25d10b52b3a", size = 20985, upload-time = "2025-07-27T09:07:44.565Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/10/c78f463b4ef22eef8491f218f692be838282cd65480f6e423d7730dfd1fb/sse_starlette-3.0.2-py3-none-any.whl", hash = "sha256:16b7cbfddbcd4eaca11f7b586f3b8a080f1afe952c15813455b162edea619e5a", size = 11297, upload-time = "2025-07-27T09:07:43.268Z" }, +] + +[[package]] +name = "starlette" +version = "0.48.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a7/a5/d6f429d43394057b67a6b5bbe6eae2f77a6bf7459d961fdb224bf206eee6/starlette-0.48.0.tar.gz", hash = "sha256:7e8cee469a8ab2352911528110ce9088fdc6a37d9876926e73da7ce4aa4c7a46", size = 2652949, upload-time = "2025-09-13T08:41:05.699Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/be/72/2db2f49247d0a18b4f1bb9a5a39a0162869acf235f3a96418363947b3d46/starlette-0.48.0-py3-none-any.whl", hash = "sha256:0764ca97b097582558ecb498132ed0c7d942f233f365b86ba37770e026510659", size = 73736, upload-time = "2025-09-13T08:41:03.869Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, +] + +[[package]] +name = "typing-inspection" +version = "0.4.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f8/b1/0c11f5058406b3af7609f121aaa6b609744687f1d158b3c3a5bf4cc94238/typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28", size = 75726, upload-time = "2025-05-21T18:55:23.885Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/17/69/cd203477f944c353c31bade965f880aa1061fd6bf05ded0726ca845b6ff7/typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51", size = 14552, upload-time = "2025-05-21T18:55:22.152Z" }, +] + +[[package]] +name = "urllib3" +version = "2.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" }, +] + +[[package]] +name = "uvicorn" +version = "0.36.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ef/5e/f0cd46063a02fd8515f0e880c37d2657845b7306c16ce6c4ffc44afd9036/uvicorn-0.36.0.tar.gz", hash = "sha256:527dc68d77819919d90a6b267be55f0e76704dca829d34aea9480be831a9b9d9", size = 80032, upload-time = "2025-09-20T01:07:14.418Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/96/06/5cc0542b47c0338c1cb676b348e24a1c29acabc81000bced518231dded6f/uvicorn-0.36.0-py3-none-any.whl", hash = "sha256:6bb4ba67f16024883af8adf13aba3a9919e415358604ce46780d3f9bdc36d731", size = 67675, upload-time = "2025-09-20T01:07:12.984Z" }, +] + +[[package]] +name = "werkzeug" +version = "3.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/32/af/d4502dc713b4ccea7175d764718d5183caf8d0867a4f0190d5d4a45cea49/werkzeug-3.1.1.tar.gz", hash = "sha256:8cd39dfbdfc1e051965f156163e2974e52c210f130810e9ad36858f0fd3edad4", size = 806453, upload-time = "2024-11-01T16:40:45.462Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ee/ea/c67e1dee1ba208ed22c06d1d547ae5e293374bfc43e0eb0ef5e262b68561/werkzeug-3.1.1-py3-none-any.whl", hash = "sha256:a71124d1ef06008baafa3d266c02f56e1836a5984afd6dd6c9230669d60d9fb5", size = 224371, upload-time = "2024-11-01T16:40:43.994Z" }, +] diff --git a/tox.ini b/tox.ini index 842df56e..992c9498 100644 --- a/tox.ini +++ b/tox.ini @@ -20,7 +20,8 @@ extend-exclude = src/mysql-mcp-server, src/oci-pricing-mcp-server, src/oracle-db-doc-mcp-server - src/database-mcp-server + src/database-mcp-server, + src/oci-db-dynamic-mcp-server [testenv] deps = From 7ffedcfe5053d856543e4bea7619002422823079 Mon Sep 17 00:00:00 2001 From: Shyam N V Date: Fri, 19 Dec 2025 17:36:16 +0530 Subject: [PATCH 2/5] OCI DB Dynamic MCP Server --- src/oci-db-dynamic-mcp-server/LICENSE.txt | 35 + src/oci-db-dynamic-mcp-server/README.md | 453 + .../oracle/__init__.py | 5 + .../oci_db_dynamic_mcp_server/__init__.py | 8 + .../dynamic_tools_loader.py | 322 + .../oci_db_dynamic_mcp_server/server.py | 311 + .../tests/test_db_dynamic.py | 7843 +++++++++++++++++ src/oci-db-dynamic-mcp-server/pyproject.toml | 41 + src/oci-db-dynamic-mcp-server/uv.lock | 1152 +++ tox.ini | 3 +- 10 files changed, 10172 insertions(+), 1 deletion(-) create mode 100644 src/oci-db-dynamic-mcp-server/LICENSE.txt create mode 100644 src/oci-db-dynamic-mcp-server/README.md create mode 100644 src/oci-db-dynamic-mcp-server/oracle/__init__.py create mode 100644 src/oci-db-dynamic-mcp-server/oracle/oci_db_dynamic_mcp_server/__init__.py create mode 100644 src/oci-db-dynamic-mcp-server/oracle/oci_db_dynamic_mcp_server/dynamic_tools_loader.py create mode 100644 src/oci-db-dynamic-mcp-server/oracle/oci_db_dynamic_mcp_server/server.py create mode 100644 src/oci-db-dynamic-mcp-server/oracle/oci_db_dynamic_mcp_server/tests/test_db_dynamic.py create mode 100644 src/oci-db-dynamic-mcp-server/pyproject.toml create mode 100644 src/oci-db-dynamic-mcp-server/uv.lock diff --git a/src/oci-db-dynamic-mcp-server/LICENSE.txt b/src/oci-db-dynamic-mcp-server/LICENSE.txt new file mode 100644 index 00000000..8dc7c070 --- /dev/null +++ b/src/oci-db-dynamic-mcp-server/LICENSE.txt @@ -0,0 +1,35 @@ +Copyright (c) 2025 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/src/oci-db-dynamic-mcp-server/README.md b/src/oci-db-dynamic-mcp-server/README.md new file mode 100644 index 00000000..b041d0b4 --- /dev/null +++ b/src/oci-db-dynamic-mcp-server/README.md @@ -0,0 +1,453 @@ +# OCI Database Dynamic MCP Server + +## Overview + +This server provides tools to interact with the OCI Database service. +You can load the required tools using the `--resources` filter, and the server is designed to dynamically generate the, during runtime. + +## Running the server + +```sh +uv run oracle.oci-db-dynamic-mcp-server +``` + +## Environment Variables + +The server supports the following environment variables: + +- `OCI_CONFIG_PROFILE`: OCI configuration profile name (default: "DEFAULT") + +## Parameters + +The server accepts the following parameters to control which OCI resources are loaded. This helps reduce startup time and token usage by only loading the tools you need. + +| Parameter | Type | CLI Flag | Description | +| :--- | :--- |:--------------------|:---------------------- | +| **Resources** | String | `--resources or -r` | A comma-separated list of OCI resources to load (e.g., `database`, `db_system`). If omitted, all available tools are loaded. | + +## Configuration Example +This loads only the dbSystems and the databases resources (case-insensitive) +```json + "database-dynamic": { + "autoApprove": [], + "disabled": false, + "timeout": 30, + "type": "stdio", + "command": "uv", + "args": [ + "run", + "oracle.oci-db-dynamic-mcp-server", + "--resources", + "dbSystems, databases" + ], + "env": { + "VIRTUAL_ENV": "Documents/oci-mcp/.venv", + "OCI_CONFIG_PROFILE": "DEFAULT" + } +``` + +## Tools + +| Tool Name | Resource Name | Description +| --- |----------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| ListApplicationVips | applicationVip | Gets a list of application virtual IP (VIP) addresses on a cloud VM cluster | +| CreateApplicationVip | applicationVip | Creates a new application virtual IP (VIP) address in the specified cloud VM cluster based on the request parameters you provide | +| DeleteApplicationVip | applicationVip | Deletes and deregisters the specified application virtual IP (VIP) address | +| GetApplicationVip | applicationVip | Gets information about a specified application virtual IP (VIP) address | +| ListAutonomousContainerDatabaseBackups | autonomousContainerDatabaseBackups | Gets a list of Autonomous Container Database backups by using either the 'autonomousDatabaseId' or 'compartmentId' as your query parameter | +| ListAutonomousContainerDatabaseVersions | autonomousContainerDatabaseVersions | Gets a list of supported Autonomous Container Database versions | +| ListAutonomousContainerDatabases | autonomousContainerDatabases | Gets a list of the Autonomous Container Databases in the specified compartment | +| CreateAutonomousContainerDatabase | autonomousContainerDatabases | Creates an Autonomous Container Database in the specified Autonomous Exadata Infrastructure | +| TerminateAutonomousContainerDatabase | autonomousContainerDatabases | Terminates an Autonomous Container Database, which permanently deletes the container database and any databases within the container database | +| GetAutonomousContainerDatabase | autonomousContainerDatabases | Gets information about the specified Autonomous Container Database | +| UpdateAutonomousContainerDatabase | autonomousContainerDatabases | Updates the properties of an Autonomous Container Database, such as display name, maintenance preference, backup retention, and tags | +| AddStandbyAutonomousContainerDatabase | autonomousContainerDatabases | Add a standby Autonomous Container Database | +| ChangeAutonomousContainerDatabaseCompartment | autonomousContainerDatabases | Move the Autonomous Container Database and its dependent resources to the specified compartment | +| EditAutonomousContainerDatabaseDataguard | autonomousContainerDatabases | Modify Autonomous Container Database Data Guard settings such as protection mode, automatic failover, and fast start failover lag limit | +| FailoverAutonomousContainerDatabaseDataguard | autonomousContainerDatabases | Performs failover to a standby Autonomous Container Database (ACD) identified by the autonomousContainerDatabaseId parameter | +| ReinstateAutonomousContainerDatabaseDataguard | autonomousContainerDatabases | Reinstates a disabled standby Autonomous Container Database (ACD), identified by the autonomousContainerDatabaseId parameter to an active standby ACD | +| RestartAutonomousContainerDatabase | autonomousContainerDatabases | Rolling restarts the specified Autonomous Container Database | +| RotateAutonomousContainerDatabaseEncryptionKey | autonomousContainerDatabases | Creates a new version of an existing [Vault service](/iaas/Content/KeyManagement/Concepts/keyoverview | +| ConvertStandbyAutonomousContainerDatabase | autonomousContainerDatabases | Convert the standby Autonomous Container Database (ACD) between physical standby and snapshot standby ACD | +| SwitchoverAutonomousContainerDatabaseDataguard | autonomousContainerDatabases | Switchover an Autonomous Container Database (ACD), identified by the autonomousContainerDatabaseId parameter, to an active standby ACD | +| MigrateAutonomousContainerDatabaseDataguardAssociation | autonomousContainerDatabases | Migrate Autonomous Container Database, identified by the autonomousContainerDatabaseId parameter | +| ListContainerDatabasePatches | autonomousContainerDatabases | Lists the patches applicable to the requested container database | +| GetAutonomousContainerDatabaseResourceUsage | autonomousContainerDatabases | Get resource usage details for the specified Autonomous Container Database | +| ListAutonomousDatabaseBackups | autonomousDatabaseBackups | Gets a list of Autonomous AI Database backups based on either the `autonomousDatabaseId` or `compartmentId` specified as a query parameter | +| CreateAutonomousDatabaseBackup | autonomousDatabaseBackups | Creates a new Autonomous AI Database backup for the specified database based on the provided request parameters | +| DeleteAutonomousDatabaseBackup | autonomousDatabaseBackups | Deletes a long-term backup | +| GetAutonomousDatabaseBackup | autonomousDatabaseBackups | Gets information about the specified Autonomous AI Database backup | +| UpdateAutonomousDatabaseBackup | autonomousDatabaseBackups | Updates the Autonomous AI Database backup of the specified database based on the request parameters | +| ListAutonomousDatabaseCharacterSets | autonomousDatabaseCharacterSets | Gets a list of supported character sets | +| ListAutonomousDatabaseSoftwareImages | autonomousDatabaseSoftwareImages | Gets a list of the Autonomous AI Database Software Images in the specified compartment | +| CreateAutonomousDatabaseSoftwareImage | autonomousDatabaseSoftwareImages | create Autonomous AI Database Software Image in the specified compartment | +| DeleteAutonomousDatabaseSoftwareImage | autonomousDatabaseSoftwareImages | Delete an Autonomous AI Database Software Image | +| GetAutonomousDatabaseSoftwareImage | autonomousDatabaseSoftwareImages | Gets information about the specified Autonomous AI Database Software Image | +| UpdateAutonomousDatabaseSoftwareImage | autonomousDatabaseSoftwareImages | Updates the properties of an Autonomous AI Database Software Image, like add tags | +| ChangeAutonomousDatabaseSoftwareImageCompartment | autonomousDatabaseSoftwareImages | Move the Autonomous AI Database Software Image and its dependent resources to the specified compartment | +| ListAutonomousDatabases | autonomousDatabases | Gets a list of Autonomous AI Databases based on the query parameters specified | +| CreateAutonomousDatabase | autonomousDatabases | Creates a new Autonomous AI Database | +| ResourcePoolShapes | autonomousDatabases | Lists available resource pools shapes | +| GetAutonomousDatabaseRegionalWallet | autonomousDatabases | Gets the Autonomous AI Database regional wallet details | +| UpdateAutonomousDatabaseRegionalWallet | autonomousDatabases | Updates the Autonomous AI Database regional wallet | +| DeleteAutonomousDatabase | autonomousDatabases | Deletes the specified Autonomous AI Database | +| GetAutonomousDatabase | autonomousDatabases | Gets the details of the specified Autonomous AI Database | +| UpdateAutonomousDatabase | autonomousDatabases | Updates one or more attributes of the specified Autonomous AI Database | +| ChangeAutonomousDatabaseCompartment | autonomousDatabases | Move the Autonomous AI Database and its dependent resources to the specified compartment | +| ChangeDisasterRecoveryConfiguration | autonomousDatabases | This operation updates the cross-region disaster recovery (DR) details of the standby Autonomous AI Database Serverless database, and must be run on the standby side | +| ChangeAutonomousDatabaseSubscription | autonomousDatabases | Associate an Autonomous AI Database with a different subscription | +| ConfigureAutonomousDatabaseVaultKey | autonomousDatabases | Configures the Autonomous AI Database Vault service [key](/Content/KeyManagement/Concepts/keyoverview | +| ConfigureSaasAdminUser | autonomousDatabases | This operation updates SaaS administrative user configuration of the Autonomous AI Database | +| DeregisterAutonomousDatabaseDataSafe | autonomousDatabases | Asynchronously deregisters this Autonomous AI Database with Data Safe | +| DisableAutonomousDatabaseManagement | autonomousDatabases | Disables Database Management for the Autonomous AI Database resource | +| DisableAutonomousDatabaseOperationsInsights | autonomousDatabases | Disables Operations Insights for the Autonomous AI Database resource | +| EnableAutonomousDatabaseManagement | autonomousDatabases | Enables Database Management for Autonomous AI Database | +| EnableAutonomousDatabaseOperationsInsights | autonomousDatabases | Enables the specified Autonomous AI Database with Operations Insights | +| FailOverAutonomousDatabase | autonomousDatabases | Initiates a failover of the specified Autonomous AI Database to the associated peer database | +| GenerateAutonomousDatabaseWallet | autonomousDatabases | Creates and downloads a wallet for the specified Autonomous AI Database | +| SaasAdminUserStatus | autonomousDatabases | This operation gets SaaS administrative user status of the Autonomous AI Database | +| AutonomousDatabaseManualRefresh | autonomousDatabases | Initiates a data refresh for an Autonomous AI Database refreshable clone | +| RegisterAutonomousDatabaseDataSafe | autonomousDatabases | Asynchronously registers this Autonomous AI Database with Data Safe | +| RestartAutonomousDatabase | autonomousDatabases | Restarts the specified Autonomous AI Database | +| RestoreAutonomousDatabase | autonomousDatabases | Restores an Autonomous AI Database based on the provided request parameters | +| RotateAutonomousDatabaseEncryptionKey | autonomousDatabases | Rotate existing AutonomousDatabase [Vault service](/iaas/Content/KeyManagement/Concepts/keyoverview | +| ShrinkAutonomousDatabase | autonomousDatabases | This operation shrinks the current allocated storage down to the current actual used data storage (actualUsedDataStorageSizeInTBs) | +| StartAutonomousDatabase | autonomousDatabases | Starts the specified Autonomous AI Database | +| StopAutonomousDatabase | autonomousDatabases | Stops the specified Autonomous AI Database | +| SwitchoverAutonomousDatabase | autonomousDatabases | Initiates a switchover of the specified Autonomous AI Database to the associated peer database | +| ListAutonomousDatabaseDataguardAssociations | autonomousDatabases | *Deprecated | +| GetAutonomousDatabaseDataguardAssociation | autonomousDatabases | *Deprecated | +| ListAutonomousDatabaseClones | autonomousDatabases | Lists the Autonomous AI Database clones for the specified Autonomous AI Database | +| ListAutonomousDatabasePeers | autonomousDatabases | Lists the Autonomous AI Database peers for the specified Autonomous AI Database | +| ListAutonomousDatabaseRefreshableClones | autonomousDatabases | Lists the OCIDs of the Autonomous AI Database local and connected remote refreshable clones with the region where they exist for the specified source database | +| ListResourcePoolMembers | autonomousDatabases | Lists the OCIDs of the Autonomous AI Database resource pool members for the specified Autonomous AI Database leader | +| GetAutonomousDatabaseWallet | autonomousDatabases | Gets the wallet details for the specified Autonomous AI Database | +| UpdateAutonomousDatabaseWallet | autonomousDatabases | Updates the wallet for the specified Autonomous AI Database | +| ListAutonomousDbPreviewVersions | autonomousDbPreviewVersions | Gets a list of supported Autonomous AI Database versions | +| ListAutonomousDbVersions | autonomousDbVersions | Gets a list of supported Autonomous AI Database versions | +| GetExadataInfrastructureOcpus | autonomousExadataInfrastructures | Gets details of the available and consumed OCPUs for the specified Autonomous Exadata Infrastructure resource | +| GetAutonomousPatch | autonomousPatches | Gets information about a specific autonomous patch | +| ListAutonomousVirtualMachines | autonomousVirtualMachines | Lists the Autonomous Virtual Machines in the specified Autonomous VM Cluster and Compartment | +| GetAutonomousVirtualMachine | autonomousVirtualMachines | Gets the details of specific Autonomous Virtual Machine | +| ListAutonomousVmClusters | autonomousVmClusters | Gets a list of Exadata Cloud@Customer Autonomous VM clusters in the specified compartment | +| CreateAutonomousVmCluster | autonomousVmClusters | Creates an Autonomous VM cluster for Exadata Cloud@Customer | +| DeleteAutonomousVmCluster | autonomousVmClusters | Deletes the specified Autonomous VM cluster in an Exadata Cloud@Customer system | +| GetAutonomousVmCluster | autonomousVmClusters | Gets information about the specified Autonomous VM cluster for an Exadata Cloud@Customer system | +| UpdateAutonomousVmCluster | autonomousVmClusters | Updates the specified Autonomous VM cluster for the Exadata Cloud@Customer system | +| ListAutonomousVmClusterAcdResourceUsage | autonomousVmClusters | Gets the list of resource usage details for all the Autonomous Container Database in the specified Autonomous Exadata VM cluster | +| ChangeAutonomousVmClusterCompartment | autonomousVmClusters | Moves an Autonomous VM cluster and its dependent resources to another compartment | +| RotateAutonomousVmClusterOrdsCerts | autonomousVmClusters | Rotates the Oracle REST Data Services (ORDS) certificates for Autonomous Exadata VM cluster | +| RotateAutonomousVmClusterSslCerts | autonomousVmClusters | Rotates the SSL certificates for Autonomous Exadata VM cluster | +| GetAutonomousVmClusterResourceUsage | autonomousVmClusters | Get the resource usage details for the specified Autonomous Exadata VM cluster | +| ListBackupDestination | backupDestinations | Gets a list of backup destinations in the specified compartment | +| CreateBackupDestination | backupDestinations | Creates a backup destination in an Exadata Cloud@Customer system | +| DeleteBackupDestination | backupDestinations | Deletes a backup destination in an Exadata Cloud@Customer system | +| GetBackupDestination | backupDestinations | Gets information about the specified backup destination in an Exadata Cloud@Customer system | +| UpdateBackupDestination | backupDestinations | If no database is associated with the backup destination: - For a RECOVERY_APPLIANCE backup destination, updates the connection string and/or the list of VPC users | +| ChangeBackupDestinationCompartment | backupDestinations | Move the backup destination and its dependent resources to the specified compartment | +| ListBackups | backups | Gets a list of backups based on the `databaseId` or `compartmentId` specified | +| CreateBackup | backups | Creates a new backup in the specified database based on the request parameters you provide | +| DeleteBackup | backups | Deletes a full backup | +| GetBackup | backups | Gets information about the specified backup | +| ListCloudAutonomousVmClusters | cloudAutonomousVmClusters | Lists Autonomous Exadata VM clusters in the Oracle cloud | +| CreateCloudAutonomousVmCluster | cloudAutonomousVmClusters | Creates an Autonomous Exadata VM cluster in the Oracle cloud | +| DeleteCloudAutonomousVmCluster | cloudAutonomousVmClusters | Deletes the specified Autonomous Exadata VM cluster in the Oracle cloud | +| GetCloudAutonomousVmCluster | cloudAutonomousVmClusters | Gets information about the specified Autonomous Exadata VM cluster in the Oracle cloud | +| UpdateCloudAutonomousVmCluster | cloudAutonomousVmClusters | Updates the specified Autonomous Exadata VM cluster in the Oracle cloud | +| ListCloudAutonomousVmClusterAcdResourceUsage | cloudAutonomousVmClusters | Gets the list of resource usage details for all the Cloud Autonomous Container Database in the specified Cloud Autonomous Exadata VM cluster | +| ChangeCloudAutonomousVmClusterCompartment | cloudAutonomousVmClusters | Moves an Autonomous Exadata VM cluster in the Oracle cloud and its dependent resources to another compartment | +| RotateCloudAutonomousVmClusterOrdsCerts | cloudAutonomousVmClusters | Rotates the Oracle REST Data Services (ORDS) certificates for a cloud Autonomous Exadata VM cluster | +| RotateCloudAutonomousVmClusterSslCerts | cloudAutonomousVmClusters | Rotates the SSL certficates for a cloud Autonomous Exadata VM cluster | +| GetCloudAutonomousVmClusterResourceUsage | cloudAutonomousVmClusters | Get the resource usage details for the specified Cloud Autonomous Exadata VM cluster | +| ListCloudExadataInfrastructures | cloudExadataInfrastructures | Gets a list of the cloud Exadata infrastructure resources in the specified compartment | +| CreateCloudExadataInfrastructure | cloudExadataInfrastructures | Creates a cloud Exadata infrastructure resource | +| DeleteCloudExadataInfrastructure | cloudExadataInfrastructures | Deletes the cloud Exadata infrastructure resource | +| GetCloudExadataInfrastructure | cloudExadataInfrastructures | Gets information about the specified cloud Exadata infrastructure resource | +| UpdateCloudExadataInfrastructure | cloudExadataInfrastructures | Updates the Cloud Exadata infrastructure resource | +| AddStorageCapacityCloudExadataInfrastructure | cloudExadataInfrastructures | Makes the storage capacity from additional storage servers available for Cloud VM Cluster consumption | +| ChangeCloudExadataInfrastructureCompartment | cloudExadataInfrastructures | Moves a cloud Exadata infrastructure resource and its dependent resources to another compartment | +| ChangeCloudExadataInfrastructureSubscription | cloudExadataInfrastructures | Associate a cloud Exadata infrastructure with a different subscription | +| ConfigureExascaleCloudExadataInfrastructure | cloudExadataInfrastructures | Configures Exascale on Cloud exadata infrastructure resource | +| GetCloudExadataInfrastructureUnallocatedResources | cloudExadataInfrastructures | Gets unallocated resources information for the specified Cloud Exadata infrastructure | +| ListCloudVmClusters | cloudVmClusters | Gets a list of the cloud VM clusters in the specified compartment | +| CreateCloudVmCluster | cloudVmClusters | Creates a cloud VM cluster | +| DeleteCloudVmCluster | cloudVmClusters | Deletes the specified cloud VM cluster | +| GetCloudVmCluster | cloudVmClusters | Gets information about the specified cloud VM cluster | +| UpdateCloudVmCluster | cloudVmClusters | Updates the specified cloud VM cluster | +| GetCloudVmClusterIormConfig | cloudVmClusters | Gets the IORM configuration for the specified cloud VM cluster in an Exadata Cloud Service instance | +| UpdateCloudVmClusterIormConfig | cloudVmClusters | Updates the IORM settings for the specified cloud VM cluster in an Exadata Cloud Service instance | +| AddVirtualMachineToCloudVmCluster | cloudVmClusters | Add Virtual Machines to the Cloud VM cluster | +| ChangeCloudVmClusterCompartment | cloudVmClusters | Moves a cloud VM cluster and its dependent resources to another compartment | +| ChangeCloudVmClusterSubscription | cloudVmClusters | Associate a cloud VM cluster with a different subscription | +| RemoveVirtualMachineFromCloudVmCluster | cloudVmClusters | Remove Virtual Machines from the Cloud VM cluster | +| ListCloudVmClusterUpdateHistoryEntries | cloudVmClusters | Gets the history of the maintenance update actions performed on the specified cloud VM cluster | +| GetCloudVmClusterUpdateHistoryEntry | cloudVmClusters | Gets the maintenance update history details for the specified update history entry | +| ListCloudVmClusterUpdates | cloudVmClusters | Lists the maintenance updates that can be applied to the specified cloud VM cluster | +| GetCloudVmClusterUpdate | cloudVmClusters | Gets information about a specified maintenance update package for a cloud VM cluster | +| ListDatabaseSoftwareImages | databaseSoftwareImages | Gets a list of the database software images in the specified compartment | +| CreateDatabaseSoftwareImage | databaseSoftwareImages | create database software image in the specified compartment | +| DeleteDatabaseSoftwareImage | databaseSoftwareImages | Delete a database software image | +| GetDatabaseSoftwareImage | databaseSoftwareImages | Gets information about the specified database software image | +| UpdateDatabaseSoftwareImage | databaseSoftwareImages | Updates the properties of a Database Software Image, like Display Nmae | +| ChangeDatabaseSoftwareImageCompartment | databaseSoftwareImages | Move the Database Software Image and its dependent resources to the specified compartment | +| ListDatabases | databases | Gets a list of the databases in the specified Database Home | +| CreateDatabase | databases | Creates a new database in the specified Database Home | +| DeleteDatabase | databases | Deletes the specified database | +| GetDatabase | databases | Gets information about the specified database | +| UpdateDatabase | databases | Update the specified database based on the request parameters provided | +| ChangeEncryptionKeyLocation | databases | Update the encryption key management location for the database | +| ConvertToPdb | databases | Converts a non-container database to a pluggable database | +| DisableDatabaseManagement | databases | Disables the Database Management service for the database | +| EnableDatabaseManagement | databases | Enables the Database Management service for an Oracle Database located in Oracle Cloud Infrastructure | +| MigrateVaultKey | databases | Changes encryption key management from customer-managed, using the [Vault service](/iaas/Content/KeyManagement/Concepts/keyoverview | +| ModifyDatabaseManagement | databases | Updates one or more attributes of the Database Management service for the database | +| RestoreDatabase | databases | Restore a Database based on the request parameters you provide | +| RotateVaultKey | databases | Creates a new version of an existing [Vault service](/iaas/Content/KeyManagement/Concepts/keyoverview | +| UpgradeDatabase | databases | Upgrades the specified Oracle Database instance | +| ConvertToStandalone | databases | Disassociate the standby database identified by the `databaseId` parameter from existing Data Guard group | +| FailoverDataGuard | databases | Performs a failover to transition the standby database identified by the `databaseId` path parameter into the primary role after the existing primary database fails or becomes unreachable | +| ReinstateDataGuard | databases | Reinstates the database identified by the `databaseId` parameter into the standby role in a Data Guard association | +| SwitchOverDataGuard | databases | Performs a switchover to transition primary database of this Data Guard association into a standby role | +| UpdateDataGuard | databases | Update an existing Data Guard member | +| ListDataGuardAssociations | databases | Lists all Data Guard associations for the specified database | +| CreateDataGuardAssociation | databases | Creates a new Data Guard association | +| GetDataGuardAssociation | databases | Gets the specified Data Guard association's configuration information | +| UpdateDataGuardAssociation | databases | Updates the Data Guard association the specified database | +| FailoverDataGuardAssociation | databases | Performs a failover to transition the standby database identified by the `databaseId` parameter into the specified Data Guard association's primary role after the existing primary database fails or becomes unreachable | +| MigrateDataGuardAssociationToMultiDataGuards | databases | Migrates the existing Data Guard association to new Data Guard model to support multiple standby databases functionality | +| ReinstateDataGuardAssociation | databases | Reinstates the database identified by the `databaseId` parameter into the standby role in a Data Guard association | +| SwitchoverDataGuardAssociation | databases | Performs a switchover to transition the primary database of a Data Guard association into a standby role | +| ListPdbConversionHistoryEntries | databases | Gets the pluggable database conversion history for a specified database in a bare metal or virtual machine DB system | +| GetPdbConversionHistoryEntry | databases | Gets the details of operations performed to convert the specified database from non-container (non-CDB) to pluggable (PDB) | +| ListDatabaseUpgradeHistoryEntries | databases | Gets the upgrade history for a specified database in a bare metal or virtual machine DB system | +| GetDatabaseUpgradeHistoryEntry | databases | gets the upgrade history for a specified database | +| ListDbHomes | dbHomes | Lists the Database Homes in the specified DB system and compartment | +| CreateDbHome | dbHomes | Creates a new Database Home in the specified database system based on the request parameters you provide | +| DeleteDbHome | dbHomes | Deletes a Database Home | +| GetDbHome | dbHomes | Gets information about the specified Database Home | +| UpdateDbHome | dbHomes | Patches the specified Database Home | +| ListDbHomePatchHistoryEntries | dbHomes | Lists the history of patch operations on the specified Database Home | +| GetDbHomePatchHistoryEntry | dbHomes | Gets the patch history details for the specified patchHistoryEntryId | +| ListDbHomePatches | dbHomes | Lists patches applicable to the requested Database Home | +| GetDbHomePatch | dbHomes | Gets information about a specified patch package | +| ListDbNodes | dbNodes | Lists the database nodes in the specified DB system and compartment | +| GetDbNode | dbNodes | Gets information about the specified database node | +| DbNodeAction | dbNodes | Performs one of the following power actions on the specified DB node: - start - power on - stop - power off gracefully - softreset - ACPI shutdown and power on - reset - power off and power on **Note:** Stopping a node affects billing differently, depending on the type of DB system: *Bare metal and Exadata systems* - The _stop_ state has no effect on the resources you consume | +| ListConsoleConnections | dbNodes | Lists the console connections for the specified database node | +| CreateConsoleConnection | dbNodes | Creates a new console connection to the specified database node | +| DeleteConsoleConnection | dbNodes | Deletes the specified database node console connection | +| GetConsoleConnection | dbNodes | Gets the specified database node console connection's information | +| ListConsoleHistories | dbNodes | Lists the console histories for the specified database node | +| CreateConsoleHistory | dbNodes | Captures the most recent serial console data (up to a megabyte) for the specified database node | +| DeleteConsoleHistory | dbNodes | Deletes the specified database node console history | +| GetConsoleHistory | dbNodes | Gets information about the specified database node console history | +| UpdateConsoleHistory | dbNodes | Updates the specified database node console history | +| GetConsoleHistoryContent | dbNodes | Retrieves the specified database node console history contents upto a megabyte | +| ListDbServers | dbServers | Lists the Exadata DB servers in the ExadataInfrastructureId and specified compartment | +| GetDbServer | dbServers | Gets information about the Exadata Db server | +| ListDbSystemComputePerformances | dbSystemComputePerformance | Gets a list of expected compute performance parameters for a virtual machine DB system based on system configuration | +| ListDbSystemShapes | dbSystemShapes | Gets a list of the shapes that can be used to launch a new DB system | +| ListFlexComponents | dbSystemShapes | Gets a list of the flex components that can be used to launch a new DB system | +| ListDbSystemStoragePerformances | dbSystemStoragePerformance | Gets a list of possible expected storage performance parameters of a VMDB System based on Configuration | +| ListDbSystems | dbSystems | Lists the DB systems in the specified compartment | +| LaunchDbSystem | dbSystems | Creates a new DB system in the specified compartment and availability domain | +| TerminateDbSystem | dbSystems | Terminates a DB system and permanently deletes it and any databases running on it, and any storage volumes attached to it | +| GetDbSystem | dbSystems | Gets information about the specified DB system | +| UpdateDbSystem | dbSystems | Updates the properties of the specified DB system | +| GetExadataIormConfig | dbSystems | Gets the IORM configuration settings for the specified cloud Exadata DB system | +| UpdateExadataIormConfig | dbSystems | Updates IORM settings for the specified Exadata DB system | +| ChangeDbSystemCompartment | dbSystems | Moves the DB system and its dependent resources to the specified compartment | +| MigrateExadataDbSystemResourceModel | dbSystems | Migrates the Exadata DB system to the new [Exadata resource model](/iaas/Content/Database/Concepts/exaflexsystem | +| UpgradeDbSystem | dbSystems | Upgrades the operating system and grid infrastructure of the DB system | +| ListDbSystemPatchHistoryEntries | dbSystems | Gets the history of the patch actions performed on the specified DB system | +| GetDbSystemPatchHistoryEntry | dbSystems | Gets the details of the specified patch operation on the specified DB system | +| ListDbSystemPatches | dbSystems | Lists the patches applicable to the specified DB system | +| GetDbSystemPatch | dbSystems | Gets information the specified patch | +| ListDbSystemUpgradeHistoryEntries | dbSystems | Gets the history of the upgrade actions performed on the specified DB system | +| GetDbSystemUpgradeHistoryEntry | dbSystems | Gets the details of the specified operating system upgrade operation for the specified DB system | +| ListDbVersions | dbVersions | Gets a list of supported Oracle Database versions | +| ListExadataInfrastructures | exadataInfrastructures | Lists the Exadata infrastructure resources in the specified compartment | +| CreateExadataInfrastructure | exadataInfrastructures | Creates an Exadata infrastructure resource | +| DeleteExadataInfrastructure | exadataInfrastructures | Deletes the Exadata Cloud@Customer infrastructure | +| GetExadataInfrastructure | exadataInfrastructures | Gets information about the specified Exadata infrastructure | +| UpdateExadataInfrastructure | exadataInfrastructures | Updates the Exadata infrastructure resource | +| ActivateExadataInfrastructure | exadataInfrastructures | Activates the specified Exadata infrastructure resource | +| AddStorageCapacityExadataInfrastructure | exadataInfrastructures | Makes the storage capacity from additional storage servers available for VM Cluster consumption | +| ChangeExadataInfrastructureCompartment | exadataInfrastructures | Moves an Exadata infrastructure resource and its dependent resources to another compartment | +| DownloadExadataInfrastructureConfigFile | exadataInfrastructures | Downloads the configuration file for the specified Exadata Cloud@Customer infrastructure | +| GetExadataInfrastructureUnAllocatedResources | exadataInfrastructures | Gets un allocated resources information for the specified Exadata infrastructure | +| ListVmClusterNetworks | exadataInfrastructures | Gets a list of the VM cluster networks in the specified compartment | +| CreateVmClusterNetwork | exadataInfrastructures | Creates the VM cluster network | +| GenerateRecommendedVmClusterNetwork | exadataInfrastructures | Generates a recommended Cloud@Customer VM cluster network configuration | +| DeleteVmClusterNetwork | exadataInfrastructures | Deletes the specified VM cluster network | +| GetVmClusterNetwork | exadataInfrastructures | Gets information about the specified VM cluster network | +| UpdateVmClusterNetwork | exadataInfrastructures | Updates the specified VM cluster network | +| DownloadVmClusterNetworkConfigFile | exadataInfrastructures | Downloads the configuration file for the specified VM cluster network | +| ResizeVmClusterNetwork | exadataInfrastructures | Adds or removes Db server network nodes to extend or shrink the existing VM cluster network | +| ValidateVmClusterNetwork | exadataInfrastructures | Validates the specified VM cluster network | +| ListExadbVmClusters | exadbVmClusters | Gets a list of the Exadata VM clusters on Exascale Infrastructure in the specified compartment | +| CreateExadbVmCluster | exadbVmClusters | Creates an Exadata VM cluster on Exascale Infrastructure | +| DeleteExadbVmCluster | exadbVmClusters | Deletes the specified Exadata VM cluster on Exascale Infrastructure | +| GetExadbVmCluster | exadbVmClusters | Gets information about the specified Exadata VM cluster on Exascale Infrastructure | +| UpdateExadbVmCluster | exadbVmClusters | Updates the specified Exadata VM cluster on Exascale Infrastructure | +| ChangeExadbVmClusterCompartment | exadbVmClusters | Moves a Exadata VM cluster on Exascale Infrastructure and its dependent resources to another compartment | +| ChangeExadbVmClusterSubscription | exadbVmClusters | Associate a Exadata VM cluster on Exascale Infrastructure with a different subscription | +| RemoveVirtualMachineFromExadbVmCluster | exadbVmClusters | Remove Virtual Machines from the Exadata VM cluster on Exascale Infrastructure | +| ListExadbVmClusterUpdateHistoryEntries | exadbVmClusters | Gets the history of the maintenance update actions performed on the specified Exadata VM cluster on Exascale Infrastructure | +| GetExadbVmClusterUpdateHistoryEntry | exadbVmClusters | Gets the maintenance update history details for the specified update history entry | +| ListExadbVmClusterUpdates | exadbVmClusters | Lists the maintenance updates that can be applied to the specified Exadata VM cluster on Exascale Infrastructure | +| GetExadbVmClusterUpdate | exadbVmClusters | Gets information about a specified maintenance update package for a Exadata VM cluster on Exascale Infrastructure | +| ListExascaleDbStorageVaults | exascaleDbStorageVaults | Gets a list of the Exadata Database Storage Vaults in the specified compartment | +| CreateExascaleDbStorageVault | exascaleDbStorageVaults | Creates an Exadata Database Storage Vault | +| DeleteExascaleDbStorageVault | exascaleDbStorageVaults | Deletes the specified Exadata Database Storage Vault | +| GetExascaleDbStorageVault | exascaleDbStorageVaults | Gets information about the specified Exadata Database Storage Vaults in the specified compartment | +| UpdateExascaleDbStorageVault | exascaleDbStorageVaults | Updates the specified Exadata Database Storage Vault | +| ChangeExascaleDbStorageVaultCompartment | exascaleDbStorageVaults | Moves a Exadata Database Storage Vault to another compartment | +| ChangeExascaleDbStorageVaultSubscription | exascaleDbStorageVaults | Associate a Exadata Database Storage Vault with a different subscription | +| ListExecutionActions | executionActions | Lists the execution action resources in the specified compartment | +| CreateExecutionAction | executionActions | Creates an execution action resource | +| DeleteExecutionAction | executionActions | Deletes the execution action | +| GetExecutionAction | executionActions | Gets information about the specified execution action | +| UpdateExecutionAction | executionActions | Updates the execution action resource | +| MoveExecutionActionMember | executionActions | Moves an execution action member to this execution action resource from another | +| ListExecutionWindows | executionWindows | Lists the execution window resources in the specified compartment | +| CreateExecutionWindow | executionWindows | Creates an execution window resource | +| DeleteExecutionWindow | executionWindows | Deletes the execution window | +| GetExecutionWindow | executionWindows | Gets information about the specified execution window | +| UpdateExecutionWindow | executionWindows | Updates the execution window resource | +| ReorderExecutionActions | executionWindows | Reorders the execution actions under this execution window resource | +| CreateExternalBackupJob | externalBackupJobs | Creates a new backup resource and returns the information the caller needs to back up an on-premises Oracle Database to Oracle Cloud Infrastructure | +| GetExternalBackupJob | externalBackupJobs | Gets information about the specified external backup job | +| CompleteExternalBackupJob | externalBackupJobs | Changes the status of the standalone backup resource to `ACTIVE` after the backup is created from the on-premises database and placed in Oracle Cloud Infrastructure Object Storage | +| ListExternalContainerDatabases | externalcontainerdatabases | Gets a list of the external container databases in the specified compartment | +| CreateExternalContainerDatabase | externalcontainerdatabases | Creates a new external container database resource | +| DeleteExternalContainerDatabase | externalcontainerdatabases | Deletes the [external container database](#/en/database/latest/datatypes/CreateExternalContainerDatabaseDetails) resource | +| GetExternalContainerDatabase | externalcontainerdatabases | Gets information about the specified external container database | +| UpdateExternalContainerDatabase | externalcontainerdatabases | Updates the properties of an [ExternalContainerDatabase](#/en/database/latest/datatypes/CreateExternalContainerDatabaseDetails) resource, such as the display name | +| ChangeExternalContainerDatabaseCompartment | externalcontainerdatabases | Move the [external container database](#/en/database/latest/datatypes/CreateExternalContainerDatabaseDetails) and its dependent resources to the specified compartment | +| DisableExternalContainerDatabaseDatabaseManagement | externalcontainerdatabases | Disable Database Management service for the external container database | +| DisableExternalContainerDatabaseStackMonitoring | externalcontainerdatabases | Disable Stack Monitoring for the external container database | +| EnableExternalContainerDatabaseDatabaseManagement | externalcontainerdatabases | Enables Database Management Service for the external container database | +| EnableExternalContainerDatabaseStackMonitoring | externalcontainerdatabases | Enable Stack Monitoring for the external container database | +| ScanExternalContainerDatabasePluggableDatabases | externalcontainerdatabases | Scans for pluggable databases in the specified external container database | +| ListExternalDatabaseConnectors | externaldatabaseconnectors | Gets a list of the external database connectors in the specified compartment | +| CreateExternalDatabaseConnector | externaldatabaseconnectors | Creates a new external database connector | +| DeleteExternalDatabaseConnector | externaldatabaseconnectors | Deletes an external database connector | +| GetExternalDatabaseConnector | externaldatabaseconnectors | Gets information about the specified external database connector | +| UpdateExternalDatabaseConnector | externaldatabaseconnectors | Updates the properties of an external database connector, such as the display name | +| CheckExternalDatabaseConnectorConnectionStatus | externaldatabaseconnectors | Check the status of the external database connection specified in this connector | +| ListExternalNonContainerDatabases | externalnoncontainerdatabases | Gets a list of the ExternalNonContainerDatabases in the specified compartment | +| CreateExternalNonContainerDatabase | externalnoncontainerdatabases | Creates a new ExternalNonContainerDatabase resource | +| DeleteExternalNonContainerDatabase | externalnoncontainerdatabases | Deletes the Oracle Cloud Infrastructure resource representing an external non-container database | +| GetExternalNonContainerDatabase | externalnoncontainerdatabases | Gets information about a specific external non-container database | +| UpdateExternalNonContainerDatabase | externalnoncontainerdatabases | Updates the properties of an external non-container database, such as the display name | +| ChangeExternalNonContainerDatabaseCompartment | externalnoncontainerdatabases | Move the external non-container database and its dependent resources to the specified compartment | +| DisableExternalNonContainerDatabaseDatabaseManagement | externalnoncontainerdatabases | Disable Database Management Service for the external non-container database | +| DisableExternalNonContainerDatabaseOperationsInsights | externalnoncontainerdatabases | Disable Operations Insights for the external non-container database | +| DisableExternalNonContainerDatabaseStackMonitoring | externalnoncontainerdatabases | Disable Stack Monitoring for the external non-container database | +| EnableExternalNonContainerDatabaseDatabaseManagement | externalnoncontainerdatabases | Enable Database Management Service for the external non-container database | +| EnableExternalNonContainerDatabaseOperationsInsights | externalnoncontainerdatabases | Enable Operations Insights for the external non-container database | +| EnableExternalNonContainerDatabaseStackMonitoring | externalnoncontainerdatabases | Enable Stack Monitoring for the external non-container database | +| ListExternalPluggableDatabases | externalpluggabledatabases | Gets a list of the [ExternalPluggableDatabase](#/en/database/latest/datatypes/CreateExternalPluggableDatabaseDetails) resources in the specified compartment | +| CreateExternalPluggableDatabase | externalpluggabledatabases | Registers a new [ExternalPluggableDatabase](#/en/database/latest/datatypes/CreateExternalPluggableDatabaseDetails) resource | +| DeleteExternalPluggableDatabase | externalpluggabledatabases | Deletes the [external pluggable database](#/en/database/latest/datatypes/CreateExternalPluggableDatabaseDetails) | +| GetExternalPluggableDatabase | externalpluggabledatabases | Gets information about a specific [external pluggable database](#/en/database/latest/datatypes/CreateExternalPluggableDatabaseDetails) resource | +| UpdateExternalPluggableDatabase | externalpluggabledatabases | Updates the properties of an [external pluggable database](#/en/database/latest/datatypes/CreateExternalPluggableDatabaseDetails) resource, such as the display name | +| ChangeExternalPluggableDatabaseCompartment | externalpluggabledatabases | Move the [external pluggable database](#/en/database/latest/datatypes/CreateExternalPluggableDatabaseDetails) and its dependent resources to the specified compartment | +| DisableExternalPluggableDatabaseDatabaseManagement | externalpluggabledatabases | Disable Database Management Service for the external pluggable database | +| DisableExternalPluggableDatabaseOperationsInsights | externalpluggabledatabases | Disable Operations Insights for the external pluggable database | +| DisableExternalPluggableDatabaseStackMonitoring | externalpluggabledatabases | Disable Stack Monitoring for the external pluggable database | +| EnableExternalPluggableDatabaseDatabaseManagement | externalpluggabledatabases | Enable Database Management Service for the external pluggable database | +| EnableExternalPluggableDatabaseOperationsInsights | externalpluggabledatabases | Enable Operations Insights for the external pluggable database | +| EnableExternalPluggableDatabaseStackMonitoring | externalpluggabledatabases | Enable Stack Monitoring for the external pluggable database | +| ListGiVersions | giVersions | Gets a list of supported GI versions | +| ListGiVersionMinorVersions | giVersions | Gets a list of supported Oracle Grid Infrastructure minor versions for the given major version and shape family | +| ListKeyStores | keyStores | Gets a list of key stores in the specified compartment | +| CreateKeyStore | keyStores | Creates a Key Store | +| DeleteKeyStore | keyStores | Deletes a key store | +| GetKeyStore | keyStores | Gets information about the specified key store | +| UpdateKeyStore | keyStores | Edit the key store | +| ChangeKeyStoreCompartment | keyStores | Move the key store resource to the specified compartment | +| ListMaintenanceRunHistory | maintenanceRunHistory | Gets a list of the maintenance run histories in the specified compartment | +| GetMaintenanceRunHistory | maintenanceRunHistory | Gets information about the specified maintenance run history | +| ListMaintenanceRuns | maintenanceRuns | Gets a list of the maintenance runs in the specified compartment | +| CreateMaintenanceRun | maintenanceRuns | Creates a maintenance run with one of the following: 1 | +| GetMaintenanceRun | maintenanceRuns | Gets information about the specified maintenance run | +| UpdateMaintenanceRun | maintenanceRuns | Updates the properties of a maintenance run, such as the state of a maintenance run | +| ListOneoffPatches | oneoffPatches | Lists one-off patches in the specified compartment | +| CreateOneoffPatch | oneoffPatches | Creates one-off patch for specified database version to download | +| DeleteOneoffPatch | oneoffPatches | Deletes a one-off patch | +| GetOneoffPatch | oneoffPatches | Gets information about the specified one-off patch | +| UpdateOneoffPatch | oneoffPatches | Updates the properties of the specified one-off patch | +| ChangeOneoffPatchCompartment | oneoffPatches | Move the one-off patch to the specified compartment | +| DownloadOneoffPatch | oneoffPatches | Download one-off patch | +| ListPluggableDatabases | pluggableDatabases | Gets a list of the pluggable databases in a database or compartment | +| CreatePluggableDatabase | pluggableDatabases | Creates and starts a pluggable database in the specified container database | +| DeletePluggableDatabase | pluggableDatabases | Deletes the specified pluggable database | +| GetPluggableDatabase | pluggableDatabases | Gets information about the specified pluggable database | +| UpdatePluggableDatabase | pluggableDatabases | Updates the specified pluggable database | +| ConvertToRegularPluggableDatabase | pluggableDatabases | Converts a Refreshable clone to Regular pluggable database (PDB) | +| RefreshPluggableDatabase | pluggableDatabases | Refreshes a pluggable database (PDB) Refreshable clone | +| StartPluggableDatabase | pluggableDatabases | Starts a stopped pluggable database | +| StopPluggableDatabase | pluggableDatabases | Stops a pluggable database | +| GetResourcePrincipalToken | resourcePrincipalToken | Gets a resource principal intermediate token that contains mapping information between the instance prinicpal and resource | +| ListParamsForActionType | scheduledActionParams | List all the action params and their possible values for a given action type | +| ListScheduledActions | scheduledActions | Lists the Scheduled Action resources in the specified compartment | +| CreateScheduledAction | scheduledActions | Creates a Scheduled Action resource | +| DeleteScheduledAction | scheduledActions | Deletes the scheduled action | +| GetScheduledAction | scheduledActions | Gets information about the specified Scheduled Action | +| UpdateScheduledAction | scheduledActions | Updates the Scheduled Action resource | +| ListSchedulingPlans | schedulingPlans | Lists the Scheduling Plan resources in the specified compartment | +| CreateSchedulingPlan | schedulingPlans | Creates a Scheduling Plan resource | +| DeleteSchedulingPlan | schedulingPlans | Deletes the scheduling plan | +| GetSchedulingPlan | schedulingPlans | Gets information about the specified Scheduling Plan | +| ChangeSchedulingPlanCompartment | schedulingPlans | Moves an scheduling plan resource to another compartment | +| ReorderScheduledActions | schedulingPlans | Re-order the scheduled actions under this scheduling plan resource | +| ListSchedulingPolicies | schedulingPolicies | Lists the Scheduling Policy resources in the specified compartment | +| CreateSchedulingPolicy | schedulingPolicies | Creates a Scheduling Policy resource | +| DeleteSchedulingPolicy | schedulingPolicies | Deletes the scheduling policy | +| GetSchedulingPolicy | schedulingPolicies | Gets information about the specified Scheduling Policy | +| UpdateSchedulingPolicy | schedulingPolicies | Updates the Scheduling Policy resource | +| ChangeSchedulingPolicyCompartment | schedulingPolicies | Moves an scheduling policy resource to another compartment | +| ListRecommendedScheduledActions | schedulingPolicies | Returns a recommended Scheduled Actions configuration for a given resource, plan intent and scheduling policy | +| ListSchedulingWindows | schedulingPolicies | Lists the Scheduling Window resources in the specified compartment | +| CreateSchedulingWindow | schedulingPolicies | Creates a Scheduling Window resource | +| DeleteSchedulingWindow | schedulingPolicies | Deletes the scheduling window | +| GetSchedulingWindow | schedulingPolicies | Gets information about the specified Scheduling Window | +| UpdateSchedulingWindow | schedulingPolicies | Updates the Scheduling Window resource | +| ListSystemVersions | systemVersions | Gets a list of supported Exadata system versions for a given shape and GI version | +| ListVmClusters | vmClusters | Lists the VM clusters in the specified compartment | +| CreateVmCluster | vmClusters | Creates an Exadata Cloud@Customer VM cluster | +| DeleteVmCluster | vmClusters | Deletes the specified VM cluster | +| GetVmCluster | vmClusters | Gets information about the VM cluster | +| UpdateVmCluster | vmClusters | Updates the specified VM cluster | +| AddVirtualMachineToVmCluster | vmClusters | Add Virtual Machines to the VM cluster | +| ChangeVmClusterCompartment | vmClusters | Moves a VM cluster and its dependent resources to another compartment | +| RemoveVirtualMachineFromVmCluster | vmClusters | Remove Virtual Machines from the VM cluster | +| ListVmClusterPatchHistoryEntries | vmClusters | Gets the history of the patch actions performed on the specified VM cluster in an Exadata Cloud@Customer system | +| GetVmClusterPatchHistoryEntry | vmClusters | Gets the patch history details for the specified patch history entry | +| ListVmClusterPatches | vmClusters | Lists the patches applicable to the specified VM cluster in an Exadata Cloud@Customer system | +| GetVmClusterPatch | vmClusters | Gets information about a specified patch package | +| ListVmClusterUpdateHistoryEntries | vmClusters | Gets the history of the maintenance update actions performed on the specified VM cluster | +| GetVmClusterUpdateHistoryEntry | vmClusters | Gets the maintenance update history details for the specified update history entry | +| ListVmClusterUpdates | vmClusters | Lists the maintenance updates that can be applied to the specified VM cluster | +| GetVmClusterUpdate | vmClusters | Gets information about a specified maintenance update package for a VM cluster | + + +⚠️ **NOTE**: All actions are performed with the permissions of the configured OCI CLI profile. We advise least-privilege IAM setup, secure credential management, safe network practices, secure logging, and warn against exposing secrets. + +## Third-Party APIs + +Developers choosing to distribute a binary implementation of this project are responsible for obtaining and providing all required licenses and copyright notices for the third-party code used in order to ensure compliance with their respective open source licenses. + +## Disclaimer + +Users are responsible for their local environment and credential safety. Different language model selections may yield different results and performance. + +## License + +Copyright (c) 2025 Oracle and/or its affiliates. + +Released under the Universal Permissive License v1.0 as shown at +. + diff --git a/src/oci-db-dynamic-mcp-server/oracle/__init__.py b/src/oci-db-dynamic-mcp-server/oracle/__init__.py new file mode 100644 index 00000000..d9dff098 --- /dev/null +++ b/src/oci-db-dynamic-mcp-server/oracle/__init__.py @@ -0,0 +1,5 @@ +""" +Copyright (c) 2025, Oracle and/or its affiliates. +Licensed under the Universal Permissive License v1.0 as shown at +https://oss.oracle.com/licenses/upl. +""" diff --git a/src/oci-db-dynamic-mcp-server/oracle/oci_db_dynamic_mcp_server/__init__.py b/src/oci-db-dynamic-mcp-server/oracle/oci_db_dynamic_mcp_server/__init__.py new file mode 100644 index 00000000..8d062ba9 --- /dev/null +++ b/src/oci-db-dynamic-mcp-server/oracle/oci_db_dynamic_mcp_server/__init__.py @@ -0,0 +1,8 @@ +""" +Copyright (c) 2025, Oracle and/or its affiliates. +Licensed under the Universal Permissive License v1.0 as shown at +https://oss.oracle.com/licenses/upl. +""" + +__project__ = "oracle.oci-db-dynamic-mcp-server" +__version__ = "1.0.1" diff --git a/src/oci-db-dynamic-mcp-server/oracle/oci_db_dynamic_mcp_server/dynamic_tools_loader.py b/src/oci-db-dynamic-mcp-server/oracle/oci_db_dynamic_mcp_server/dynamic_tools_loader.py new file mode 100644 index 00000000..85677697 --- /dev/null +++ b/src/oci-db-dynamic-mcp-server/oracle/oci_db_dynamic_mcp_server/dynamic_tools_loader.py @@ -0,0 +1,322 @@ +from dataclasses import dataclass, field +from typing import Any, Dict, List, Optional + +import requests +import yaml + +SPEC_INDEX_JSON = "https://docs.oracle.com/en-us/iaas/api/specs/index.json" +BASE_SPEC_URL = "https://docs.oracle.com/en-us/iaas/api/specs/" +HTTP_METHODS = {"get", "post", "put", "delete", "patch"} + + +@dataclass +class OperationMeta: + operationId: str + httpMethod: str + path: str + summary: str + description: str + parameters: List[Dict[str, Any]] = field(default_factory=list) + requestBodySchema: Dict[str, Any] = field(default_factory=dict) + responseSchema: Dict[str, Any] = field(default_factory=dict) + relatedResource: str = "other" + + +def load_yaml_from_url(url: str): + resp = requests.get(url, timeout=15) + resp.raise_for_status() + return yaml.safe_load(resp.text) + + +def load_yaml_from_public_docs(): + try: + resp = requests.get(SPEC_INDEX_JSON, timeout=15) + resp.raise_for_status() + index_json = resp.json() + specs_node = index_json.get("database", {}).get("specs", []) + if specs_node: + full_url = BASE_SPEC_URL + specs_node[0].split("/")[-1] + print(f"Loading OCI Spec from: {full_url}") + return load_yaml_from_url(full_url) + return {} + except Exception as e: + print(f"Spec load failed: {e}") + return {} + + +def resolve_schema(schema: Dict[str, Any], spec: Dict[str, Any]) -> Dict[str, Any]: + """ + Recursively resolve $ref AND merge 'allOf' inheritance. + """ + if not isinstance(schema, dict): + return schema + + # 1. Resolve $ref + if "$ref" in schema: + ref = schema["$ref"] + # Handle both root-based (#/definitions/...) and relative refs + if ref.startswith("#/"): + parts = ref[2:].split("/") + node = spec + for p in parts: + node = node.get(p, {}) + return resolve_schema(node, spec) + else: + parts = ref.split("/") + node = spec + for p in parts: + node = node.get(p, {}) + return resolve_schema(node, spec) + + # 2. Handle 'allOf' (Merge properties from parents) + if "allOf" in schema: + merged = {"type": "object", "properties": {}, "required": []} + + for part in schema["allOf"]: + resolved_part = resolve_schema(part, spec) + + if "properties" in resolved_part: + merged["properties"].update(resolved_part["properties"]) + + if "required" in resolved_part: + merged["required"].extend(resolved_part["required"]) + + if "type" in resolved_part and "type" not in merged: + merged["type"] = resolved_part["type"] + + if "properties" in schema: + merged["properties"].update(schema["properties"]) + if "required" in schema: + merged["required"].extend(schema["required"]) + + merged["required"] = list(set(merged["required"])) + return merged + + # 3. Recurse + result = {} + for k, v in schema.items(): + if isinstance(v, dict): + result[k] = resolve_schema(v, spec) + elif isinstance(v, list): + result[k] = [ + resolve_schema(i, spec) if isinstance(i, dict) else i for i in v + ] + else: + result[k] = v + return result + + +def flatten_schema( + schema: Dict[str, Any], spec: Optional[Dict[str, Any]] = None +) -> Dict[str, Dict[str, Any]]: + flat: Dict[str, Dict[str, Any]] = {} + if not schema or not isinstance(schema, dict): + return flat + + def _walk(obj_schema: Dict[str, Any], path: List[str]): + if not isinstance(obj_schema, dict): + return + + props = obj_schema.get("properties", {}) + required_props = set(obj_schema.get("required", []) or []) + + for prop_name, prop_schema in props.items(): + prop_path = path + [prop_name] + prop_type = prop_schema.get("type") + + if not prop_type: + if "items" in prop_schema: + prop_type = "array" + elif "properties" in prop_schema: + prop_type = "object" + else: + prop_type = "string" + + flat_key = "_".join(prop_path) + + if prop_type == "array": + flat[flat_key] = { + "path": prop_path, + "type": "array", + "required": prop_name in required_props, + } + continue + + if prop_type == "object" and "properties" in prop_schema: + _walk(prop_schema, prop_path) + continue + + flat[flat_key] = { + "path": prop_path, + "type": prop_type, + "required": prop_name in required_props, + "raw_schema": prop_schema, + } + + if schema.get("type") == "object" or "properties" in schema: + _walk(schema, []) + return flat + + +def infer_resource_from_path_or_tags(path: str, tags: list) -> str: + if not path: + return "unknown" + parts = path.strip("/").split("/") + return parts[0] if parts else "unknown" + + +def extract_required_output_fields(schema: Dict[str, Any]) -> Dict[str, Any]: + """ + Given a resolved schema, return a simplified schema containing + ONLY the 'required' fields. Handles Arrays and Objects. + """ + if not schema or not isinstance(schema, dict): + return {} + + prop_type = schema.get("type") + + # CASE A: ARRAY (e.g. ListDbSystems returns [DbSystem]) + if prop_type == "array" and "items" in schema: + item_schema = schema["items"] + # Recurse into the item definition + simplified_item = extract_required_output_fields(item_schema) + return {"type": "array", "items": simplified_item} + + # CASE B: OBJECT (e.g. GetDbSystem returns DbSystem) + if prop_type == "object" or "properties" in schema: + required_keys = schema.get("required", []) + all_props = schema.get("properties", {}) + + simplified_props = {} + for key in required_keys: + if key in all_props: + simplified_props[key] = all_props[key] + + return { + "type": "object", + "properties": simplified_props, + "required": required_keys, + } + + # Fallback for scalars + return schema + + +def build_registry(api_spec: Dict[str, Any]) -> Dict[str, OperationMeta]: + paths = api_spec.get("paths", {}) + registry = {} + + for path, path_item in paths.items(): + if not isinstance(path_item, dict): + continue + path_params = path_item.get("parameters", []) + + for method, op in path_item.items(): + if method.lower() not in HTTP_METHODS or not isinstance(op, dict): + continue + + op_id = op.get("operationId", f"{method}_{path}") + + # 1. Parameters + params = [] + all_raw_params = path_params + op.get("parameters", []) + for p in all_raw_params: + params.append(resolve_schema(p, api_spec)) + + # 2. Request Body + req_schema = {} + if "requestBody" in op: # OpenAPI 3 + content = op["requestBody"].get("content", {}) + if "application/json" in content: + req_schema = resolve_schema( + content["application/json"].get("schema", {}), api_spec + ) + for p in params: # Swagger 2 + if p.get("in") == "body" and "schema" in p: + req_schema = resolve_schema(p["schema"], api_spec) + + # 3. Response Schema + resp_schema = {} + responses = op.get("responses", {}) + success_code = next( + (c for c in ["200", "201", "202", "204"] if c in responses), None + ) + + if success_code: + resp_obj = responses[success_code] + if "schema" in resp_obj: + resp_schema = resolve_schema(resp_obj["schema"], api_spec) + elif "content" in resp_obj: + content = resp_obj["content"] + if "application/json" in content: + resp_schema = resolve_schema( + content["application/json"].get("schema", {}), api_spec + ) + + registry[op_id] = OperationMeta( + operationId=op_id, + httpMethod=method.upper(), + path=path, + summary=op.get("summary", ""), + description=op.get("description", ""), + parameters=params, + requestBodySchema=req_schema, + responseSchema=resp_schema, + relatedResource=infer_resource_from_path_or_tags( + path, op.get("tags", []) + ), + ) + return registry + + +def build_tools_from_latest_spec( + allowed_resources: List[str] = None, +) -> List[Dict[str, Any]]: + api_spec = load_yaml_from_public_docs() + if not api_spec: + return [] + registry = build_registry(api_spec) + exposed_tools = [] + + allowed_set = {r.lower() for r in allowed_resources} if allowed_resources else None + + for op_id, meta in registry.items(): + + if allowed_set and meta.relatedResource.lower() not in allowed_set: + continue + if meta.description.startswith("**Deprecated"): + continue + + flat_schema = ( + flatten_schema(meta.requestBodySchema) if meta.requestBodySchema else {} + ) + + final_params = [] + for p in meta.parameters: + if p.get("in") == "body": + continue + if p.get("name") in flat_schema: + continue + final_params.append(p) + + filtered_output_schema = extract_required_output_fields(meta.responseSchema) + + exposed_tools.append( + { + "name": meta.operationId, + "description": meta.description, + "method": meta.httpMethod, + "path": meta.path, + "schema": meta.requestBodySchema, + "flatSchema": flat_schema, + "output_schema": filtered_output_schema, + "parameters": final_params, + "resource": meta.relatedResource, + } + ) + return exposed_tools + + +if __name__ == "__main__": + tools = build_tools_from_latest_spec() + print(f"Loaded {len(tools)} tools.") diff --git a/src/oci-db-dynamic-mcp-server/oracle/oci_db_dynamic_mcp_server/server.py b/src/oci-db-dynamic-mcp-server/oracle/oci_db_dynamic_mcp_server/server.py new file mode 100644 index 00000000..9b505aad --- /dev/null +++ b/src/oci-db-dynamic-mcp-server/oracle/oci_db_dynamic_mcp_server/server.py @@ -0,0 +1,311 @@ +""" +Copyright (c) 2025, Oracle and/or its affiliates. +Licensed under the Universal Permissive License v1.0. +""" + +import argparse +import os +import re +from typing import Annotated, Any, Dict, List, Optional + +import oci +import requests +from fastmcp import FastMCP +from oci.auth.signers import security_token_signer +from pydantic import Field + +from . import __project__ +from .dynamic_tools_loader import build_tools_from_latest_spec + +mcp = FastMCP(name=__project__) + +DEFAULT_ENDPOINT = "https://database.us-ashburn-1.oraclecloud.com/20160918/" + +# ---------------- TYPE MAPPING ---------------- +TYPE_MAP = { + "integer": "int", + "boolean": "bool", + "number": "float", + "array": "list", + "object": "dict", + "string": "str", +} + + +# ---------------- OCI API INVOKER ---------------- +def invoke_oci_api(method, path, params=None, payload=None, headers=None): + config = oci.config.from_file( + profile_name=os.getenv("OCI_CONFIG_PROFILE", oci.config.DEFAULT_PROFILE) + ) + + # Load security token + with open(config["security_token_file"], "r") as f: + security_token = f.read().strip() + + # Create signer + signer = security_token_signer.SecurityTokenSigner( + token=security_token, + private_key=oci.signer.load_private_key_from_file( + config["key_file"], pass_phrase=config.get("pass_phrase") + ), + ) + + endpoint = f"https://database.{config['region']}.oraclecloud.com/20160918/" + url = endpoint.rstrip("/") + "/" + path.lstrip("/") + user_agent_name = __project__.split("oracle.", 1)[1].split("-server", 1)[0] + + headers = headers or {"Content-Type": "application/json"} + headers["authorization"] = f"Bearer {security_token}" + headers["x-oci-secondary-auth"] = "true" + headers["User-Agent"] = user_agent_name + + with requests.Session() as session: + + req = requests.Request( + method=method.upper(), + url=url, + headers=headers, + json=payload, + params=params or {}, + auth=signer, + ) + + prepared = req.prepare() + + response = session.send(prepared) + return response + + +# ---------------- UNFLATTENER ---------------- +def unflatten_payload(flat_input: dict, flat_schema: dict): + root = {} + for flat_key, meta in flat_schema.items(): + if flat_key not in flat_input: + continue + + value = flat_input[flat_key] + path = meta.get("path", []) + if not path: + root[flat_key] = value + continue + + cursor = root + for p in path[:-1]: + if p not in cursor or not isinstance(cursor[p], dict): + cursor[p] = {} + cursor = cursor[p] + cursor[path[-1]] = value + return root + + +# ---------------- Utilities ---------------- +def escape_string(s: str) -> str: + if not s: + return "" + return ( + s.replace("\\", "\\\\") + .replace('"', '\\"') + .replace("\n", "\\n") + .replace("\r", "\\r") + ) + + +def clean_description_text(text: str) -> str: + if not text: + return "" + text = text.strip() + text = re.sub(r"(?i)^Parameters\s*$", "", text) + text = re.sub(r"<[^>]+>", "", text) + text = re.sub(r"(?m)^\s*`[^`]+`.*$", "", text) + text = re.sub(r"\n{3,}", "\n\n", text) + return text.strip() + + +def build_collapsed_parent_notes(resolved_schema: dict, flat_schema: dict) -> str: + """ + Identify top-level objects that were 'collapsed' during flattening + and append their descriptions to the tool context. + These usually contain high-level logic (e.g., which subtype to use). + """ + if not resolved_schema or "properties" not in resolved_schema: + return "" + + lines = [] + # Iterate over the ORIGINAL schema properties + for name, prop in resolved_schema["properties"].items(): + + # If this top-level name is NOT in the flattened list, it means it was + # a container object that got flattened away. + if name not in flat_schema: + desc_raw = prop.get("description", "").strip() + if desc_raw: + desc_clean = " ".join(desc_raw.splitlines()).strip() + # Add it as a context note + lines.append(f"\n* **{name} (Context)**: {desc_clean}") + + if not lines: + return "" + + return "\n\n### Important Context" + "".join(lines) + + +def register_tools(allowed_resources: Optional[List[str]] = None): + """ + Load tools dynamically. + allowed_resources: List of strings (e.g. ['database', 'dbsystem']) or None for ALL. + """ + print(f"Loading OCI Specs (Filter: {allowed_resources})...") + tools = build_tools_from_latest_spec(allowed_resources=allowed_resources) + print(f"Loaded {len(tools)} tools.") + + for t in tools: + tool_name = t.get("name") + flat_schema = t.get("flatSchema", {}) + resolved_schema = t.get("schema", {}) + + param_map = {} + required_args = [] + optional_args = [] + + # --- A. Process Query/Path Params --- + flat_top_names = {k.split("_", 1)[0] for k in flat_schema.keys()} + + for p in t.get("parameters", []): + pname = p.get("name") + if not pname: + continue + if p.get("in") == "body": + continue + if pname in flat_top_names: + continue + if pname in flat_schema: + continue + + sanitized = pname.replace("-", "_") + desc = escape_string(p.get("description", "No description").strip()) + + raw_type = p.get("type") or p.get("schema", {}).get("type", "string") + py_type = TYPE_MAP.get(raw_type, "str") + + param_map[sanitized] = { + "orig_name": pname, + "location": p.get("in", "query"), + "type": py_type, + } + + if p.get("required"): + required_args.append( + f'{sanitized}: Annotated[{py_type}, Field(description="{desc}")]' + ) + else: + optional_args.append( + f'{sanitized}: Annotated[{py_type}, Field(description="{desc}")] = None' + ) + + # --- B. Process Flattened Body Fields --- + for flat_key, meta in flat_schema.items(): + sanitized = flat_key.replace("-", "_") + desc_raw = ( + meta.get("description") + or (meta.get("raw_schema") or {}).get("description") + or "Body field" + ) + desc = escape_string(desc_raw.strip()) + + raw_type = meta.get("type") or (meta.get("raw_schema") or {}).get( + "type", "string" + ) + py_type = TYPE_MAP.get(raw_type, "str") + + param_map[sanitized] = { + "orig_name": flat_key, + "location": "body_flat", + "type": py_type, + } + + if meta.get("required"): + required_args.append( + f'{sanitized}: Annotated[{py_type}, Field(description="{desc}")]' + ) + else: + optional_args.append( + f'{sanitized}: Annotated[{py_type}, Field(description="{desc}")] = None' + ) + + # --- C. Build Docstring --- + top_desc = clean_description_text(t.get("description", "")) + context_notes = build_collapsed_parent_notes(resolved_schema, flat_schema) + docstring = escape_string(top_desc + context_notes) + + # --- D. Generate Function Code --- + args_sig = ", ".join(required_args + optional_args) + + func_code = f''' +async def {tool_name}({args_sig}): + """ + {docstring} + """ + from oracle.oci_db_dynamic_mcp_server.server import invoke_oci_api, unflatten_payload + args = locals() + params = {{}} + flat_body = {{}} + path = "{t.get('path', '')}" + for sanitized, info in param_map.items(): + val = args.get(sanitized) + if val is None: continue + # Remove 'args' from locals if it exists to avoid polluting param map + if sanitized == "args": continue + + if info["location"] == "body_flat": + flat_body[info["orig_name"]] = val + else: + placeholder = "{{" + info['orig_name'] + "}}" + if placeholder in path: + path = path.replace(placeholder, str(val)) + else: + params[info['orig_name']] = val + payload = unflatten_payload(flat_body, flat_schema) + return invoke_oci_api( + method="{t.get('method', 'GET')}", + path=path, + params=params, + payload=payload + ) +''' + exec_globals = { + "Annotated": Annotated, + "Field": Field, + "List": List, + "Dict": Dict, + "Any": Any, + "Optional": Optional, + "param_map": param_map, + "flat_schema": flat_schema, + } + + try: + exec(func_code, exec_globals) + tool_func = exec_globals[tool_name] + mcp.tool(tool_func) + except Exception as e: + print(f"Failed to register tool {tool_name}: {e}") + + +def main(): + parser = argparse.ArgumentParser(description="OCI DBaaS MCP Server") + parser.add_argument( + "--resources", "-r", type=str, help="Comma-separated resources (e.g. databases)" + ) + args = parser.parse_args() + + allowed = [r.strip() for r in args.resources.split(",")] if args.resources else None + register_tools(allowed) + + print("Server running...") + mcp.run(transport="stdio") + + +if __name__ == "__main__": + main() +else: + register_tools() diff --git a/src/oci-db-dynamic-mcp-server/oracle/oci_db_dynamic_mcp_server/tests/test_db_dynamic.py b/src/oci-db-dynamic-mcp-server/oracle/oci_db_dynamic_mcp_server/tests/test_db_dynamic.py new file mode 100644 index 00000000..8ba0dda5 --- /dev/null +++ b/src/oci-db-dynamic-mcp-server/oracle/oci_db_dynamic_mcp_server/tests/test_db_dynamic.py @@ -0,0 +1,7843 @@ +from unittest.mock import patch + +import pytest +from fastmcp import Client +from oracle.oci_db_dynamic_mcp_server.server import mcp + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListApplicationVips(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListApplicationVips", + arguments={ + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "cloudVmClusterId": "ocid1.cloudvmcluster.oc1..mockcloudvmclusterid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateApplicationVip(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateApplicationVip", + arguments={ + "cloudVmClusterId": "ocid1.cloudvmcluster.oc1..mockcloudvmclusterid", + "hostnameLabel": "mockhost", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteApplicationVip(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteApplicationVip", + arguments={ + "applicationVipId": "ocid1.applicationvip.oc1..mockapplicationvipid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetApplicationVip(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetApplicationVip", + arguments={ + "applicationVipId": "ocid1.applicationvip.oc1..mockapplicationvipid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListAutonomousContainerDatabaseBackups(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListAutonomousContainerDatabaseBackups", arguments={} + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListAutonomousContainerDatabaseVersions(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListAutonomousContainerDatabaseVersions", + arguments={ + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "serviceComponent": "DATABASE", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListAutonomousContainerDatabases(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListAutonomousContainerDatabases", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateAutonomousContainerDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateAutonomousContainerDatabase", + arguments={ + "displayName": "Mock_Display_Name", + "patchModel": "RELEASE_UPDATE", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_TerminateAutonomousContainerDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "TerminateAutonomousContainerDatabase", + arguments={ + "autonomousContainerDatabaseId": "ocid1.autonomouscontainerdatabase.oc1..mockacdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetAutonomousContainerDatabase(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetAutonomousContainerDatabase", + arguments={ + "autonomousContainerDatabaseId": "ocid1.autonomouscontainerdatabase.oc1..mockacdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateAutonomousContainerDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateAutonomousContainerDatabase", + arguments={ + "autonomousContainerDatabaseId": "ocid1.autonomouscontainerdatabase.oc1..mockacdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_AddStandbyAutonomousContainerDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "AddStandbyAutonomousContainerDatabase", + arguments={ + "autonomousContainerDatabaseId": "ocid1.autonomouscontainerdatabase.oc1..mockacdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeAutonomousContainerDatabaseCompartment(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeAutonomousContainerDatabaseCompartment", + arguments={ + "autonomousContainerDatabaseId": "ocid1.autonomouscontainerdatabase.oc1..mockacdbid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_EditAutonomousContainerDatabaseDataguard(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "EditAutonomousContainerDatabaseDataguard", + arguments={ + "autonomousContainerDatabaseId": "ocid1.autonomouscontainerdatabase.oc1..mockacdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_FailoverAutonomousContainerDatabaseDataguard(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "FailoverAutonomousContainerDatabaseDataguard", + arguments={ + "autonomousContainerDatabaseId": "ocid1.autonomouscontainerdatabase.oc1..mockacdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ReinstateAutonomousContainerDatabaseDataguard(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ReinstateAutonomousContainerDatabaseDataguard", + arguments={ + "autonomousContainerDatabaseId": "ocid1.autonomouscontainerdatabase.oc1..mockacdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_RestartAutonomousContainerDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "RestartAutonomousContainerDatabase", + arguments={ + "autonomousContainerDatabaseId": "ocid1.autonomouscontainerdatabase.oc1..mockacdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_RotateAutonomousContainerDatabaseEncryptionKey(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "RotateAutonomousContainerDatabaseEncryptionKey", + arguments={ + "autonomousContainerDatabaseId": "ocid1.autonomouscontainerdatabase.oc1..mockacdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ConvertStandbyAutonomousContainerDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ConvertStandbyAutonomousContainerDatabase", + arguments={ + "autonomousContainerDatabaseId": "ocid1.autonomouscontainerdatabase.oc1..mockacdbid", + "role": "PRIMARY", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_SwitchoverAutonomousContainerDatabaseDataguard(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "SwitchoverAutonomousContainerDatabaseDataguard", + arguments={ + "autonomousContainerDatabaseId": "ocid1.autonomouscontainerdatabase.oc1..mockacdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_MigrateAutonomousContainerDatabaseDataguardAssociation(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "MigrateAutonomousContainerDatabaseDataguardAssociation", + arguments={ + "autonomousContainerDatabaseId": "ocid1.autonomouscontainerdatabase.oc1..mockacdbid", + "autonomousContainerDatabaseDataguardAssociationId": "ocid1.autonomouscontainerdatabasedataguardassociation.oc1..mockacddgassocid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListContainerDatabasePatches(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListContainerDatabasePatches", + arguments={ + "autonomousContainerDatabaseId": "ocid1.autonomouscontainerdatabase.oc1..mockacdbid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetAutonomousContainerDatabaseResourceUsage(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetAutonomousContainerDatabaseResourceUsage", + arguments={ + "autonomousContainerDatabaseId": "ocid1.autonomouscontainerdatabase.oc1..mockacdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListAutonomousDatabaseBackups(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool("ListAutonomousDatabaseBackups", arguments={}) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateAutonomousDatabaseBackup(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateAutonomousDatabaseBackup", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid", + "backupDestinationDetails_type": "NFS", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteAutonomousDatabaseBackup(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteAutonomousDatabaseBackup", + arguments={ + "autonomousDatabaseBackupId": "ocid1.autonomousdatabasebackup.oc1..mockadbbackupid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetAutonomousDatabaseBackup(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetAutonomousDatabaseBackup", + arguments={ + "autonomousDatabaseBackupId": "ocid1.autonomousdatabasebackup.oc1..mockadbbackupid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateAutonomousDatabaseBackup(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateAutonomousDatabaseBackup", + arguments={ + "autonomousDatabaseBackupId": "ocid1.autonomousdatabasebackup.oc1..mockadbbackupid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListAutonomousDatabaseCharacterSets(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListAutonomousDatabaseCharacterSets", arguments={} + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListAutonomousDatabaseSoftwareImages(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListAutonomousDatabaseSoftwareImages", + arguments={ + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "imageShapeFamily": "VM.Standard", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateAutonomousDatabaseSoftwareImage(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateAutonomousDatabaseSoftwareImage", + arguments={ + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "displayName": "Mock_Display_Name", + "imageShapeFamily": "VM.Standard", + "sourceCdbId": "ocid1.database.oc1..mocksourcecdbid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteAutonomousDatabaseSoftwareImage(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteAutonomousDatabaseSoftwareImage", + arguments={ + "autonomousDatabaseSoftwareImageId": "ocid1.autonomousdatabasesoftwareimage.oc1..mockadbimageid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetAutonomousDatabaseSoftwareImage(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetAutonomousDatabaseSoftwareImage", + arguments={ + "autonomousDatabaseSoftwareImageId": "ocid1.autonomousdatabasesoftwareimage.oc1..mockadbimageid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateAutonomousDatabaseSoftwareImage(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateAutonomousDatabaseSoftwareImage", + arguments={ + "autonomousDatabaseSoftwareImageId": "ocid1.autonomousdatabasesoftwareimage.oc1..mockadbimageid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeAutonomousDatabaseSoftwareImageCompartment(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeAutonomousDatabaseSoftwareImageCompartment", + arguments={ + "autonomousDatabaseSoftwareImageId": "ocid1.autonomousdatabasesoftwareimage.oc1..mockadbimageid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListAutonomousDatabases(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListAutonomousDatabases", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateAutonomousDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateAutonomousDatabase", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ResourcePoolShapes(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool("ResourcePoolShapes", arguments={}) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetAutonomousDatabaseRegionalWallet(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetAutonomousDatabaseRegionalWallet", arguments={} + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateAutonomousDatabaseRegionalWallet(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateAutonomousDatabaseRegionalWallet", arguments={} + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteAutonomousDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteAutonomousDatabase", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetAutonomousDatabase(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetAutonomousDatabase", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateAutonomousDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateAutonomousDatabase", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeAutonomousDatabaseCompartment(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeAutonomousDatabaseCompartment", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeDisasterRecoveryConfiguration(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeDisasterRecoveryConfiguration", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeAutonomousDatabaseSubscription(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeAutonomousDatabaseSubscription", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ConfigureAutonomousDatabaseVaultKey(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ConfigureAutonomousDatabaseVaultKey", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ConfigureSaasAdminUser(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ConfigureSaasAdminUser", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeregisterAutonomousDatabaseDataSafe(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeregisterAutonomousDatabaseDataSafe", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid", + "pdbAdminPassword": "MockPdbPassword123!", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DisableAutonomousDatabaseManagement(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DisableAutonomousDatabaseManagement", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DisableAutonomousDatabaseOperationsInsights(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DisableAutonomousDatabaseOperationsInsights", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_EnableAutonomousDatabaseManagement(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "EnableAutonomousDatabaseManagement", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_EnableAutonomousDatabaseOperationsInsights(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "EnableAutonomousDatabaseOperationsInsights", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_FailOverAutonomousDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "FailOverAutonomousDatabase", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GenerateAutonomousDatabaseWallet(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GenerateAutonomousDatabaseWallet", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid", + "password": "MockPassword!", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_SaasAdminUserStatus(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "SaasAdminUserStatus", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_AutonomousDatabaseManualRefresh(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "AutonomousDatabaseManualRefresh", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_RegisterAutonomousDatabaseDataSafe(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "RegisterAutonomousDatabaseDataSafe", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid", + "pdbAdminPassword": "MockPdbPassword123!", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_RestartAutonomousDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "RestartAutonomousDatabase", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_RestoreAutonomousDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "RestoreAutonomousDatabase", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_RotateAutonomousDatabaseEncryptionKey(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "RotateAutonomousDatabaseEncryptionKey", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ShrinkAutonomousDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ShrinkAutonomousDatabase", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_StartAutonomousDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "StartAutonomousDatabase", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_StopAutonomousDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "StopAutonomousDatabase", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_SwitchoverAutonomousDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "SwitchoverAutonomousDatabase", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListAutonomousDatabaseDataguardAssociations(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListAutonomousDatabaseDataguardAssociations", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetAutonomousDatabaseDataguardAssociation(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetAutonomousDatabaseDataguardAssociation", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid", + "autonomousDatabaseDataguardAssociationId": "ocid1.autonomousdatabasedataguardassociation.oc1..mockadbdgassocid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListAutonomousDatabaseClones(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListAutonomousDatabaseClones", + arguments={ + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListAutonomousDatabasePeers(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListAutonomousDatabasePeers", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListAutonomousDatabaseRefreshableClones(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListAutonomousDatabaseRefreshableClones", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListResourcePoolMembers(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListResourcePoolMembers", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetAutonomousDatabaseWallet(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetAutonomousDatabaseWallet", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateAutonomousDatabaseWallet(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateAutonomousDatabaseWallet", + arguments={ + "autonomousDatabaseId": "ocid1.autonomousdatabase.oc1..mockadbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListAutonomousDbPreviewVersions(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListAutonomousDbPreviewVersions", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListAutonomousDbVersions(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListAutonomousDbVersions", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetExadataInfrastructureOcpus(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetExadataInfrastructureOcpus", + arguments={ + "autonomousExadataInfrastructureId": "ocid1.autonomousexadatainfrastructure.oc1..mockaxid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetAutonomousPatch(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetAutonomousPatch", + arguments={ + "autonomousPatchId": "ocid1.autonomouspatch.oc1..mockautonomouspatchid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListAutonomousVirtualMachines(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListAutonomousVirtualMachines", + arguments={ + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "autonomousVmClusterId": "ocid1.autonomousvmcluster.oc1..mockavmclusterid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetAutonomousVirtualMachine(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetAutonomousVirtualMachine", + arguments={ + "autonomousVirtualMachineId": "ocid1.autonomousvirtualmachine.oc1..mockavmid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListAutonomousVmClusters(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListAutonomousVmClusters", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateAutonomousVmCluster(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateAutonomousVmCluster", + arguments={ + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "displayName": "Mock_Display_Name", + "exadataInfrastructureId": "ocid1.exadatainfrastructure.oc1..mockexadatainfraid", + "vmClusterNetworkId": "ocid1.vmclusternetwork.oc1..mockvmclusternetworkid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteAutonomousVmCluster(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteAutonomousVmCluster", + arguments={ + "autonomousVmClusterId": "ocid1.autonomousvmcluster.oc1..mockavmclusterid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetAutonomousVmCluster(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetAutonomousVmCluster", + arguments={ + "autonomousVmClusterId": "ocid1.autonomousvmcluster.oc1..mockavmclusterid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateAutonomousVmCluster(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateAutonomousVmCluster", + arguments={ + "autonomousVmClusterId": "ocid1.autonomousvmcluster.oc1..mockavmclusterid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListAutonomousVmClusterAcdResourceUsage(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListAutonomousVmClusterAcdResourceUsage", + arguments={ + "autonomousVmClusterId": "ocid1.autonomousvmcluster.oc1..mockavmclusterid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeAutonomousVmClusterCompartment(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeAutonomousVmClusterCompartment", + arguments={ + "autonomousVmClusterId": "ocid1.autonomousvmcluster.oc1..mockavmclusterid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_RotateAutonomousVmClusterOrdsCerts(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "RotateAutonomousVmClusterOrdsCerts", + arguments={ + "autonomousVmClusterId": "ocid1.autonomousvmcluster.oc1..mockavmclusterid", + "certificateGenerationType": "BYOC", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_RotateAutonomousVmClusterSslCerts(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "RotateAutonomousVmClusterSslCerts", + arguments={ + "autonomousVmClusterId": "ocid1.autonomousvmcluster.oc1..mockavmclusterid", + "certificateGenerationType": "BYOC", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetAutonomousVmClusterResourceUsage(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetAutonomousVmClusterResourceUsage", + arguments={ + "autonomousVmClusterId": "ocid1.autonomousvmcluster.oc1..mockavmclusterid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListBackupDestination(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListBackupDestination", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateBackupDestination(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateBackupDestination", + arguments={ + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "displayName": "Mock_Display_Name", + "type": "FULL", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteBackupDestination(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteBackupDestination", + arguments={ + "backupDestinationId": "ocid1.backupdestination.oc1..mockbackupdestinationid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetBackupDestination(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetBackupDestination", + arguments={ + "backupDestinationId": "ocid1.backupdestination.oc1..mockbackupdestinationid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateBackupDestination(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateBackupDestination", + arguments={ + "backupDestinationId": "ocid1.backupdestination.oc1..mockbackupdestinationid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeBackupDestinationCompartment(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeBackupDestinationCompartment", + arguments={ + "backupDestinationId": "ocid1.backupdestination.oc1..mockbackupdestinationid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListBackups(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool("ListBackups", arguments={}) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateBackup(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateBackup", + arguments={ + "databaseId": "ocid1.database.oc1..mockdatabaseid", + "displayName": "Mock_Display_Name", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteBackup(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteBackup", arguments={"backupId": "ocid1.backup.oc1..mockbackupid"} + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetBackup(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetBackup", arguments={"backupId": "ocid1.backup.oc1..mockbackupid"} + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListCloudAutonomousVmClusters(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListCloudAutonomousVmClusters", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateCloudAutonomousVmCluster(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateCloudAutonomousVmCluster", + arguments={ + "cloudExadataInfrastructureId": "ocid1.cloudexadatainfrastructure.oc1..mockcloudexadataid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "displayName": "Mock_Display_Name", + "subnetId": "ocid1.subnet.oc1..mocksubnetid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteCloudAutonomousVmCluster(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteCloudAutonomousVmCluster", + arguments={ + "cloudAutonomousVmClusterId": "ocid1.cloudautonomousvmcluster.oc1..mockcloudavmclusterid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetCloudAutonomousVmCluster(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetCloudAutonomousVmCluster", + arguments={ + "cloudAutonomousVmClusterId": "ocid1.cloudautonomousvmcluster.oc1..mockcloudavmclusterid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateCloudAutonomousVmCluster(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateCloudAutonomousVmCluster", + arguments={ + "cloudAutonomousVmClusterId": "ocid1.cloudautonomousvmcluster.oc1..mockcloudavmclusterid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListCloudAutonomousVmClusterAcdResourceUsage(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListCloudAutonomousVmClusterAcdResourceUsage", + arguments={ + "cloudAutonomousVmClusterId": "ocid1.cloudautonomousvmcluster.oc1..mockcloudavmclusterid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeCloudAutonomousVmClusterCompartment(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeCloudAutonomousVmClusterCompartment", + arguments={ + "cloudAutonomousVmClusterId": "ocid1.cloudautonomousvmcluster.oc1..mockcloudavmclusterid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_RotateCloudAutonomousVmClusterOrdsCerts(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "RotateCloudAutonomousVmClusterOrdsCerts", + arguments={ + "cloudAutonomousVmClusterId": "ocid1.cloudautonomousvmcluster.oc1..mockcloudavmclusterid", + "certificateGenerationType": "BYOC", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_RotateCloudAutonomousVmClusterSslCerts(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "RotateCloudAutonomousVmClusterSslCerts", + arguments={ + "cloudAutonomousVmClusterId": "ocid1.cloudautonomousvmcluster.oc1..mockcloudavmclusterid", + "certificateGenerationType": "BYOC", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetCloudAutonomousVmClusterResourceUsage(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetCloudAutonomousVmClusterResourceUsage", + arguments={ + "cloudAutonomousVmClusterId": "ocid1.cloudautonomousvmcluster.oc1..mockcloudavmclusterid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListCloudExadataInfrastructures(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListCloudExadataInfrastructures", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateCloudExadataInfrastructure(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateCloudExadataInfrastructure", + arguments={ + "availabilityDomain": "Uocm:US-ASHBURN-AD-1", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "displayName": "Mock_Display_Name", + "shape": "Exadata.X8M", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteCloudExadataInfrastructure(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteCloudExadataInfrastructure", + arguments={ + "cloudExadataInfrastructureId": "ocid1.cloudexadatainfrastructure.oc1..mockcloudexadataid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetCloudExadataInfrastructure(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetCloudExadataInfrastructure", + arguments={ + "cloudExadataInfrastructureId": "ocid1.cloudexadatainfrastructure.oc1..mockcloudexadataid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateCloudExadataInfrastructure(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateCloudExadataInfrastructure", + arguments={ + "cloudExadataInfrastructureId": "ocid1.cloudexadatainfrastructure.oc1..mockcloudexadataid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_AddStorageCapacityCloudExadataInfrastructure(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "AddStorageCapacityCloudExadataInfrastructure", + arguments={ + "cloudExadataInfrastructureId": "ocid1.cloudexadatainfrastructure.oc1..mockcloudexadataid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeCloudExadataInfrastructureCompartment(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeCloudExadataInfrastructureCompartment", + arguments={ + "cloudExadataInfrastructureId": "ocid1.cloudexadatainfrastructure.oc1..mockcloudexadataid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeCloudExadataInfrastructureSubscription(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeCloudExadataInfrastructureSubscription", + arguments={ + "cloudExadataInfrastructureId": "ocid1.cloudexadatainfrastructure.oc1..mockcloudexadataid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ConfigureExascaleCloudExadataInfrastructure(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ConfigureExascaleCloudExadataInfrastructure", + arguments={ + "cloudExadataInfrastructureId": "ocid1.cloudexadatainfrastructure.oc1..mockcloudexadataid", + "totalStorageInGBs": 5000, + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetCloudExadataInfrastructureUnallocatedResources(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetCloudExadataInfrastructureUnallocatedResources", + arguments={ + "cloudExadataInfrastructureId": "ocid1.cloudexadatainfrastructure.oc1..mockcloudexadataid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListCloudVmClusters(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListCloudVmClusters", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateCloudVmCluster(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateCloudVmCluster", + arguments={ + "backupSubnetId": "ocid1.subnet.oc1..mockbackupsubnetid", + "cloudExadataInfrastructureId": "ocid1.cloudexadatainfrastructure.oc1..mockcloudexadataid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "cpuCoreCount": 16, + "displayName": "Mock_Display_Name", + "giVersion": "19.0.0.0", + "hostname": "mock-host-1", + "sshPublicKeys": ["ssh-rsa AAAAB3Nza... mockKey1"], + "subnetId": "ocid1.subnet.oc1..mocksubnetid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteCloudVmCluster(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteCloudVmCluster", + arguments={ + "cloudVmClusterId": "ocid1.cloudvmcluster.oc1..mockcloudvmclusterid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetCloudVmCluster(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetCloudVmCluster", + arguments={ + "cloudVmClusterId": "ocid1.cloudvmcluster.oc1..mockcloudvmclusterid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateCloudVmCluster(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateCloudVmCluster", + arguments={ + "cloudVmClusterId": "ocid1.cloudvmcluster.oc1..mockcloudvmclusterid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetCloudVmClusterIormConfig(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetCloudVmClusterIormConfig", + arguments={ + "cloudVmClusterId": "ocid1.cloudvmcluster.oc1..mockcloudvmclusterid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateCloudVmClusterIormConfig(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateCloudVmClusterIormConfig", + arguments={ + "cloudVmClusterId": "ocid1.cloudvmcluster.oc1..mockcloudvmclusterid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_AddVirtualMachineToCloudVmCluster(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "AddVirtualMachineToCloudVmCluster", + arguments={ + "cloudVmClusterId": "ocid1.cloudvmcluster.oc1..mockcloudvmclusterid", + "dbServers": [ + "ocid1.dbserver.oc1..server1", + "ocid1.dbserver.oc1..server2", + ], + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeCloudVmClusterCompartment(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeCloudVmClusterCompartment", + arguments={ + "cloudVmClusterId": "ocid1.cloudvmcluster.oc1..mockcloudvmclusterid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeCloudVmClusterSubscription(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeCloudVmClusterSubscription", + arguments={ + "cloudVmClusterId": "ocid1.cloudvmcluster.oc1..mockcloudvmclusterid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_RemoveVirtualMachineFromCloudVmCluster(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "RemoveVirtualMachineFromCloudVmCluster", + arguments={ + "cloudVmClusterId": "ocid1.cloudvmcluster.oc1..mockcloudvmclusterid", + "dbServers": [ + "ocid1.dbserver.oc1..server1", + "ocid1.dbserver.oc1..server2", + ], + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListCloudVmClusterUpdateHistoryEntries(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListCloudVmClusterUpdateHistoryEntries", + arguments={ + "cloudVmClusterId": "ocid1.cloudvmcluster.oc1..mockcloudvmclusterid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetCloudVmClusterUpdateHistoryEntry(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetCloudVmClusterUpdateHistoryEntry", + arguments={ + "cloudVmClusterId": "ocid1.cloudvmcluster.oc1..mockcloudvmclusterid", + "updateHistoryEntryId": "ocid1.updatehistory.oc1..mockupdatehistoryid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListCloudVmClusterUpdates(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListCloudVmClusterUpdates", + arguments={ + "cloudVmClusterId": "ocid1.cloudvmcluster.oc1..mockcloudvmclusterid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetCloudVmClusterUpdate(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetCloudVmClusterUpdate", + arguments={ + "cloudVmClusterId": "ocid1.cloudvmcluster.oc1..mockcloudvmclusterid", + "updateId": "ocid1.update.oc1..mockupdateid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListDatabaseSoftwareImages(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListDatabaseSoftwareImages", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateDatabaseSoftwareImage(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateDatabaseSoftwareImage", + arguments={ + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "displayName": "Mock_Display_Name", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteDatabaseSoftwareImage(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteDatabaseSoftwareImage", + arguments={ + "databaseSoftwareImageId": "ocid1.databasesoftwareimage.oc1..mockdbsoftwareimageid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetDatabaseSoftwareImage(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetDatabaseSoftwareImage", + arguments={ + "databaseSoftwareImageId": "ocid1.databasesoftwareimage.oc1..mockdbsoftwareimageid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateDatabaseSoftwareImage(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateDatabaseSoftwareImage", + arguments={ + "databaseSoftwareImageId": "ocid1.databasesoftwareimage.oc1..mockdbsoftwareimageid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeDatabaseSoftwareImageCompartment(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeDatabaseSoftwareImageCompartment", + arguments={ + "databaseSoftwareImageId": "ocid1.databasesoftwareimage.oc1..mockdbsoftwareimageid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListDatabases(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListDatabases", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateDatabase", + arguments={ + "dbHomeId": "ocid1.dbhome.oc1..mockdbhomeid", + "source": "DB_SYSTEM", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteDatabase", + arguments={"databaseId": "ocid1.database.oc1..mockdatabaseid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetDatabase(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetDatabase", + arguments={"databaseId": "ocid1.database.oc1..mockdatabaseid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateDatabase", + arguments={ + "databaseId": "ocid1.database.oc1..mockdatabaseid", + "storageSizeDetails_dataStorageSizeInGBs": 1024, + "storageSizeDetails_recoStorageSizeInGBs": 256, + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeEncryptionKeyLocation(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeEncryptionKeyLocation", + arguments={ + "databaseId": "ocid1.database.oc1..mockdatabaseid", + "providerType": "OCI", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ConvertToPdb(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ConvertToPdb", + arguments={ + "databaseId": "ocid1.database.oc1..mockdatabaseid", + "action": "STOP", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DisableDatabaseManagement(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DisableDatabaseManagement", + arguments={"databaseId": "ocid1.database.oc1..mockdatabaseid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_EnableDatabaseManagement(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "EnableDatabaseManagement", + arguments={ + "databaseId": "ocid1.database.oc1..mockdatabaseid", + "credentialDetails_passwordSecretId": "ocid1.vaultsecret.oc1..mockpasswordsecretid", + "credentialDetails_userName": "db_admin", + "privateEndPointId": "ocid1.privateendpoint.oc1..mockprivateendpointid", + "serviceName": "mockservice.example.com", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_MigrateVaultKey(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "MigrateVaultKey", + arguments={ + "databaseId": "ocid1.database.oc1..mockdatabaseid", + "kmsKeyId": "ocid1.key.oc1..mockkmskeyid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ModifyDatabaseManagement(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ModifyDatabaseManagement", + arguments={ + "databaseId": "ocid1.database.oc1..mockdatabaseid", + "credentialDetails_passwordSecretId": "ocid1.vaultsecret.oc1..mockpasswordsecretid", + "credentialDetails_userName": "db_admin", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_RestoreDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "RestoreDatabase", + arguments={"databaseId": "ocid1.database.oc1..mockdatabaseid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_RotateVaultKey(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "RotateVaultKey", + arguments={"databaseId": "ocid1.database.oc1..mockdatabaseid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpgradeDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpgradeDatabase", + arguments={ + "databaseId": "ocid1.database.oc1..mockdatabaseid", + "action": "STOP", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ConvertToStandalone(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ConvertToStandalone", + arguments={ + "databaseId": "ocid1.database.oc1..mockdatabaseid", + "databaseAdminPassword": "MockDbPassword123!", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_FailoverDataGuard(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "FailoverDataGuard", + arguments={ + "databaseId": "ocid1.database.oc1..mockdatabaseid", + "databaseAdminPassword": "MockDbPassword123!", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ReinstateDataGuard(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ReinstateDataGuard", + arguments={ + "databaseId": "ocid1.database.oc1..mockdatabaseid", + "databaseAdminPassword": "MockDbPassword123!", + "sourceDatabaseId": "ocid1.database.oc1..mocksourcedbid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_SwitchOverDataGuard(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "SwitchOverDataGuard", + arguments={ + "databaseId": "ocid1.database.oc1..mockdatabaseid", + "databaseAdminPassword": "MockDbPassword123!", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateDataGuard(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateDataGuard", + arguments={"databaseId": "ocid1.database.oc1..mockdatabaseid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListDataGuardAssociations(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListDataGuardAssociations", + arguments={"databaseId": "ocid1.database.oc1..mockdatabaseid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateDataGuardAssociation(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateDataGuardAssociation", + arguments={ + "databaseId": "ocid1.database.oc1..mockdatabaseid", + "creationType": "CLONE", + "databaseAdminPassword": "MockDbPassword123!", + "protectionMode": "MAXIMUM_PERFORMANCE", + "sourceEncryptionKeyLocationDetails_providerType": "OCI_VAULT", + "transportType": "TCP", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetDataGuardAssociation(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetDataGuardAssociation", + arguments={ + "databaseId": "ocid1.database.oc1..mockdatabaseid", + "dataGuardAssociationId": "ocid1.dataguardassociation.oc1..mockdgassocid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateDataGuardAssociation(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateDataGuardAssociation", + arguments={ + "databaseId": "ocid1.database.oc1..mockdatabaseid", + "dataGuardAssociationId": "ocid1.dataguardassociation.oc1..mockdgassocid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_FailoverDataGuardAssociation(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "FailoverDataGuardAssociation", + arguments={ + "databaseId": "ocid1.database.oc1..mockdatabaseid", + "dataGuardAssociationId": "ocid1.dataguardassociation.oc1..mockdgassocid", + "databaseAdminPassword": "MockDbPassword123!", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_MigrateDataGuardAssociationToMultiDataGuards(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "MigrateDataGuardAssociationToMultiDataGuards", + arguments={ + "databaseId": "ocid1.database.oc1..mockdatabaseid", + "dataGuardAssociationId": "ocid1.dataguardassociation.oc1..mockdgassocid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ReinstateDataGuardAssociation(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ReinstateDataGuardAssociation", + arguments={ + "databaseId": "ocid1.database.oc1..mockdatabaseid", + "dataGuardAssociationId": "ocid1.dataguardassociation.oc1..mockdgassocid", + "databaseAdminPassword": "MockDbPassword123!", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_SwitchoverDataGuardAssociation(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "SwitchoverDataGuardAssociation", + arguments={ + "databaseId": "ocid1.database.oc1..mockdatabaseid", + "dataGuardAssociationId": "ocid1.dataguardassociation.oc1..mockdgassocid", + "databaseAdminPassword": "MockDbPassword123!", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListPdbConversionHistoryEntries(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListPdbConversionHistoryEntries", + arguments={"databaseId": "ocid1.database.oc1..mockdatabaseid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetPdbConversionHistoryEntry(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetPdbConversionHistoryEntry", + arguments={ + "databaseId": "ocid1.database.oc1..mockdatabaseid", + "pdbConversionHistoryEntryId": "ocid1.pdbconversionhistory.oc1..mockpdbhistoryid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListDatabaseUpgradeHistoryEntries(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListDatabaseUpgradeHistoryEntries", + arguments={"databaseId": "ocid1.database.oc1..mockdatabaseid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetDatabaseUpgradeHistoryEntry(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetDatabaseUpgradeHistoryEntry", + arguments={ + "databaseId": "ocid1.database.oc1..mockdatabaseid", + "upgradeHistoryEntryId": "ocid1.upgradehistory.oc1..mockupgradehistoryid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListDbHomes(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListDbHomes", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateDbHome(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool("CreateDbHome", arguments={}) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteDbHome(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteDbHome", arguments={"dbHomeId": "ocid1.dbhome.oc1..mockdbhomeid"} + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetDbHome(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetDbHome", arguments={"dbHomeId": "ocid1.dbhome.oc1..mockdbhomeid"} + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateDbHome(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateDbHome", arguments={"dbHomeId": "ocid1.dbhome.oc1..mockdbhomeid"} + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListDbHomePatchHistoryEntries(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListDbHomePatchHistoryEntries", + arguments={"dbHomeId": "ocid1.dbhome.oc1..mockdbhomeid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetDbHomePatchHistoryEntry(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetDbHomePatchHistoryEntry", + arguments={ + "dbHomeId": "ocid1.dbhome.oc1..mockdbhomeid", + "patchHistoryEntryId": "ocid1.patchhistory.oc1..mockpatchhistoryid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListDbHomePatches(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListDbHomePatches", + arguments={"dbHomeId": "ocid1.dbhome.oc1..mockdbhomeid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetDbHomePatch(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetDbHomePatch", + arguments={ + "dbHomeId": "ocid1.dbhome.oc1..mockdbhomeid", + "patchId": "ocid1.patch.oc1..mockpatchid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListDbNodes(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListDbNodes", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetDbNode(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetDbNode", arguments={"dbNodeId": "ocid1.dbnode.oc1..mockdbnodeid"} + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DbNodeAction(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DbNodeAction", + arguments={"dbNodeId": "ocid1.dbnode.oc1..mockdbnodeid", "action": "STOP"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListConsoleConnections(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListConsoleConnections", + arguments={"dbNodeId": "ocid1.dbnode.oc1..mockdbnodeid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateConsoleConnection(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateConsoleConnection", + arguments={ + "dbNodeId": "ocid1.dbnode.oc1..mockdbnodeid", + "publicKey": "ssh-rsa AAAAB3Nza... mockPublicKey", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteConsoleConnection(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteConsoleConnection", + arguments={ + "dbNodeId": "ocid1.dbnode.oc1..mockdbnodeid", + "consoleConnectionId": "ocid1.consoleconnection.oc1..mockconsoleconnid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetConsoleConnection(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetConsoleConnection", + arguments={ + "dbNodeId": "ocid1.dbnode.oc1..mockdbnodeid", + "consoleConnectionId": "ocid1.consoleconnection.oc1..mockconsoleconnid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListConsoleHistories(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListConsoleHistories", + arguments={"dbNodeId": "ocid1.dbnode.oc1..mockdbnodeid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateConsoleHistory(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateConsoleHistory", + arguments={ + "dbNodeId": "ocid1.dbnode.oc1..mockdbnodeid", + "displayName": "Mock_Display_Name", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteConsoleHistory(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteConsoleHistory", + arguments={ + "dbNodeId": "ocid1.dbnode.oc1..mockdbnodeid", + "consoleHistoryId": "ocid1.consolehistory.oc1..mockconsolehistoryid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetConsoleHistory(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetConsoleHistory", + arguments={ + "dbNodeId": "ocid1.dbnode.oc1..mockdbnodeid", + "consoleHistoryId": "ocid1.consolehistory.oc1..mockconsolehistoryid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateConsoleHistory(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateConsoleHistory", + arguments={ + "dbNodeId": "ocid1.dbnode.oc1..mockdbnodeid", + "consoleHistoryId": "ocid1.consolehistory.oc1..mockconsolehistoryid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetConsoleHistoryContent(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetConsoleHistoryContent", + arguments={ + "dbNodeId": "ocid1.dbnode.oc1..mockdbnodeid", + "consoleHistoryId": "ocid1.consolehistory.oc1..mockconsolehistoryid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListDbServers(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListDbServers", + arguments={ + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "exadataInfrastructureId": "ocid1.exadatainfrastructure.oc1..mockexadatainfraid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetDbServer(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetDbServer", + arguments={ + "exadataInfrastructureId": "ocid1.exadatainfrastructure.oc1..mockexadatainfraid", + "dbServerId": "ocid1.dbserver.oc1..mockdbserverid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListDbSystemComputePerformances(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListDbSystemComputePerformances", arguments={} + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListDbSystemShapes(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListDbSystemShapes", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListFlexComponents(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListFlexComponents", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListDbSystemStoragePerformances(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListDbSystemStoragePerformances", arguments={"storageManagement": "ASM"} + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListDbSystems(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListDbSystems", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_LaunchDbSystem(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "LaunchDbSystem", + arguments={ + "availabilityDomain": "Uocm:US-ASHBURN-AD-1", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "hostname": "mock-host-1", + "shape": "Exadata.X8M", + "sshPublicKeys": ["ssh-rsa AAAAB3Nza... mockKey1"], + "subnetId": "ocid1.subnet.oc1..mocksubnetid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_TerminateDbSystem(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "TerminateDbSystem", + arguments={"dbSystemId": "ocid1.dbsystem.oc1..mockdbsystemid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetDbSystem(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetDbSystem", + arguments={"dbSystemId": "ocid1.dbsystem.oc1..mockdbsystemid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateDbSystem(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateDbSystem", + arguments={"dbSystemId": "ocid1.dbsystem.oc1..mockdbsystemid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetExadataIormConfig(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetExadataIormConfig", + arguments={"dbSystemId": "ocid1.dbsystem.oc1..mockdbsystemid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateExadataIormConfig(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateExadataIormConfig", + arguments={"dbSystemId": "ocid1.dbsystem.oc1..mockdbsystemid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeDbSystemCompartment(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeDbSystemCompartment", + arguments={ + "dbSystemId": "ocid1.dbsystem.oc1..mockdbsystemid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_MigrateExadataDbSystemResourceModel(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "MigrateExadataDbSystemResourceModel", + arguments={"dbSystemId": "ocid1.dbsystem.oc1..mockdbsystemid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpgradeDbSystem(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpgradeDbSystem", + arguments={ + "dbSystemId": "ocid1.dbsystem.oc1..mockdbsystemid", + "action": "STOP", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListDbSystemPatchHistoryEntries(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListDbSystemPatchHistoryEntries", + arguments={"dbSystemId": "ocid1.dbsystem.oc1..mockdbsystemid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetDbSystemPatchHistoryEntry(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetDbSystemPatchHistoryEntry", + arguments={ + "dbSystemId": "ocid1.dbsystem.oc1..mockdbsystemid", + "patchHistoryEntryId": "ocid1.patchhistory.oc1..mockpatchhistoryid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListDbSystemPatches(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListDbSystemPatches", + arguments={"dbSystemId": "ocid1.dbsystem.oc1..mockdbsystemid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetDbSystemPatch(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetDbSystemPatch", + arguments={ + "dbSystemId": "ocid1.dbsystem.oc1..mockdbsystemid", + "patchId": "ocid1.patch.oc1..mockpatchid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListDbSystemUpgradeHistoryEntries(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListDbSystemUpgradeHistoryEntries", + arguments={"dbSystemId": "ocid1.dbsystem.oc1..mockdbsystemid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetDbSystemUpgradeHistoryEntry(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetDbSystemUpgradeHistoryEntry", + arguments={ + "dbSystemId": "ocid1.dbsystem.oc1..mockdbsystemid", + "upgradeHistoryEntryId": "ocid1.upgradehistory.oc1..mockupgradehistoryid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListDbVersions(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListDbVersions", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListExadataInfrastructures(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListExadataInfrastructures", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateExadataInfrastructure(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateExadataInfrastructure", + arguments={ + "adminNetworkCIDR": "192.168.1.0/24", + "cloudControlPlaneServer1": "10.0.0.5", + "cloudControlPlaneServer2": "10.0.0.6", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "corporateProxy": "http://corp-proxy:8080", + "displayName": "Mock_Display_Name", + "dnsServer": ["169.254.169.254"], + "gateway": "10.0.0.1", + "infiniBandNetworkCIDR": "192.168.0.0/24", + "netmask": "255.255.255.0", + "ntpServer": ["169.254.169.254"], + "shape": "Exadata.X8M", + "timeZone": "UTC", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteExadataInfrastructure(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteExadataInfrastructure", + arguments={ + "exadataInfrastructureId": "ocid1.exadatainfrastructure.oc1..mockexadatainfraid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetExadataInfrastructure(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetExadataInfrastructure", + arguments={ + "exadataInfrastructureId": "ocid1.exadatainfrastructure.oc1..mockexadatainfraid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateExadataInfrastructure(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateExadataInfrastructure", + arguments={ + "exadataInfrastructureId": "ocid1.exadatainfrastructure.oc1..mockexadatainfraid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ActivateExadataInfrastructure(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ActivateExadataInfrastructure", + arguments={ + "exadataInfrastructureId": "ocid1.exadatainfrastructure.oc1..mockexadatainfraid", + "activationFile": "mock_activation_file_path_or_content", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_AddStorageCapacityExadataInfrastructure(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "AddStorageCapacityExadataInfrastructure", + arguments={ + "exadataInfrastructureId": "ocid1.exadatainfrastructure.oc1..mockexadatainfraid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeExadataInfrastructureCompartment(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeExadataInfrastructureCompartment", + arguments={ + "exadataInfrastructureId": "ocid1.exadatainfrastructure.oc1..mockexadatainfraid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DownloadExadataInfrastructureConfigFile(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DownloadExadataInfrastructureConfigFile", + arguments={ + "exadataInfrastructureId": "ocid1.exadatainfrastructure.oc1..mockexadatainfraid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetExadataInfrastructureUnAllocatedResources(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetExadataInfrastructureUnAllocatedResources", + arguments={ + "exadataInfrastructureId": "ocid1.exadatainfrastructure.oc1..mockexadatainfraid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListVmClusterNetworks(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListVmClusterNetworks", + arguments={ + "exadataInfrastructureId": "ocid1.exadatainfrastructure.oc1..mockexadatainfraid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateVmClusterNetwork(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateVmClusterNetwork", + arguments={ + "exadataInfrastructureId": "ocid1.exadatainfrastructure.oc1..mockexadatainfraid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "displayName": "Mock_Display_Name", + "scans": [{"hostname": "scan1", "port": 1521}], + "vmNetworks": [ + { + "networkType": "CLIENT", + "netmask": "255.255.255.0", + "gateway": "10.0.0.1", + } + ], + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GenerateRecommendedVmClusterNetwork(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GenerateRecommendedVmClusterNetwork", + arguments={ + "exadataInfrastructureId": "ocid1.exadatainfrastructure.oc1..mockexadatainfraid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "displayName": "Mock_Display_Name", + "networks": [{"id": "ocid1.network.oc1..mocknetworkid"}], + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteVmClusterNetwork(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteVmClusterNetwork", + arguments={ + "exadataInfrastructureId": "ocid1.exadatainfrastructure.oc1..mockexadatainfraid", + "vmClusterNetworkId": "ocid1.vmclusternetwork.oc1..mockvmclusternetworkid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetVmClusterNetwork(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetVmClusterNetwork", + arguments={ + "exadataInfrastructureId": "ocid1.exadatainfrastructure.oc1..mockexadatainfraid", + "vmClusterNetworkId": "ocid1.vmclusternetwork.oc1..mockvmclusternetworkid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateVmClusterNetwork(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateVmClusterNetwork", + arguments={ + "exadataInfrastructureId": "ocid1.exadatainfrastructure.oc1..mockexadatainfraid", + "vmClusterNetworkId": "ocid1.vmclusternetwork.oc1..mockvmclusternetworkid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DownloadVmClusterNetworkConfigFile(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DownloadVmClusterNetworkConfigFile", + arguments={ + "exadataInfrastructureId": "ocid1.exadatainfrastructure.oc1..mockexadatainfraid", + "vmClusterNetworkId": "ocid1.vmclusternetwork.oc1..mockvmclusternetworkid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ResizeVmClusterNetwork(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ResizeVmClusterNetwork", + arguments={ + "exadataInfrastructureId": "ocid1.exadatainfrastructure.oc1..mockexadatainfraid", + "vmClusterNetworkId": "ocid1.vmclusternetwork.oc1..mockvmclusternetworkid", + "action": "STOP", + "vmNetworks": [ + { + "networkType": "CLIENT", + "netmask": "255.255.255.0", + "gateway": "10.0.0.1", + } + ], + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ValidateVmClusterNetwork(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ValidateVmClusterNetwork", + arguments={ + "exadataInfrastructureId": "ocid1.exadatainfrastructure.oc1..mockexadatainfraid", + "vmClusterNetworkId": "ocid1.vmclusternetwork.oc1..mockvmclusternetworkid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListExadbVmClusters(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListExadbVmClusters", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateExadbVmCluster(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateExadbVmCluster", + arguments={ + "availabilityDomain": "Uocm:US-ASHBURN-AD-1", + "backupSubnetId": "ocid1.subnet.oc1..mockbackupsubnetid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "displayName": "Mock_Display_Name", + "enabledECpuCount": 8, + "exascaleDbStorageVaultId": "ocid1.exascaledbstoragevault.oc1..mockexascalevaultid", + "gridImageId": "ocid1.gridimage.oc1..mockgridimageid", + "hostname": "mock-host-1", + "nodeCount": 3, + "shape": "Exadata.X8M", + "sshPublicKeys": ["ssh-rsa AAAAB3Nza... mockKey1"], + "subnetId": "ocid1.subnet.oc1..mocksubnetid", + "totalECpuCount": 32, + "vmFileSystemStorage_totalSizeInGbs": 500, + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteExadbVmCluster(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteExadbVmCluster", + arguments={ + "exadbVmClusterId": "ocid1.exadbvmcluster.oc1..mockexadbvmclusterid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetExadbVmCluster(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetExadbVmCluster", + arguments={ + "exadbVmClusterId": "ocid1.exadbvmcluster.oc1..mockexadbvmclusterid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateExadbVmCluster(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateExadbVmCluster", + arguments={ + "exadbVmClusterId": "ocid1.exadbvmcluster.oc1..mockexadbvmclusterid", + "vmFileSystemStorage_totalSizeInGbs": 500, + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeExadbVmClusterCompartment(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeExadbVmClusterCompartment", + arguments={ + "exadbVmClusterId": "ocid1.exadbvmcluster.oc1..mockexadbvmclusterid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeExadbVmClusterSubscription(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeExadbVmClusterSubscription", + arguments={ + "exadbVmClusterId": "ocid1.exadbvmcluster.oc1..mockexadbvmclusterid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_RemoveVirtualMachineFromExadbVmCluster(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "RemoveVirtualMachineFromExadbVmCluster", + arguments={ + "exadbVmClusterId": "ocid1.exadbvmcluster.oc1..mockexadbvmclusterid", + "dbNodes": [ + {"id": "ocid1.dbnode.oc1..node1"}, + {"id": "ocid1.dbnode.oc1..node2"}, + ], + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListExadbVmClusterUpdateHistoryEntries(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListExadbVmClusterUpdateHistoryEntries", + arguments={ + "exadbVmClusterId": "ocid1.exadbvmcluster.oc1..mockexadbvmclusterid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetExadbVmClusterUpdateHistoryEntry(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetExadbVmClusterUpdateHistoryEntry", + arguments={ + "exadbVmClusterId": "ocid1.exadbvmcluster.oc1..mockexadbvmclusterid", + "updateHistoryEntryId": "ocid1.updatehistory.oc1..mockupdatehistoryid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListExadbVmClusterUpdates(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListExadbVmClusterUpdates", + arguments={ + "exadbVmClusterId": "ocid1.exadbvmcluster.oc1..mockexadbvmclusterid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetExadbVmClusterUpdate(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetExadbVmClusterUpdate", + arguments={ + "exadbVmClusterId": "ocid1.exadbvmcluster.oc1..mockexadbvmclusterid", + "updateId": "ocid1.update.oc1..mockupdateid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListExascaleDbStorageVaults(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListExascaleDbStorageVaults", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateExascaleDbStorageVault(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateExascaleDbStorageVault", + arguments={ + "availabilityDomain": "Uocm:US-ASHBURN-AD-1", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "displayName": "Mock_Display_Name", + "highCapacityDatabaseStorage_totalSizeInGbs": 4096, + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteExascaleDbStorageVault(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteExascaleDbStorageVault", + arguments={ + "exascaleDbStorageVaultId": "ocid1.exascaledbstoragevault.oc1..mockexascalevaultid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetExascaleDbStorageVault(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetExascaleDbStorageVault", + arguments={ + "exascaleDbStorageVaultId": "ocid1.exascaledbstoragevault.oc1..mockexascalevaultid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateExascaleDbStorageVault(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateExascaleDbStorageVault", + arguments={ + "exascaleDbStorageVaultId": "ocid1.exascaledbstoragevault.oc1..mockexascalevaultid", + "highCapacityDatabaseStorage_totalSizeInGbs": 4096, + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeExascaleDbStorageVaultCompartment(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeExascaleDbStorageVaultCompartment", + arguments={ + "exascaleDbStorageVaultId": "ocid1.exascaledbstoragevault.oc1..mockexascalevaultid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeExascaleDbStorageVaultSubscription(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeExascaleDbStorageVaultSubscription", + arguments={ + "exascaleDbStorageVaultId": "ocid1.exascaledbstoragevault.oc1..mockexascalevaultid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListExecutionActions(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListExecutionActions", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateExecutionAction(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateExecutionAction", + arguments={ + "actionType": "DB_Server_Patching", + "executionWindowId": "ocid1.executionwindow.oc1..mockexecutionwindowid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteExecutionAction(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteExecutionAction", + arguments={ + "executionActionId": "ocid1.executionaction.oc1..mockexecutionactionid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetExecutionAction(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetExecutionAction", + arguments={ + "executionActionId": "ocid1.executionaction.oc1..mockexecutionactionid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateExecutionAction(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateExecutionAction", + arguments={ + "executionActionId": "ocid1.executionaction.oc1..mockexecutionactionid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_MoveExecutionActionMember(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "MoveExecutionActionMember", + arguments={ + "executionActionId": "ocid1.executionaction.oc1..mockexecutionactionid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListExecutionWindows(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListExecutionWindows", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateExecutionWindow(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateExecutionWindow", + arguments={ + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "executionResourceId": "ocid1.executionresource.oc1..mockexecutionresourceid", + "timeScheduled": "2025-01-01T00:00:00.000Z", + "windowDurationInMins": 240, + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteExecutionWindow(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteExecutionWindow", + arguments={ + "executionWindowId": "ocid1.executionwindow.oc1..mockexecutionwindowid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetExecutionWindow(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetExecutionWindow", + arguments={ + "executionWindowId": "ocid1.executionwindow.oc1..mockexecutionwindowid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateExecutionWindow(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateExecutionWindow", + arguments={ + "executionWindowId": "ocid1.executionwindow.oc1..mockexecutionwindowid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ReorderExecutionActions(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ReorderExecutionActions", + arguments={ + "executionWindowId": "ocid1.executionwindow.oc1..mockexecutionwindowid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateExternalBackupJob(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateExternalBackupJob", + arguments={ + "availabilityDomain": "Uocm:US-ASHBURN-AD-1", + "characterSet": "AL32UTF8", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "databaseEdition": "ENTERPRISE_EDITION_EXTREME_PERFORMANCE", + "databaseMode": "READ_WRITE", + "dbName": "MOCKDB", + "dbVersion": "19.0.0.0", + "displayName": "Mock_Display_Name", + "externalDatabaseIdentifier": 1, + "ncharacterSet": "AL16UTF16", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetExternalBackupJob(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetExternalBackupJob", + arguments={"backupId": "ocid1.backup.oc1..mockbackupid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CompleteExternalBackupJob(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CompleteExternalBackupJob", + arguments={"backupId": "ocid1.backup.oc1..mockbackupid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListExternalContainerDatabases(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListExternalContainerDatabases", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateExternalContainerDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateExternalContainerDatabase", + arguments={ + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "displayName": "Mock_Display_Name", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteExternalContainerDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteExternalContainerDatabase", + arguments={ + "externalContainerDatabaseId": "ocid1.externalcontainerdatabase.oc1..mockextcdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetExternalContainerDatabase(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetExternalContainerDatabase", + arguments={ + "externalContainerDatabaseId": "ocid1.externalcontainerdatabase.oc1..mockextcdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateExternalContainerDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateExternalContainerDatabase", + arguments={ + "externalContainerDatabaseId": "ocid1.externalcontainerdatabase.oc1..mockextcdbid", + "displayName": "Mock_Display_Name", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeExternalContainerDatabaseCompartment(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeExternalContainerDatabaseCompartment", + arguments={ + "externalContainerDatabaseId": "ocid1.externalcontainerdatabase.oc1..mockextcdbid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DisableExternalContainerDatabaseDatabaseManagement(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DisableExternalContainerDatabaseDatabaseManagement", + arguments={ + "externalContainerDatabaseId": "ocid1.externalcontainerdatabase.oc1..mockextcdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DisableExternalContainerDatabaseStackMonitoring(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DisableExternalContainerDatabaseStackMonitoring", + arguments={ + "externalContainerDatabaseId": "ocid1.externalcontainerdatabase.oc1..mockextcdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_EnableExternalContainerDatabaseDatabaseManagement(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "EnableExternalContainerDatabaseDatabaseManagement", + arguments={ + "externalContainerDatabaseId": "ocid1.externalcontainerdatabase.oc1..mockextcdbid", + "externalDatabaseConnectorId": "ocid1.externaldatabaseconnector.oc1..mockextdbconnectorid", + "licenseModel": "BRING_YOUR_OWN_LICENSE", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_EnableExternalContainerDatabaseStackMonitoring(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "EnableExternalContainerDatabaseStackMonitoring", + arguments={ + "externalContainerDatabaseId": "ocid1.externalcontainerdatabase.oc1..mockextcdbid", + "externalDatabaseConnectorId": "ocid1.externaldatabaseconnector.oc1..mockextdbconnectorid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ScanExternalContainerDatabasePluggableDatabases(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ScanExternalContainerDatabasePluggableDatabases", + arguments={ + "externalContainerDatabaseId": "ocid1.externalcontainerdatabase.oc1..mockextcdbid", + "externalDatabaseConnectorId": "ocid1.externaldatabaseconnector.oc1..mockextdbconnectorid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListExternalDatabaseConnectors(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListExternalDatabaseConnectors", + arguments={ + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "externalDatabaseId": "ocid1.externaldatabase.oc1..mockexternaldatabaseid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateExternalDatabaseConnector(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateExternalDatabaseConnector", + arguments={ + "displayName": "Mock_Display_Name", + "externalDatabaseId": "ocid1.externaldatabase.oc1..mockexternaldatabaseid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteExternalDatabaseConnector(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteExternalDatabaseConnector", + arguments={ + "externalDatabaseConnectorId": "ocid1.externaldatabaseconnector.oc1..mockextdbconnectorid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetExternalDatabaseConnector(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetExternalDatabaseConnector", + arguments={ + "externalDatabaseConnectorId": "ocid1.externaldatabaseconnector.oc1..mockextdbconnectorid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateExternalDatabaseConnector(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateExternalDatabaseConnector", + arguments={ + "externalDatabaseConnectorId": "ocid1.externaldatabaseconnector.oc1..mockextdbconnectorid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CheckExternalDatabaseConnectorConnectionStatus(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CheckExternalDatabaseConnectorConnectionStatus", + arguments={ + "externalDatabaseConnectorId": "ocid1.externaldatabaseconnector.oc1..mockextdbconnectorid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListExternalNonContainerDatabases(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListExternalNonContainerDatabases", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateExternalNonContainerDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateExternalNonContainerDatabase", + arguments={ + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "displayName": "Mock_Display_Name", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteExternalNonContainerDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteExternalNonContainerDatabase", + arguments={ + "externalNonContainerDatabaseId": "ocid1.externalnoncontainerdatabase.oc1..mockextnoncdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetExternalNonContainerDatabase(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetExternalNonContainerDatabase", + arguments={ + "externalNonContainerDatabaseId": "ocid1.externalnoncontainerdatabase.oc1..mockextnoncdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateExternalNonContainerDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateExternalNonContainerDatabase", + arguments={ + "externalNonContainerDatabaseId": "ocid1.externalnoncontainerdatabase.oc1..mockextnoncdbid", + "displayName": "Mock_Display_Name", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeExternalNonContainerDatabaseCompartment(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeExternalNonContainerDatabaseCompartment", + arguments={ + "externalNonContainerDatabaseId": "ocid1.externalnoncontainerdatabase.oc1..mockextnoncdbid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DisableExternalNonContainerDatabaseDatabaseManagement(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DisableExternalNonContainerDatabaseDatabaseManagement", + arguments={ + "externalNonContainerDatabaseId": "ocid1.externalnoncontainerdatabase.oc1..mockextnoncdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DisableExternalNonContainerDatabaseOperationsInsights(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DisableExternalNonContainerDatabaseOperationsInsights", + arguments={ + "externalNonContainerDatabaseId": "ocid1.externalnoncontainerdatabase.oc1..mockextnoncdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DisableExternalNonContainerDatabaseStackMonitoring(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DisableExternalNonContainerDatabaseStackMonitoring", + arguments={ + "externalNonContainerDatabaseId": "ocid1.externalnoncontainerdatabase.oc1..mockextnoncdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_EnableExternalNonContainerDatabaseDatabaseManagement(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "EnableExternalNonContainerDatabaseDatabaseManagement", + arguments={ + "externalNonContainerDatabaseId": "ocid1.externalnoncontainerdatabase.oc1..mockextnoncdbid", + "externalDatabaseConnectorId": "ocid1.externaldatabaseconnector.oc1..mockextdbconnectorid", + "licenseModel": "BRING_YOUR_OWN_LICENSE", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_EnableExternalNonContainerDatabaseOperationsInsights(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "EnableExternalNonContainerDatabaseOperationsInsights", + arguments={ + "externalNonContainerDatabaseId": "ocid1.externalnoncontainerdatabase.oc1..mockextnoncdbid", + "externalDatabaseConnectorId": "ocid1.externaldatabaseconnector.oc1..mockextdbconnectorid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_EnableExternalNonContainerDatabaseStackMonitoring(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "EnableExternalNonContainerDatabaseStackMonitoring", + arguments={ + "externalNonContainerDatabaseId": "ocid1.externalnoncontainerdatabase.oc1..mockextnoncdbid", + "externalDatabaseConnectorId": "ocid1.externaldatabaseconnector.oc1..mockextdbconnectorid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListExternalPluggableDatabases(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListExternalPluggableDatabases", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateExternalPluggableDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateExternalPluggableDatabase", + arguments={ + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "displayName": "Mock_Display_Name", + "externalContainerDatabaseId": "ocid1.externalcontainerdatabase.oc1..mockextcdbid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteExternalPluggableDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteExternalPluggableDatabase", + arguments={ + "externalPluggableDatabaseId": "ocid1.externalpluggabledatabase.oc1..mockextpdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetExternalPluggableDatabase(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetExternalPluggableDatabase", + arguments={ + "externalPluggableDatabaseId": "ocid1.externalpluggabledatabase.oc1..mockextpdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateExternalPluggableDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateExternalPluggableDatabase", + arguments={ + "externalPluggableDatabaseId": "ocid1.externalpluggabledatabase.oc1..mockextpdbid", + "displayName": "Mock_Display_Name", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeExternalPluggableDatabaseCompartment(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeExternalPluggableDatabaseCompartment", + arguments={ + "externalPluggableDatabaseId": "ocid1.externalpluggabledatabase.oc1..mockextpdbid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DisableExternalPluggableDatabaseDatabaseManagement(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DisableExternalPluggableDatabaseDatabaseManagement", + arguments={ + "externalPluggableDatabaseId": "ocid1.externalpluggabledatabase.oc1..mockextpdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DisableExternalPluggableDatabaseOperationsInsights(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DisableExternalPluggableDatabaseOperationsInsights", + arguments={ + "externalPluggableDatabaseId": "ocid1.externalpluggabledatabase.oc1..mockextpdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DisableExternalPluggableDatabaseStackMonitoring(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DisableExternalPluggableDatabaseStackMonitoring", + arguments={ + "externalPluggableDatabaseId": "ocid1.externalpluggabledatabase.oc1..mockextpdbid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_EnableExternalPluggableDatabaseDatabaseManagement(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "EnableExternalPluggableDatabaseDatabaseManagement", + arguments={ + "externalPluggableDatabaseId": "ocid1.externalpluggabledatabase.oc1..mockextpdbid", + "externalDatabaseConnectorId": "ocid1.externaldatabaseconnector.oc1..mockextdbconnectorid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_EnableExternalPluggableDatabaseOperationsInsights(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "EnableExternalPluggableDatabaseOperationsInsights", + arguments={ + "externalPluggableDatabaseId": "ocid1.externalpluggabledatabase.oc1..mockextpdbid", + "externalDatabaseConnectorId": "ocid1.externaldatabaseconnector.oc1..mockextdbconnectorid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_EnableExternalPluggableDatabaseStackMonitoring(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "EnableExternalPluggableDatabaseStackMonitoring", + arguments={ + "externalPluggableDatabaseId": "ocid1.externalpluggabledatabase.oc1..mockextpdbid", + "externalDatabaseConnectorId": "ocid1.externaldatabaseconnector.oc1..mockextdbconnectorid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListGiVersions(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListGiVersions", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListGiVersionMinorVersions(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListGiVersionMinorVersions", arguments={"version": "1.0"} + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListKeyStores(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListKeyStores", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateKeyStore(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateKeyStore", + arguments={ + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "displayName": "Mock_Display_Name", + "typeDetails_type": "VM_CLUSTER", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteKeyStore(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteKeyStore", + arguments={"keyStoreId": "ocid1.keystore.oc1..mockkeystoreid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetKeyStore(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetKeyStore", + arguments={"keyStoreId": "ocid1.keystore.oc1..mockkeystoreid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateKeyStore(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateKeyStore", + arguments={ + "keyStoreId": "ocid1.keystore.oc1..mockkeystoreid", + "typeDetails_type": "VM_CLUSTER", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeKeyStoreCompartment(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeKeyStoreCompartment", + arguments={ + "keyStoreId": "ocid1.keystore.oc1..mockkeystoreid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListMaintenanceRunHistory(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListMaintenanceRunHistory", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetMaintenanceRunHistory(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetMaintenanceRunHistory", + arguments={ + "maintenanceRunHistoryId": "ocid1.maintenancerunhistory.oc1..mockmrhistoryid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListMaintenanceRuns(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListMaintenanceRuns", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateMaintenanceRun(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateMaintenanceRun", + arguments={ + "patchType": "GI", + "targetResourceId": "ocid1.resource.oc1..mocktargetresourceid", + "timeScheduled": "2025-01-01T00:00:00.000Z", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetMaintenanceRun(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetMaintenanceRun", + arguments={"maintenanceRunId": "ocid1.maintenancerun.oc1..mockmrid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateMaintenanceRun(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateMaintenanceRun", + arguments={"maintenanceRunId": "ocid1.maintenancerun.oc1..mockmrid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListOneoffPatches(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListOneoffPatches", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateOneoffPatch(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateOneoffPatch", + arguments={ + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "dbVersion": "19.0.0.0", + "displayName": "Mock_Display_Name", + "releaseUpdate": "19.15", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteOneoffPatch(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteOneoffPatch", + arguments={"oneoffPatchId": "ocid1.oneoffpatch.oc1..mockoneoffpatchid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetOneoffPatch(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetOneoffPatch", + arguments={"oneoffPatchId": "ocid1.oneoffpatch.oc1..mockoneoffpatchid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateOneoffPatch(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateOneoffPatch", + arguments={"oneoffPatchId": "ocid1.oneoffpatch.oc1..mockoneoffpatchid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeOneoffPatchCompartment(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeOneoffPatchCompartment", + arguments={ + "oneoffPatchId": "ocid1.oneoffpatch.oc1..mockoneoffpatchid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DownloadOneoffPatch(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DownloadOneoffPatch", + arguments={"oneoffPatchId": "ocid1.oneoffpatch.oc1..mockoneoffpatchid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListPluggableDatabases(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool("ListPluggableDatabases", arguments={}) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreatePluggableDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreatePluggableDatabase", + arguments={ + "containerDatabaseId": "ocid1.database.oc1..mockcontainerdatabaseid", + "pdbCreationTypeDetails_creationType": "LOCAL_CLONE", + "pdbName": "PDB1", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeletePluggableDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeletePluggableDatabase", + arguments={"pluggableDatabaseId": "ocid1.pluggabledatabase.oc1..mockpdbid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetPluggableDatabase(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetPluggableDatabase", + arguments={"pluggableDatabaseId": "ocid1.pluggabledatabase.oc1..mockpdbid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdatePluggableDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdatePluggableDatabase", + arguments={"pluggableDatabaseId": "ocid1.pluggabledatabase.oc1..mockpdbid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ConvertToRegularPluggableDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ConvertToRegularPluggableDatabase", + arguments={"pluggableDatabaseId": "ocid1.pluggabledatabase.oc1..mockpdbid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_RefreshPluggableDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "RefreshPluggableDatabase", + arguments={"pluggableDatabaseId": "ocid1.pluggabledatabase.oc1..mockpdbid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_StartPluggableDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "StartPluggableDatabase", + arguments={"pluggableDatabaseId": "ocid1.pluggabledatabase.oc1..mockpdbid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_StopPluggableDatabase(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "StopPluggableDatabase", + arguments={"pluggableDatabaseId": "ocid1.pluggabledatabase.oc1..mockpdbid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetResourcePrincipalToken(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetResourcePrincipalToken", + arguments={"instanceId": "ocid1.instance.oc1..mockinstanceid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListParamsForActionType(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListParamsForActionType", arguments={"type": "FULL"} + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListScheduledActions(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListScheduledActions", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateScheduledAction(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateScheduledAction", + arguments={ + "actionOrder": [1], + "actionType": "DB_Server_Patching", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "schedulingPlanId": "ocid1.schedulingplan.oc1..mockschedulingplanid", + "schedulingWindowId": "ocid1.schedulingwindow.oc1..mockschedulingwindowid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteScheduledAction(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteScheduledAction", + arguments={ + "scheduledActionId": "ocid1.scheduledaction.oc1..mockscheduledactionid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetScheduledAction(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetScheduledAction", + arguments={ + "scheduledActionId": "ocid1.scheduledaction.oc1..mockscheduledactionid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateScheduledAction(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateScheduledAction", + arguments={ + "scheduledActionId": "ocid1.scheduledaction.oc1..mockscheduledactionid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListSchedulingPlans(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListSchedulingPlans", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateSchedulingPlan(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateSchedulingPlan", + arguments={ + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "resourceId": "ocid1.resource.oc1..mockresourceid", + "schedulingPolicyId": "ocid1.schedulingpolicy.oc1..mockschedulingpolicyid", + "serviceType": "EXADATA", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteSchedulingPlan(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteSchedulingPlan", + arguments={ + "schedulingPlanId": "ocid1.schedulingplan.oc1..mockschedulingplanid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetSchedulingPlan(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetSchedulingPlan", + arguments={ + "schedulingPlanId": "ocid1.schedulingplan.oc1..mockschedulingplanid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeSchedulingPlanCompartment(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeSchedulingPlanCompartment", + arguments={ + "schedulingPlanId": "ocid1.schedulingplan.oc1..mockschedulingplanid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ReorderScheduledActions(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ReorderScheduledActions", + arguments={ + "schedulingPlanId": "ocid1.schedulingplan.oc1..mockschedulingplanid", + "scheduledActionIdOrders": [ + {"actionId": "ocid1.scheduledaction.oc1..id1", "order": 1} + ], + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListSchedulingPolicies(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListSchedulingPolicies", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateSchedulingPolicy(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateSchedulingPolicy", + arguments={ + "cadence": "MONTHLY", + "cadenceStartMonth_name": "JANUARY", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "displayName": "Mock_Display_Name", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteSchedulingPolicy(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteSchedulingPolicy", + arguments={ + "schedulingPolicyId": "ocid1.schedulingpolicy.oc1..mockschedulingpolicyid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetSchedulingPolicy(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetSchedulingPolicy", + arguments={ + "schedulingPolicyId": "ocid1.schedulingpolicy.oc1..mockschedulingpolicyid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateSchedulingPolicy(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateSchedulingPolicy", + arguments={ + "schedulingPolicyId": "ocid1.schedulingpolicy.oc1..mockschedulingpolicyid", + "cadenceStartMonth_name": "JANUARY", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeSchedulingPolicyCompartment(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeSchedulingPolicyCompartment", + arguments={ + "schedulingPolicyId": "ocid1.schedulingpolicy.oc1..mockschedulingpolicyid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListRecommendedScheduledActions(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListRecommendedScheduledActions", + arguments={ + "schedulingPolicyId": "ocid1.schedulingpolicy.oc1..mockschedulingpolicyid", + "schedulingPolicyTargetResourceId": "ocid1.resource.oc1..mockpolicytargetid", + "planIntent": "EXADATA", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListSchedulingWindows(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListSchedulingWindows", + arguments={ + "schedulingPolicyId": "ocid1.schedulingpolicy.oc1..mockschedulingpolicyid" + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateSchedulingWindow(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateSchedulingWindow", + arguments={ + "schedulingPolicyId": "ocid1.schedulingpolicy.oc1..mockschedulingpolicyid", + "windowPreference_daysOfWeek": [{"name": "SUNDAY"}], + "windowPreference_duration": 4, + "windowPreference_isEnforcedDuration": True, + "windowPreference_startTime": "02:00", + "windowPreference_weeksOfMonth": [1, 3], + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteSchedulingWindow(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteSchedulingWindow", + arguments={ + "schedulingPolicyId": "ocid1.schedulingpolicy.oc1..mockschedulingpolicyid", + "schedulingWindowId": "ocid1.schedulingwindow.oc1..mockschedulingwindowid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetSchedulingWindow(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetSchedulingWindow", + arguments={ + "schedulingPolicyId": "ocid1.schedulingpolicy.oc1..mockschedulingpolicyid", + "schedulingWindowId": "ocid1.schedulingwindow.oc1..mockschedulingwindowid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateSchedulingWindow(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateSchedulingWindow", + arguments={ + "schedulingPolicyId": "ocid1.schedulingpolicy.oc1..mockschedulingpolicyid", + "schedulingWindowId": "ocid1.schedulingwindow.oc1..mockschedulingwindowid", + "windowPreference_daysOfWeek": [{"name": "SUNDAY"}], + "windowPreference_duration": 4, + "windowPreference_isEnforcedDuration": True, + "windowPreference_startTime": "02:00", + "windowPreference_weeksOfMonth": [1, 3], + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListSystemVersions(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListSystemVersions", + arguments={ + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "shape": "Exadata.X8M", + "giVersion": "19.0.0.0", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListVmClusters(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListVmClusters", + arguments={"compartmentId": "ocid1.compartment.oc1..mockcompartmentid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_CreateVmCluster(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "CreateVmCluster", + arguments={ + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + "cpuCoreCount": 16, + "displayName": "Mock_Display_Name", + "exadataInfrastructureId": "ocid1.exadatainfrastructure.oc1..mockexadatainfraid", + "giVersion": "19.0.0.0", + "sshPublicKeys": ["ssh-rsa AAAAB3Nza... mockKey1"], + "vmClusterNetworkId": "ocid1.vmclusternetwork.oc1..mockvmclusternetworkid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_DeleteVmCluster(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "DeleteVmCluster", + arguments={"vmClusterId": "ocid1.vmcluster.oc1..mockvmclusterid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetVmCluster(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetVmCluster", + arguments={"vmClusterId": "ocid1.vmcluster.oc1..mockvmclusterid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_UpdateVmCluster(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "UpdateVmCluster", + arguments={"vmClusterId": "ocid1.vmcluster.oc1..mockvmclusterid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_AddVirtualMachineToVmCluster(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "AddVirtualMachineToVmCluster", + arguments={ + "vmClusterId": "ocid1.vmcluster.oc1..mockvmclusterid", + "dbServers": [ + "ocid1.dbserver.oc1..server1", + "ocid1.dbserver.oc1..server2", + ], + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ChangeVmClusterCompartment(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ChangeVmClusterCompartment", + arguments={ + "vmClusterId": "ocid1.vmcluster.oc1..mockvmclusterid", + "compartmentId": "ocid1.compartment.oc1..mockcompartmentid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_RemoveVirtualMachineFromVmCluster(mock_invoke): + mock_data = {} + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "RemoveVirtualMachineFromVmCluster", + arguments={ + "vmClusterId": "ocid1.vmcluster.oc1..mockvmclusterid", + "dbServers": [ + "ocid1.dbserver.oc1..server1", + "ocid1.dbserver.oc1..server2", + ], + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListVmClusterPatchHistoryEntries(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListVmClusterPatchHistoryEntries", + arguments={"vmClusterId": "ocid1.vmcluster.oc1..mockvmclusterid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetVmClusterPatchHistoryEntry(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetVmClusterPatchHistoryEntry", + arguments={ + "vmClusterId": "ocid1.vmcluster.oc1..mockvmclusterid", + "patchHistoryEntryId": "ocid1.patchhistory.oc1..mockpatchhistoryid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListVmClusterPatches(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListVmClusterPatches", + arguments={"vmClusterId": "ocid1.vmcluster.oc1..mockvmclusterid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetVmClusterPatch(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetVmClusterPatch", + arguments={ + "vmClusterId": "ocid1.vmcluster.oc1..mockvmclusterid", + "patchId": "ocid1.patch.oc1..mockpatchid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListVmClusterUpdateHistoryEntries(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListVmClusterUpdateHistoryEntries", + arguments={"vmClusterId": "ocid1.vmcluster.oc1..mockvmclusterid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetVmClusterUpdateHistoryEntry(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetVmClusterUpdateHistoryEntry", + arguments={ + "vmClusterId": "ocid1.vmcluster.oc1..mockvmclusterid", + "updateHistoryEntryId": "ocid1.updatehistory.oc1..mockupdatehistoryid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_ListVmClusterUpdates(mock_invoke): + mock_data = [ + { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + ] + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "ListVmClusterUpdates", + arguments={"vmClusterId": "ocid1.vmcluster.oc1..mockvmclusterid"}, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() + + +@pytest.mark.asyncio +@patch("oracle.oci_db_dynamic_mcp_server.server.invoke_oci_api") +async def test_GetVmClusterUpdate(mock_invoke): + mock_data = { + "id": "ocid1.resource.oc1..fallbackmockid", + "displayName": "Fallback_Mock_Resource", + "lifecycleState": "AVAILABLE", + "timeCreated": "2025-01-01T00:00:00.000Z", + } + mock_invoke.return_value = {"status": 200, "data": mock_data} + + async with Client(mcp) as client: + response = await client.call_tool( + "GetVmClusterUpdate", + arguments={ + "vmClusterId": "ocid1.vmcluster.oc1..mockvmclusterid", + "updateId": "ocid1.update.oc1..mockupdateid", + }, + ) + assert response is not None + assert not response.is_error + mock_invoke.assert_called_once() diff --git a/src/oci-db-dynamic-mcp-server/pyproject.toml b/src/oci-db-dynamic-mcp-server/pyproject.toml new file mode 100644 index 00000000..fe501c94 --- /dev/null +++ b/src/oci-db-dynamic-mcp-server/pyproject.toml @@ -0,0 +1,41 @@ +[project] +name = "oracle.oci-db-dynamic-mcp-server" +version = "1.0.1" +description = "OCI Database Service Dynamic MCP server" +readme = "README.md" +requires-python = ">=3.13" +license = "UPL-1.0" +license-files = ["LICENSE.txt"] +authors = [ + {name = "Oracle MCP", email = "237432095+oracle-mcp@users.noreply.github.com"}, +] +dependencies = [ + "fastmcp==2.12.2", + "oci==2.160.0", + "mcp>=1.0.0", + "requests", +] + +classifiers = [ + "License :: OSI Approved :: Universal Permissive License (UPL)", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3.13", +] + +[project.scripts] +"oracle.oci-db-dynamic-mcp-server" = "oracle.oci_db_dynamic_mcp_server.server:main" + +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[tool.hatch.build.targets.wheel] +packages = ["oracle"] + +[dependency-groups] +dev = [ + "pytest>=8.4.2", + "pytest-asyncio>=1.2.0", + "pytest-cov>=7.0.0", +] diff --git a/src/oci-db-dynamic-mcp-server/uv.lock b/src/oci-db-dynamic-mcp-server/uv.lock new file mode 100644 index 00000000..3535161b --- /dev/null +++ b/src/oci-db-dynamic-mcp-server/uv.lock @@ -0,0 +1,1152 @@ +version = 1 +revision = 3 +requires-python = ">=3.13" + +[[package]] +name = "annotated-types" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, +] + +[[package]] +name = "anyio" +version = "4.10.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "sniffio" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f1/b4/636b3b65173d3ce9a38ef5f0522789614e590dab6a8d505340a4efe4c567/anyio-4.10.0.tar.gz", hash = "sha256:3f3fae35c96039744587aa5b8371e7e8e603c0702999535961dd336026973ba6", size = 213252, upload-time = "2025-08-04T08:54:26.451Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6f/12/e5e0282d673bb9746bacfb6e2dba8719989d3660cdb2ea79aee9a9651afb/anyio-4.10.0-py3-none-any.whl", hash = "sha256:60e474ac86736bbfd6f210f7a61218939c318f43f9972497381f1c5e930ed3d1", size = 107213, upload-time = "2025-08-04T08:54:24.882Z" }, +] + +[[package]] +name = "attrs" +version = "25.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/1367933a8532ee6ff8d63537de4f1177af4bff9f3e829baf7331f595bb24/attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b", size = 812032, upload-time = "2025-03-13T11:10:22.779Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", size = 63815, upload-time = "2025-03-13T11:10:21.14Z" }, +] + +[[package]] +name = "authlib" +version = "1.6.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cryptography" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ce/bb/73a1f1c64ee527877f64122422dafe5b87a846ccf4ac933fe21bcbb8fee8/authlib-1.6.4.tar.gz", hash = "sha256:104b0442a43061dc8bc23b133d1d06a2b0a9c2e3e33f34c4338929e816287649", size = 164046, upload-time = "2025-09-17T09:59:23.897Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0e/aa/91355b5f539caf1b94f0e66ff1e4ee39373b757fce08204981f7829ede51/authlib-1.6.4-py2.py3-none-any.whl", hash = "sha256:39313d2a2caac3ecf6d8f95fbebdfd30ae6ea6ae6a6db794d976405fdd9aa796", size = 243076, upload-time = "2025-09-17T09:59:22.259Z" }, +] + +[[package]] +name = "certifi" +version = "2025.8.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/dc/67/960ebe6bf230a96cda2e0abcf73af550ec4f090005363542f0765df162e0/certifi-2025.8.3.tar.gz", hash = "sha256:e564105f78ded564e3ae7c923924435e1daa7463faeab5bb932bc53ffae63407", size = 162386, upload-time = "2025-08-03T03:07:47.08Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/48/1549795ba7742c948d2ad169c1c8cdbae65bc450d6cd753d124b17c8cd32/certifi-2025.8.3-py3-none-any.whl", hash = "sha256:f6c12493cfb1b06ba2ff328595af9350c65d6644968e5d3a2ffd78699af217a5", size = 161216, upload-time = "2025-08-03T03:07:45.777Z" }, +] + +[[package]] +name = "cffi" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser", marker = "implementation_name != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" }, + { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" }, + { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" }, + { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" }, + { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" }, + { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" }, + { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" }, + { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" }, + { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" }, + { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" }, + { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" }, + { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" }, + { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" }, + { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" }, + { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" }, + { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" }, + { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" }, + { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" }, + { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" }, + { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" }, + { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" }, + { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" }, + { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" }, + { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" }, + { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" }, + { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" }, + { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" }, + { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" }, + { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" }, + { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" }, + { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" }, + { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" }, + { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" }, + { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/83/2d/5fd176ceb9b2fc619e63405525573493ca23441330fcdaee6bef9460e924/charset_normalizer-3.4.3.tar.gz", hash = "sha256:6fce4b8500244f6fcb71465d4a4930d132ba9ab8e71a7859e6a5d59851068d14", size = 122371, upload-time = "2025-08-09T07:57:28.46Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/65/ca/2135ac97709b400c7654b4b764daf5c5567c2da45a30cdd20f9eefe2d658/charset_normalizer-3.4.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:14c2a87c65b351109f6abfc424cab3927b3bdece6f706e4d12faaf3d52ee5efe", size = 205326, upload-time = "2025-08-09T07:56:24.721Z" }, + { url = "https://files.pythonhosted.org/packages/71/11/98a04c3c97dd34e49c7d247083af03645ca3730809a5509443f3c37f7c99/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41d1fc408ff5fdfb910200ec0e74abc40387bccb3252f3f27c0676731df2b2c8", size = 146008, upload-time = "2025-08-09T07:56:26.004Z" }, + { url = "https://files.pythonhosted.org/packages/60/f5/4659a4cb3c4ec146bec80c32d8bb16033752574c20b1252ee842a95d1a1e/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1bb60174149316da1c35fa5233681f7c0f9f514509b8e399ab70fea5f17e45c9", size = 159196, upload-time = "2025-08-09T07:56:27.25Z" }, + { url = "https://files.pythonhosted.org/packages/86/9e/f552f7a00611f168b9a5865a1414179b2c6de8235a4fa40189f6f79a1753/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:30d006f98569de3459c2fc1f2acde170b7b2bd265dc1943e87e1a4efe1b67c31", size = 156819, upload-time = "2025-08-09T07:56:28.515Z" }, + { url = "https://files.pythonhosted.org/packages/7e/95/42aa2156235cbc8fa61208aded06ef46111c4d3f0de233107b3f38631803/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:416175faf02e4b0810f1f38bcb54682878a4af94059a1cd63b8747244420801f", size = 151350, upload-time = "2025-08-09T07:56:29.716Z" }, + { url = "https://files.pythonhosted.org/packages/c2/a9/3865b02c56f300a6f94fc631ef54f0a8a29da74fb45a773dfd3dcd380af7/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6aab0f181c486f973bc7262a97f5aca3ee7e1437011ef0c2ec04b5a11d16c927", size = 148644, upload-time = "2025-08-09T07:56:30.984Z" }, + { url = "https://files.pythonhosted.org/packages/77/d9/cbcf1a2a5c7d7856f11e7ac2d782aec12bdfea60d104e60e0aa1c97849dc/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabf8315679312cfa71302f9bd509ded4f2f263fb5b765cf1433b39106c3cc9", size = 160468, upload-time = "2025-08-09T07:56:32.252Z" }, + { url = "https://files.pythonhosted.org/packages/f6/42/6f45efee8697b89fda4d50580f292b8f7f9306cb2971d4b53f8914e4d890/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:bd28b817ea8c70215401f657edef3a8aa83c29d447fb0b622c35403780ba11d5", size = 158187, upload-time = "2025-08-09T07:56:33.481Z" }, + { url = "https://files.pythonhosted.org/packages/70/99/f1c3bdcfaa9c45b3ce96f70b14f070411366fa19549c1d4832c935d8e2c3/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:18343b2d246dc6761a249ba1fb13f9ee9a2bcd95decc767319506056ea4ad4dc", size = 152699, upload-time = "2025-08-09T07:56:34.739Z" }, + { url = "https://files.pythonhosted.org/packages/a3/ad/b0081f2f99a4b194bcbb1934ef3b12aa4d9702ced80a37026b7607c72e58/charset_normalizer-3.4.3-cp313-cp313-win32.whl", hash = "sha256:6fb70de56f1859a3f71261cbe41005f56a7842cc348d3aeb26237560bfa5e0ce", size = 99580, upload-time = "2025-08-09T07:56:35.981Z" }, + { url = "https://files.pythonhosted.org/packages/9a/8f/ae790790c7b64f925e5c953b924aaa42a243fb778fed9e41f147b2a5715a/charset_normalizer-3.4.3-cp313-cp313-win_amd64.whl", hash = "sha256:cf1ebb7d78e1ad8ec2a8c4732c7be2e736f6e5123a4146c5b89c9d1f585f8cef", size = 107366, upload-time = "2025-08-09T07:56:37.339Z" }, + { url = "https://files.pythonhosted.org/packages/8e/91/b5a06ad970ddc7a0e513112d40113e834638f4ca1120eb727a249fb2715e/charset_normalizer-3.4.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3cd35b7e8aedeb9e34c41385fda4f73ba609e561faedfae0a9e75e44ac558a15", size = 204342, upload-time = "2025-08-09T07:56:38.687Z" }, + { url = "https://files.pythonhosted.org/packages/ce/ec/1edc30a377f0a02689342f214455c3f6c2fbedd896a1d2f856c002fc3062/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b89bc04de1d83006373429975f8ef9e7932534b8cc9ca582e4db7d20d91816db", size = 145995, upload-time = "2025-08-09T07:56:40.048Z" }, + { url = "https://files.pythonhosted.org/packages/17/e5/5e67ab85e6d22b04641acb5399c8684f4d37caf7558a53859f0283a650e9/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2001a39612b241dae17b4687898843f254f8748b796a2e16f1051a17078d991d", size = 158640, upload-time = "2025-08-09T07:56:41.311Z" }, + { url = "https://files.pythonhosted.org/packages/f1/e5/38421987f6c697ee3722981289d554957c4be652f963d71c5e46a262e135/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8dcfc373f888e4fb39a7bc57e93e3b845e7f462dacc008d9749568b1c4ece096", size = 156636, upload-time = "2025-08-09T07:56:43.195Z" }, + { url = "https://files.pythonhosted.org/packages/a0/e4/5a075de8daa3ec0745a9a3b54467e0c2967daaaf2cec04c845f73493e9a1/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18b97b8404387b96cdbd30ad660f6407799126d26a39ca65729162fd810a99aa", size = 150939, upload-time = "2025-08-09T07:56:44.819Z" }, + { url = "https://files.pythonhosted.org/packages/02/f7/3611b32318b30974131db62b4043f335861d4d9b49adc6d57c1149cc49d4/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ccf600859c183d70eb47e05a44cd80a4ce77394d1ac0f79dbd2dd90a69a3a049", size = 148580, upload-time = "2025-08-09T07:56:46.684Z" }, + { url = "https://files.pythonhosted.org/packages/7e/61/19b36f4bd67f2793ab6a99b979b4e4f3d8fc754cbdffb805335df4337126/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:53cd68b185d98dde4ad8990e56a58dea83a4162161b1ea9272e5c9182ce415e0", size = 159870, upload-time = "2025-08-09T07:56:47.941Z" }, + { url = "https://files.pythonhosted.org/packages/06/57/84722eefdd338c04cf3030ada66889298eaedf3e7a30a624201e0cbe424a/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:30a96e1e1f865f78b030d65241c1ee850cdf422d869e9028e2fc1d5e4db73b92", size = 157797, upload-time = "2025-08-09T07:56:49.756Z" }, + { url = "https://files.pythonhosted.org/packages/72/2a/aff5dd112b2f14bcc3462c312dce5445806bfc8ab3a7328555da95330e4b/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d716a916938e03231e86e43782ca7878fb602a125a91e7acb8b5112e2e96ac16", size = 152224, upload-time = "2025-08-09T07:56:51.369Z" }, + { url = "https://files.pythonhosted.org/packages/b7/8c/9839225320046ed279c6e839d51f028342eb77c91c89b8ef2549f951f3ec/charset_normalizer-3.4.3-cp314-cp314-win32.whl", hash = "sha256:c6dbd0ccdda3a2ba7c2ecd9d77b37f3b5831687d8dc1b6ca5f56a4880cc7b7ce", size = 100086, upload-time = "2025-08-09T07:56:52.722Z" }, + { url = "https://files.pythonhosted.org/packages/ee/7a/36fbcf646e41f710ce0a563c1c9a343c6edf9be80786edeb15b6f62e17db/charset_normalizer-3.4.3-cp314-cp314-win_amd64.whl", hash = "sha256:73dc19b562516fc9bcf6e5d6e596df0b4eb98d87e4f79f3ae71840e6ed21361c", size = 107400, upload-time = "2025-08-09T07:56:55.172Z" }, + { url = "https://files.pythonhosted.org/packages/8a/1f/f041989e93b001bc4e44bb1669ccdcf54d3f00e628229a85b08d330615c5/charset_normalizer-3.4.3-py3-none-any.whl", hash = "sha256:ce571ab16d890d23b5c278547ba694193a45011ff86a9162a71307ed9f86759a", size = 53175, upload-time = "2025-08-09T07:57:26.864Z" }, +] + +[[package]] +name = "circuitbreaker" +version = "2.1.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/df/ac/de7a92c4ed39cba31fe5ad9203b76a25ca67c530797f6bb420fff5f65ccb/circuitbreaker-2.1.3.tar.gz", hash = "sha256:1a4baee510f7bea3c91b194dcce7c07805fe96c4423ed5594b75af438531d084", size = 10787, upload-time = "2025-03-31T08:12:08.963Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ae/34/15f08edd4628f65217de1fc3c1a27c82e46fe357d60c217fc9881e12ebcc/circuitbreaker-2.1.3-py3-none-any.whl", hash = "sha256:87ba6a3ed03fdc7032bc175561c2b04d52ade9d5faf94ca2b035fbdc5e6b1dd1", size = 7737, upload-time = "2025-03-31T08:12:07.802Z" }, +] + +[[package]] +name = "click" +version = "8.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/46/61/de6cd827efad202d7057d93e0fed9294b96952e188f7384832791c7b2254/click-8.3.0.tar.gz", hash = "sha256:e7b8232224eba16f4ebe410c25ced9f7875cb5f3263ffc93cc3e8da705e229c4", size = 276943, upload-time = "2025-09-18T17:32:23.696Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/d3/9dcc0f5797f070ec8edf30fbadfb200e71d9db6b84d211e3b2085a7589a0/click-8.3.0-py3-none-any.whl", hash = "sha256:9b9f285302c6e3064f4330c05f05b81945b2a39544279343e6e7c5f27a9baddc", size = 107295, upload-time = "2025-09-18T17:32:22.42Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "coverage" +version = "7.13.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b6/45/2c665ca77ec32ad67e25c77daf1cee28ee4558f3bc571cdbaf88a00b9f23/coverage-7.13.0.tar.gz", hash = "sha256:a394aa27f2d7ff9bc04cf703817773a59ad6dfbd577032e690f961d2460ee936", size = 820905, upload-time = "2025-12-08T13:14:38.055Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7c/cc/bce226595eb3bf7d13ccffe154c3c487a22222d87ff018525ab4dd2e9542/coverage-7.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:28ee1c96109974af104028a8ef57cec21447d42d0e937c0275329272e370ebcf", size = 218297, upload-time = "2025-12-08T13:13:10.977Z" }, + { url = "https://files.pythonhosted.org/packages/3b/9f/73c4d34600aae03447dff3d7ad1d0ac649856bfb87d1ca7d681cfc913f9e/coverage-7.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d1e97353dcc5587b85986cda4ff3ec98081d7e84dd95e8b2a6d59820f0545f8a", size = 218673, upload-time = "2025-12-08T13:13:12.562Z" }, + { url = "https://files.pythonhosted.org/packages/63/ab/8fa097db361a1e8586535ae5073559e6229596b3489ec3ef2f5b38df8cb2/coverage-7.13.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:99acd4dfdfeb58e1937629eb1ab6ab0899b131f183ee5f23e0b5da5cba2fec74", size = 249652, upload-time = "2025-12-08T13:13:13.909Z" }, + { url = "https://files.pythonhosted.org/packages/90/3a/9bfd4de2ff191feb37ef9465855ca56a6f2f30a3bca172e474130731ac3d/coverage-7.13.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ff45e0cd8451e293b63ced93161e189780baf444119391b3e7d25315060368a6", size = 252251, upload-time = "2025-12-08T13:13:15.553Z" }, + { url = "https://files.pythonhosted.org/packages/df/61/b5d8105f016e1b5874af0d7c67542da780ccd4a5f2244a433d3e20ceb1ad/coverage-7.13.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f4f72a85316d8e13234cafe0a9f81b40418ad7a082792fa4165bd7d45d96066b", size = 253492, upload-time = "2025-12-08T13:13:16.849Z" }, + { url = "https://files.pythonhosted.org/packages/f3/b8/0fad449981803cc47a4694768b99823fb23632150743f9c83af329bb6090/coverage-7.13.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:11c21557d0e0a5a38632cbbaca5f008723b26a89d70db6315523df6df77d6232", size = 249850, upload-time = "2025-12-08T13:13:18.142Z" }, + { url = "https://files.pythonhosted.org/packages/9a/e9/8d68337c3125014d918cf4327d5257553a710a2995a6a6de2ac77e5aa429/coverage-7.13.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:76541dc8d53715fb4f7a3a06b34b0dc6846e3c69bc6204c55653a85dd6220971", size = 251633, upload-time = "2025-12-08T13:13:19.56Z" }, + { url = "https://files.pythonhosted.org/packages/55/14/d4112ab26b3a1bc4b3c1295d8452dcf399ed25be4cf649002fb3e64b2d93/coverage-7.13.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:6e9e451dee940a86789134b6b0ffbe31c454ade3b849bb8a9d2cca2541a8e91d", size = 249586, upload-time = "2025-12-08T13:13:20.883Z" }, + { url = "https://files.pythonhosted.org/packages/2c/a9/22b0000186db663b0d82f86c2f1028099ae9ac202491685051e2a11a5218/coverage-7.13.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:5c67dace46f361125e6b9cace8fe0b729ed8479f47e70c89b838d319375c8137", size = 249412, upload-time = "2025-12-08T13:13:22.22Z" }, + { url = "https://files.pythonhosted.org/packages/a1/2e/42d8e0d9e7527fba439acdc6ed24a2b97613b1dc85849b1dd935c2cffef0/coverage-7.13.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f59883c643cb19630500f57016f76cfdcd6845ca8c5b5ea1f6e17f74c8e5f511", size = 251191, upload-time = "2025-12-08T13:13:23.899Z" }, + { url = "https://files.pythonhosted.org/packages/a4/af/8c7af92b1377fd8860536aadd58745119252aaaa71a5213e5a8e8007a9f5/coverage-7.13.0-cp313-cp313-win32.whl", hash = "sha256:58632b187be6f0be500f553be41e277712baa278147ecb7559983c6d9faf7ae1", size = 220829, upload-time = "2025-12-08T13:13:25.182Z" }, + { url = "https://files.pythonhosted.org/packages/58/f9/725e8bf16f343d33cbe076c75dc8370262e194ff10072c0608b8e5cf33a3/coverage-7.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:73419b89f812f498aca53f757dd834919b48ce4799f9d5cad33ca0ae442bdb1a", size = 221640, upload-time = "2025-12-08T13:13:26.836Z" }, + { url = "https://files.pythonhosted.org/packages/8a/ff/e98311000aa6933cc79274e2b6b94a2fe0fe3434fca778eba82003675496/coverage-7.13.0-cp313-cp313-win_arm64.whl", hash = "sha256:eb76670874fdd6091eedcc856128ee48c41a9bbbb9c3f1c7c3cf169290e3ffd6", size = 220269, upload-time = "2025-12-08T13:13:28.116Z" }, + { url = "https://files.pythonhosted.org/packages/cf/cf/bbaa2e1275b300343ea865f7d424cc0a2e2a1df6925a070b2b2d5d765330/coverage-7.13.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:6e63ccc6e0ad8986386461c3c4b737540f20426e7ec932f42e030320896c311a", size = 218990, upload-time = "2025-12-08T13:13:29.463Z" }, + { url = "https://files.pythonhosted.org/packages/21/1d/82f0b3323b3d149d7672e7744c116e9c170f4957e0c42572f0366dbb4477/coverage-7.13.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:494f5459ffa1bd45e18558cd98710c36c0b8fbfa82a5eabcbe671d80ecffbfe8", size = 219340, upload-time = "2025-12-08T13:13:31.524Z" }, + { url = "https://files.pythonhosted.org/packages/fb/e3/fe3fd4702a3832a255f4d43013eacb0ef5fc155a5960ea9269d8696db28b/coverage-7.13.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:06cac81bf10f74034e055e903f5f946e3e26fc51c09fc9f584e4a1605d977053", size = 260638, upload-time = "2025-12-08T13:13:32.965Z" }, + { url = "https://files.pythonhosted.org/packages/ad/01/63186cb000307f2b4da463f72af9b85d380236965574c78e7e27680a2593/coverage-7.13.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f2ffc92b46ed6e6760f1d47a71e56b5664781bc68986dbd1836b2b70c0ce2071", size = 262705, upload-time = "2025-12-08T13:13:34.378Z" }, + { url = "https://files.pythonhosted.org/packages/7c/a1/c0dacef0cc865f2455d59eed3548573ce47ed603205ffd0735d1d78b5906/coverage-7.13.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0602f701057c6823e5db1b74530ce85f17c3c5be5c85fc042ac939cbd909426e", size = 265125, upload-time = "2025-12-08T13:13:35.73Z" }, + { url = "https://files.pythonhosted.org/packages/ef/92/82b99223628b61300bd382c205795533bed021505eab6dd86e11fb5d7925/coverage-7.13.0-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:25dc33618d45456ccb1d37bce44bc78cf269909aa14c4db2e03d63146a8a1493", size = 259844, upload-time = "2025-12-08T13:13:37.69Z" }, + { url = "https://files.pythonhosted.org/packages/cf/2c/89b0291ae4e6cd59ef042708e1c438e2290f8c31959a20055d8768349ee2/coverage-7.13.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:71936a8b3b977ddd0b694c28c6a34f4fff2e9dd201969a4ff5d5fc7742d614b0", size = 262700, upload-time = "2025-12-08T13:13:39.525Z" }, + { url = "https://files.pythonhosted.org/packages/bf/f9/a5f992efae1996245e796bae34ceb942b05db275e4b34222a9a40b9fbd3b/coverage-7.13.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:936bc20503ce24770c71938d1369461f0c5320830800933bc3956e2a4ded930e", size = 260321, upload-time = "2025-12-08T13:13:41.172Z" }, + { url = "https://files.pythonhosted.org/packages/4c/89/a29f5d98c64fedbe32e2ac3c227fbf78edc01cc7572eee17d61024d89889/coverage-7.13.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:af0a583efaacc52ae2521f8d7910aff65cdb093091d76291ac5820d5e947fc1c", size = 259222, upload-time = "2025-12-08T13:13:43.282Z" }, + { url = "https://files.pythonhosted.org/packages/b3/c3/940fe447aae302a6701ee51e53af7e08b86ff6eed7631e5740c157ee22b9/coverage-7.13.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f1c23e24a7000da892a312fb17e33c5f94f8b001de44b7cf8ba2e36fbd15859e", size = 261411, upload-time = "2025-12-08T13:13:44.72Z" }, + { url = "https://files.pythonhosted.org/packages/eb/31/12a4aec689cb942a89129587860ed4d0fd522d5fda81237147fde554b8ae/coverage-7.13.0-cp313-cp313t-win32.whl", hash = "sha256:5f8a0297355e652001015e93be345ee54393e45dc3050af4a0475c5a2b767d46", size = 221505, upload-time = "2025-12-08T13:13:46.332Z" }, + { url = "https://files.pythonhosted.org/packages/65/8c/3b5fe3259d863572d2b0827642c50c3855d26b3aefe80bdc9eba1f0af3b0/coverage-7.13.0-cp313-cp313t-win_amd64.whl", hash = "sha256:6abb3a4c52f05e08460bd9acf04fec027f8718ecaa0d09c40ffbc3fbd70ecc39", size = 222569, upload-time = "2025-12-08T13:13:47.79Z" }, + { url = "https://files.pythonhosted.org/packages/b0/39/f71fa8316a96ac72fc3908839df651e8eccee650001a17f2c78cdb355624/coverage-7.13.0-cp313-cp313t-win_arm64.whl", hash = "sha256:3ad968d1e3aa6ce5be295ab5fe3ae1bf5bb4769d0f98a80a0252d543a2ef2e9e", size = 220841, upload-time = "2025-12-08T13:13:49.243Z" }, + { url = "https://files.pythonhosted.org/packages/f8/4b/9b54bedda55421449811dcd5263a2798a63f48896c24dfb92b0f1b0845bd/coverage-7.13.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:453b7ec753cf5e4356e14fe858064e5520c460d3bbbcb9c35e55c0d21155c256", size = 218343, upload-time = "2025-12-08T13:13:50.811Z" }, + { url = "https://files.pythonhosted.org/packages/59/df/c3a1f34d4bba2e592c8979f924da4d3d4598b0df2392fbddb7761258e3dc/coverage-7.13.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:af827b7cbb303e1befa6c4f94fd2bf72f108089cfa0f8abab8f4ca553cf5ca5a", size = 218672, upload-time = "2025-12-08T13:13:52.284Z" }, + { url = "https://files.pythonhosted.org/packages/07/62/eec0659e47857698645ff4e6ad02e30186eb8afd65214fd43f02a76537cb/coverage-7.13.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:9987a9e4f8197a1000280f7cc089e3ea2c8b3c0a64d750537809879a7b4ceaf9", size = 249715, upload-time = "2025-12-08T13:13:53.791Z" }, + { url = "https://files.pythonhosted.org/packages/23/2d/3c7ff8b2e0e634c1f58d095f071f52ed3c23ff25be524b0ccae8b71f99f8/coverage-7.13.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:3188936845cd0cb114fa6a51842a304cdbac2958145d03be2377ec41eb285d19", size = 252225, upload-time = "2025-12-08T13:13:55.274Z" }, + { url = "https://files.pythonhosted.org/packages/aa/ac/fb03b469d20e9c9a81093575003f959cf91a4a517b783aab090e4538764b/coverage-7.13.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a2bdb3babb74079f021696cb46b8bb5f5661165c385d3a238712b031a12355be", size = 253559, upload-time = "2025-12-08T13:13:57.161Z" }, + { url = "https://files.pythonhosted.org/packages/29/62/14afa9e792383c66cc0a3b872a06ded6e4ed1079c7d35de274f11d27064e/coverage-7.13.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7464663eaca6adba4175f6c19354feea61ebbdd735563a03d1e472c7072d27bb", size = 249724, upload-time = "2025-12-08T13:13:58.692Z" }, + { url = "https://files.pythonhosted.org/packages/31/b7/333f3dab2939070613696ab3ee91738950f0467778c6e5a5052e840646b7/coverage-7.13.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:8069e831f205d2ff1f3d355e82f511eb7c5522d7d413f5db5756b772ec8697f8", size = 251582, upload-time = "2025-12-08T13:14:00.642Z" }, + { url = "https://files.pythonhosted.org/packages/81/cb/69162bda9381f39b2287265d7e29ee770f7c27c19f470164350a38318764/coverage-7.13.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:6fb2d5d272341565f08e962cce14cdf843a08ac43bd621783527adb06b089c4b", size = 249538, upload-time = "2025-12-08T13:14:02.556Z" }, + { url = "https://files.pythonhosted.org/packages/e0/76/350387b56a30f4970abe32b90b2a434f87d29f8b7d4ae40d2e8a85aacfb3/coverage-7.13.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:5e70f92ef89bac1ac8a99b3324923b4749f008fdbd7aa9cb35e01d7a284a04f9", size = 249349, upload-time = "2025-12-08T13:14:04.015Z" }, + { url = "https://files.pythonhosted.org/packages/86/0d/7f6c42b8d59f4c7e43ea3059f573c0dcfed98ba46eb43c68c69e52ae095c/coverage-7.13.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4b5de7d4583e60d5fd246dd57fcd3a8aa23c6e118a8c72b38adf666ba8e7e927", size = 251011, upload-time = "2025-12-08T13:14:05.505Z" }, + { url = "https://files.pythonhosted.org/packages/d7/f1/4bb2dff379721bb0b5c649d5c5eaf438462cad824acf32eb1b7ca0c7078e/coverage-7.13.0-cp314-cp314-win32.whl", hash = "sha256:a6c6e16b663be828a8f0b6c5027d36471d4a9f90d28444aa4ced4d48d7d6ae8f", size = 221091, upload-time = "2025-12-08T13:14:07.127Z" }, + { url = "https://files.pythonhosted.org/packages/ba/44/c239da52f373ce379c194b0ee3bcc121020e397242b85f99e0afc8615066/coverage-7.13.0-cp314-cp314-win_amd64.whl", hash = "sha256:0900872f2fdb3ee5646b557918d02279dc3af3dfb39029ac4e945458b13f73bc", size = 221904, upload-time = "2025-12-08T13:14:08.542Z" }, + { url = "https://files.pythonhosted.org/packages/89/1f/b9f04016d2a29c2e4a0307baefefad1a4ec5724946a2b3e482690486cade/coverage-7.13.0-cp314-cp314-win_arm64.whl", hash = "sha256:3a10260e6a152e5f03f26db4a407c4c62d3830b9af9b7c0450b183615f05d43b", size = 220480, upload-time = "2025-12-08T13:14:10.958Z" }, + { url = "https://files.pythonhosted.org/packages/16/d4/364a1439766c8e8647860584171c36010ca3226e6e45b1753b1b249c5161/coverage-7.13.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:9097818b6cc1cfb5f174e3263eba4a62a17683bcfe5c4b5d07f4c97fa51fbf28", size = 219074, upload-time = "2025-12-08T13:14:13.345Z" }, + { url = "https://files.pythonhosted.org/packages/ce/f4/71ba8be63351e099911051b2089662c03d5671437a0ec2171823c8e03bec/coverage-7.13.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0018f73dfb4301a89292c73be6ba5f58722ff79f51593352759c1790ded1cabe", size = 219342, upload-time = "2025-12-08T13:14:15.02Z" }, + { url = "https://files.pythonhosted.org/packages/5e/25/127d8ed03d7711a387d96f132589057213e3aef7475afdaa303412463f22/coverage-7.13.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:166ad2a22ee770f5656e1257703139d3533b4a0b6909af67c6b4a3adc1c98657", size = 260713, upload-time = "2025-12-08T13:14:16.907Z" }, + { url = "https://files.pythonhosted.org/packages/fd/db/559fbb6def07d25b2243663b46ba9eb5a3c6586c0c6f4e62980a68f0ee1c/coverage-7.13.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f6aaef16d65d1787280943f1c8718dc32e9cf141014e4634d64446702d26e0ff", size = 262825, upload-time = "2025-12-08T13:14:18.68Z" }, + { url = "https://files.pythonhosted.org/packages/37/99/6ee5bf7eff884766edb43bd8736b5e1c5144d0fe47498c3779326fe75a35/coverage-7.13.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e999e2dcc094002d6e2c7bbc1fb85b58ba4f465a760a8014d97619330cdbbbf3", size = 265233, upload-time = "2025-12-08T13:14:20.55Z" }, + { url = "https://files.pythonhosted.org/packages/d8/90/92f18fe0356ea69e1f98f688ed80cec39f44e9f09a1f26a1bbf017cc67f2/coverage-7.13.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:00c3d22cf6fb1cf3bf662aaaa4e563be8243a5ed2630339069799835a9cc7f9b", size = 259779, upload-time = "2025-12-08T13:14:22.367Z" }, + { url = "https://files.pythonhosted.org/packages/90/5d/b312a8b45b37a42ea7d27d7d3ff98ade3a6c892dd48d1d503e773503373f/coverage-7.13.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:22ccfe8d9bb0d6134892cbe1262493a8c70d736b9df930f3f3afae0fe3ac924d", size = 262700, upload-time = "2025-12-08T13:14:24.309Z" }, + { url = "https://files.pythonhosted.org/packages/63/f8/b1d0de5c39351eb71c366f872376d09386640840a2e09b0d03973d791e20/coverage-7.13.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:9372dff5ea15930fea0445eaf37bbbafbc771a49e70c0aeed8b4e2c2614cc00e", size = 260302, upload-time = "2025-12-08T13:14:26.068Z" }, + { url = "https://files.pythonhosted.org/packages/aa/7c/d42f4435bc40c55558b3109a39e2d456cddcec37434f62a1f1230991667a/coverage-7.13.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:69ac2c492918c2461bc6ace42d0479638e60719f2a4ef3f0815fa2df88e9f940", size = 259136, upload-time = "2025-12-08T13:14:27.604Z" }, + { url = "https://files.pythonhosted.org/packages/b8/d3/23413241dc04d47cfe19b9a65b32a2edd67ecd0b817400c2843ebc58c847/coverage-7.13.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:739c6c051a7540608d097b8e13c76cfa85263ced467168dc6b477bae3df7d0e2", size = 261467, upload-time = "2025-12-08T13:14:29.09Z" }, + { url = "https://files.pythonhosted.org/packages/13/e6/6e063174500eee216b96272c0d1847bf215926786f85c2bd024cf4d02d2f/coverage-7.13.0-cp314-cp314t-win32.whl", hash = "sha256:fe81055d8c6c9de76d60c94ddea73c290b416e061d40d542b24a5871bad498b7", size = 221875, upload-time = "2025-12-08T13:14:31.106Z" }, + { url = "https://files.pythonhosted.org/packages/3b/46/f4fb293e4cbe3620e3ac2a3e8fd566ed33affb5861a9b20e3dd6c1896cbc/coverage-7.13.0-cp314-cp314t-win_amd64.whl", hash = "sha256:445badb539005283825959ac9fa4a28f712c214b65af3a2c464f1adc90f5fcbc", size = 222982, upload-time = "2025-12-08T13:14:33.1Z" }, + { url = "https://files.pythonhosted.org/packages/68/62/5b3b9018215ed9733fbd1ae3b2ed75c5de62c3b55377a52cae732e1b7805/coverage-7.13.0-cp314-cp314t-win_arm64.whl", hash = "sha256:de7f6748b890708578fc4b7bb967d810aeb6fcc9bff4bb77dbca77dab2f9df6a", size = 221016, upload-time = "2025-12-08T13:14:34.601Z" }, + { url = "https://files.pythonhosted.org/packages/8d/4c/1968f32fb9a2604645827e11ff84a31e59d532e01995f904723b4f5328b3/coverage-7.13.0-py3-none-any.whl", hash = "sha256:850d2998f380b1e266459ca5b47bc9e7daf9af1d070f66317972f382d46f1904", size = 210068, upload-time = "2025-12-08T13:14:36.236Z" }, +] + +[[package]] +name = "cryptography" +version = "44.0.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/53/d6/1411ab4d6108ab167d06254c5be517681f1e331f90edf1379895bcb87020/cryptography-44.0.3.tar.gz", hash = "sha256:fe19d8bc5536a91a24a8133328880a41831b6c5df54599a8417b62fe015d3053", size = 711096, upload-time = "2025-05-02T19:36:04.667Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/08/53/c776d80e9d26441bb3868457909b4e74dd9ccabd182e10b2b0ae7a07e265/cryptography-44.0.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:962bc30480a08d133e631e8dfd4783ab71cc9e33d5d7c1e192f0b7c06397bb88", size = 6670281, upload-time = "2025-05-02T19:34:50.665Z" }, + { url = "https://files.pythonhosted.org/packages/6a/06/af2cf8d56ef87c77319e9086601bef621bedf40f6f59069e1b6d1ec498c5/cryptography-44.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ffc61e8f3bf5b60346d89cd3d37231019c17a081208dfbbd6e1605ba03fa137", size = 3959305, upload-time = "2025-05-02T19:34:53.042Z" }, + { url = "https://files.pythonhosted.org/packages/ae/01/80de3bec64627207d030f47bf3536889efee8913cd363e78ca9a09b13c8e/cryptography-44.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58968d331425a6f9eedcee087f77fd3c927c88f55368f43ff7e0a19891f2642c", size = 4171040, upload-time = "2025-05-02T19:34:54.675Z" }, + { url = "https://files.pythonhosted.org/packages/bd/48/bb16b7541d207a19d9ae8b541c70037a05e473ddc72ccb1386524d4f023c/cryptography-44.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:e28d62e59a4dbd1d22e747f57d4f00c459af22181f0b2f787ea83f5a876d7c76", size = 3963411, upload-time = "2025-05-02T19:34:56.61Z" }, + { url = "https://files.pythonhosted.org/packages/42/b2/7d31f2af5591d217d71d37d044ef5412945a8a8e98d5a2a8ae4fd9cd4489/cryptography-44.0.3-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:af653022a0c25ef2e3ffb2c673a50e5a0d02fecc41608f4954176f1933b12359", size = 3689263, upload-time = "2025-05-02T19:34:58.591Z" }, + { url = "https://files.pythonhosted.org/packages/25/50/c0dfb9d87ae88ccc01aad8eb93e23cfbcea6a6a106a9b63a7b14c1f93c75/cryptography-44.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:157f1f3b8d941c2bd8f3ffee0af9b049c9665c39d3da9db2dc338feca5e98a43", size = 4196198, upload-time = "2025-05-02T19:35:00.988Z" }, + { url = "https://files.pythonhosted.org/packages/66/c9/55c6b8794a74da652690c898cb43906310a3e4e4f6ee0b5f8b3b3e70c441/cryptography-44.0.3-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:c6cd67722619e4d55fdb42ead64ed8843d64638e9c07f4011163e46bc512cf01", size = 3966502, upload-time = "2025-05-02T19:35:03.091Z" }, + { url = "https://files.pythonhosted.org/packages/b6/f7/7cb5488c682ca59a02a32ec5f975074084db4c983f849d47b7b67cc8697a/cryptography-44.0.3-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:b424563394c369a804ecbee9b06dfb34997f19d00b3518e39f83a5642618397d", size = 4196173, upload-time = "2025-05-02T19:35:05.018Z" }, + { url = "https://files.pythonhosted.org/packages/d2/0b/2f789a8403ae089b0b121f8f54f4a3e5228df756e2146efdf4a09a3d5083/cryptography-44.0.3-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c91fc8e8fd78af553f98bc7f2a1d8db977334e4eea302a4bfd75b9461c2d8904", size = 4087713, upload-time = "2025-05-02T19:35:07.187Z" }, + { url = "https://files.pythonhosted.org/packages/1d/aa/330c13655f1af398fc154089295cf259252f0ba5df93b4bc9d9c7d7f843e/cryptography-44.0.3-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:25cd194c39fa5a0aa4169125ee27d1172097857b27109a45fadc59653ec06f44", size = 4299064, upload-time = "2025-05-02T19:35:08.879Z" }, + { url = "https://files.pythonhosted.org/packages/10/a8/8c540a421b44fd267a7d58a1fd5f072a552d72204a3f08194f98889de76d/cryptography-44.0.3-cp37-abi3-win32.whl", hash = "sha256:3be3f649d91cb182c3a6bd336de8b61a0a71965bd13d1a04a0e15b39c3d5809d", size = 2773887, upload-time = "2025-05-02T19:35:10.41Z" }, + { url = "https://files.pythonhosted.org/packages/b9/0d/c4b1657c39ead18d76bbd122da86bd95bdc4095413460d09544000a17d56/cryptography-44.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:3883076d5c4cc56dbef0b898a74eb6992fdac29a7b9013870b34efe4ddb39a0d", size = 3209737, upload-time = "2025-05-02T19:35:12.12Z" }, + { url = "https://files.pythonhosted.org/packages/34/a3/ad08e0bcc34ad436013458d7528e83ac29910943cea42ad7dd4141a27bbb/cryptography-44.0.3-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:5639c2b16764c6f76eedf722dbad9a0914960d3489c0cc38694ddf9464f1bb2f", size = 6673501, upload-time = "2025-05-02T19:35:13.775Z" }, + { url = "https://files.pythonhosted.org/packages/b1/f0/7491d44bba8d28b464a5bc8cc709f25a51e3eac54c0a4444cf2473a57c37/cryptography-44.0.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3ffef566ac88f75967d7abd852ed5f182da252d23fac11b4766da3957766759", size = 3960307, upload-time = "2025-05-02T19:35:15.917Z" }, + { url = "https://files.pythonhosted.org/packages/f7/c8/e5c5d0e1364d3346a5747cdcd7ecbb23ca87e6dea4f942a44e88be349f06/cryptography-44.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:192ed30fac1728f7587c6f4613c29c584abdc565d7417c13904708db10206645", size = 4170876, upload-time = "2025-05-02T19:35:18.138Z" }, + { url = "https://files.pythonhosted.org/packages/73/96/025cb26fc351d8c7d3a1c44e20cf9a01e9f7cf740353c9c7a17072e4b264/cryptography-44.0.3-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:7d5fe7195c27c32a64955740b949070f21cba664604291c298518d2e255931d2", size = 3964127, upload-time = "2025-05-02T19:35:19.864Z" }, + { url = "https://files.pythonhosted.org/packages/01/44/eb6522db7d9f84e8833ba3bf63313f8e257729cf3a8917379473fcfd6601/cryptography-44.0.3-cp39-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3f07943aa4d7dad689e3bb1638ddc4944cc5e0921e3c227486daae0e31a05e54", size = 3689164, upload-time = "2025-05-02T19:35:21.449Z" }, + { url = "https://files.pythonhosted.org/packages/68/fb/d61a4defd0d6cee20b1b8a1ea8f5e25007e26aeb413ca53835f0cae2bcd1/cryptography-44.0.3-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:cb90f60e03d563ca2445099edf605c16ed1d5b15182d21831f58460c48bffb93", size = 4198081, upload-time = "2025-05-02T19:35:23.187Z" }, + { url = "https://files.pythonhosted.org/packages/1b/50/457f6911d36432a8811c3ab8bd5a6090e8d18ce655c22820994913dd06ea/cryptography-44.0.3-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:ab0b005721cc0039e885ac3503825661bd9810b15d4f374e473f8c89b7d5460c", size = 3967716, upload-time = "2025-05-02T19:35:25.426Z" }, + { url = "https://files.pythonhosted.org/packages/35/6e/dca39d553075980ccb631955c47b93d87d27f3596da8d48b1ae81463d915/cryptography-44.0.3-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:3bb0847e6363c037df8f6ede57d88eaf3410ca2267fb12275370a76f85786a6f", size = 4197398, upload-time = "2025-05-02T19:35:27.678Z" }, + { url = "https://files.pythonhosted.org/packages/9b/9d/d1f2fe681eabc682067c66a74addd46c887ebacf39038ba01f8860338d3d/cryptography-44.0.3-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:b0cc66c74c797e1db750aaa842ad5b8b78e14805a9b5d1348dc603612d3e3ff5", size = 4087900, upload-time = "2025-05-02T19:35:29.312Z" }, + { url = "https://files.pythonhosted.org/packages/c4/f5/3599e48c5464580b73b236aafb20973b953cd2e7b44c7c2533de1d888446/cryptography-44.0.3-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6866df152b581f9429020320e5eb9794c8780e90f7ccb021940d7f50ee00ae0b", size = 4301067, upload-time = "2025-05-02T19:35:31.547Z" }, + { url = "https://files.pythonhosted.org/packages/a7/6c/d2c48c8137eb39d0c193274db5c04a75dab20d2f7c3f81a7dcc3a8897701/cryptography-44.0.3-cp39-abi3-win32.whl", hash = "sha256:c138abae3a12a94c75c10499f1cbae81294a6f983b3af066390adee73f433028", size = 2775467, upload-time = "2025-05-02T19:35:33.805Z" }, + { url = "https://files.pythonhosted.org/packages/c9/ad/51f212198681ea7b0deaaf8846ee10af99fba4e894f67b353524eab2bbe5/cryptography-44.0.3-cp39-abi3-win_amd64.whl", hash = "sha256:5d186f32e52e66994dce4f766884bcb9c68b8da62d61d9d215bfe5fb56d21334", size = 3210375, upload-time = "2025-05-02T19:35:35.369Z" }, +] + +[[package]] +name = "cyclopts" +version = "3.24.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "docstring-parser", marker = "python_full_version < '4'" }, + { name = "rich" }, + { name = "rich-rst" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/30/ca/7782da3b03242d5f0a16c20371dff99d4bd1fedafe26bc48ff82e42be8c9/cyclopts-3.24.0.tar.gz", hash = "sha256:de6964a041dfb3c57bf043b41e68c43548227a17de1bad246e3a0bfc5c4b7417", size = 76131, upload-time = "2025-09-08T15:40:57.75Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f0/8b/2c95f0645c6f40211896375e6fa51f504b8ccb29c21f6ae661fe87ab044e/cyclopts-3.24.0-py3-none-any.whl", hash = "sha256:809d04cde9108617106091140c3964ee6fceb33cecdd537f7ffa360bde13ed71", size = 86154, upload-time = "2025-09-08T15:40:56.41Z" }, +] + +[[package]] +name = "dnspython" +version = "2.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8c/8b/57666417c0f90f08bcafa776861060426765fdb422eb10212086fb811d26/dnspython-2.8.0.tar.gz", hash = "sha256:181d3c6996452cb1189c4046c61599b84a5a86e099562ffde77d26984ff26d0f", size = 368251, upload-time = "2025-09-07T18:58:00.022Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", size = 331094, upload-time = "2025-09-07T18:57:58.071Z" }, +] + +[[package]] +name = "docstring-parser" +version = "0.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/9d/c3b43da9515bd270df0f80548d9944e389870713cc1fe2b8fb35fe2bcefd/docstring_parser-0.17.0.tar.gz", hash = "sha256:583de4a309722b3315439bb31d64ba3eebada841f2e2cee23b99df001434c912", size = 27442, upload-time = "2025-07-21T07:35:01.868Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/55/e2/2537ebcff11c1ee1ff17d8d0b6f4db75873e3b0fb32c2d4a2ee31ecb310a/docstring_parser-0.17.0-py3-none-any.whl", hash = "sha256:cf2569abd23dce8099b300f9b4fa8191e9582dda731fd533daf54c4551658708", size = 36896, upload-time = "2025-07-21T07:35:00.684Z" }, +] + +[[package]] +name = "docutils" +version = "0.22.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e4/47/d869000fb74438584858acc628a364b277fc012695f0dfd513cb10f99768/docutils-0.22.1.tar.gz", hash = "sha256:d2fb50923a313532b6d41a77776d24cb459a594be9b7e4afa1fbcb5bda1893e6", size = 2291655, upload-time = "2025-09-17T17:58:45.409Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8c/dc/1948b90c5d9dbfa4d1fd3991013a042ba3ac62ebd3afdcb3fac08366e755/docutils-0.22.1-py3-none-any.whl", hash = "sha256:806e896f256a17466426544038f30cb860a99f5d4af640e36c284bfcb1824512", size = 638455, upload-time = "2025-09-17T17:58:42.498Z" }, +] + +[[package]] +name = "email-validator" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "dnspython" }, + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f5/22/900cb125c76b7aaa450ce02fd727f452243f2e91a61af068b40adba60ea9/email_validator-2.3.0.tar.gz", hash = "sha256:9fc05c37f2f6cf439ff414f8fc46d917929974a82244c20eb10231ba60c54426", size = 51238, upload-time = "2025-08-26T13:09:06.831Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl", hash = "sha256:80f13f623413e6b197ae73bb10bf4eb0908faf509ad8362c5edeb0be7fd450b4", size = 35604, upload-time = "2025-08-26T13:09:05.858Z" }, +] + +[[package]] +name = "exceptiongroup" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0b/9f/a65090624ecf468cdca03533906e7c69ed7588582240cfe7cc9e770b50eb/exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88", size = 29749, upload-time = "2025-05-10T17:42:51.123Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/36/f4/c6e662dade71f56cd2f3735141b265c3c79293c109549c1e6933b0651ffc/exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10", size = 16674, upload-time = "2025-05-10T17:42:49.33Z" }, +] + +[[package]] +name = "fastmcp" +version = "2.12.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "authlib" }, + { name = "cyclopts" }, + { name = "exceptiongroup" }, + { name = "httpx" }, + { name = "mcp" }, + { name = "openapi-core" }, + { name = "openapi-pydantic" }, + { name = "pydantic", extra = ["email"] }, + { name = "pyperclip" }, + { name = "python-dotenv" }, + { name = "rich" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/35/8a/c46759bb41a53187191e5b3d963c0bde54783ecc89186a93c4947607b8e4/fastmcp-2.12.2.tar.gz", hash = "sha256:6d13e2f9be57b99763fc22485f9f603daa23bfbca35a8172baa43b283d6fc1ff", size = 5244547, upload-time = "2025-09-03T21:28:09.869Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5c/0a/7a8d564b1b9909dbfc36eb93d76410a4acfada6b1e13ee451a753bb6dbc2/fastmcp-2.12.2-py3-none-any.whl", hash = "sha256:0b58d68e819c82078d1fd51989d3d81f2be7382d527308b06df55f4d0a4ec94f", size = 312029, upload-time = "2025-09-03T21:28:08.62Z" }, +] + +[[package]] +name = "h11" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, +] + +[[package]] +name = "httpcore" +version = "1.0.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, +] + +[[package]] +name = "httpx" +version = "0.28.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "certifi" }, + { name = "httpcore" }, + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, +] + +[[package]] +name = "httpx-sse" +version = "0.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6e/fa/66bd985dd0b7c109a3bcb89272ee0bfb7e2b4d06309ad7b38ff866734b2a/httpx_sse-0.4.1.tar.gz", hash = "sha256:8f44d34414bc7b21bf3602713005c5df4917884f76072479b21f68befa4ea26e", size = 12998, upload-time = "2025-06-24T13:21:05.71Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/25/0a/6269e3473b09aed2dab8aa1a600c70f31f00ae1349bee30658f7e358a159/httpx_sse-0.4.1-py3-none-any.whl", hash = "sha256:cba42174344c3a5b06f255ce65b350880f962d99ead85e776f23c6618a377a37", size = 8054, upload-time = "2025-06-24T13:21:04.772Z" }, +] + +[[package]] +name = "idna" +version = "3.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, +] + +[[package]] +name = "iniconfig" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793, upload-time = "2025-03-19T20:09:59.721Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050, upload-time = "2025-03-19T20:10:01.071Z" }, +] + +[[package]] +name = "isodate" +version = "0.7.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/54/4d/e940025e2ce31a8ce1202635910747e5a87cc3a6a6bb2d00973375014749/isodate-0.7.2.tar.gz", hash = "sha256:4cd1aa0f43ca76f4a6c6c0292a85f40b35ec2e43e315b59f06e6d32171a953e6", size = 29705, upload-time = "2024-10-08T23:04:11.5Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/15/aa/0aca39a37d3c7eb941ba736ede56d689e7be91cab5d9ca846bde3999eba6/isodate-0.7.2-py3-none-any.whl", hash = "sha256:28009937d8031054830160fce6d409ed342816b543597cece116d966c6d99e15", size = 22320, upload-time = "2024-10-08T23:04:09.501Z" }, +] + +[[package]] +name = "jsonschema" +version = "4.25.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "jsonschema-specifications" }, + { name = "referencing" }, + { name = "rpds-py" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/74/69/f7185de793a29082a9f3c7728268ffb31cb5095131a9c139a74078e27336/jsonschema-4.25.1.tar.gz", hash = "sha256:e4a9655ce0da0c0b67a085847e00a3a51449e1157f4f75e9fb5aa545e122eb85", size = 357342, upload-time = "2025-08-18T17:03:50.038Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bf/9c/8c95d856233c1f82500c2450b8c68576b4cf1c871db3afac5c34ff84e6fd/jsonschema-4.25.1-py3-none-any.whl", hash = "sha256:3fba0169e345c7175110351d456342c364814cfcf3b964ba4587f22915230a63", size = 90040, upload-time = "2025-08-18T17:03:48.373Z" }, +] + +[[package]] +name = "jsonschema-path" +version = "0.3.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pathable" }, + { name = "pyyaml" }, + { name = "referencing" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6e/45/41ebc679c2a4fced6a722f624c18d658dee42612b83ea24c1caf7c0eb3a8/jsonschema_path-0.3.4.tar.gz", hash = "sha256:8365356039f16cc65fddffafda5f58766e34bebab7d6d105616ab52bc4297001", size = 11159, upload-time = "2025-01-24T14:33:16.547Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/58/3485da8cb93d2f393bce453adeef16896751f14ba3e2024bc21dc9597646/jsonschema_path-0.3.4-py3-none-any.whl", hash = "sha256:f502191fdc2b22050f9a81c9237be9d27145b9001c55842bece5e94e382e52f8", size = 14810, upload-time = "2025-01-24T14:33:14.652Z" }, +] + +[[package]] +name = "jsonschema-specifications" +version = "2025.9.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "referencing" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/19/74/a633ee74eb36c44aa6d1095e7cc5569bebf04342ee146178e2d36600708b/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d", size = 32855, upload-time = "2025-09-08T01:34:59.186Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437, upload-time = "2025-09-08T01:34:57.871Z" }, +] + +[[package]] +name = "lazy-object-proxy" +version = "1.12.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/08/a2/69df9c6ba6d316cfd81fe2381e464db3e6de5db45f8c43c6a23504abf8cb/lazy_object_proxy-1.12.0.tar.gz", hash = "sha256:1f5a462d92fd0cfb82f1fab28b51bfb209fabbe6aabf7f0d51472c0c124c0c61", size = 43681, upload-time = "2025-08-22T13:50:06.783Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/26/b74c791008841f8ad896c7f293415136c66cc27e7c7577de4ee68040c110/lazy_object_proxy-1.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:86fd61cb2ba249b9f436d789d1356deae69ad3231dc3c0f17293ac535162672e", size = 26745, upload-time = "2025-08-22T13:42:44.982Z" }, + { url = "https://files.pythonhosted.org/packages/9b/52/641870d309e5d1fb1ea7d462a818ca727e43bfa431d8c34b173eb090348c/lazy_object_proxy-1.12.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:81d1852fb30fab81696f93db1b1e55a5d1ff7940838191062f5f56987d5fcc3e", size = 71537, upload-time = "2025-08-22T13:42:46.141Z" }, + { url = "https://files.pythonhosted.org/packages/47/b6/919118e99d51c5e76e8bf5a27df406884921c0acf2c7b8a3b38d847ab3e9/lazy_object_proxy-1.12.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:be9045646d83f6c2664c1330904b245ae2371b5c57a3195e4028aedc9f999655", size = 71141, upload-time = "2025-08-22T13:42:47.375Z" }, + { url = "https://files.pythonhosted.org/packages/e5/47/1d20e626567b41de085cf4d4fb3661a56c159feaa73c825917b3b4d4f806/lazy_object_proxy-1.12.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:67f07ab742f1adfb3966c40f630baaa7902be4222a17941f3d85fd1dae5565ff", size = 69449, upload-time = "2025-08-22T13:42:48.49Z" }, + { url = "https://files.pythonhosted.org/packages/58/8d/25c20ff1a1a8426d9af2d0b6f29f6388005fc8cd10d6ee71f48bff86fdd0/lazy_object_proxy-1.12.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:75ba769017b944fcacbf6a80c18b2761a1795b03f8899acdad1f1c39db4409be", size = 70744, upload-time = "2025-08-22T13:42:49.608Z" }, + { url = "https://files.pythonhosted.org/packages/c0/67/8ec9abe15c4f8a4bcc6e65160a2c667240d025cbb6591b879bea55625263/lazy_object_proxy-1.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:7b22c2bbfb155706b928ac4d74c1a63ac8552a55ba7fff4445155523ea4067e1", size = 26568, upload-time = "2025-08-22T13:42:57.719Z" }, + { url = "https://files.pythonhosted.org/packages/23/12/cd2235463f3469fd6c62d41d92b7f120e8134f76e52421413a0ad16d493e/lazy_object_proxy-1.12.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4a79b909aa16bde8ae606f06e6bbc9d3219d2e57fb3e0076e17879072b742c65", size = 27391, upload-time = "2025-08-22T13:42:50.62Z" }, + { url = "https://files.pythonhosted.org/packages/60/9e/f1c53e39bbebad2e8609c67d0830cc275f694d0ea23d78e8f6db526c12d3/lazy_object_proxy-1.12.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:338ab2f132276203e404951205fe80c3fd59429b3a724e7b662b2eb539bb1be9", size = 80552, upload-time = "2025-08-22T13:42:51.731Z" }, + { url = "https://files.pythonhosted.org/packages/4c/b6/6c513693448dcb317d9d8c91d91f47addc09553613379e504435b4cc8b3e/lazy_object_proxy-1.12.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8c40b3c9faee2e32bfce0df4ae63f4e73529766893258eca78548bac801c8f66", size = 82857, upload-time = "2025-08-22T13:42:53.225Z" }, + { url = "https://files.pythonhosted.org/packages/12/1c/d9c4aaa4c75da11eb7c22c43d7c90a53b4fca0e27784a5ab207768debea7/lazy_object_proxy-1.12.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:717484c309df78cedf48396e420fa57fc8a2b1f06ea889df7248fdd156e58847", size = 80833, upload-time = "2025-08-22T13:42:54.391Z" }, + { url = "https://files.pythonhosted.org/packages/0b/ae/29117275aac7d7d78ae4f5a4787f36ff33262499d486ac0bf3e0b97889f6/lazy_object_proxy-1.12.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a6b7ea5ea1ffe15059eb44bcbcb258f97bcb40e139b88152c40d07b1a1dfc9ac", size = 79516, upload-time = "2025-08-22T13:42:55.812Z" }, + { url = "https://files.pythonhosted.org/packages/19/40/b4e48b2c38c69392ae702ae7afa7b6551e0ca5d38263198b7c79de8b3bdf/lazy_object_proxy-1.12.0-cp313-cp313t-win_amd64.whl", hash = "sha256:08c465fb5cd23527512f9bd7b4c7ba6cec33e28aad36fbbe46bf7b858f9f3f7f", size = 27656, upload-time = "2025-08-22T13:42:56.793Z" }, + { url = "https://files.pythonhosted.org/packages/ef/3a/277857b51ae419a1574557c0b12e0d06bf327b758ba94cafc664cb1e2f66/lazy_object_proxy-1.12.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c9defba70ab943f1df98a656247966d7729da2fe9c2d5d85346464bf320820a3", size = 26582, upload-time = "2025-08-22T13:49:49.366Z" }, + { url = "https://files.pythonhosted.org/packages/1a/b6/c5e0fa43535bb9c87880e0ba037cdb1c50e01850b0831e80eb4f4762f270/lazy_object_proxy-1.12.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6763941dbf97eea6b90f5b06eb4da9418cc088fce0e3883f5816090f9afcde4a", size = 71059, upload-time = "2025-08-22T13:49:50.488Z" }, + { url = "https://files.pythonhosted.org/packages/06/8a/7dcad19c685963c652624702f1a968ff10220b16bfcc442257038216bf55/lazy_object_proxy-1.12.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fdc70d81235fc586b9e3d1aeef7d1553259b62ecaae9db2167a5d2550dcc391a", size = 71034, upload-time = "2025-08-22T13:49:54.224Z" }, + { url = "https://files.pythonhosted.org/packages/12/ac/34cbfb433a10e28c7fd830f91c5a348462ba748413cbb950c7f259e67aa7/lazy_object_proxy-1.12.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:0a83c6f7a6b2bfc11ef3ed67f8cbe99f8ff500b05655d8e7df9aab993a6abc95", size = 69529, upload-time = "2025-08-22T13:49:55.29Z" }, + { url = "https://files.pythonhosted.org/packages/6f/6a/11ad7e349307c3ca4c0175db7a77d60ce42a41c60bcb11800aabd6a8acb8/lazy_object_proxy-1.12.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:256262384ebd2a77b023ad02fbcc9326282bcfd16484d5531154b02bc304f4c5", size = 70391, upload-time = "2025-08-22T13:49:56.35Z" }, + { url = "https://files.pythonhosted.org/packages/59/97/9b410ed8fbc6e79c1ee8b13f8777a80137d4bc189caf2c6202358e66192c/lazy_object_proxy-1.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:7601ec171c7e8584f8ff3f4e440aa2eebf93e854f04639263875b8c2971f819f", size = 26988, upload-time = "2025-08-22T13:49:57.302Z" }, +] + +[[package]] +name = "markdown-it-py" +version = "4.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mdurl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" }, +] + +[[package]] +name = "markupsafe" +version = "3.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537, upload-time = "2024-10-18T15:21:54.129Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274, upload-time = "2024-10-18T15:21:24.577Z" }, + { url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352, upload-time = "2024-10-18T15:21:25.382Z" }, + { url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122, upload-time = "2024-10-18T15:21:26.199Z" }, + { url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085, upload-time = "2024-10-18T15:21:27.029Z" }, + { url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978, upload-time = "2024-10-18T15:21:27.846Z" }, + { url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208, upload-time = "2024-10-18T15:21:28.744Z" }, + { url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357, upload-time = "2024-10-18T15:21:29.545Z" }, + { url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344, upload-time = "2024-10-18T15:21:30.366Z" }, + { url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101, upload-time = "2024-10-18T15:21:31.207Z" }, + { url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603, upload-time = "2024-10-18T15:21:32.032Z" }, + { url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510, upload-time = "2024-10-18T15:21:33.625Z" }, + { url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486, upload-time = "2024-10-18T15:21:34.611Z" }, + { url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480, upload-time = "2024-10-18T15:21:35.398Z" }, + { url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914, upload-time = "2024-10-18T15:21:36.231Z" }, + { url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796, upload-time = "2024-10-18T15:21:37.073Z" }, + { url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473, upload-time = "2024-10-18T15:21:37.932Z" }, + { url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114, upload-time = "2024-10-18T15:21:39.799Z" }, + { url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098, upload-time = "2024-10-18T15:21:40.813Z" }, + { url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208, upload-time = "2024-10-18T15:21:41.814Z" }, + { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739, upload-time = "2024-10-18T15:21:42.784Z" }, +] + +[[package]] +name = "mcp" +version = "1.14.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "httpx" }, + { name = "httpx-sse" }, + { name = "jsonschema" }, + { name = "pydantic" }, + { name = "pydantic-settings" }, + { name = "python-multipart" }, + { name = "pywin32", marker = "sys_platform == 'win32'" }, + { name = "sse-starlette" }, + { name = "starlette" }, + { name = "uvicorn", marker = "sys_platform != 'emscripten'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/48/e9/242096400d702924b49f8d202c6ded7efb8841cacba826b5d2e6183aef7b/mcp-1.14.1.tar.gz", hash = "sha256:31c4406182ba15e8f30a513042719c3f0a38c615e76188ee5a736aaa89e20134", size = 454944, upload-time = "2025-09-18T13:37:19.971Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8e/11/d334fbb7c2aeddd2e762b86d7a619acffae012643a5738e698f975a2a9e2/mcp-1.14.1-py3-none-any.whl", hash = "sha256:3b7a479e8e5cbf5361bdc1da8bc6d500d795dc3aff44b44077a363a7f7e945a4", size = 163809, upload-time = "2025-09-18T13:37:18.165Z" }, +] + +[[package]] +name = "mdurl" +version = "0.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, +] + +[[package]] +name = "more-itertools" +version = "10.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ea/5d/38b681d3fce7a266dd9ab73c66959406d565b3e85f21d5e66e1181d93721/more_itertools-10.8.0.tar.gz", hash = "sha256:f638ddf8a1a0d134181275fb5d58b086ead7c6a72429ad725c67503f13ba30bd", size = 137431, upload-time = "2025-09-02T15:23:11.018Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a4/8e/469e5a4a2f5855992e425f3cb33804cc07bf18d48f2db061aec61ce50270/more_itertools-10.8.0-py3-none-any.whl", hash = "sha256:52d4362373dcf7c52546bc4af9a86ee7c4579df9a8dc268be0a2f949d376cc9b", size = 69667, upload-time = "2025-09-02T15:23:09.635Z" }, +] + +[[package]] +name = "oci" +version = "2.160.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "circuitbreaker" }, + { name = "cryptography" }, + { name = "pyopenssl" }, + { name = "python-dateutil" }, + { name = "pytz" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f3/7b/c9d7fc28f11c25c7875db3584eab5d52ccb2d7df553d07ac47f19a14d075/oci-2.160.0.tar.gz", hash = "sha256:f8e3410204c1405b40247179550cf74f5145a8e17025c4f2a92f2b9ffdc7d26b", size = 15601606, upload-time = "2025-09-09T04:17:43.728Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/51/752375a4e0d2de371c2788414157eda337417010d2ef7383cd7140388f1e/oci-2.160.0-py3-none-any.whl", hash = "sha256:3dba1ec671ebea23f255fabf836cb0fd08aea0913a8df85610fccaa5a4344ee9", size = 31715365, upload-time = "2025-09-09T04:17:34.998Z" }, +] + +[[package]] +name = "openapi-core" +version = "0.19.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "isodate" }, + { name = "jsonschema" }, + { name = "jsonschema-path" }, + { name = "more-itertools" }, + { name = "openapi-schema-validator" }, + { name = "openapi-spec-validator" }, + { name = "parse" }, + { name = "typing-extensions" }, + { name = "werkzeug" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/35/1acaa5f2fcc6e54eded34a2ec74b479439c4e469fc4e8d0e803fda0234db/openapi_core-0.19.5.tar.gz", hash = "sha256:421e753da56c391704454e66afe4803a290108590ac8fa6f4a4487f4ec11f2d3", size = 103264, upload-time = "2025-03-20T20:17:28.193Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/27/6f/83ead0e2e30a90445ee4fc0135f43741aebc30cca5b43f20968b603e30b6/openapi_core-0.19.5-py3-none-any.whl", hash = "sha256:ef7210e83a59394f46ce282639d8d26ad6fc8094aa904c9c16eb1bac8908911f", size = 106595, upload-time = "2025-03-20T20:17:26.77Z" }, +] + +[[package]] +name = "openapi-pydantic" +version = "0.5.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pydantic" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/02/2e/58d83848dd1a79cb92ed8e63f6ba901ca282c5f09d04af9423ec26c56fd7/openapi_pydantic-0.5.1.tar.gz", hash = "sha256:ff6835af6bde7a459fb93eb93bb92b8749b754fc6e51b2f1590a19dc3005ee0d", size = 60892, upload-time = "2025-01-08T19:29:27.083Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/cf/03675d8bd8ecbf4445504d8071adab19f5f993676795708e36402ab38263/openapi_pydantic-0.5.1-py3-none-any.whl", hash = "sha256:a3a09ef4586f5bd760a8df7f43028b60cafb6d9f61de2acba9574766255ab146", size = 96381, upload-time = "2025-01-08T19:29:25.275Z" }, +] + +[[package]] +name = "openapi-schema-validator" +version = "0.6.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jsonschema" }, + { name = "jsonschema-specifications" }, + { name = "rfc3339-validator" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8b/f3/5507ad3325169347cd8ced61c232ff3df70e2b250c49f0fe140edb4973c6/openapi_schema_validator-0.6.3.tar.gz", hash = "sha256:f37bace4fc2a5d96692f4f8b31dc0f8d7400fd04f3a937798eaf880d425de6ee", size = 11550, upload-time = "2025-01-10T18:08:22.268Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/21/c6/ad0fba32775ae749016829dace42ed80f4407b171da41313d1a3a5f102e4/openapi_schema_validator-0.6.3-py3-none-any.whl", hash = "sha256:f3b9870f4e556b5a62a1c39da72a6b4b16f3ad9c73dc80084b1b11e74ba148a3", size = 8755, upload-time = "2025-01-10T18:08:19.758Z" }, +] + +[[package]] +name = "openapi-spec-validator" +version = "0.7.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jsonschema" }, + { name = "jsonschema-path" }, + { name = "lazy-object-proxy" }, + { name = "openapi-schema-validator" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/82/af/fe2d7618d6eae6fb3a82766a44ed87cd8d6d82b4564ed1c7cfb0f6378e91/openapi_spec_validator-0.7.2.tar.gz", hash = "sha256:cc029309b5c5dbc7859df0372d55e9d1ff43e96d678b9ba087f7c56fc586f734", size = 36855, upload-time = "2025-06-07T14:48:56.299Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/27/dd/b3fd642260cb17532f66cc1e8250f3507d1e580483e209dc1e9d13bd980d/openapi_spec_validator-0.7.2-py3-none-any.whl", hash = "sha256:4bbdc0894ec85f1d1bea1d6d9c8b2c3c8d7ccaa13577ef40da9c006c9fd0eb60", size = 39713, upload-time = "2025-06-07T14:48:54.077Z" }, +] + +[[package]] +name = "oracle-oci-db-dynamic-mcp-server" +version = "1.0.1" +source = { editable = "." } +dependencies = [ + { name = "fastmcp" }, + { name = "mcp" }, + { name = "oci" }, + { name = "requests" }, +] + +[package.dev-dependencies] +dev = [ + { name = "pytest" }, + { name = "pytest-asyncio" }, + { name = "pytest-cov" }, +] + +[package.metadata] +requires-dist = [ + { name = "fastmcp", specifier = "==2.12.2" }, + { name = "mcp", specifier = ">=1.0.0" }, + { name = "oci", specifier = "==2.160.0" }, + { name = "requests" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "pytest", specifier = ">=8.4.2" }, + { name = "pytest-asyncio", specifier = ">=1.2.0" }, + { name = "pytest-cov", specifier = ">=7.0.0" }, +] + +[[package]] +name = "packaging" +version = "25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, +] + +[[package]] +name = "parse" +version = "1.20.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4f/78/d9b09ba24bb36ef8b83b71be547e118d46214735b6dfb39e4bfde0e9b9dd/parse-1.20.2.tar.gz", hash = "sha256:b41d604d16503c79d81af5165155c0b20f6c8d6c559efa66b4b695c3e5a0a0ce", size = 29391, upload-time = "2024-06-11T04:41:57.34Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d0/31/ba45bf0b2aa7898d81cbbfac0e88c267befb59ad91a19e36e1bc5578ddb1/parse-1.20.2-py2.py3-none-any.whl", hash = "sha256:967095588cb802add9177d0c0b6133b5ba33b1ea9007ca800e526f42a85af558", size = 20126, upload-time = "2024-06-11T04:41:55.057Z" }, +] + +[[package]] +name = "pathable" +version = "0.4.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/67/93/8f2c2075b180c12c1e9f6a09d1a985bc2036906b13dff1d8917e395f2048/pathable-0.4.4.tar.gz", hash = "sha256:6905a3cd17804edfac7875b5f6c9142a218c7caef78693c2dbbbfbac186d88b2", size = 8124, upload-time = "2025-01-10T18:43:13.247Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7d/eb/b6260b31b1a96386c0a880edebe26f89669098acea8e0318bff6adb378fd/pathable-0.4.4-py3-none-any.whl", hash = "sha256:5ae9e94793b6ef5a4cbe0a7ce9dbbefc1eec38df253763fd0aeeacf2762dbbc2", size = 9592, upload-time = "2025-01-10T18:43:11.88Z" }, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + +[[package]] +name = "pycparser" +version = "2.23" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/cf/d2d3b9f5699fb1e4615c8e32ff220203e43b248e1dfcc6736ad9057731ca/pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2", size = 173734, upload-time = "2025-09-09T13:23:47.91Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140, upload-time = "2025-09-09T13:23:46.651Z" }, +] + +[[package]] +name = "pydantic" +version = "2.11.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-types" }, + { name = "pydantic-core" }, + { name = "typing-extensions" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ff/5d/09a551ba512d7ca404d785072700d3f6727a02f6f3c24ecfd081c7cf0aa8/pydantic-2.11.9.tar.gz", hash = "sha256:6b8ffda597a14812a7975c90b82a8a2e777d9257aba3453f973acd3c032a18e2", size = 788495, upload-time = "2025-09-13T11:26:39.325Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3e/d3/108f2006987c58e76691d5ae5d200dd3e0f532cb4e5fa3560751c3a1feba/pydantic-2.11.9-py3-none-any.whl", hash = "sha256:c42dd626f5cfc1c6950ce6205ea58c93efa406da65f479dcb4029d5934857da2", size = 444855, upload-time = "2025-09-13T11:26:36.909Z" }, +] + +[package.optional-dependencies] +email = [ + { name = "email-validator" }, +] + +[[package]] +name = "pydantic-core" +version = "2.33.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ad/88/5f2260bdfae97aabf98f1778d43f69574390ad787afb646292a638c923d4/pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc", size = 435195, upload-time = "2025-04-23T18:33:52.104Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/46/8c/99040727b41f56616573a28771b1bfa08a3d3fe74d3d513f01251f79f172/pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f", size = 2015688, upload-time = "2025-04-23T18:31:53.175Z" }, + { url = "https://files.pythonhosted.org/packages/3a/cc/5999d1eb705a6cefc31f0b4a90e9f7fc400539b1a1030529700cc1b51838/pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6", size = 1844808, upload-time = "2025-04-23T18:31:54.79Z" }, + { url = "https://files.pythonhosted.org/packages/6f/5e/a0a7b8885c98889a18b6e376f344da1ef323d270b44edf8174d6bce4d622/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef", size = 1885580, upload-time = "2025-04-23T18:31:57.393Z" }, + { url = "https://files.pythonhosted.org/packages/3b/2a/953581f343c7d11a304581156618c3f592435523dd9d79865903272c256a/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a", size = 1973859, upload-time = "2025-04-23T18:31:59.065Z" }, + { url = "https://files.pythonhosted.org/packages/e6/55/f1a813904771c03a3f97f676c62cca0c0a4138654107c1b61f19c644868b/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916", size = 2120810, upload-time = "2025-04-23T18:32:00.78Z" }, + { url = "https://files.pythonhosted.org/packages/aa/c3/053389835a996e18853ba107a63caae0b9deb4a276c6b472931ea9ae6e48/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a", size = 2676498, upload-time = "2025-04-23T18:32:02.418Z" }, + { url = "https://files.pythonhosted.org/packages/eb/3c/f4abd740877a35abade05e437245b192f9d0ffb48bbbbd708df33d3cda37/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d", size = 2000611, upload-time = "2025-04-23T18:32:04.152Z" }, + { url = "https://files.pythonhosted.org/packages/59/a7/63ef2fed1837d1121a894d0ce88439fe3e3b3e48c7543b2a4479eb99c2bd/pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56", size = 2107924, upload-time = "2025-04-23T18:32:06.129Z" }, + { url = "https://files.pythonhosted.org/packages/04/8f/2551964ef045669801675f1cfc3b0d74147f4901c3ffa42be2ddb1f0efc4/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5", size = 2063196, upload-time = "2025-04-23T18:32:08.178Z" }, + { url = "https://files.pythonhosted.org/packages/26/bd/d9602777e77fc6dbb0c7db9ad356e9a985825547dce5ad1d30ee04903918/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e", size = 2236389, upload-time = "2025-04-23T18:32:10.242Z" }, + { url = "https://files.pythonhosted.org/packages/42/db/0e950daa7e2230423ab342ae918a794964b053bec24ba8af013fc7c94846/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162", size = 2239223, upload-time = "2025-04-23T18:32:12.382Z" }, + { url = "https://files.pythonhosted.org/packages/58/4d/4f937099c545a8a17eb52cb67fe0447fd9a373b348ccfa9a87f141eeb00f/pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849", size = 1900473, upload-time = "2025-04-23T18:32:14.034Z" }, + { url = "https://files.pythonhosted.org/packages/a0/75/4a0a9bac998d78d889def5e4ef2b065acba8cae8c93696906c3a91f310ca/pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9", size = 1955269, upload-time = "2025-04-23T18:32:15.783Z" }, + { url = "https://files.pythonhosted.org/packages/f9/86/1beda0576969592f1497b4ce8e7bc8cbdf614c352426271b1b10d5f0aa64/pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9", size = 1893921, upload-time = "2025-04-23T18:32:18.473Z" }, + { url = "https://files.pythonhosted.org/packages/a4/7d/e09391c2eebeab681df2b74bfe6c43422fffede8dc74187b2b0bf6fd7571/pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac", size = 1806162, upload-time = "2025-04-23T18:32:20.188Z" }, + { url = "https://files.pythonhosted.org/packages/f1/3d/847b6b1fed9f8ed3bb95a9ad04fbd0b212e832d4f0f50ff4d9ee5a9f15cf/pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5", size = 1981560, upload-time = "2025-04-23T18:32:22.354Z" }, + { url = "https://files.pythonhosted.org/packages/6f/9a/e73262f6c6656262b5fdd723ad90f518f579b7bc8622e43a942eec53c938/pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9", size = 1935777, upload-time = "2025-04-23T18:32:25.088Z" }, +] + +[[package]] +name = "pydantic-settings" +version = "2.10.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pydantic" }, + { name = "python-dotenv" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/68/85/1ea668bbab3c50071ca613c6ab30047fb36ab0da1b92fa8f17bbc38fd36c/pydantic_settings-2.10.1.tar.gz", hash = "sha256:06f0062169818d0f5524420a360d632d5857b83cffd4d42fe29597807a1614ee", size = 172583, upload-time = "2025-06-24T13:26:46.841Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/58/f0/427018098906416f580e3cf1366d3b1abfb408a0652e9f31600c24a1903c/pydantic_settings-2.10.1-py3-none-any.whl", hash = "sha256:a60952460b99cf661dc25c29c0ef171721f98bfcb52ef8d9ea4c943d7c8cc796", size = 45235, upload-time = "2025-06-24T13:26:45.485Z" }, +] + +[[package]] +name = "pygments" +version = "2.19.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, +] + +[[package]] +name = "pyopenssl" +version = "24.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cryptography" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c1/d4/1067b82c4fc674d6f6e9e8d26b3dff978da46d351ca3bac171544693e085/pyopenssl-24.3.0.tar.gz", hash = "sha256:49f7a019577d834746bc55c5fce6ecbcec0f2b4ec5ce1cf43a9a173b8138bb36", size = 178944, upload-time = "2024-11-27T20:43:12.755Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/42/22/40f9162e943f86f0fc927ebc648078be87def360d9d8db346619fb97df2b/pyOpenSSL-24.3.0-py3-none-any.whl", hash = "sha256:e474f5a473cd7f92221cc04976e48f4d11502804657a08a989fb3be5514c904a", size = 56111, upload-time = "2024-11-27T20:43:21.112Z" }, +] + +[[package]] +name = "pyperclip" +version = "1.10.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/15/99/25f4898cf420efb6f45f519de018f4faea5391114a8618b16736ef3029f1/pyperclip-1.10.0.tar.gz", hash = "sha256:180c8346b1186921c75dfd14d9048a6b5d46bfc499778811952c6dd6eb1ca6be", size = 12193, upload-time = "2025-09-18T00:54:00.384Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/bc/22540e73c5f5ae18f02924cd3954a6c9a4aa6b713c841a94c98335d333a1/pyperclip-1.10.0-py3-none-any.whl", hash = "sha256:596fbe55dc59263bff26e61d2afbe10223e2fccb5210c9c96a28d6887cfcc7ec", size = 11062, upload-time = "2025-09-18T00:53:59.252Z" }, +] + +[[package]] +name = "pytest" +version = "8.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a3/5c/00a0e072241553e1a7496d638deababa67c5058571567b92a7eaa258397c/pytest-8.4.2.tar.gz", hash = "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01", size = 1519618, upload-time = "2025-09-04T14:34:22.711Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79", size = 365750, upload-time = "2025-09-04T14:34:20.226Z" }, +] + +[[package]] +name = "pytest-asyncio" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/86/9e3c5f48f7b7b638b216e4b9e645f54d199d7abbbab7a64a13b4e12ba10f/pytest_asyncio-1.2.0.tar.gz", hash = "sha256:c609a64a2a8768462d0c99811ddb8bd2583c33fd33cf7f21af1c142e824ffb57", size = 50119, upload-time = "2025-09-12T07:33:53.816Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/93/2fa34714b7a4ae72f2f8dad66ba17dd9a2c793220719e736dda28b7aec27/pytest_asyncio-1.2.0-py3-none-any.whl", hash = "sha256:8e17ae5e46d8e7efe51ab6494dd2010f4ca8dae51652aa3c8d55acf50bfb2e99", size = 15095, upload-time = "2025-09-12T07:33:52.639Z" }, +] + +[[package]] +name = "pytest-cov" +version = "7.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "coverage" }, + { name = "pluggy" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5e/f7/c933acc76f5208b3b00089573cf6a2bc26dc80a8aece8f52bb7d6b1855ca/pytest_cov-7.0.0.tar.gz", hash = "sha256:33c97eda2e049a0c5298e91f519302a1334c26ac65c1a483d6206fd458361af1", size = 54328, upload-time = "2025-09-09T10:57:02.113Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ee/49/1377b49de7d0c1ce41292161ea0f721913fa8722c19fb9c1e3aa0367eecb/pytest_cov-7.0.0-py3-none-any.whl", hash = "sha256:3b8e9558b16cc1479da72058bdecf8073661c7f57f7d3c5f22a1c23507f2d861", size = 22424, upload-time = "2025-09-09T10:57:00.695Z" }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + +[[package]] +name = "python-dotenv" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/b0/4bc07ccd3572a2f9df7e6782f52b0c6c90dcbb803ac4a167702d7d0dfe1e/python_dotenv-1.1.1.tar.gz", hash = "sha256:a8a6399716257f45be6a007360200409fce5cda2661e3dec71d23dc15f6189ab", size = 41978, upload-time = "2025-06-24T04:21:07.341Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5f/ed/539768cf28c661b5b068d66d96a2f155c4971a5d55684a514c1a0e0dec2f/python_dotenv-1.1.1-py3-none-any.whl", hash = "sha256:31f23644fe2602f88ff55e1f5c79ba497e01224ee7737937930c448e4d0e24dc", size = 20556, upload-time = "2025-06-24T04:21:06.073Z" }, +] + +[[package]] +name = "python-multipart" +version = "0.0.20" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/87/f44d7c9f274c7ee665a29b885ec97089ec5dc034c7f3fafa03da9e39a09e/python_multipart-0.0.20.tar.gz", hash = "sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13", size = 37158, upload-time = "2024-12-16T19:45:46.972Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl", hash = "sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104", size = 24546, upload-time = "2024-12-16T19:45:44.423Z" }, +] + +[[package]] +name = "pytz" +version = "2025.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884, upload-time = "2025-03-25T02:25:00.538Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" }, +] + +[[package]] +name = "pywin32" +version = "311" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a5/be/3fd5de0979fcb3994bfee0d65ed8ca9506a8a1260651b86174f6a86f52b3/pywin32-311-cp313-cp313-win32.whl", hash = "sha256:f95ba5a847cba10dd8c4d8fefa9f2a6cf283b8b88ed6178fa8a6c1ab16054d0d", size = 8705700, upload-time = "2025-07-14T20:13:26.471Z" }, + { url = "https://files.pythonhosted.org/packages/e3/28/e0a1909523c6890208295a29e05c2adb2126364e289826c0a8bc7297bd5c/pywin32-311-cp313-cp313-win_amd64.whl", hash = "sha256:718a38f7e5b058e76aee1c56ddd06908116d35147e133427e59a3983f703a20d", size = 9494700, upload-time = "2025-07-14T20:13:28.243Z" }, + { url = "https://files.pythonhosted.org/packages/04/bf/90339ac0f55726dce7d794e6d79a18a91265bdf3aa70b6b9ca52f35e022a/pywin32-311-cp313-cp313-win_arm64.whl", hash = "sha256:7b4075d959648406202d92a2310cb990fea19b535c7f4a78d3f5e10b926eeb8a", size = 8709318, upload-time = "2025-07-14T20:13:30.348Z" }, + { url = "https://files.pythonhosted.org/packages/c9/31/097f2e132c4f16d99a22bfb777e0fd88bd8e1c634304e102f313af69ace5/pywin32-311-cp314-cp314-win32.whl", hash = "sha256:b7a2c10b93f8986666d0c803ee19b5990885872a7de910fc460f9b0c2fbf92ee", size = 8840714, upload-time = "2025-07-14T20:13:32.449Z" }, + { url = "https://files.pythonhosted.org/packages/90/4b/07c77d8ba0e01349358082713400435347df8426208171ce297da32c313d/pywin32-311-cp314-cp314-win_amd64.whl", hash = "sha256:3aca44c046bd2ed8c90de9cb8427f581c479e594e99b5c0bb19b29c10fd6cb87", size = 9656800, upload-time = "2025-07-14T20:13:34.312Z" }, + { url = "https://files.pythonhosted.org/packages/c0/d2/21af5c535501a7233e734b8af901574572da66fcc254cb35d0609c9080dd/pywin32-311-cp314-cp314-win_arm64.whl", hash = "sha256:a508e2d9025764a8270f93111a970e1d0fbfc33f4153b388bb649b7eec4f9b42", size = 8932540, upload-time = "2025-07-14T20:13:36.379Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631, upload-time = "2024-08-06T20:33:50.674Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309, upload-time = "2024-08-06T20:32:43.4Z" }, + { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679, upload-time = "2024-08-06T20:32:44.801Z" }, + { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428, upload-time = "2024-08-06T20:32:46.432Z" }, + { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361, upload-time = "2024-08-06T20:32:51.188Z" }, + { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523, upload-time = "2024-08-06T20:32:53.019Z" }, + { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660, upload-time = "2024-08-06T20:32:54.708Z" }, + { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597, upload-time = "2024-08-06T20:32:56.985Z" }, + { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527, upload-time = "2024-08-06T20:33:03.001Z" }, + { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446, upload-time = "2024-08-06T20:33:04.33Z" }, +] + +[[package]] +name = "referencing" +version = "0.36.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "rpds-py" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2f/db/98b5c277be99dd18bfd91dd04e1b759cad18d1a338188c936e92f921c7e2/referencing-0.36.2.tar.gz", hash = "sha256:df2e89862cd09deabbdba16944cc3f10feb6b3e6f18e902f7cc25609a34775aa", size = 74744, upload-time = "2025-01-25T08:48:16.138Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/b1/3baf80dc6d2b7bc27a95a67752d0208e410351e3feb4eb78de5f77454d8d/referencing-0.36.2-py3-none-any.whl", hash = "sha256:e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0", size = 26775, upload-time = "2025-01-25T08:48:14.241Z" }, +] + +[[package]] +name = "requests" +version = "2.32.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, +] + +[[package]] +name = "rfc3339-validator" +version = "0.1.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/28/ea/a9387748e2d111c3c2b275ba970b735e04e15cdb1eb30693b6b5708c4dbd/rfc3339_validator-0.1.4.tar.gz", hash = "sha256:138a2abdf93304ad60530167e51d2dfb9549521a836871b88d7f4695d0022f6b", size = 5513, upload-time = "2021-05-12T16:37:54.178Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7b/44/4e421b96b67b2daff264473f7465db72fbdf36a07e05494f50300cc7b0c6/rfc3339_validator-0.1.4-py2.py3-none-any.whl", hash = "sha256:24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa", size = 3490, upload-time = "2021-05-12T16:37:52.536Z" }, +] + +[[package]] +name = "rich" +version = "14.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown-it-py" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fe/75/af448d8e52bf1d8fa6a9d089ca6c07ff4453d86c65c145d0a300bb073b9b/rich-14.1.0.tar.gz", hash = "sha256:e497a48b844b0320d45007cdebfeaeed8db2a4f4bcf49f15e455cfc4af11eaa8", size = 224441, upload-time = "2025-07-25T07:32:58.125Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e3/30/3c4d035596d3cf444529e0b2953ad0466f6049528a879d27534700580395/rich-14.1.0-py3-none-any.whl", hash = "sha256:536f5f1785986d6dbdea3c75205c473f970777b4a0d6c6dd1b696aa05a3fa04f", size = 243368, upload-time = "2025-07-25T07:32:56.73Z" }, +] + +[[package]] +name = "rich-rst" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "docutils" }, + { name = "rich" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b0/69/5514c3a87b5f10f09a34bb011bc0927bc12c596c8dae5915604e71abc386/rich_rst-1.3.1.tar.gz", hash = "sha256:fad46e3ba42785ea8c1785e2ceaa56e0ffa32dbe5410dec432f37e4107c4f383", size = 13839, upload-time = "2024-04-30T04:40:38.125Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fd/bc/cc4e3dbc5e7992398dcb7a8eda0cbcf4fb792a0cdb93f857b478bf3cf884/rich_rst-1.3.1-py3-none-any.whl", hash = "sha256:498a74e3896507ab04492d326e794c3ef76e7cda078703aa592d1853d91098c1", size = 11621, upload-time = "2024-04-30T04:40:32.619Z" }, +] + +[[package]] +name = "rpds-py" +version = "0.27.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e9/dd/2c0cbe774744272b0ae725f44032c77bdcab6e8bcf544bffa3b6e70c8dba/rpds_py-0.27.1.tar.gz", hash = "sha256:26a1c73171d10b7acccbded82bf6a586ab8203601e565badc74bbbf8bc5a10f8", size = 27479, upload-time = "2025-08-27T12:16:36.024Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cc/77/610aeee8d41e39080c7e14afa5387138e3c9fa9756ab893d09d99e7d8e98/rpds_py-0.27.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:e4b9fcfbc021633863a37e92571d6f91851fa656f0180246e84cbd8b3f6b329b", size = 361741, upload-time = "2025-08-27T12:13:31.039Z" }, + { url = "https://files.pythonhosted.org/packages/3a/fc/c43765f201c6a1c60be2043cbdb664013def52460a4c7adace89d6682bf4/rpds_py-0.27.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1441811a96eadca93c517d08df75de45e5ffe68aa3089924f963c782c4b898cf", size = 345574, upload-time = "2025-08-27T12:13:32.902Z" }, + { url = "https://files.pythonhosted.org/packages/20/42/ee2b2ca114294cd9847d0ef9c26d2b0851b2e7e00bf14cc4c0b581df0fc3/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55266dafa22e672f5a4f65019015f90336ed31c6383bd53f5e7826d21a0e0b83", size = 385051, upload-time = "2025-08-27T12:13:34.228Z" }, + { url = "https://files.pythonhosted.org/packages/fd/e8/1e430fe311e4799e02e2d1af7c765f024e95e17d651612425b226705f910/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d78827d7ac08627ea2c8e02c9e5b41180ea5ea1f747e9db0915e3adf36b62dcf", size = 398395, upload-time = "2025-08-27T12:13:36.132Z" }, + { url = "https://files.pythonhosted.org/packages/82/95/9dc227d441ff2670651c27a739acb2535ccaf8b351a88d78c088965e5996/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae92443798a40a92dc5f0b01d8a7c93adde0c4dc965310a29ae7c64d72b9fad2", size = 524334, upload-time = "2025-08-27T12:13:37.562Z" }, + { url = "https://files.pythonhosted.org/packages/87/01/a670c232f401d9ad461d9a332aa4080cd3cb1d1df18213dbd0d2a6a7ab51/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c46c9dd2403b66a2a3b9720ec4b74d4ab49d4fabf9f03dfdce2d42af913fe8d0", size = 407691, upload-time = "2025-08-27T12:13:38.94Z" }, + { url = "https://files.pythonhosted.org/packages/03/36/0a14aebbaa26fe7fab4780c76f2239e76cc95a0090bdb25e31d95c492fcd/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2efe4eb1d01b7f5f1939f4ef30ecea6c6b3521eec451fb93191bf84b2a522418", size = 386868, upload-time = "2025-08-27T12:13:40.192Z" }, + { url = "https://files.pythonhosted.org/packages/3b/03/8c897fb8b5347ff6c1cc31239b9611c5bf79d78c984430887a353e1409a1/rpds_py-0.27.1-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:15d3b4d83582d10c601f481eca29c3f138d44c92187d197aff663a269197c02d", size = 405469, upload-time = "2025-08-27T12:13:41.496Z" }, + { url = "https://files.pythonhosted.org/packages/da/07/88c60edc2df74850d496d78a1fdcdc7b54360a7f610a4d50008309d41b94/rpds_py-0.27.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4ed2e16abbc982a169d30d1a420274a709949e2cbdef119fe2ec9d870b42f274", size = 422125, upload-time = "2025-08-27T12:13:42.802Z" }, + { url = "https://files.pythonhosted.org/packages/6b/86/5f4c707603e41b05f191a749984f390dabcbc467cf833769b47bf14ba04f/rpds_py-0.27.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a75f305c9b013289121ec0f1181931975df78738cdf650093e6b86d74aa7d8dd", size = 562341, upload-time = "2025-08-27T12:13:44.472Z" }, + { url = "https://files.pythonhosted.org/packages/b2/92/3c0cb2492094e3cd9baf9e49bbb7befeceb584ea0c1a8b5939dca4da12e5/rpds_py-0.27.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:67ce7620704745881a3d4b0ada80ab4d99df390838839921f99e63c474f82cf2", size = 592511, upload-time = "2025-08-27T12:13:45.898Z" }, + { url = "https://files.pythonhosted.org/packages/10/bb/82e64fbb0047c46a168faa28d0d45a7851cd0582f850b966811d30f67ad8/rpds_py-0.27.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9d992ac10eb86d9b6f369647b6a3f412fc0075cfd5d799530e84d335e440a002", size = 557736, upload-time = "2025-08-27T12:13:47.408Z" }, + { url = "https://files.pythonhosted.org/packages/00/95/3c863973d409210da7fb41958172c6b7dbe7fc34e04d3cc1f10bb85e979f/rpds_py-0.27.1-cp313-cp313-win32.whl", hash = "sha256:4f75e4bd8ab8db624e02c8e2fc4063021b58becdbe6df793a8111d9343aec1e3", size = 221462, upload-time = "2025-08-27T12:13:48.742Z" }, + { url = "https://files.pythonhosted.org/packages/ce/2c/5867b14a81dc217b56d95a9f2a40fdbc56a1ab0181b80132beeecbd4b2d6/rpds_py-0.27.1-cp313-cp313-win_amd64.whl", hash = "sha256:f9025faafc62ed0b75a53e541895ca272815bec18abe2249ff6501c8f2e12b83", size = 232034, upload-time = "2025-08-27T12:13:50.11Z" }, + { url = "https://files.pythonhosted.org/packages/c7/78/3958f3f018c01923823f1e47f1cc338e398814b92d83cd278364446fac66/rpds_py-0.27.1-cp313-cp313-win_arm64.whl", hash = "sha256:ed10dc32829e7d222b7d3b93136d25a406ba9788f6a7ebf6809092da1f4d279d", size = 222392, upload-time = "2025-08-27T12:13:52.587Z" }, + { url = "https://files.pythonhosted.org/packages/01/76/1cdf1f91aed5c3a7bf2eba1f1c4e4d6f57832d73003919a20118870ea659/rpds_py-0.27.1-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:92022bbbad0d4426e616815b16bc4127f83c9a74940e1ccf3cfe0b387aba0228", size = 358355, upload-time = "2025-08-27T12:13:54.012Z" }, + { url = "https://files.pythonhosted.org/packages/c3/6f/bf142541229374287604caf3bb2a4ae17f0a580798fd72d3b009b532db4e/rpds_py-0.27.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:47162fdab9407ec3f160805ac3e154df042e577dd53341745fc7fb3f625e6d92", size = 342138, upload-time = "2025-08-27T12:13:55.791Z" }, + { url = "https://files.pythonhosted.org/packages/1a/77/355b1c041d6be40886c44ff5e798b4e2769e497b790f0f7fd1e78d17e9a8/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb89bec23fddc489e5d78b550a7b773557c9ab58b7946154a10a6f7a214a48b2", size = 380247, upload-time = "2025-08-27T12:13:57.683Z" }, + { url = "https://files.pythonhosted.org/packages/d6/a4/d9cef5c3946ea271ce2243c51481971cd6e34f21925af2783dd17b26e815/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e48af21883ded2b3e9eb48cb7880ad8598b31ab752ff3be6457001d78f416723", size = 390699, upload-time = "2025-08-27T12:13:59.137Z" }, + { url = "https://files.pythonhosted.org/packages/3a/06/005106a7b8c6c1a7e91b73169e49870f4af5256119d34a361ae5240a0c1d/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6f5b7bd8e219ed50299e58551a410b64daafb5017d54bbe822e003856f06a802", size = 521852, upload-time = "2025-08-27T12:14:00.583Z" }, + { url = "https://files.pythonhosted.org/packages/e5/3e/50fb1dac0948e17a02eb05c24510a8fe12d5ce8561c6b7b7d1339ab7ab9c/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08f1e20bccf73b08d12d804d6e1c22ca5530e71659e6673bce31a6bb71c1e73f", size = 402582, upload-time = "2025-08-27T12:14:02.034Z" }, + { url = "https://files.pythonhosted.org/packages/cb/b0/f4e224090dc5b0ec15f31a02d746ab24101dd430847c4d99123798661bfc/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0dc5dceeaefcc96dc192e3a80bbe1d6c410c469e97bdd47494a7d930987f18b2", size = 384126, upload-time = "2025-08-27T12:14:03.437Z" }, + { url = "https://files.pythonhosted.org/packages/54/77/ac339d5f82b6afff1df8f0fe0d2145cc827992cb5f8eeb90fc9f31ef7a63/rpds_py-0.27.1-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:d76f9cc8665acdc0c9177043746775aa7babbf479b5520b78ae4002d889f5c21", size = 399486, upload-time = "2025-08-27T12:14:05.443Z" }, + { url = "https://files.pythonhosted.org/packages/d6/29/3e1c255eee6ac358c056a57d6d6869baa00a62fa32eea5ee0632039c50a3/rpds_py-0.27.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:134fae0e36022edad8290a6661edf40c023562964efea0cc0ec7f5d392d2aaef", size = 414832, upload-time = "2025-08-27T12:14:06.902Z" }, + { url = "https://files.pythonhosted.org/packages/3f/db/6d498b844342deb3fa1d030598db93937a9964fcf5cb4da4feb5f17be34b/rpds_py-0.27.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:eb11a4f1b2b63337cfd3b4d110af778a59aae51c81d195768e353d8b52f88081", size = 557249, upload-time = "2025-08-27T12:14:08.37Z" }, + { url = "https://files.pythonhosted.org/packages/60/f3/690dd38e2310b6f68858a331399b4d6dbb9132c3e8ef8b4333b96caf403d/rpds_py-0.27.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:13e608ac9f50a0ed4faec0e90ece76ae33b34c0e8656e3dceb9a7db994c692cd", size = 587356, upload-time = "2025-08-27T12:14:10.034Z" }, + { url = "https://files.pythonhosted.org/packages/86/e3/84507781cccd0145f35b1dc32c72675200c5ce8d5b30f813e49424ef68fc/rpds_py-0.27.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dd2135527aa40f061350c3f8f89da2644de26cd73e4de458e79606384f4f68e7", size = 555300, upload-time = "2025-08-27T12:14:11.783Z" }, + { url = "https://files.pythonhosted.org/packages/e5/ee/375469849e6b429b3516206b4580a79e9ef3eb12920ddbd4492b56eaacbe/rpds_py-0.27.1-cp313-cp313t-win32.whl", hash = "sha256:3020724ade63fe320a972e2ffd93b5623227e684315adce194941167fee02688", size = 216714, upload-time = "2025-08-27T12:14:13.629Z" }, + { url = "https://files.pythonhosted.org/packages/21/87/3fc94e47c9bd0742660e84706c311a860dcae4374cf4a03c477e23ce605a/rpds_py-0.27.1-cp313-cp313t-win_amd64.whl", hash = "sha256:8ee50c3e41739886606388ba3ab3ee2aae9f35fb23f833091833255a31740797", size = 228943, upload-time = "2025-08-27T12:14:14.937Z" }, + { url = "https://files.pythonhosted.org/packages/70/36/b6e6066520a07cf029d385de869729a895917b411e777ab1cde878100a1d/rpds_py-0.27.1-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:acb9aafccaae278f449d9c713b64a9e68662e7799dbd5859e2c6b3c67b56d334", size = 362472, upload-time = "2025-08-27T12:14:16.333Z" }, + { url = "https://files.pythonhosted.org/packages/af/07/b4646032e0dcec0df9c73a3bd52f63bc6c5f9cda992f06bd0e73fe3fbebd/rpds_py-0.27.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:b7fb801aa7f845ddf601c49630deeeccde7ce10065561d92729bfe81bd21fb33", size = 345676, upload-time = "2025-08-27T12:14:17.764Z" }, + { url = "https://files.pythonhosted.org/packages/b0/16/2f1003ee5d0af4bcb13c0cf894957984c32a6751ed7206db2aee7379a55e/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe0dd05afb46597b9a2e11c351e5e4283c741237e7f617ffb3252780cca9336a", size = 385313, upload-time = "2025-08-27T12:14:19.829Z" }, + { url = "https://files.pythonhosted.org/packages/05/cd/7eb6dd7b232e7f2654d03fa07f1414d7dfc980e82ba71e40a7c46fd95484/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b6dfb0e058adb12d8b1d1b25f686e94ffa65d9995a5157afe99743bf7369d62b", size = 399080, upload-time = "2025-08-27T12:14:21.531Z" }, + { url = "https://files.pythonhosted.org/packages/20/51/5829afd5000ec1cb60f304711f02572d619040aa3ec033d8226817d1e571/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ed090ccd235f6fa8bb5861684567f0a83e04f52dfc2e5c05f2e4b1309fcf85e7", size = 523868, upload-time = "2025-08-27T12:14:23.485Z" }, + { url = "https://files.pythonhosted.org/packages/05/2c/30eebca20d5db95720ab4d2faec1b5e4c1025c473f703738c371241476a2/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf876e79763eecf3e7356f157540d6a093cef395b65514f17a356f62af6cc136", size = 408750, upload-time = "2025-08-27T12:14:24.924Z" }, + { url = "https://files.pythonhosted.org/packages/90/1a/cdb5083f043597c4d4276eae4e4c70c55ab5accec078da8611f24575a367/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:12ed005216a51b1d6e2b02a7bd31885fe317e45897de81d86dcce7d74618ffff", size = 387688, upload-time = "2025-08-27T12:14:27.537Z" }, + { url = "https://files.pythonhosted.org/packages/7c/92/cf786a15320e173f945d205ab31585cc43969743bb1a48b6888f7a2b0a2d/rpds_py-0.27.1-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:ee4308f409a40e50593c7e3bb8cbe0b4d4c66d1674a316324f0c2f5383b486f9", size = 407225, upload-time = "2025-08-27T12:14:28.981Z" }, + { url = "https://files.pythonhosted.org/packages/33/5c/85ee16df5b65063ef26017bef33096557a4c83fbe56218ac7cd8c235f16d/rpds_py-0.27.1-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0b08d152555acf1f455154d498ca855618c1378ec810646fcd7c76416ac6dc60", size = 423361, upload-time = "2025-08-27T12:14:30.469Z" }, + { url = "https://files.pythonhosted.org/packages/4b/8e/1c2741307fcabd1a334ecf008e92c4f47bb6f848712cf15c923becfe82bb/rpds_py-0.27.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:dce51c828941973a5684d458214d3a36fcd28da3e1875d659388f4f9f12cc33e", size = 562493, upload-time = "2025-08-27T12:14:31.987Z" }, + { url = "https://files.pythonhosted.org/packages/04/03/5159321baae9b2222442a70c1f988cbbd66b9be0675dd3936461269be360/rpds_py-0.27.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:c1476d6f29eb81aa4151c9a31219b03f1f798dc43d8af1250a870735516a1212", size = 592623, upload-time = "2025-08-27T12:14:33.543Z" }, + { url = "https://files.pythonhosted.org/packages/ff/39/c09fd1ad28b85bc1d4554a8710233c9f4cefd03d7717a1b8fbfd171d1167/rpds_py-0.27.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:3ce0cac322b0d69b63c9cdb895ee1b65805ec9ffad37639f291dd79467bee675", size = 558800, upload-time = "2025-08-27T12:14:35.436Z" }, + { url = "https://files.pythonhosted.org/packages/c5/d6/99228e6bbcf4baa764b18258f519a9035131d91b538d4e0e294313462a98/rpds_py-0.27.1-cp314-cp314-win32.whl", hash = "sha256:dfbfac137d2a3d0725758cd141f878bf4329ba25e34979797c89474a89a8a3a3", size = 221943, upload-time = "2025-08-27T12:14:36.898Z" }, + { url = "https://files.pythonhosted.org/packages/be/07/c802bc6b8e95be83b79bdf23d1aa61d68324cb1006e245d6c58e959e314d/rpds_py-0.27.1-cp314-cp314-win_amd64.whl", hash = "sha256:a6e57b0abfe7cc513450fcf529eb486b6e4d3f8aee83e92eb5f1ef848218d456", size = 233739, upload-time = "2025-08-27T12:14:38.386Z" }, + { url = "https://files.pythonhosted.org/packages/c8/89/3e1b1c16d4c2d547c5717377a8df99aee8099ff050f87c45cb4d5fa70891/rpds_py-0.27.1-cp314-cp314-win_arm64.whl", hash = "sha256:faf8d146f3d476abfee026c4ae3bdd9ca14236ae4e4c310cbd1cf75ba33d24a3", size = 223120, upload-time = "2025-08-27T12:14:39.82Z" }, + { url = "https://files.pythonhosted.org/packages/62/7e/dc7931dc2fa4a6e46b2a4fa744a9fe5c548efd70e0ba74f40b39fa4a8c10/rpds_py-0.27.1-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:ba81d2b56b6d4911ce735aad0a1d4495e808b8ee4dc58715998741a26874e7c2", size = 358944, upload-time = "2025-08-27T12:14:41.199Z" }, + { url = "https://files.pythonhosted.org/packages/e6/22/4af76ac4e9f336bfb1a5f240d18a33c6b2fcaadb7472ac7680576512b49a/rpds_py-0.27.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:84f7d509870098de0e864cad0102711c1e24e9b1a50ee713b65928adb22269e4", size = 342283, upload-time = "2025-08-27T12:14:42.699Z" }, + { url = "https://files.pythonhosted.org/packages/1c/15/2a7c619b3c2272ea9feb9ade67a45c40b3eeb500d503ad4c28c395dc51b4/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9e960fc78fecd1100539f14132425e1d5fe44ecb9239f8f27f079962021523e", size = 380320, upload-time = "2025-08-27T12:14:44.157Z" }, + { url = "https://files.pythonhosted.org/packages/a2/7d/4c6d243ba4a3057e994bb5bedd01b5c963c12fe38dde707a52acdb3849e7/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:62f85b665cedab1a503747617393573995dac4600ff51869d69ad2f39eb5e817", size = 391760, upload-time = "2025-08-27T12:14:45.845Z" }, + { url = "https://files.pythonhosted.org/packages/b4/71/b19401a909b83bcd67f90221330bc1ef11bc486fe4e04c24388d28a618ae/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fed467af29776f6556250c9ed85ea5a4dd121ab56a5f8b206e3e7a4c551e48ec", size = 522476, upload-time = "2025-08-27T12:14:47.364Z" }, + { url = "https://files.pythonhosted.org/packages/e4/44/1a3b9715c0455d2e2f0f6df5ee6d6f5afdc423d0773a8a682ed2b43c566c/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2729615f9d430af0ae6b36cf042cb55c0936408d543fb691e1a9e36648fd35a", size = 403418, upload-time = "2025-08-27T12:14:49.991Z" }, + { url = "https://files.pythonhosted.org/packages/1c/4b/fb6c4f14984eb56673bc868a66536f53417ddb13ed44b391998100a06a96/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b207d881a9aef7ba753d69c123a35d96ca7cb808056998f6b9e8747321f03b8", size = 384771, upload-time = "2025-08-27T12:14:52.159Z" }, + { url = "https://files.pythonhosted.org/packages/c0/56/d5265d2d28b7420d7b4d4d85cad8ef891760f5135102e60d5c970b976e41/rpds_py-0.27.1-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:639fd5efec029f99b79ae47e5d7e00ad8a773da899b6309f6786ecaf22948c48", size = 400022, upload-time = "2025-08-27T12:14:53.859Z" }, + { url = "https://files.pythonhosted.org/packages/8f/e9/9f5fc70164a569bdd6ed9046486c3568d6926e3a49bdefeeccfb18655875/rpds_py-0.27.1-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fecc80cb2a90e28af8a9b366edacf33d7a91cbfe4c2c4544ea1246e949cfebeb", size = 416787, upload-time = "2025-08-27T12:14:55.673Z" }, + { url = "https://files.pythonhosted.org/packages/d4/64/56dd03430ba491db943a81dcdef115a985aac5f44f565cd39a00c766d45c/rpds_py-0.27.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:42a89282d711711d0a62d6f57d81aa43a1368686c45bc1c46b7f079d55692734", size = 557538, upload-time = "2025-08-27T12:14:57.245Z" }, + { url = "https://files.pythonhosted.org/packages/3f/36/92cc885a3129993b1d963a2a42ecf64e6a8e129d2c7cc980dbeba84e55fb/rpds_py-0.27.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:cf9931f14223de59551ab9d38ed18d92f14f055a5f78c1d8ad6493f735021bbb", size = 588512, upload-time = "2025-08-27T12:14:58.728Z" }, + { url = "https://files.pythonhosted.org/packages/dd/10/6b283707780a81919f71625351182b4f98932ac89a09023cb61865136244/rpds_py-0.27.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f39f58a27cc6e59f432b568ed8429c7e1641324fbe38131de852cd77b2d534b0", size = 555813, upload-time = "2025-08-27T12:15:00.334Z" }, + { url = "https://files.pythonhosted.org/packages/04/2e/30b5ea18c01379da6272a92825dd7e53dc9d15c88a19e97932d35d430ef7/rpds_py-0.27.1-cp314-cp314t-win32.whl", hash = "sha256:d5fa0ee122dc09e23607a28e6d7b150da16c662e66409bbe85230e4c85bb528a", size = 217385, upload-time = "2025-08-27T12:15:01.937Z" }, + { url = "https://files.pythonhosted.org/packages/32/7d/97119da51cb1dd3f2f3c0805f155a3aa4a95fa44fe7d78ae15e69edf4f34/rpds_py-0.27.1-cp314-cp314t-win_amd64.whl", hash = "sha256:6567d2bb951e21232c2f660c24cf3470bb96de56cdcb3f071a83feeaff8a2772", size = 230097, upload-time = "2025-08-27T12:15:03.961Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + +[[package]] +name = "sniffio" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, +] + +[[package]] +name = "sse-starlette" +version = "3.0.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/6f/22ed6e33f8a9e76ca0a412405f31abb844b779d52c5f96660766edcd737c/sse_starlette-3.0.2.tar.gz", hash = "sha256:ccd60b5765ebb3584d0de2d7a6e4f745672581de4f5005ab31c3a25d10b52b3a", size = 20985, upload-time = "2025-07-27T09:07:44.565Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/10/c78f463b4ef22eef8491f218f692be838282cd65480f6e423d7730dfd1fb/sse_starlette-3.0.2-py3-none-any.whl", hash = "sha256:16b7cbfddbcd4eaca11f7b586f3b8a080f1afe952c15813455b162edea619e5a", size = 11297, upload-time = "2025-07-27T09:07:43.268Z" }, +] + +[[package]] +name = "starlette" +version = "0.48.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a7/a5/d6f429d43394057b67a6b5bbe6eae2f77a6bf7459d961fdb224bf206eee6/starlette-0.48.0.tar.gz", hash = "sha256:7e8cee469a8ab2352911528110ce9088fdc6a37d9876926e73da7ce4aa4c7a46", size = 2652949, upload-time = "2025-09-13T08:41:05.699Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/be/72/2db2f49247d0a18b4f1bb9a5a39a0162869acf235f3a96418363947b3d46/starlette-0.48.0-py3-none-any.whl", hash = "sha256:0764ca97b097582558ecb498132ed0c7d942f233f365b86ba37770e026510659", size = 73736, upload-time = "2025-09-13T08:41:03.869Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, +] + +[[package]] +name = "typing-inspection" +version = "0.4.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f8/b1/0c11f5058406b3af7609f121aaa6b609744687f1d158b3c3a5bf4cc94238/typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28", size = 75726, upload-time = "2025-05-21T18:55:23.885Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/17/69/cd203477f944c353c31bade965f880aa1061fd6bf05ded0726ca845b6ff7/typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51", size = 14552, upload-time = "2025-05-21T18:55:22.152Z" }, +] + +[[package]] +name = "urllib3" +version = "2.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" }, +] + +[[package]] +name = "uvicorn" +version = "0.36.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ef/5e/f0cd46063a02fd8515f0e880c37d2657845b7306c16ce6c4ffc44afd9036/uvicorn-0.36.0.tar.gz", hash = "sha256:527dc68d77819919d90a6b267be55f0e76704dca829d34aea9480be831a9b9d9", size = 80032, upload-time = "2025-09-20T01:07:14.418Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/96/06/5cc0542b47c0338c1cb676b348e24a1c29acabc81000bced518231dded6f/uvicorn-0.36.0-py3-none-any.whl", hash = "sha256:6bb4ba67f16024883af8adf13aba3a9919e415358604ce46780d3f9bdc36d731", size = 67675, upload-time = "2025-09-20T01:07:12.984Z" }, +] + +[[package]] +name = "werkzeug" +version = "3.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/32/af/d4502dc713b4ccea7175d764718d5183caf8d0867a4f0190d5d4a45cea49/werkzeug-3.1.1.tar.gz", hash = "sha256:8cd39dfbdfc1e051965f156163e2974e52c210f130810e9ad36858f0fd3edad4", size = 806453, upload-time = "2024-11-01T16:40:45.462Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ee/ea/c67e1dee1ba208ed22c06d1d547ae5e293374bfc43e0eb0ef5e262b68561/werkzeug-3.1.1-py3-none-any.whl", hash = "sha256:a71124d1ef06008baafa3d266c02f56e1836a5984afd6dd6c9230669d60d9fb5", size = 224371, upload-time = "2024-11-01T16:40:43.994Z" }, +] diff --git a/tox.ini b/tox.ini index 842df56e..992c9498 100644 --- a/tox.ini +++ b/tox.ini @@ -20,7 +20,8 @@ extend-exclude = src/mysql-mcp-server, src/oci-pricing-mcp-server, src/oracle-db-doc-mcp-server - src/database-mcp-server + src/database-mcp-server, + src/oci-db-dynamic-mcp-server [testenv] deps = From c84c754a0d00e160fd4f7ce420458feabd909d50 Mon Sep 17 00:00:00 2001 From: Shyam N V Date: Mon, 22 Dec 2025 19:50:43 +0530 Subject: [PATCH 3/5] OCI DB Dynamic MCP Server --- .../oci_db_dynamic_mcp_server/server.py | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/src/oci-db-dynamic-mcp-server/oracle/oci_db_dynamic_mcp_server/server.py b/src/oci-db-dynamic-mcp-server/oracle/oci_db_dynamic_mcp_server/server.py index 9b505aad..3a333e01 100644 --- a/src/oci-db-dynamic-mcp-server/oracle/oci_db_dynamic_mcp_server/server.py +++ b/src/oci-db-dynamic-mcp-server/oracle/oci_db_dynamic_mcp_server/server.py @@ -19,7 +19,7 @@ mcp = FastMCP(name=__project__) -DEFAULT_ENDPOINT = "https://database.us-ashburn-1.oraclecloud.com/20160918/" +DEFAULT_ENDPOINT = "https://preprod-database.eu-zurich-1.oraclecloud.com/20160918/" # ---------------- TYPE MAPPING ---------------- TYPE_MAP = { @@ -150,10 +150,12 @@ def build_collapsed_parent_notes(resolved_schema: dict, flat_schema: dict) -> st def register_tools(allowed_resources: Optional[List[str]] = None): - """ - Load tools dynamically. - allowed_resources: List of strings (e.g. ['database', 'dbsystem']) or None for ALL. - """ + + if allowed_resources is None: + env_resources = os.getenv("OCI_ALLOWED_RESOURCES") + if env_resources: + allowed_resources = [r.strip() for r in env_resources.split(",")] + print(f"Loading OCI Specs (Filter: {allowed_resources})...") tools = build_tools_from_latest_spec(allowed_resources=allowed_resources) print(f"Loaded {len(tools)} tools.") @@ -292,15 +294,7 @@ async def {tool_name}({args_sig}): def main(): - parser = argparse.ArgumentParser(description="OCI DBaaS MCP Server") - parser.add_argument( - "--resources", "-r", type=str, help="Comma-separated resources (e.g. databases)" - ) - args = parser.parse_args() - - allowed = [r.strip() for r in args.resources.split(",")] if args.resources else None - register_tools(allowed) - + register_tools() print("Server running...") mcp.run(transport="stdio") From 1e91fd84aff1766e17997556eb603e76b65162f8 Mon Sep 17 00:00:00 2001 From: Shyam N V Date: Mon, 22 Dec 2025 19:55:54 +0530 Subject: [PATCH 4/5] OCI DB Dynamic MCP Server --- src/oci-db-dynamic-mcp-server/README.md | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/oci-db-dynamic-mcp-server/README.md b/src/oci-db-dynamic-mcp-server/README.md index b041d0b4..4193b817 100644 --- a/src/oci-db-dynamic-mcp-server/README.md +++ b/src/oci-db-dynamic-mcp-server/README.md @@ -16,18 +16,13 @@ uv run oracle.oci-db-dynamic-mcp-server The server supports the following environment variables: - `OCI_CONFIG_PROFILE`: OCI configuration profile name (default: "DEFAULT") +- `OCI_ALLOWED_RESOURCES`: A comma-separated list of OCI resources to load (e.g., `database`, `db_system`). If omitted, all available tools are loaded. -## Parameters - -The server accepts the following parameters to control which OCI resources are loaded. This helps reduce startup time and token usage by only loading the tools you need. - -| Parameter | Type | CLI Flag | Description | -| :--- | :--- |:--------------------|:---------------------- | -| **Resources** | String | `--resources or -r` | A comma-separated list of OCI resources to load (e.g., `database`, `db_system`). If omitted, all available tools are loaded. | ## Configuration Example This loads only the dbSystems and the databases resources (case-insensitive) ```json +{ "database-dynamic": { "autoApprove": [], "disabled": false, @@ -36,14 +31,15 @@ This loads only the dbSystems and the databases resources (case-insensitive) "command": "uv", "args": [ "run", - "oracle.oci-db-dynamic-mcp-server", - "--resources", - "dbSystems, databases" + "oracle.oci-db-dynamic-mcp-server" ], "env": { "VIRTUAL_ENV": "Documents/oci-mcp/.venv", - "OCI_CONFIG_PROFILE": "DEFAULT" + "OCI_CONFIG_PROFILE": "DEFAULT", + "OCI_ALLOWED_RESOURCES": "databases, dbSystems" } + } +} ``` ## Tools From 3af11670877dfe4b6a33dc9b83db4ff1c08a20a1 Mon Sep 17 00:00:00 2001 From: Shyam N V Date: Tue, 23 Dec 2025 01:29:19 +0530 Subject: [PATCH 5/5] OCI DB Dynamic MCP Server --- .../oracle/oci_db_dynamic_mcp_server/server.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/oci-db-dynamic-mcp-server/oracle/oci_db_dynamic_mcp_server/server.py b/src/oci-db-dynamic-mcp-server/oracle/oci_db_dynamic_mcp_server/server.py index 3a333e01..cb39084a 100644 --- a/src/oci-db-dynamic-mcp-server/oracle/oci_db_dynamic_mcp_server/server.py +++ b/src/oci-db-dynamic-mcp-server/oracle/oci_db_dynamic_mcp_server/server.py @@ -19,8 +19,6 @@ mcp = FastMCP(name=__project__) -DEFAULT_ENDPOINT = "https://preprod-database.eu-zurich-1.oraclecloud.com/20160918/" - # ---------------- TYPE MAPPING ---------------- TYPE_MAP = { "integer": "int", @@ -52,12 +50,11 @@ def invoke_oci_api(method, path, params=None, payload=None, headers=None): endpoint = f"https://database.{config['region']}.oraclecloud.com/20160918/" url = endpoint.rstrip("/") + "/" + path.lstrip("/") - user_agent_name = __project__.split("oracle.", 1)[1].split("-server", 1)[0] headers = headers or {"Content-Type": "application/json"} headers["authorization"] = f"Bearer {security_token}" headers["x-oci-secondary-auth"] = "true" - headers["User-Agent"] = user_agent_name + headers["User-Agent"] = "oci-database-mcp-server" with requests.Session() as session: @@ -73,7 +70,7 @@ def invoke_oci_api(method, path, params=None, payload=None, headers=None): prepared = req.prepare() response = session.send(prepared) - return response + return response.text # ---------------- UNFLATTENER ----------------