├── .github ├── pull_request_template.md └── workflows │ ├── build-doc-mcp.yml │ ├── build.yml │ └── lint.yml ├── .gitignore ├── BEST_PRACTICES.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE.txt ├── Makefile ├── README.md ├── SECURITY.md ├── oracle.svg ├── requirements-dev.txt ├── requirements.txt ├── scripts ├── .gitignore ├── README.md ├── commands_3.66.1.txt ├── denylist └── oci-api-denylist-generator.py ├── src ├── database-mcp-server │ ├── LICENSE.txt │ ├── README.md │ ├── oracle │ │ ├── __init__.py │ │ └── database_mcp_server │ │ │ ├── __init__.py │ │ │ ├── models.py │ │ │ ├── server.py │ │ │ └── tests │ │ │ └── test_database.py │ ├── pyproject.toml │ └── uv.lock ├── dbtools-mcp-server │ ├── README.md │ ├── dbtools-mcp-server.py │ ├── requirements.txt │ └── test_dbtools_mcp_server.py ├── mysql-mcp-server │ ├── README.md │ ├── example_config.json │ ├── local_config.json │ ├── mysql_mcp_server.py │ ├── requirements.txt │ ├── test_mysql_mcp_server.py │ └── utils.py ├── oci-api-mcp-server │ ├── LICENSE.txt │ ├── README.md │ ├── oracle │ │ ├── __init__.py │ │ └── oci_api_mcp_server │ │ │ ├── __init__.py │ │ │ ├── denylist │ │ │ ├── denylist.py │ │ │ ├── server.py │ │ │ ├── tests │ │ │ └── test_oci_api_tools.py │ │ │ └── utils.py │ ├── pyproject.toml │ └── uv.lock ├── oci-cloud-guard-mcp-server │ ├── .python-version │ ├── LICENSE.txt │ ├── README.md │ ├── oracle │ │ ├── __init__.py │ │ └── oci_cloud_guard_mcp_server │ │ │ ├── __init__.py │ │ │ ├── models.py │ │ │ ├── server.py │ │ │ └── tests │ │ │ └── test_cloud_guard_tools.py │ ├── pyproject.toml │ └── uv.lock ├── oci-compute-instance-agent-mcp-server │ ├── .python-version │ ├── LICENSE.txt │ ├── README.md │ ├── oracle │ │ ├── __init__.py │ │ └── oci_compute_instance_agent_mcp_server │ │ │ ├── __init__.py │ │ │ ├── models.py │ │ │ ├── server.py │ │ │ └── tests │ │ │ └── test_compute_instance_agent.py │ ├── pyproject.toml │ └── uv.lock ├── oci-compute-mcp-server │ ├── .python-version │ ├── LICENSE.txt │ ├── README.md │ ├── oracle │ │ ├── __init__.py │ │ └── oci_compute_mcp_server │ │ │ ├── __init__.py │ │ │ ├── consts.py │ │ │ ├── models.py │ │ │ ├── server.py │ │ │ └── tests │ │ │ └── test_compute_tools.py │ ├── pyproject.toml │ └── uv.lock ├── oci-identity-mcp-server │ ├── .python-version │ ├── LICENSE.txt │ ├── README.md │ ├── oracle │ │ ├── __init__.py │ │ └── oci_identity_mcp_server │ │ │ ├── __init__.py │ │ │ ├── server.py │ │ │ └── tests │ │ │ └── test_identity_tools.py │ ├── pyproject.toml │ └── uv.lock ├── oci-logging-mcp-server │ ├── .python-version │ ├── LICENSE.txt │ ├── README.md │ ├── oracle │ │ ├── __init__.py │ │ └── oci_logging_mcp_server │ │ │ ├── __init__.py │ │ │ ├── models.py │ │ │ ├── scripts.py │ │ │ ├── scripts │ │ │ ├── SEARCH_LOG.md │ │ │ └── SEARCH_LOG_EVENT_TYPES.md │ │ │ ├── server.py │ │ │ └── tests │ │ │ └── test_logging_tools.py │ ├── pyproject.toml │ └── uv.lock ├── oci-migration-mcp-server │ ├── .python-version │ ├── LICENSE.txt │ ├── README.md │ ├── oracle │ │ ├── __init__.py │ │ └── oci_migration_mcp_server │ │ │ ├── __init__.py │ │ │ ├── server.py │ │ │ └── tests │ │ │ └── test_migration_tools.py │ ├── pyproject.toml │ └── uv.lock ├── oci-monitoring-mcp-server │ ├── .python-version │ ├── LICENSE.txt │ ├── README.md │ ├── oracle │ │ ├── __init__.py │ │ └── oci_monitoring_mcp_server │ │ │ ├── __init__.py │ │ │ ├── server.py │ │ │ └── tests │ │ │ └── test_monitoring_tools.py │ ├── pyproject.toml │ └── uv.lock ├── oci-network-load-balancer-mcp-server │ ├── .python-version │ ├── LICENSE.txt │ ├── README.md │ ├── oracle │ │ ├── __init__.py │ │ └── oci_network_load_balancer_mcp_server │ │ │ ├── __init__.py │ │ │ ├── server.py │ │ │ └── tests │ │ │ └── test_network_load_balancer_tools.py │ ├── pyproject.toml │ └── uv.lock ├── oci-networking-mcp-server │ ├── .python-version │ ├── LICENSE.txt │ ├── README.md │ ├── oracle │ │ ├── __init__.py │ │ └── oci_networking_mcp_server │ │ │ ├── __init__.py │ │ │ ├── models.py │ │ │ ├── server.py │ │ │ └── tests │ │ │ └── test_networking_tools.py │ ├── pyproject.toml │ └── uv.lock ├── oci-object-storage-mcp-server │ ├── .python-version │ ├── LICENSE.txt │ ├── README.md │ ├── oracle │ │ ├── __init__.py │ │ └── oci_object_storage_mcp_server │ │ │ ├── __init__.py │ │ │ ├── models.py │ │ │ ├── server.py │ │ │ └── tests │ │ │ └── test_object_storage_tools.py │ ├── pyproject.toml │ └── uv.lock ├── oci-pricing-mcp-server │ ├── .dockerignore │ ├── .gitignore │ ├── Dockerfile │ ├── LICENSE.txt │ ├── README.md │ ├── oci-pricing-mcp-server.py │ ├── pyproject.toml │ └── test_oci_pricing_mcp_server.py ├── oci-registry-mcp-server │ ├── .python-version │ ├── LICENSE.txt │ ├── README.md │ ├── oracle │ │ ├── __init__.py │ │ └── oci_registry_mcp_server │ │ │ ├── __init__.py │ │ │ ├── server.py │ │ │ └── tests │ │ │ └── test_registry_tools.py │ ├── pyproject.toml │ └── uv.lock ├── oci-resource-search-mcp-server │ ├── .python-version │ ├── LICENSE.txt │ ├── README.md │ ├── oracle │ │ ├── __init__.py │ │ └── oci_resource_search_mcp_server │ │ │ ├── __init__.py │ │ │ ├── server.py │ │ │ └── tests │ │ │ └── test_resource_search_tools.py │ ├── pyproject.toml │ └── uv.lock ├── oci-usage-mcp-server │ ├── LICENSE.txt │ ├── README.md │ ├── oracle │ │ ├── __init__.py │ │ └── oci_usage_mcp_server │ │ │ ├── __init__.py │ │ │ ├── server.py │ │ │ └── tests │ │ │ └── test_usage_tools.py │ ├── pyproject.toml │ └── uv.lock └── oracle-db-doc-mcp-server │ ├── .gitignore │ ├── Dockerfile │ ├── README.md │ ├── fastmcp.json │ ├── oracle-db-doc-mcp-server.py │ ├── pyproject.toml │ └── requirements.txt ├── tests ├── LICENSE.txt ├── README.md ├── e2e │ └── features │ │ ├── .env.template │ │ ├── environment.py │ │ ├── general-prompts.feature │ │ ├── mcphost.json │ │ ├── oci-api-mcp-server.feature │ │ ├── oci-compute-mcp-server.feature │ │ ├── oci-object-storage-mcp-server.feature │ │ └── steps │ │ ├── general-prompts.py │ │ ├── oci-api-mcp-server-steps.py │ │ ├── oci-compute-mcp-server-steps.py │ │ └── oci-object-storage-mcp-server-steps.py ├── pyproject.toml └── uv.lock └── tox.ini /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | # Description 2 | 3 | Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change. 4 | 5 | Fixes # (issue) 6 | 7 | ## Type of change 8 | 9 | Please delete options that are not relevant. 10 | 11 | - [ ] Bug fix (non-breaking change which fixes an issue) 12 | - [ ] New feature (non-breaking change which adds functionality) 13 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) 14 | - [ ] This change requires a documentation update 15 | 16 | # How Has This Been Tested? 17 | 18 | Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration 19 | 20 | - [ ] Test A 21 | - [ ] Test B 22 | 23 | **Test Configuration**: 24 | * Firmware version: 25 | * Hardware: 26 | * Toolchain: 27 | * SDK: 28 | 29 | # Checklist: 30 | 31 | - [ ] My code follows the style guidelines of this project 32 | - [ ] I have performed a self-review of my own code 33 | - [ ] I have commented my code, particularly in hard-to-understand areas 34 | - [ ] I have made corresponding changes to the documentation 35 | - [ ] My changes generate no new warnings 36 | - [ ] I have added tests that prove my fix is effective or that my feature works 37 | - [ ] New and existing unit tests pass locally with my changes 38 | - [ ] Any dependent changes have been merged and published in downstream modules 39 | -------------------------------------------------------------------------------- /.github/workflows/build-doc-mcp.yml: -------------------------------------------------------------------------------- 1 | name: 🛠️ Build Docker image for Oracle Database Documentation MCP Server 2 | on: 3 | push: 4 | branches: 5 | - main 6 | paths: 7 | - "src/oracle-db-doc-mcp-server/**" 8 | - ".github/workflows/build-doc-mcp.yml" 9 | 10 | jobs: 11 | build-image: 12 | strategy: 13 | matrix: 14 | runner: ["ubuntu-24.04", "ubuntu-24.04-arm"] 15 | 16 | permissions: 17 | packages: write 18 | 19 | name: 🛠️ Build image 20 | runs-on: ${{ matrix.runner }} 21 | 22 | steps: 23 | - name: 📂 Checkout repo 24 | uses: actions/checkout@v4 25 | 26 | - name: 🔄 Generate environment variables 27 | id: os_arch 28 | run: | 29 | if [ "$(uname -m)" == "aarch64" ]; then 30 | echo "OS_ARCH=arm64" >> "$GITHUB_OUTPUT" 31 | else 32 | echo "OS_ARCH=amd64" >> "$GITHUB_OUTPUT" 33 | fi; 34 | 35 | - name: Build image 36 | run: | 37 | cd src/oracle-db-doc-mcp-server/ 38 | buildah bud -f Dockerfile -t oracle-db-doc:latest-${{ steps.os_arch.outputs.OS_ARCH }} . 39 | 40 | - name: 🫸 Push arch-specific image to Container Registry 41 | run: | 42 | podman login ghcr.io -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }} 43 | podman tag oracle-db-doc:latest-${{ steps.os_arch.outputs.OS_ARCH }} ghcr.io/oracle/mcp/oracle-db-doc:latest-${{ steps.os_arch.outputs.OS_ARCH }} 44 | podman push ghcr.io/oracle/mcp/oracle-db-doc:latest-${{ steps.os_arch.outputs.OS_ARCH }} 45 | 46 | upload-multi-arch: 47 | name: 🫸 Push multi-arch manifest 48 | runs-on: "ubuntu-24.04" 49 | needs: build-image 50 | 51 | permissions: 52 | packages: write 53 | 54 | steps: 55 | - name: 🫸 Push multi-arch image to Container Registry 56 | run: | 57 | podman login ghcr.io -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }} 58 | podman manifest create ghcr.io/oracle/mcp/oracle-db-doc:latest 59 | podman manifest add ghcr.io/oracle/mcp/oracle-db-doc:latest ghcr.io/oracle/mcp/oracle-db-doc:latest-amd64 60 | podman manifest add ghcr.io/oracle/mcp/oracle-db-doc:latest ghcr.io/oracle/mcp/oracle-db-doc:latest-arm64 61 | podman push ghcr.io/oracle/mcp/oracle-db-doc:latest 62 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build and Test 2 | on: 3 | push: 4 | branches: 5 | - "main" 6 | pull_request: 7 | branches: 8 | - "main" 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | needs: get-directories 13 | strategy: 14 | matrix: 15 | directory: ${{ fromJson(needs.get-directories.outputs.directories) }} 16 | steps: 17 | - name: Checkout code 18 | uses: actions/checkout@v4 19 | 20 | - name: Set up Python 21 | uses: actions/setup-python@v5 22 | with: 23 | python-version: "3.13" 24 | 25 | - name: Install requirements 26 | run: pip install -r requirements-dev.txt 27 | 28 | - name: Update __init__.py 29 | working-directory: src/${{ matrix.directory }} 30 | run: | 31 | name=$(uv run tomlq -r '.project.name' pyproject.toml) 32 | version=$(uv run tomlq -r '.project.version' pyproject.toml) 33 | if [ -d oracle/*_mcp_server ]; then 34 | init_py_file=oracle/*_mcp_server/__init__.py 35 | echo "\"\"\"\nCopyright (c) 2025, Oracle and/or its affiliates.\nLicensed under the Universal Permissive License v1.0 as shown at\nhttps://oss.oracle.com/licenses/upl.\n\"\"\"\n" > $$init_py_file; \ 36 | echo "__project__ = \"$name\"" >> $init_py_file 37 | echo "__version__ = \"$version\"" >> $init_py_file 38 | fi 39 | 40 | - name: Sync 41 | working-directory: src/${{ matrix.directory }} 42 | run: uv sync --locked --all-extras --dev 43 | 44 | - name: Test and Coverage 45 | working-directory: src/${{ matrix.directory }} 46 | run: uv run pytest --cov=. --cov-branch --cov-report=html:htmlcov/${{ matrix.directory }} --cov-report=term-missing 47 | env: 48 | COVERAGE_FILE: .coverage.${{ matrix.directory }} 49 | 50 | - name: Build 51 | working-directory: src/${{ matrix.directory }} 52 | run: uv build 53 | 54 | - name: Test install 55 | working-directory: src/${{ matrix.directory }} 56 | run: uv pip install . 57 | 58 | - name: Upload coverage report 59 | uses: actions/upload-artifact@v4 60 | with: 61 | name: ${{ matrix.directory }}-coverage-report 62 | path: | 63 | src/${{ matrix.directory }}/htmlcov/* 64 | src/${{ matrix.directory }}/.coverage.${{ matrix.directory }} 65 | include-hidden-files: true 66 | 67 | get-directories: 68 | runs-on: ubuntu-latest 69 | outputs: 70 | directories: ${{ steps.get-directories.outputs.directories }} 71 | steps: 72 | - name: Checkout code 73 | uses: actions/checkout@v4 74 | 75 | - name: Get directories 76 | id: get-directories 77 | run: | 78 | directories=$(ls src | grep -v dbtools-mcp-server | grep -v mysql-mcp-server | grep -v oci-pricing-mcp-server | grep -v oracle-db-doc-mcp-server | jq -R -s -c 'split("\n")[:-1]') 79 | echo "directories=$directories" >> $GITHUB_OUTPUT 80 | 81 | combined-coverage: 82 | runs-on: ubuntu-latest 83 | needs: build 84 | steps: 85 | - name: Checkout code 86 | uses: actions/checkout@v4 87 | 88 | - name: Set up Python 89 | uses: actions/setup-python@v5 90 | with: 91 | python-version: "3.13" 92 | 93 | - name: Install requirements 94 | run: pip install -r requirements-dev.txt 95 | 96 | - name: Download Artifacts 97 | uses: actions/download-artifact@v4 98 | with: 99 | pattern: '*-coverage-report' # Downloads all artifacts starting with 'my-artifact-' 100 | merge-multiple: true # Merges the contents of multiple artifacts into a single directory 101 | 102 | - name: Combine Coverage reports 103 | run: | 104 | make combine-coverage 105 | 106 | - name: Upload combined reports 107 | uses: actions/upload-artifact@v4 108 | with: 109 | name: all-in-one-coverage-report 110 | path: | 111 | oracle-mcp-coverage-report/* 112 | .coverage 113 | include-hidden-files: true 114 | 115 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | on: 3 | push: 4 | branches: 5 | - "main" 6 | pull_request: 7 | branches: 8 | - "main" 9 | jobs: 10 | lint: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v4 14 | - name: Set up Python 3.13 15 | uses: actions/setup-python@v3 16 | with: 17 | python-version: 3.13 18 | - name: Install dependencies 19 | run: | 20 | python -m pip install --upgrade pip 21 | python -m pip install -r requirements-dev.txt 22 | - name: Test with tox 23 | run: | 24 | tox run -e lint 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/__pycache__/** 2 | 3 | # Virtual environment 4 | venv/ 5 | .env/ 6 | .venv/ 7 | ENV/ 8 | env/ 9 | env.bak/ 10 | venv.bak/ 11 | 12 | # Python uv 13 | .python-version 14 | 15 | # VScode 16 | .vscode 17 | 18 | # Mac files 19 | .DS_Store 20 | 21 | #IDE 22 | .idea 23 | 24 | # test environments 25 | .env 26 | 27 | .coverage* 28 | htmlcov/ 29 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to make participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies within all project spaces, and it also applies when 49 | an individual is representing the project or its community in public spaces. 50 | Examples of representing a project or community include using an official 51 | project e-mail address, posting via an official social media account, or acting 52 | as an appointed representative at an online or offline event. Representation of 53 | a project may be further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at . All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | *Detailed instructions on how to contribute to the project, if applicable. Must include section about Oracle Contributor Agreement with link and instructions* 2 | 3 | # Contributing to this repository 4 | 5 | We welcome your contributions! There are multiple ways to contribute. 6 | 7 | ## Opening issues 8 | 9 | For bugs or enhancement requests, please file a GitHub issue unless it's 10 | security related. When filing a bug remember that the better written the bug is, 11 | the more likely it is to be fixed. If you think you've found a security 12 | vulnerability, do not raise a GitHub issue and follow the instructions in our 13 | [security policy](./SECURITY.md). 14 | 15 | ## Contributing code 16 | 17 | We welcome your code contributions. Before submitting code via a pull request, 18 | you will need to have signed the [Oracle Contributor Agreement][OCA] (OCA) and 19 | your commits need to include the following line using the name and e-mail 20 | address you used to sign the OCA: 21 | 22 | ```text 23 | Signed-off-by: Your Name 24 | ``` 25 | 26 | This can be automatically added to pull requests by committing with `--sign-off` 27 | or `-s`, e.g. 28 | 29 | ```text 30 | git commit --signoff 31 | ``` 32 | 33 | Only pull requests from committers that can be verified as having signed the OCA 34 | can be accepted. 35 | 36 | ## Pull request process 37 | 38 | 1. Ensure there is an issue created to track and discuss the fix or enhancement 39 | you intend to submit. 40 | 2. Fork this repository. 41 | 3. Create a branch in your fork to implement the changes. We recommend using 42 | the issue number as part of your branch name, e.g. `1234-fixes`. 43 | 4. Ensure that any documentation is updated with the changes that are required 44 | by your change. 45 | 5. Ensure that any samples are updated if the base image has been changed. 46 | 6. Submit the pull request. *Do not leave the pull request blank*. Explain exactly 47 | what your changes are meant to do and provide simple steps on how to validate. 48 | your changes. Ensure that you reference the issue you created as well. 49 | 1. We will assign the pull request to 2-3 people for review before it is merged. 50 | 51 | ## Code of conduct 52 | 53 | Follow the [Golden Rule](https://en.wikipedia.org/wiki/Golden_Rule). If you'd 54 | like more specific guidelines, see the [Contributor Covenant Code of Conduct][COC]. 55 | 56 | [OCA]: https://oca.opensource.oracle.com 57 | [COC]: https://www.contributor-covenant.org/version/1/4/code-of-conduct/ 58 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2025 Oracle and/or its affiliates. 2 | 3 | The Universal Permissive License (UPL), Version 1.0 4 | 5 | Subject to the condition set forth below, permission is hereby granted to any 6 | person obtaining a copy of this software, associated documentation and/or data 7 | (collectively the "Software"), free of charge and under any and all copyright 8 | rights in the Software, and any and all patent rights owned or freely 9 | licensable by each licensor hereunder covering either (i) the unmodified 10 | Software as contributed to or provided by such licensor, or (ii) the Larger 11 | Works (as defined below), to deal in both 12 | 13 | (a) the Software, and 14 | (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if 15 | one is included with the Software (each a "Larger Work" to which the Software 16 | is contributed by such licensors), 17 | 18 | without restriction, including without limitation the rights to copy, create 19 | derivative works of, display, perform, and distribute the Software and make, 20 | use, sell, offer for sale, import, export, have made, and have sold the 21 | Software and the Larger Work(s), and to sublicense the foregoing rights on 22 | either these or other terms. 23 | 24 | This license is subject to the following condition: 25 | The above copyright notice and either this complete permission notice or at 26 | a minimum a reference to the UPL must be included in all copies or 27 | substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 35 | SOFTWARE. 36 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SUBDIRS := $(filter-out src/dbtools-mcp-server src/mysql-mcp-server src/oci-pricing-mcp-server src/oracle-db-doc-mcp-server,$(wildcard src/*)) 2 | 3 | .PHONY: test format 4 | 5 | build: 6 | @for dir in $(SUBDIRS); do \ 7 | if [ -f $$dir/pyproject.toml ]; then \ 8 | echo "Building $$dir"; \ 9 | name=$$(uv run tomlq -r '.project.name' $$dir/pyproject.toml); \ 10 | version=$$(uv run tomlq -r '.project.version' $$dir/pyproject.toml); \ 11 | if [ -d $$dir/oracle/*_mcp_server ]; then \ 12 | init_py_file=$$(echo $$dir/oracle/*_mcp_server/__init__.py); \ 13 | echo "\"\"\"\nCopyright (c) 2025, Oracle and/or its affiliates.\nLicensed under the Universal Permissive License v1.0 as shown at\nhttps://oss.oracle.com/licenses/upl.\n\"\"\"\n" > $$init_py_file; \ 14 | echo "__project__ = \"$$name\"" >> $$init_py_file; \ 15 | echo "__version__ = \"$$version\"" >> $$init_py_file; \ 16 | fi; \ 17 | cd $$dir && uv build && cd ../..; \ 18 | fi \ 19 | done 20 | 21 | install: 22 | @for dir in $(SUBDIRS); do \ 23 | if [ -f $$dir/pyproject.toml ]; then \ 24 | echo "Installing $$dir"; \ 25 | cd $$dir && uv pip install . && cd ../..; \ 26 | fi \ 27 | done 28 | 29 | sync: 30 | @for dir in $(SUBDIRS); do \ 31 | if [ -f $$dir/pyproject.toml ]; then \ 32 | echo "Installing $$dir"; \ 33 | cd $$dir && uv sync --locked --all-extras --dev && cd ../..; \ 34 | fi \ 35 | done 36 | 37 | lock: 38 | @for dir in $(SUBDIRS); do \ 39 | if [ -f $$dir/pyproject.toml ]; then \ 40 | echo "Installing $$dir"; \ 41 | cd $$dir && uv lock && cd ../..; \ 42 | fi \ 43 | done 44 | 45 | lint: 46 | uv tool run --from 'tox==4.30.2' tox -e lint 47 | 48 | test: 49 | @for dir in $(SUBDIRS); do \ 50 | if [ -f $$dir/pyproject.toml ]; then \ 51 | echo "Testing $$dir"; \ 52 | cd $$dir && \ 53 | COVERAGE_FILE=../../.coverage.$$(_basename=$$(basename $$dir); echo $$_basename) \ 54 | uv run pytest --cov=. --cov-branch --cov-append --cov-report=html --cov-report=term-missing && \ 55 | cd ../..; \ 56 | fi \ 57 | done 58 | $(MAKE) combine-coverage 59 | 60 | combine-coverage: 61 | uv run coverage combine 62 | uv run coverage html 63 | uv run coverage report --fail-under=69 64 | 65 | format: 66 | uv tool run --from 'tox==4.30.2' tox -e format 67 | 68 | e2e-tests: build install 69 | behave tests/e2e/features && cd .. 70 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Reporting security vulnerabilities 2 | 3 | Oracle values the independent security research community and believes that 4 | responsible disclosure of security vulnerabilities helps us ensure the security 5 | and privacy of all our users. 6 | 7 | Please do NOT raise a GitHub Issue to report a security vulnerability. If you 8 | believe you have found a security vulnerability, please submit a report to 9 | [secalert_us@oracle.com][1] preferably with a proof of concept. Please review 10 | some additional information on [how to report security vulnerabilities to Oracle][2]. 11 | We encourage people who contact Oracle Security to use email encryption using 12 | [our encryption key][3]. 13 | 14 | We ask that you do not use other channels or contact the project maintainers 15 | directly. 16 | 17 | Non-vulnerability related security issues including ideas for new or improved 18 | security features are welcome on GitHub Issues. 19 | 20 | ## Security updates, alerts and bulletins 21 | 22 | Security updates will be released on a regular cadence. Many of our projects 23 | will typically release security fixes in conjunction with the 24 | Oracle Critical Patch Update program. Additional 25 | information, including past advisories, is available on our [security alerts][4] 26 | page. 27 | 28 | ## Security-related information 29 | 30 | We will provide security related information such as a threat model, considerations 31 | for secure use, or any known security issues in our documentation. Please note 32 | that labs and sample code are intended to demonstrate a concept and may not be 33 | sufficiently hardened for production use. 34 | 35 | [1]: mailto:secalert_us@oracle.com 36 | [2]: https://www.oracle.com/corporate/security-practices/assurance/vulnerability/reporting.html 37 | [3]: https://www.oracle.com/security-alerts/encryptionkey.html 38 | [4]: https://www.oracle.com/security-alerts/ 39 | -------------------------------------------------------------------------------- /oracle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /requirements-dev.txt: -------------------------------------------------------------------------------- 1 | -r requirements.txt 2 | pytest 3 | pytest-asyncio 4 | pytest-cov 5 | tox 6 | tomlq 7 | uv 8 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pydantic 2 | fastmcp 3 | oci 4 | -------------------------------------------------------------------------------- /scripts/.gitignore: -------------------------------------------------------------------------------- 1 | *_backup* 2 | denylist_* 3 | -------------------------------------------------------------------------------- /scripts/README.md: -------------------------------------------------------------------------------- 1 | # OCI API Deny List Generator 2 | 3 | ## Overview 4 | 5 | The `oci-api-denylist-generator.py` script generates a deny list of OCI CLI commands that can modify the cloud system's configuration. It creates a list of commands to be denied execution by filtering out commands containing actions like "delete", "terminate", "put", "update", "replace", "remove", and "patch". 6 | 7 | ## Usage 8 | 9 | To generate an updated version of the deny list, follow these steps: 10 | 11 | 1. Ensure you have the OCI CLI installed and configured on your system. 12 | 2. Navigate to the `scripts` directory. 13 | 3. Run the `oci-api-denylist-generator.py` script using Python: 14 | ```bash 15 | python oci-api-denylist-generator.py 16 | ``` 17 | 4. The script will generate a new `denylist_` file and update the `denylist` file with the latest deny list based on the current OCI CLI version. 18 | 5. To use the newly generated deny list, copy the denylist to the [oci-api-mcp-server denylist](../src/oci-api-mcp-server/oracle/oci_api_mcp_server/denylist) and restart the `oci-api-mcp-server`. 19 | 20 | ## Notes 21 | 22 | - The script automatically backs up the existing deny list file if it already exists for the current OCI CLI version. 23 | - The deny list includes commands that can potentially change the configuration of the cloud system. 24 | - The generated `denylist` file is used by the AI client to determine which commands to deny execution for. 25 | 26 | ---- 27 | 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. 28 | -------------------------------------------------------------------------------- /scripts/oci-api-denylist-generator.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | 7 | import os 8 | import re 9 | import subprocess 10 | from datetime import datetime 11 | 12 | 13 | def get_oci_version(): 14 | result = subprocess.run( 15 | ["oci", "--version", "--raw-output"], capture_output=True, text=True 16 | ) 17 | return result.stdout.strip() 18 | 19 | 20 | def get_services(): 21 | result = subprocess.run(["oci", "--help"], capture_output=True, text=True) 22 | output = result.stdout.splitlines() 23 | services = [] 24 | for line in output: 25 | match = re.match(r"^\s{4}(\w+(-\w+)*)", line) 26 | if match: 27 | services.append(match.group(1)) 28 | services = services[5:] # Skipping the first 5 lines as they are not services 29 | services.sort() 30 | return services 31 | 32 | 33 | def get_sub_commands(command: str): 34 | indentation_level = len(command.split()) 35 | print(f"{' '*indentation_level}Getting subcommands for: {command}") 36 | try: 37 | result = subprocess.run( 38 | f"oci {command} --help", shell=True, capture_output=True, text=True 39 | ) 40 | output = result.stdout.splitlines() 41 | sub_commands = [] 42 | in_commands_section = False 43 | for line in output: 44 | if "Commands:" in line: 45 | in_commands_section = True 46 | continue 47 | if in_commands_section: 48 | if line.startswith(" "): 49 | continue 50 | # match = re.match(r"^\s{2}(\w+)", line) 51 | match = line.split()[0] 52 | if match: 53 | print(f"{' '*indentation_level}Appending sub command {match}") 54 | sub_commands.append(match) 55 | if not sub_commands: 56 | return [command] 57 | else: 58 | commands = [] 59 | for sub_command in sub_commands: 60 | commands.extend(get_sub_commands(f"{command} {sub_command}")) 61 | return commands 62 | except Exception as e: 63 | print(f"Error getting sub-commands for {command}: {e}") 64 | return [] 65 | 66 | 67 | def get_commands(version): 68 | commands_file = f"commands_{version}.txt" 69 | if not os.path.exists(commands_file): 70 | print(f"Creating {commands_file} file..") 71 | services = get_services() 72 | with open(commands_file, "w") as f: 73 | f.write( 74 | ( 75 | "# Copyright (c) 2025, Oracle and/or its affiliates.\n" 76 | "# Licensed under the Universal Permissive License v1.0 as shown at\n" 77 | "# https://oss.oracle.com/licenses/upl.\n\n" 78 | "# This list contains all OCI cli commands\n\n" 79 | ) 80 | ) 81 | 82 | for service in services: 83 | print(f"Generating commands for service: {service}") 84 | commands = get_sub_commands(service) 85 | for command in commands: 86 | f.write(command + "\n") 87 | f.flush() 88 | else: 89 | print(f"Commands already exist for version {version}") 90 | 91 | 92 | def create_denylist(version): 93 | denylist_prefix = "denylist" 94 | denylist_filename = f"{denylist_prefix}_{version}" 95 | commands_file = f"commands_{version}.txt" 96 | 97 | if os.path.exists(denylist_filename): 98 | backup_filename = ( 99 | f"{denylist_filename}_backup_{datetime.now().strftime('%d%b%y_%H%M')}" 100 | ) 101 | os.rename(denylist_filename, backup_filename) 102 | 103 | with open(commands_file, "r") as f: 104 | commands = [ 105 | line.strip() 106 | for line in f 107 | if not line.strip().startswith("#") and len(line.strip()) > 0 108 | ] 109 | 110 | actions = [ 111 | "delete", 112 | "terminate", 113 | "put", 114 | "update", 115 | "replace", 116 | "remove", 117 | "patch", 118 | ] 119 | 120 | denied_commands = [ 121 | cmd.strip() 122 | for cmd in commands 123 | if any(cmd.split()[-1].startswith(action) for action in actions) 124 | ] 125 | 126 | with open(denylist_filename, "w") as f: 127 | for command in sorted(denied_commands): 128 | f.write(command + "\n") 129 | 130 | with open(denylist_prefix, "w") as f: 131 | f.write( 132 | ( 133 | "# Copyright (c) 2025, Oracle and/or its affiliates.\n" 134 | "# Licensed under the Universal Permissive License v1.0 as shown at\n" 135 | "# https://oss.oracle.com/licenses/upl.\n\n" 136 | "# This list contains the list of commands that can change the configuration of the cloud system.\n" # noqa E501 137 | "# These commands will be denied execution and the AI client should immediately stop processing the command.\n" # noqa E501 138 | "# It should also stop suggesting any alternatives to the user\n\n" 139 | ) 140 | ) 141 | f.write("\n".join(sorted(denied_commands))) 142 | 143 | print(f"{denylist_prefix} has been created successfully") 144 | 145 | denied_count = len(denied_commands) 146 | total_count = len(commands) 147 | print(f"{denied_count} commands will be denied out of {total_count} commands") 148 | 149 | 150 | def main(): 151 | version = get_oci_version() 152 | get_commands(version) 153 | create_denylist(version) 154 | 155 | 156 | if __name__ == "__main__": 157 | main() 158 | -------------------------------------------------------------------------------- /src/database-mcp-server/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2025 Oracle and/or its affiliates. 2 | 3 | The Universal Permissive License (UPL), Version 1.0 4 | 5 | Subject to the condition set forth below, permission is hereby granted to any 6 | person obtaining a copy of this software, associated documentation and/or data 7 | (collectively the "Software"), free of charge and under any and all copyright 8 | rights in the Software, and any and all patent rights owned or freely 9 | licensable by each licensor hereunder covering either (i) the unmodified 10 | Software as contributed to or provided by such licensor, or (ii) the Larger 11 | Works (as defined below), to deal in both 12 | 13 | (a) the Software, and 14 | (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if 15 | one is included with the Software (each a "Larger Work" to which the Software 16 | is contributed by such licensors), 17 | 18 | without restriction, including without limitation the rights to copy, create 19 | derivative works of, display, perform, and distribute the Software and make, 20 | use, sell, offer for sale, import, export, have made, and have sold the 21 | Software and the Larger Work(s), and to sublicense the foregoing rights on 22 | either these or other terms. 23 | 24 | This license is subject to the following condition: 25 | The above copyright notice and either this complete permission notice or at 26 | a minimum a reference to the UPL must be included in all copies or 27 | substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 35 | SOFTWARE. -------------------------------------------------------------------------------- /src/database-mcp-server/oracle/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | -------------------------------------------------------------------------------- /src/database-mcp-server/oracle/database_mcp_server/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | 7 | __project__ = "oracle.database-mcp-server" 8 | __version__ = "1.0.0" 9 | -------------------------------------------------------------------------------- /src/database-mcp-server/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "oracle.database-mcp-server" 3 | version = "1.0.1" 4 | description = "OCI Database Service MCP server" 5 | readme = "README.md" 6 | requires-python = ">=3.13" 7 | license = "UPL-1.0" 8 | license-files = ["LICENSE.txt"] 9 | authors = [ 10 | {name = "Oracle MCP", email = "237432095+oracle-mcp@users.noreply.github.com"}, 11 | ] 12 | dependencies = [ 13 | "fastmcp==2.12.2", 14 | "oci==2.160.0", 15 | "mcp>=1.0.0", 16 | "pytest-cov>=7.0.0", 17 | ] 18 | 19 | classifiers = [ 20 | "License :: OSI Approved :: Universal Permissive License (UPL)", 21 | "Operating System :: OS Independent", 22 | "Programming Language :: Python", 23 | "Programming Language :: Python :: 3.13", 24 | ] 25 | 26 | [project.scripts] 27 | "oracle.database-mcp-server" = "oracle.database_mcp_server.server:main" 28 | 29 | [build-system] 30 | requires = ["hatchling"] 31 | build-backend = "hatchling.build" 32 | 33 | [tool.hatch.build.targets.wheel] 34 | packages = ["oracle"] 35 | 36 | [dependency-groups] 37 | dev = [ 38 | "pytest>=8.4.2", 39 | "pytest-asyncio>=1.2.0", 40 | ] 41 | -------------------------------------------------------------------------------- /src/dbtools-mcp-server/requirements.txt: -------------------------------------------------------------------------------- 1 | oci 2 | requests 3 | fastmcp 4 | -------------------------------------------------------------------------------- /src/mysql-mcp-server/example_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "server_infos": { 3 | "example_local_server": { 4 | "host": "", 5 | "user": "", 6 | "password": "", 7 | "database": "", 8 | "port": 3306 9 | }, 10 | "example_remote_server": { 11 | "host": "", 12 | "user": "", 13 | "password": "", 14 | "database": "", 15 | "port": 3306 16 | } 17 | }, 18 | "bastion": { 19 | "bastion_host": "", 20 | "bastion_username": "", 21 | "private_key_path": "", 22 | "db_host": "", 23 | "db_port": 3306, 24 | "bastion_port": 22, 25 | "local_bind_host": "127.0.0.1", 26 | "local_bind_port": 3306 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/mysql-mcp-server/local_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "server_infos": { 3 | "local_server": { 4 | "host": "localhost", 5 | "user": "root", 6 | "password": "", 7 | "database": "mysql_mcp", 8 | "port": 3306 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/mysql-mcp-server/requirements.txt: -------------------------------------------------------------------------------- 1 | oci 2 | fastmcp 3 | mysql-connector-python 4 | -------------------------------------------------------------------------------- /src/oci-api-mcp-server/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2025 Oracle and/or its affiliates. 2 | 3 | The Universal Permissive License (UPL), Version 1.0 4 | 5 | Subject to the condition set forth below, permission is hereby granted to any 6 | person obtaining a copy of this software, associated documentation and/or data 7 | (collectively the "Software"), free of charge and under any and all copyright 8 | rights in the Software, and any and all patent rights owned or freely 9 | licensable by each licensor hereunder covering either (i) the unmodified 10 | Software as contributed to or provided by such licensor, or (ii) the Larger 11 | Works (as defined below), to deal in both 12 | 13 | (a) the Software, and 14 | (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if 15 | one is included with the Software (each a "Larger Work" to which the Software 16 | is contributed by such licensors), 17 | 18 | without restriction, including without limitation the rights to copy, create 19 | derivative works of, display, perform, and distribute the Software and make, 20 | use, sell, offer for sale, import, export, have made, and have sold the 21 | Software and the Larger Work(s), and to sublicense the foregoing rights on 22 | either these or other terms. 23 | 24 | This license is subject to the following condition: 25 | The above copyright notice and either this complete permission notice or at 26 | a minimum a reference to the UPL must be included in all copies or 27 | substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 35 | SOFTWARE. -------------------------------------------------------------------------------- /src/oci-api-mcp-server/README.md: -------------------------------------------------------------------------------- 1 | # OCI API MCP Server 2 | 3 | ## Overview 4 | 5 | This server provides tools to run OCI CLI commands to interact with the OCI services. 6 | It includes tools to help with OCI command execution and provide helpful information. 7 | 8 | ## Running the server 9 | 10 | ```sh 11 | uv run oracle.oci-api-mcp-server 12 | ``` 13 | ## Tools 14 | 15 | | Tool Name | Description | 16 | | --- | --- | 17 | | get_oci_command_help | Returns helpful instructions for running an OCI CLI command. Only provide the command after 'oci', do not include the string 'oci' in your command. | 18 | | run_oci_command | Runs an OCI CLI command. This tool allows you to run OCI CLI commands on the user's behalf. Only provide the command after 'oci', do not include the string 'oci' in your command. | 19 | | get_oci_commands (Resource) | Returns helpful information on various OCI services and related commands. | 20 | 21 | ⚠️ **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. 22 | 23 | ## Third-Party APIs 24 | 25 | 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. 26 | 27 | ## Disclaimer 28 | 29 | Users are responsible for their local environment and credential safety. Different language model selections may yield different results and performance. 30 | 31 | ## License 32 | 33 | Copyright (c) 2025 Oracle and/or its affiliates. 34 | 35 | Released under the Universal Permissive License v1.0 as shown at 36 | . 37 | -------------------------------------------------------------------------------- /src/oci-api-mcp-server/oracle/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | -------------------------------------------------------------------------------- /src/oci-api-mcp-server/oracle/oci_api_mcp_server/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | 7 | __project__ = "oracle.oci-api-mcp-server" 8 | __version__ = "1.0.2" 9 | -------------------------------------------------------------------------------- /src/oci-api-mcp-server/oracle/oci_api_mcp_server/denylist.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | 7 | import os 8 | 9 | 10 | class Denylist: 11 | _denylist_path = os.path.join(os.path.dirname(__file__), "denylist") 12 | 13 | def __init__(self, logger, user_specific_path: str = ""): 14 | self.logger = logger 15 | self.denylist_path = user_specific_path or self._denylist_path 16 | self.denylist = self.read_denylist() 17 | self.logger.info( 18 | "Read denylist from %s successfully. Blocking %d commands", 19 | self._denylist_path, 20 | len(self.denylist), 21 | ) 22 | 23 | def read_denylist(self): 24 | try: 25 | with open(self.denylist_path, "r") as denylist_file: 26 | return [ 27 | line.strip() 28 | for line in denylist_file.read().splitlines() 29 | if line.strip() and not line.strip().startswith("#") 30 | ] 31 | except FileNotFoundError: 32 | self.logger.warning(f"Denylist file not found at {self.denylist_path}") 33 | return [] 34 | 35 | def remove_params_from_command(self, command: str) -> str: 36 | """Removes parameters from an OCI CLI command.""" 37 | command_parts = command.split() 38 | filtered_parts = [] 39 | i = 0 40 | while i < len(command_parts): 41 | if command_parts[i].startswith("--"): 42 | i += ( 43 | 1 44 | if i + 1 >= len(command_parts) 45 | or command_parts[i + 1].startswith("--") 46 | else 2 47 | ) 48 | else: 49 | filtered_parts.append(command_parts[i]) 50 | i += 1 51 | return " ".join(filtered_parts) 52 | 53 | def isCommandInDenyList(self, command: str) -> bool: 54 | command_without_params = self.remove_params_from_command(command.strip()) 55 | self.logger.info("Checking command: %s", command_without_params) 56 | return command_without_params in self.denylist 57 | -------------------------------------------------------------------------------- /src/oci-api-mcp-server/oracle/oci_api_mcp_server/utils.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | 7 | import logging 8 | from logging.handlers import RotatingFileHandler 9 | 10 | 11 | def initAuditLogger(logger): 12 | # Create a rotating file handler 13 | handler = RotatingFileHandler( 14 | "/tmp/audit.log", maxBytes=5 * 1024 * 1024, backupCount=1 15 | ) 16 | handler.setLevel(logging.INFO) 17 | 18 | # Create a logging format 19 | formatter = logging.Formatter( 20 | "%(asctime)s - %(name)s - %(levelname)s - %(message)s" 21 | ) 22 | handler.setFormatter(formatter) 23 | 24 | # Add the handler to the logger 25 | logger.addHandler(handler) 26 | -------------------------------------------------------------------------------- /src/oci-api-mcp-server/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "oracle.oci-api-mcp-server" 3 | version = "1.0.2" 4 | description = "OCI CLI MCP server" 5 | readme = "README.md" 6 | requires-python = ">=3.13" 7 | license = "UPL-1.0" 8 | license-files = ["LICENSE.txt"] 9 | authors = [ 10 | {name = "Oracle MCP", email = "237432095+oracle-mcp@users.noreply.github.com"}, 11 | ] 12 | dependencies = [ 13 | "fastmcp==2.12.2", 14 | "oci==2.160.0", 15 | ] 16 | 17 | classifiers = [ 18 | "License :: OSI Approved :: Universal Permissive License (UPL)", 19 | "Operating System :: OS Independent", 20 | "Programming Language :: Python", 21 | "Programming Language :: Python :: 3.13", 22 | ] 23 | 24 | [project.scripts] 25 | "oracle.oci-api-mcp-server" = "oracle.oci_api_mcp_server.server:main" 26 | 27 | [build-system] 28 | requires = ["hatchling"] 29 | build-backend = "hatchling.build" 30 | 31 | [tool.hatch.build.targets.wheel] 32 | packages = ["oracle"] 33 | 34 | [dependency-groups] 35 | dev = [ 36 | "pytest>=8.4.2", 37 | "pytest-asyncio>=1.2.0", 38 | "pytest-cov>=7.0.0", 39 | ] 40 | 41 | [tool.coverage.run] 42 | omit = [ 43 | "**/__init__.py", 44 | "**/tests/*", 45 | "dist/*", 46 | ".venv/*", 47 | ] 48 | 49 | [tool.coverage.report] 50 | precision = 2 51 | fail_under = 91.81 52 | 53 | 54 | -------------------------------------------------------------------------------- /src/oci-cloud-guard-mcp-server/.python-version: -------------------------------------------------------------------------------- 1 | 3.13 2 | -------------------------------------------------------------------------------- /src/oci-cloud-guard-mcp-server/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2025 Oracle and/or its affiliates. 2 | 3 | The Universal Permissive License (UPL), Version 1.0 4 | 5 | Subject to the condition set forth below, permission is hereby granted to any 6 | person obtaining a copy of this software, associated documentation and/or data 7 | (collectively the "Software"), free of charge and under any and all copyright 8 | rights in the Software, and any and all patent rights owned or freely 9 | licensable by each licensor hereunder covering either (i) the unmodified 10 | Software as contributed to or provided by such licensor, or (ii) the Larger 11 | Works (as defined below), to deal in both 12 | 13 | (a) the Software, and 14 | (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if 15 | one is included with the Software (each a "Larger Work" to which the Software 16 | is contributed by such licensors), 17 | 18 | without restriction, including without limitation the rights to copy, create 19 | derivative works of, display, perform, and distribute the Software and make, 20 | use, sell, offer for sale, import, export, have made, and have sold the 21 | Software and the Larger Work(s), and to sublicense the foregoing rights on 22 | either these or other terms. 23 | 24 | This license is subject to the following condition: 25 | The above copyright notice and either this complete permission notice or at 26 | a minimum a reference to the UPL must be included in all copies or 27 | substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 35 | SOFTWARE. -------------------------------------------------------------------------------- /src/oci-cloud-guard-mcp-server/README.md: -------------------------------------------------------------------------------- 1 | # OCI Cloud Guard MCP Server 2 | 3 | ## Overview 4 | 5 | This package implements certain functions of the [OCI Cloud Guard Service](https://docs.oracle.com/en-us/iaas/Content/cloud-guard/home.htm). 6 | It includes tools to help with managing cloud guard problems. 7 | 8 | ## Running the server 9 | 10 | ```sh 11 | uv run oracle.oci-cloud-guard-mcp-server 12 | ``` 13 | 14 | ## Tools 15 | 16 | | Tool Name | Description | 17 | |-----------------------|-------------------------------------------| 18 | | list_problems | List the problems in a given compartment | 19 | | get_problem_details | Get the problem details with a given OCID | 20 | | update_problem_status | Updates the status of a problem | 21 | 22 | ⚠️ **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. 23 | 24 | ## Third-Party APIs 25 | 26 | 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. 27 | 28 | ## Disclaimer 29 | 30 | Users are responsible for their local environment and credential safety. Different language model selections may yield different results and performance. 31 | 32 | ## License 33 | 34 | Copyright (c) 2025 Oracle and/or its affiliates. 35 | 36 | Released under the Universal Permissive License v1.0 as shown at 37 | . 38 | 39 | 40 | -------------------------------------------------------------------------------- /src/oci-cloud-guard-mcp-server/oracle/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | -------------------------------------------------------------------------------- /src/oci-cloud-guard-mcp-server/oracle/oci_cloud_guard_mcp_server/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | 7 | __project__ = "oracle.oci-cloud-guard-mcp-server" 8 | __version__ = "1.0.0" 9 | -------------------------------------------------------------------------------- /src/oci-cloud-guard-mcp-server/oracle/oci_cloud_guard_mcp_server/server.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | 7 | import os 8 | from datetime import datetime, timedelta, timezone 9 | from logging import Logger 10 | from typing import Literal, Optional 11 | 12 | import oci 13 | from fastmcp import FastMCP 14 | from oci.cloud_guard import CloudGuardClient 15 | from oracle.oci_cloud_guard_mcp_server.models import ( 16 | Problem, 17 | map_problem, 18 | ) 19 | from pydantic import Field 20 | 21 | from . import __project__, __version__ 22 | 23 | logger = Logger(__name__, level="INFO") 24 | 25 | mcp = FastMCP(name=__project__) 26 | 27 | 28 | def get_cloud_guard_client(): 29 | config = oci.config.from_file( 30 | profile_name=os.getenv("OCI_CONFIG_PROFILE", oci.config.DEFAULT_PROFILE) 31 | ) 32 | 33 | user_agent_name = __project__.split("oracle.", 1)[1].split("-server", 1)[0] 34 | config["additional_user_agent"] = f"{user_agent_name}/{__version__}" 35 | 36 | private_key = oci.signer.load_private_key_from_file(config["key_file"]) 37 | token_file = config["security_token_file"] 38 | token = None 39 | with open(token_file, "r") as f: 40 | token = f.read() 41 | signer = oci.auth.signers.SecurityTokenSigner(token, private_key) 42 | return CloudGuardClient(config, signer=signer) 43 | 44 | 45 | @mcp.tool( 46 | name="list_problems", 47 | description="Returns a list of all Problems identified by Cloud Guard.", 48 | ) 49 | def list_problems( 50 | compartment_id: str = Field(..., description="The OCID of the compartment"), 51 | risk_level: Optional[str] = Field(None, description="Risk level of the problem"), 52 | lifecycle_state: Optional[str] = Field( 53 | "ACTIVE", 54 | description="The field lifecycle state. " 55 | "Only one state can be provided. Default value for state is active.", 56 | ), 57 | detector_rule_ids: Optional[list[str]] = Field( 58 | None, 59 | description="Comma separated list of detector rule IDs to be passed in to match against Problems.", 60 | ), 61 | time_range_days: Optional[int] = Field( 62 | 30, description="Number of days to look back for problems" 63 | ), 64 | limit: Optional[int] = Field(10, description="The number of problems to return"), 65 | ) -> list[Problem]: 66 | time_filter = ( 67 | datetime.now(timezone.utc) - timedelta(days=time_range_days) 68 | ).isoformat() 69 | 70 | kwargs = { 71 | "compartment_id": compartment_id, 72 | "time_last_detected_greater_than_or_equal_to": time_filter, 73 | "limit": limit, 74 | } 75 | 76 | if risk_level: 77 | kwargs["risk_level"] = risk_level 78 | if lifecycle_state: 79 | kwargs["lifecycle_state"] = lifecycle_state 80 | if detector_rule_ids: 81 | kwargs["detector_rule_id_list"] = detector_rule_ids 82 | 83 | response = get_cloud_guard_client().list_problems(**kwargs) 84 | 85 | problems: list[Problem] = [] 86 | data: list[oci.cloud_guard.models.Problem] = response.data.items 87 | for d in data: 88 | problem = map_problem(d) 89 | problems.append(problem) 90 | return problems 91 | 92 | 93 | @mcp.tool( 94 | name="get_problem_details", 95 | description="Get the details for a Problem identified by problemId.", 96 | ) 97 | def get_problem_details( 98 | problem_id: str = Field(..., description="The OCID of the problem") 99 | ) -> Problem: 100 | response = get_cloud_guard_client().get_problem(problem_id=problem_id) 101 | problem = response.data 102 | return map_problem(problem) 103 | 104 | 105 | @mcp.tool( 106 | name="update_problem_status", 107 | description="Changes the current status of the problem, identified by problemId, to the status " 108 | "specified in the UpdateProblemStatusDetails resource that you pass.", 109 | ) 110 | def update_problem_status( 111 | problem_id: str = Field(..., description="The OCID of the problem"), 112 | status: str = Field( 113 | Literal["OPEN", "RESOLVED", "DISMISSED", "DELETED", "UNKNOWN_ENUM_VALUE"], 114 | description="Action taken by user. Allowed values are: OPEN, RESOLVED, DISMISSED, CLOSED", 115 | ), 116 | comment: str = Field(None, description="A comment from the user"), 117 | ) -> Problem: 118 | updated_problem_status = oci.cloud_guard.models.UpdateProblemStatusDetails( 119 | status=status, comment=comment 120 | ) 121 | response = get_cloud_guard_client().update_problem_status( 122 | problem_id=problem_id, 123 | update_problem_status_details=updated_problem_status, 124 | ) 125 | problem = response.data 126 | return map_problem(problem) 127 | 128 | 129 | def main(): 130 | mcp.run() 131 | 132 | 133 | if __name__ == "__main__": 134 | main() 135 | -------------------------------------------------------------------------------- /src/oci-cloud-guard-mcp-server/oracle/oci_cloud_guard_mcp_server/tests/test_cloud_guard_tools.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | 7 | # noinspection PyPackageRequirements 8 | from unittest.mock import MagicMock, create_autospec, patch 9 | 10 | import oci 11 | import pytest 12 | from fastmcp import Client 13 | from oracle.oci_cloud_guard_mcp_server.server import mcp 14 | 15 | 16 | class TestResourceSearchTools: 17 | @pytest.mark.asyncio 18 | @patch("oracle.oci_cloud_guard_mcp_server.server.get_cloud_guard_client") 19 | async def test_list_all_problems(self, mock_get_client): 20 | resource_id = "ocid.resource1" 21 | mock_client = MagicMock() 22 | mock_get_client.return_value = mock_client 23 | 24 | mock_problems_response = create_autospec(oci.response.Response) 25 | mock_problems_response.data = oci.cloud_guard.models.ProblemCollection( 26 | items=[ 27 | oci.cloud_guard.models.ProblemSummary( 28 | id=resource_id, 29 | resource_type="instance", 30 | resource_id="resource1", 31 | lifecycle_state="ACTIVE", 32 | lifecycle_detail="OPEN", 33 | ) 34 | ] 35 | ) 36 | mock_client.list_problems.return_value = mock_problems_response 37 | 38 | async with Client(mcp) as client: 39 | result = ( 40 | await client.call_tool( 41 | "list_problems", {"compartment_id": "test_compartment"} 42 | ) 43 | ).structured_content["result"] 44 | 45 | assert len(result) == 1 46 | assert result[0]["id"] == resource_id 47 | 48 | @pytest.mark.asyncio 49 | @patch("oracle.oci_cloud_guard_mcp_server.server.get_cloud_guard_client") 50 | async def test_get_problem_details(self, mock_get_client): 51 | problem_id = "ocid.resource1" 52 | mock_client = MagicMock() 53 | mock_get_client.return_value = mock_client 54 | 55 | mock_get_problem_response = create_autospec(oci.response.Response) 56 | mock_get_problem_response.data = oci.cloud_guard.models.Problem( 57 | id=problem_id, 58 | resource_type="instance", 59 | resource_id="resource1", 60 | lifecycle_state="ACTIVE", 61 | lifecycle_detail="OPEN", 62 | compartment_id="test_compartment", 63 | region="test_region", 64 | impacted_resource_type="123", 65 | impacted_resource_name="123", 66 | risk_level="HIGH", 67 | ) 68 | mock_client.get_problem.return_value = mock_get_problem_response 69 | 70 | async with Client(mcp) as client: 71 | result = ( 72 | await client.call_tool( 73 | "get_problem_details", 74 | { 75 | "problem_id": problem_id, 76 | }, 77 | ) 78 | ).structured_content 79 | 80 | assert result["id"] == problem_id 81 | 82 | @pytest.mark.asyncio 83 | @patch("oracle.oci_cloud_guard_mcp_server.server.get_cloud_guard_client") 84 | async def test_update_problem_status(self, mock_get_client): 85 | problem_id = "ocid.resource1" 86 | status = "OPEN" 87 | comment = "this is updated with ai" 88 | mock_client = MagicMock() 89 | mock_get_client.return_value = mock_client 90 | 91 | mock_update_problem_status_response = create_autospec(oci.response.Response) 92 | mock_update_problem_status_response.data = oci.cloud_guard.models.Problem( 93 | id=problem_id, 94 | resource_type="instance", 95 | resource_id="resource1", 96 | lifecycle_state="ACTIVE", 97 | lifecycle_detail=status, 98 | comment=comment, 99 | ) 100 | mock_client.update_problem_status.return_value = ( 101 | mock_update_problem_status_response 102 | ) 103 | 104 | async with Client(mcp) as client: 105 | result = ( 106 | await client.call_tool( 107 | "update_problem_status", 108 | {"problem_id": problem_id, "status": status, "comment": comment}, 109 | ) 110 | ).structured_content 111 | 112 | print(result) 113 | assert result["id"] == problem_id 114 | assert result["lifecycle_detail"] == status 115 | assert result["comment"] == comment 116 | -------------------------------------------------------------------------------- /src/oci-cloud-guard-mcp-server/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "oracle.oci-cloud-guard-mcp-server" 3 | version = "1.0.0" 4 | description = "OCI Cloud Guard Service MCP server" 5 | readme = "README.md" 6 | requires-python = ">=3.13" 7 | license = "UPL-1.0" 8 | license-files = ["LICENSE.txt"] 9 | authors = [ 10 | {name = "Oracle MCP", email = "237432095+oracle-mcp@users.noreply.github.com"}, 11 | ] 12 | dependencies = [ 13 | "fastmcp==2.12.2", 14 | "oci==2.160.0", 15 | "pydantic==2.12.3" 16 | ] 17 | 18 | classifiers = [ 19 | "License :: OSI Approved :: Universal Permissive License (UPL)", 20 | "Operating System :: OS Independent", 21 | "Programming Language :: Python", 22 | "Programming Language :: Python :: 3.13", 23 | ] 24 | 25 | [project.scripts] 26 | "oracle.oci-cloud-guard-mcp-server" = "oracle.oci_cloud_guard_mcp_server.server:main" 27 | 28 | [build-system] 29 | requires = ["hatchling"] 30 | build-backend = "hatchling.build" 31 | 32 | [tool.hatch.build.targets.wheel] 33 | packages = ["oracle"] 34 | 35 | [dependency-groups] 36 | dev = [ 37 | "pytest>=8.4.2", 38 | "pytest-asyncio>=1.2.0", 39 | "pytest-cov>=7.0.0", 40 | ] 41 | 42 | [tool.coverage.run] 43 | omit = [ 44 | "**/__init__.py", 45 | "**/tests/*", 46 | "dist/*", 47 | ".venv/*", 48 | ] 49 | 50 | [tool.coverage.report] 51 | precision = 2 52 | fail_under = 64.8 53 | 54 | -------------------------------------------------------------------------------- /src/oci-compute-instance-agent-mcp-server/.python-version: -------------------------------------------------------------------------------- 1 | 3.13 2 | -------------------------------------------------------------------------------- /src/oci-compute-instance-agent-mcp-server/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2025 Oracle and/or its affiliates. 2 | 3 | The Universal Permissive License (UPL), Version 1.0 4 | 5 | Subject to the condition set forth below, permission is hereby granted to any 6 | person obtaining a copy of this software, associated documentation and/or data 7 | (collectively the "Software"), free of charge and under any and all copyright 8 | rights in the Software, and any and all patent rights owned or freely 9 | licensable by each licensor hereunder covering either (i) the unmodified 10 | Software as contributed to or provided by such licensor, or (ii) the Larger 11 | Works (as defined below), to deal in both 12 | 13 | (a) the Software, and 14 | (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if 15 | one is included with the Software (each a "Larger Work" to which the Software 16 | is contributed by such licensors), 17 | 18 | without restriction, including without limitation the rights to copy, create 19 | derivative works of, display, perform, and distribute the Software and make, 20 | use, sell, offer for sale, import, export, have made, and have sold the 21 | Software and the Larger Work(s), and to sublicense the foregoing rights on 22 | either these or other terms. 23 | 24 | This license is subject to the following condition: 25 | The above copyright notice and either this complete permission notice or at 26 | a minimum a reference to the UPL must be included in all copies or 27 | substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 35 | SOFTWARE. -------------------------------------------------------------------------------- /src/oci-compute-instance-agent-mcp-server/README.md: -------------------------------------------------------------------------------- 1 | # OCI Compute Instance Agent MCP Server 2 | 3 | ## Overview 4 | 5 | This server provides tools for interacting with Oracle Cloud Infrastructure (OCI) Compute Instance Agent service. 6 | 7 | ## Running the server 8 | 9 | ```sh 10 | uv run oracle.oci-compute-instance-agent-mcp-server 11 | ``` 12 | 13 | ## Tools 14 | 15 | | Tool Name | Description | 16 | | --- | --- | 17 | | list_instance_agent_commands | List instance agent commands | 18 | | get_instance_agent_command | Get instance agent command by ID | 19 | | create_instance_agent_command | Create a new instance agent command | 20 | | list_instance_agent_command_executions | List command executions for an instance agent command | 21 | 22 | ⚠️ **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. 23 | 24 | ## Third-Party APIs 25 | 26 | 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. 27 | 28 | ## Disclaimer 29 | 30 | Users are responsible for their local environment and credential safety. Different language model selections may yield different results and performance. 31 | 32 | ## License 33 | 34 | Copyright (c) 2025 Oracle and/or its affiliates. 35 | 36 | Released under the Universal Permissive License v1.0 as shown at 37 | . 38 | -------------------------------------------------------------------------------- /src/oci-compute-instance-agent-mcp-server/oracle/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | -------------------------------------------------------------------------------- /src/oci-compute-instance-agent-mcp-server/oracle/oci_compute_instance_agent_mcp_server/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | 7 | __project__ = "oracle.oci-compute-instance-agent-mcp-server" 8 | __version__ = "2.0.0" 9 | -------------------------------------------------------------------------------- /src/oci-compute-instance-agent-mcp-server/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "oracle.oci-compute-instance-agent-mcp-server" 3 | version = "2.0.0" 4 | description = "OCI Compute Instance Agent MCP Server" 5 | readme = "README.md" 6 | requires-python = ">=3.13" 7 | license = "UPL-1.0" 8 | license-files = ["LICENSE.txt"] 9 | authors = [ 10 | {name = "Oracle MCP", email = "237432095+oracle-mcp@users.noreply.github.com"}, 11 | ] 12 | dependencies = [ 13 | "oci==2.160.0", 14 | "fastmcp==2.12.2", 15 | ] 16 | 17 | classifiers = [ 18 | "License :: OSI Approved :: Universal Permissive License (UPL)", 19 | "Operating System :: OS Independent", 20 | "Programming Language :: Python", 21 | "Programming Language :: Python :: 3.13", 22 | ] 23 | 24 | [project.scripts] 25 | "oracle.oci-compute-instance-agent-mcp-server" = "oracle.oci_compute_instance_agent_mcp_server.server:main" 26 | 27 | [build-system] 28 | requires = ["hatchling"] 29 | build-backend = "hatchling.build" 30 | 31 | [tool.hatch.build.targets.wheel] 32 | packages = ["oracle"] 33 | 34 | [dependency-groups] 35 | dev = [ 36 | "pytest>=8.4.2", 37 | "pytest-asyncio>=1.2.0", 38 | "pytest-cov>=7.0.0", 39 | ] 40 | 41 | [tool.coverage.run] 42 | omit = [ 43 | "**/__init__.py", 44 | "**/tests/*", 45 | "dist/*", 46 | ".venv/*", 47 | ] 48 | 49 | [tool.coverage.report] 50 | precision = 2 51 | fail_under = 42.5 52 | 53 | -------------------------------------------------------------------------------- /src/oci-compute-mcp-server/.python-version: -------------------------------------------------------------------------------- 1 | 3.13 2 | -------------------------------------------------------------------------------- /src/oci-compute-mcp-server/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2025 Oracle and/or its affiliates. 2 | 3 | The Universal Permissive License (UPL), Version 1.0 4 | 5 | Subject to the condition set forth below, permission is hereby granted to any 6 | person obtaining a copy of this software, associated documentation and/or data 7 | (collectively the "Software"), free of charge and under any and all copyright 8 | rights in the Software, and any and all patent rights owned or freely 9 | licensable by each licensor hereunder covering either (i) the unmodified 10 | Software as contributed to or provided by such licensor, or (ii) the Larger 11 | Works (as defined below), to deal in both 12 | 13 | (a) the Software, and 14 | (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if 15 | one is included with the Software (each a "Larger Work" to which the Software 16 | is contributed by such licensors), 17 | 18 | without restriction, including without limitation the rights to copy, create 19 | derivative works of, display, perform, and distribute the Software and make, 20 | use, sell, offer for sale, import, export, have made, and have sold the 21 | Software and the Larger Work(s), and to sublicense the foregoing rights on 22 | either these or other terms. 23 | 24 | This license is subject to the following condition: 25 | The above copyright notice and either this complete permission notice or at 26 | a minimum a reference to the UPL must be included in all copies or 27 | substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 35 | SOFTWARE. -------------------------------------------------------------------------------- /src/oci-compute-mcp-server/README.md: -------------------------------------------------------------------------------- 1 | # OCI Compute MCP Server 2 | 3 | ## Overview 4 | 5 | This server provides tools to interact with the OCI Compute resources. 6 | It includes tools to help with managing compute instances. 7 | 8 | ## Running the server 9 | 10 | ```sh 11 | uv run oracle.oci-compute-mcp-server 12 | ``` 13 | 14 | ## Tools 15 | 16 | | Tool Name | Description | 17 | | --- | --- | 18 | | list_instances | List Instances in a given compartment | 19 | | get_instance | Get Instance with a given instance OCID | 20 | | launch_instance | Create a new instance | 21 | | terminate_instance | Terminate an instance | 22 | | update_instance | Update instance configuration | 23 | | list_images | List images in a given compartment | 24 | | get_image | Get Image with a given image OCID | 25 | | instance_action | Perform actions on a given instance | 26 | 27 | ⚠️ **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. 28 | 29 | ## Third-Party APIs 30 | 31 | 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. 32 | 33 | ## Disclaimer 34 | 35 | Users are responsible for their local environment and credential safety. Different language model selections may yield different results and performance. 36 | 37 | ## License 38 | 39 | Copyright (c) 2025 Oracle and/or its affiliates. 40 | 41 | Released under the Universal Permissive License v1.0 as shown at 42 | . 43 | 44 | -------------------------------------------------------------------------------- /src/oci-compute-mcp-server/oracle/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | -------------------------------------------------------------------------------- /src/oci-compute-mcp-server/oracle/oci_compute_mcp_server/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | 7 | __project__ = "oracle.oci-compute-mcp-server" 8 | __version__ = "1.0.2" 9 | -------------------------------------------------------------------------------- /src/oci-compute-mcp-server/oracle/oci_compute_mcp_server/consts.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | 7 | ORACLE_LINUX_9_IMAGE = ( 8 | "ocid1.image.oc1.iad.aaaaaaaa4l64brs5udx52nedrhlex4cpaorcd2jwvpoududksmw4lgmameqq" 9 | ) 10 | E5_FLEX = "VM.Standard.E5.Flex" 11 | DEFAULT_OCPU_COUNT = 1 12 | DEFAULT_MEMORY_IN_GBS = 12 13 | -------------------------------------------------------------------------------- /src/oci-compute-mcp-server/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "oracle.oci-compute-mcp-server" 3 | version = "1.0.2" 4 | description = "OCI Compute Service MCP server" 5 | readme = "README.md" 6 | requires-python = ">=3.13" 7 | license = "UPL-1.0" 8 | license-files = ["LICENSE.txt"] 9 | authors = [ 10 | {name = "Oracle MCP", email = "237432095+oracle-mcp@users.noreply.github.com"}, 11 | ] 12 | dependencies = [ 13 | "fastmcp==2.12.2", 14 | "oci==2.160.0", 15 | "pydantic==2.12.3", 16 | ] 17 | 18 | classifiers = [ 19 | "License :: OSI Approved :: Universal Permissive License (UPL)", 20 | "Operating System :: OS Independent", 21 | "Programming Language :: Python", 22 | "Programming Language :: Python :: 3.13", 23 | ] 24 | 25 | [project.scripts] 26 | "oracle.oci-compute-mcp-server" = "oracle.oci_compute_mcp_server.server:main" 27 | 28 | [build-system] 29 | requires = ["hatchling"] 30 | build-backend = "hatchling.build" 31 | 32 | [tool.hatch.build.targets.wheel] 33 | packages = ["oracle"] 34 | 35 | [dependency-groups] 36 | dev = [ 37 | "pytest>=8.4.2", 38 | "pytest-asyncio>=1.2.0", 39 | "pytest-cov>=7.0.0", 40 | ] 41 | 42 | [tool.coverage.run] 43 | omit = [ 44 | "**/__init__.py", 45 | "**/tests/*", 46 | "dist/*", 47 | ".venv/*", 48 | ] 49 | 50 | [tool.coverage.report] 51 | precision = 2 52 | fail_under = 69.64 53 | -------------------------------------------------------------------------------- /src/oci-identity-mcp-server/.python-version: -------------------------------------------------------------------------------- 1 | 3.13 2 | -------------------------------------------------------------------------------- /src/oci-identity-mcp-server/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2025 Oracle and/or its affiliates. 2 | 3 | The Universal Permissive License (UPL), Version 1.0 4 | 5 | Subject to the condition set forth below, permission is hereby granted to any 6 | person obtaining a copy of this software, associated documentation and/or data 7 | (collectively the "Software"), free of charge and under any and all copyright 8 | rights in the Software, and any and all patent rights owned or freely 9 | licensable by each licensor hereunder covering either (i) the unmodified 10 | Software as contributed to or provided by such licensor, or (ii) the Larger 11 | Works (as defined below), to deal in both 12 | 13 | (a) the Software, and 14 | (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if 15 | one is included with the Software (each a "Larger Work" to which the Software 16 | is contributed by such licensors), 17 | 18 | without restriction, including without limitation the rights to copy, create 19 | derivative works of, display, perform, and distribute the Software and make, 20 | use, sell, offer for sale, import, export, have made, and have sold the 21 | Software and the Larger Work(s), and to sublicense the foregoing rights on 22 | either these or other terms. 23 | 24 | This license is subject to the following condition: 25 | The above copyright notice and either this complete permission notice or at 26 | a minimum a reference to the UPL must be included in all copies or 27 | substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 35 | SOFTWARE. -------------------------------------------------------------------------------- /src/oci-identity-mcp-server/README.md: -------------------------------------------------------------------------------- 1 | # OCI Identity MCP Server 2 | 3 | ## Overview 4 | 5 | This server provides tools to interact with the OCI Identity service. 6 | 7 | ## Running the server 8 | 9 | ```sh 10 | uv run oracle.oci-identity-mcp-server 11 | ``` 12 | 13 | ## Tools 14 | 15 | | Tool Name | Description | 16 | | --- | --- | 17 | | list_compartments | List compartments in a given tenancy. | 18 | | get_tenancy_info | Get tenancy information. | 19 | | list_availability_domains | List availability domains in a given tenancy. | 20 | | get_current_tenancy | Get current tenancy information. | 21 | | create_auth_token | Create an authentication token for a user. | 22 | | get_current_user | Get current user information. | 23 | 24 | ⚠️ **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. 25 | 26 | ## Third-Party APIs 27 | 28 | 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. 29 | 30 | ## Disclaimer 31 | 32 | Users are responsible for their local environment and credential safety. Different language model selections may yield different results and performance. 33 | 34 | ## License 35 | 36 | Copyright (c) 2025 Oracle and/or its affiliates. 37 | 38 | Released under the Universal Permissive License v1.0 as shown at 39 | . 40 | 41 | -------------------------------------------------------------------------------- /src/oci-identity-mcp-server/oracle/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | -------------------------------------------------------------------------------- /src/oci-identity-mcp-server/oracle/oci_identity_mcp_server/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | 7 | __project__ = "oracle.oci-identity-mcp-server" 8 | __version__ = "1.0.1" 9 | -------------------------------------------------------------------------------- /src/oci-identity-mcp-server/oracle/oci_identity_mcp_server/server.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | 7 | import base64 8 | import json 9 | import os 10 | 11 | import oci 12 | from fastmcp import FastMCP 13 | 14 | from . import __project__, __version__ 15 | 16 | mcp = FastMCP(name=__project__) 17 | 18 | 19 | def get_identity_client(): 20 | config = oci.config.from_file( 21 | profile_name=os.getenv("OCI_CONFIG_PROFILE", oci.config.DEFAULT_PROFILE) 22 | ) 23 | user_agent_name = __project__.split("oracle.", 1)[1].split("-server", 1)[0] 24 | config["additional_user_agent"] = f"{user_agent_name}/{__version__}" 25 | private_key = oci.signer.load_private_key_from_file(config["key_file"]) 26 | token_file = config["security_token_file"] 27 | with open(token_file, "r") as f: 28 | token = f.read() 29 | signer = oci.auth.signers.SecurityTokenSigner(token, private_key) 30 | return oci.identity.IdentityClient(config, signer=signer) 31 | 32 | 33 | @mcp.tool 34 | def list_compartments(tenancy_id: str) -> list[dict]: 35 | identity = get_identity_client() 36 | compartments = identity.list_compartments(tenancy_id).data 37 | return [ 38 | { 39 | "id": compartment.id, 40 | "name": compartment.name, 41 | "description": compartment.description, 42 | "lifecycle_state": compartment.lifecycle_state, 43 | } 44 | for compartment in compartments 45 | ] 46 | 47 | 48 | @mcp.tool 49 | def get_tenancy_info(tenancy_id: str) -> dict: 50 | identity = get_identity_client() 51 | tenancy = identity.get_tenancy(tenancy_id).data 52 | return { 53 | "id": tenancy.id, 54 | "name": tenancy.name, 55 | "description": tenancy.description, 56 | "home_region_key": tenancy.home_region_key, 57 | } 58 | 59 | 60 | @mcp.tool(description="Lists all of the availability domains in a given tenancy") 61 | def list_availability_domains(tenancy_id: str) -> list[dict]: 62 | identity = get_identity_client() 63 | ads: list[oci.identity.models.AvailabilityDomain] = ( 64 | identity.list_availability_domains(tenancy_id).data 65 | ) 66 | return [ 67 | { 68 | "id": ad.id, 69 | "name": ad.name, 70 | "compartment_id": ad.compartment_id, 71 | } 72 | for ad in ads 73 | ] 74 | 75 | 76 | @mcp.tool 77 | def get_current_tenancy() -> dict: 78 | config = oci.config.from_file( 79 | profile_name=os.getenv("OCI_CONFIG_PROFILE", oci.config.DEFAULT_PROFILE) 80 | ) 81 | tenancy_id = config["tenancy"] 82 | identity = get_identity_client() 83 | tenancy = identity.get_tenancy(tenancy_id).data 84 | return { 85 | "id": tenancy.id, 86 | "name": tenancy.name, 87 | "description": tenancy.description, 88 | "home_region_key": tenancy.home_region_key, 89 | } 90 | 91 | 92 | @mcp.tool 93 | def create_auth_token(user_id: str) -> dict: 94 | identity = get_identity_client() 95 | token = identity.create_auth_token(user_id=user_id).data 96 | return { 97 | "token": token.token, 98 | "description": token.description, 99 | "lifecycle_state": token.lifecycle_state, 100 | } 101 | 102 | 103 | @mcp.tool 104 | def get_current_user() -> dict: 105 | identity = get_identity_client() 106 | config = oci.config.from_file( 107 | profile_name=os.getenv("OCI_CONFIG_PROFILE", oci.config.DEFAULT_PROFILE) 108 | ) 109 | 110 | # Prefer explicit user from config if present 111 | user_id = config.get("user") 112 | 113 | # Fallback: derive user OCID from the security token (session auth) 114 | if not user_id: 115 | token_file = config.get("security_token_file") 116 | if token_file and os.path.exists(token_file): 117 | with open(token_file, "r") as f: 118 | token = f.read().strip() 119 | 120 | # Expect JWT-like token: header.payload.signature (base64url) 121 | if "." in token: 122 | try: 123 | payload_b64 = token.split(".", 2)[1] 124 | padding = "=" * (-len(payload_b64) % 4) 125 | payload_json = base64.urlsafe_b64decode( 126 | payload_b64 + padding 127 | ).decode("utf-8") 128 | payload = json.loads(payload_json) 129 | # 'sub' typically contains the user OCID for session tokens; 130 | # fallback to opc-user-id if present 131 | user_id = payload.get("sub") or payload.get("opc-user-id") 132 | except Exception: 133 | user_id = None 134 | 135 | if not user_id: 136 | raise KeyError( 137 | "Unable to determine current user OCID from config or security token" 138 | ) 139 | 140 | user = identity.get_user(user_id).data 141 | return { 142 | "id": user.id, 143 | "name": user.name, 144 | "description": user.description, 145 | } 146 | 147 | 148 | def main(): 149 | mcp.run() 150 | 151 | 152 | if __name__ == "__main__": 153 | main() 154 | -------------------------------------------------------------------------------- /src/oci-identity-mcp-server/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "oracle.oci-identity-mcp-server" 3 | version = "1.0.1" 4 | description = "OCI Identity Service MCP server" 5 | readme = "README.md" 6 | requires-python = ">=3.13" 7 | license = "UPL-1.0" 8 | license-files = ["LICENSE.txt"] 9 | authors = [ 10 | {name = "Oracle MCP", email = "237432095+oracle-mcp@users.noreply.github.com"}, 11 | ] 12 | dependencies = [ 13 | "fastmcp==2.12.2", 14 | "oci==2.160.0", 15 | ] 16 | 17 | classifiers = [ 18 | "License :: OSI Approved :: Universal Permissive License (UPL)", 19 | "Operating System :: OS Independent", 20 | "Programming Language :: Python", 21 | "Programming Language :: Python :: 3.13", 22 | ] 23 | 24 | [project.scripts] 25 | "oracle.oci-identity-mcp-server" = "oracle.oci_identity_mcp_server.server:main" 26 | 27 | [build-system] 28 | requires = ["hatchling"] 29 | build-backend = "hatchling.build" 30 | 31 | [tool.hatch.build.targets.wheel] 32 | packages = ["oracle"] 33 | 34 | [dependency-groups] 35 | dev = [ 36 | "pytest>=8.4.2", 37 | "pytest-asyncio>=1.2.0", 38 | "pytest-cov>=7.0.0", 39 | ] 40 | 41 | [tool.coverage.run] 42 | omit = [ 43 | "**/__init__.py", 44 | "**/tests/*", 45 | "dist/*", 46 | ".venv/*", 47 | ] 48 | 49 | [tool.coverage.report] 50 | precision = 2 51 | fail_under = 58 52 | 53 | -------------------------------------------------------------------------------- /src/oci-logging-mcp-server/.python-version: -------------------------------------------------------------------------------- 1 | 3.13 2 | -------------------------------------------------------------------------------- /src/oci-logging-mcp-server/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2025 Oracle and/or its affiliates. 2 | 3 | The Universal Permissive License (UPL), Version 1.0 4 | 5 | Subject to the condition set forth below, permission is hereby granted to any 6 | person obtaining a copy of this software, associated documentation and/or data 7 | (collectively the "Software"), free of charge and under any and all copyright 8 | rights in the Software, and any and all patent rights owned or freely 9 | licensable by each licensor hereunder covering either (i) the unmodified 10 | Software as contributed to or provided by such licensor, or (ii) the Larger 11 | Works (as defined below), to deal in both 12 | 13 | (a) the Software, and 14 | (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if 15 | one is included with the Software (each a "Larger Work" to which the Software 16 | is contributed by such licensors), 17 | 18 | without restriction, including without limitation the rights to copy, create 19 | derivative works of, display, perform, and distribute the Software and make, 20 | use, sell, offer for sale, import, export, have made, and have sold the 21 | Software and the Larger Work(s), and to sublicense the foregoing rights on 22 | either these or other terms. 23 | 24 | This license is subject to the following condition: 25 | The above copyright notice and either this complete permission notice or at 26 | a minimum a reference to the UPL must be included in all copies or 27 | substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 35 | SOFTWARE. -------------------------------------------------------------------------------- /src/oci-logging-mcp-server/README.md: -------------------------------------------------------------------------------- 1 | # OCI Logging MCP Server 2 | 3 | ## Overview 4 | 5 | This server provides tools to interact with the OCI Logging resources. 6 | It includes tools to help with managing logging configurations. 7 | 8 | ## Running the server 9 | 10 | ```sh 11 | uv run oracle.oci-logging-mcp-server 12 | ``` 13 | 14 | ## Tools 15 | 16 | | Tool Name | Description | 17 | | --- | --- | 18 | | list_log_groups | List log groups in a given compartment | 19 | | list_logs | List logs in a given log group | 20 | | get_log | Get a log with a given log OCID | 21 | 22 | ⚠️ **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. 23 | 24 | ## Third-Party APIs 25 | 26 | 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. 27 | 28 | ## Disclaimer 29 | 30 | Users are responsible for their local environment and credential safety. Different language model selections may yield different results and performance. 31 | 32 | ## License 33 | 34 | Copyright (c) 2025 Oracle and/or its affiliates. 35 | 36 | Released under the Universal Permissive License v1.0 as shown at 37 | . 38 | -------------------------------------------------------------------------------- /src/oci-logging-mcp-server/oracle/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | -------------------------------------------------------------------------------- /src/oci-logging-mcp-server/oracle/oci_logging_mcp_server/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | 7 | __project__ = "oracle.oci-logging-mcp-server" 8 | __version__ = "1.1.0" 9 | -------------------------------------------------------------------------------- /src/oci-logging-mcp-server/oracle/oci_logging_mcp_server/scripts.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | 7 | from pathlib import Path 8 | 9 | SCRIPTS_DIRECTORY = Path(__file__).parent / "scripts" 10 | 11 | SEARCH_LOG_SCRIPT = "SEARCH_LOG.md" 12 | SEARCH_LOG_EVENT_TYPES_SCRIPT = "SEARCH_LOG_EVENT_TYPES.md" 13 | 14 | 15 | def get_script_content(script_name: str) -> str: 16 | file_path = SCRIPTS_DIRECTORY / script_name 17 | with open(file_path, "r") as f: 18 | return f.read() 19 | -------------------------------------------------------------------------------- /src/oci-logging-mcp-server/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "oracle.oci-logging-mcp-server" 3 | version = "1.1.0" 4 | description = "OCI Logging Service MCP server" 5 | readme = "README.md" 6 | authors = [ 7 | {name = "Oracle MCP", email = "237432095+oracle-mcp@users.noreply.github.com"}, 8 | ] 9 | requires-python = ">=3.13" 10 | dependencies = [ 11 | "fastmcp==2.12.2", 12 | "oci==2.160.0", 13 | "pydantic==2.12.3", 14 | ] 15 | 16 | classifiers = [ 17 | "License :: OSI Approved :: Universal Permissive License (UPL)", 18 | "Operating System :: OS Independent", 19 | "Programming Language :: Python", 20 | "Programming Language :: Python :: 3.13", 21 | ] 22 | 23 | [project.scripts] 24 | "oracle.oci-logging-mcp-server" = "oracle.oci_logging_mcp_server.server:main" 25 | 26 | [build-system] 27 | requires = ["hatchling"] 28 | build-backend = "hatchling.build" 29 | 30 | [tool.hatch.build.targets.wheel] 31 | packages = ["oracle"] 32 | 33 | [dependency-groups] 34 | dev = [ 35 | "pytest>=8.4.2", 36 | "pytest-asyncio>=1.2.0", 37 | "pytest-cov>=7.0.0", 38 | ] 39 | 40 | [tool.coverage.run] 41 | omit = [ 42 | "**/__init__.py", 43 | "**/tests/*", 44 | "dist/*", 45 | ".venv/*", 46 | ] 47 | 48 | [tool.coverage.report] 49 | precision = 2 50 | fail_under = 64.71 51 | 52 | 53 | -------------------------------------------------------------------------------- /src/oci-migration-mcp-server/.python-version: -------------------------------------------------------------------------------- 1 | 3.13 2 | -------------------------------------------------------------------------------- /src/oci-migration-mcp-server/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2025 Oracle and/or its affiliates. 2 | 3 | The Universal Permissive License (UPL), Version 1.0 4 | 5 | Subject to the condition set forth below, permission is hereby granted to any 6 | person obtaining a copy of this software, associated documentation and/or data 7 | (collectively the "Software"), free of charge and under any and all copyright 8 | rights in the Software, and any and all patent rights owned or freely 9 | licensable by each licensor hereunder covering either (i) the unmodified 10 | Software as contributed to or provided by such licensor, or (ii) the Larger 11 | Works (as defined below), to deal in both 12 | 13 | (a) the Software, and 14 | (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if 15 | one is included with the Software (each a "Larger Work" to which the Software 16 | is contributed by such licensors), 17 | 18 | without restriction, including without limitation the rights to copy, create 19 | derivative works of, display, perform, and distribute the Software and make, 20 | use, sell, offer for sale, import, export, have made, and have sold the 21 | Software and the Larger Work(s), and to sublicense the foregoing rights on 22 | either these or other terms. 23 | 24 | This license is subject to the following condition: 25 | The above copyright notice and either this complete permission notice or at 26 | a minimum a reference to the UPL must be included in all copies or 27 | substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 35 | SOFTWARE. -------------------------------------------------------------------------------- /src/oci-migration-mcp-server/README.md: -------------------------------------------------------------------------------- 1 | # OCI Migration MCP Server 2 | 3 | ## Overview 4 | 5 | This server provides tools for interacting with Oracle Cloud Infrastructure (OCI) Migration service. 6 | 7 | ## Running the server 8 | 9 | ```sh 10 | uv run oracle.oci-migration-mcp-server 11 | ``` 12 | 13 | ## Tools 14 | 15 | | Tool Name | Description | 16 | | --- | --- | 17 | | list_migrations | List migrations in the tenancy | 18 | | get_migration | Get migration by ID | 19 | 20 | 21 | ⚠️ **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. 22 | 23 | ## Third-Party APIs 24 | 25 | 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. 26 | 27 | ## Disclaimer 28 | 29 | Users are responsible for their local environment and credential safety. Different language model selections may yield different results and performance. 30 | 31 | ## License 32 | 33 | Copyright (c) 2025 Oracle and/or its affiliates. 34 | 35 | Released under the Universal Permissive License v1.0 as shown at 36 | . 37 | -------------------------------------------------------------------------------- /src/oci-migration-mcp-server/oracle/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | -------------------------------------------------------------------------------- /src/oci-migration-mcp-server/oracle/oci_migration_mcp_server/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | 7 | __project__ = "oracle.oci-migration-mcp-server" 8 | __version__ = "1.0.1" 9 | -------------------------------------------------------------------------------- /src/oci-migration-mcp-server/oracle/oci_migration_mcp_server/server.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | 7 | import os 8 | from logging import Logger 9 | 10 | import oci 11 | from fastmcp import FastMCP 12 | 13 | from . import __project__, __version__ 14 | 15 | logger = Logger(__name__, level="INFO") 16 | 17 | mcp = FastMCP(name=__project__) 18 | 19 | 20 | def get_migration_client(): 21 | logger.info("entering get_migration_client") 22 | config = oci.config.from_file( 23 | profile_name=os.getenv("OCI_CONFIG_PROFILE", oci.config.DEFAULT_PROFILE) 24 | ) 25 | user_agent_name = __project__.split("oracle.", 1)[1].split("-server", 1)[0] 26 | config["additional_user_agent"] = f"{user_agent_name}/{__version__}" 27 | private_key = oci.signer.load_private_key_from_file(config["key_file"]) 28 | token_file = config["security_token_file"] 29 | token = None 30 | with open(token_file, "r") as f: 31 | token = f.read() 32 | signer = oci.auth.signers.SecurityTokenSigner(token, private_key) 33 | return oci.cloud_migrations.MigrationClient(config, signer=signer) 34 | 35 | 36 | @mcp.tool 37 | def get_migration(migration_id: str) -> dict: 38 | """ 39 | Get details for a specific Migration Project by OCID. 40 | Args: 41 | migration_id (str): OCID of the migration project. 42 | Returns: 43 | dict: Migration project details. 44 | """ 45 | client = get_migration_client() 46 | return client.get_migration(migration_id).data 47 | 48 | 49 | @mcp.tool 50 | def list_migrations(compartment_id: str, lifecycle_state: str = None) -> list[dict]: 51 | """ 52 | List Migration Projects for a compartment, optionally filtered by lifecycle state. 53 | Args: 54 | compartment_id (str): OCID of the compartment. 55 | lifecycle_state (str, optional): Filter by lifecycle state. 56 | Returns: 57 | list of dict: Each dict is a migration object. 58 | """ 59 | client = get_migration_client() 60 | list_args = {"compartment_id": compartment_id} 61 | 62 | if lifecycle_state is not None: 63 | list_args["lifecycle_state"] = lifecycle_state 64 | 65 | migrations = client.list_migrations(**list_args).data.items 66 | return [ 67 | { 68 | "id": migration.id, 69 | "display_name": migration.display_name, 70 | "compartment_id": migration.compartment_id, 71 | "lifecycle_state": migration.lifecycle_state, 72 | "lifecycle_details": migration.lifecycle_details, 73 | "time_created": migration.time_created, 74 | "replication_schedule_id": migration.replication_schedule_id, 75 | "is_completed": migration.is_completed, 76 | } 77 | for migration in migrations 78 | ] 79 | 80 | 81 | def main(): 82 | mcp.run() 83 | 84 | 85 | if __name__ == "__main__": 86 | main() 87 | -------------------------------------------------------------------------------- /src/oci-migration-mcp-server/oracle/oci_migration_mcp_server/tests/test_migration_tools.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | 7 | from unittest.mock import MagicMock, create_autospec, patch 8 | 9 | import oci 10 | import pytest 11 | from fastmcp import Client 12 | from oracle.oci_migration_mcp_server.server import mcp 13 | 14 | 15 | class TestMigrationTools: 16 | # @pytest.mark.asyncio 17 | # @patch("oracle.oci_migration_mcp_server.server.get_migration_client") 18 | # async def test_get_migration(self, mock_get_client): 19 | # mock_client = MagicMock() 20 | # mock_get_client.return_value = mock_client 21 | 22 | # mock_get_response = create_autospec(oci.response.Response) 23 | # mock_get_response.data = oci.cloud_migrations.models.Migration( 24 | # id="migration1", 25 | # display_name="Migration 1", 26 | # ) 27 | # mock_client.get_migration.return_value = mock_get_response 28 | 29 | # async with Client(mcp) as client: 30 | # result = ( 31 | # await client.call_tool( 32 | # "get_migration", 33 | # { 34 | # "migration_id": "migration1", 35 | # }, 36 | # ) 37 | # ).data 38 | 39 | # assert result.id == "migration1" 40 | 41 | @pytest.mark.asyncio 42 | @patch("oracle.oci_migration_mcp_server.server.get_migration_client") 43 | async def test_list_migrations(self, mock_get_client): 44 | mock_client = MagicMock() 45 | mock_get_client.return_value = mock_client 46 | 47 | mock_list_response = create_autospec(oci.response.Response) 48 | mock_list_response.data = oci.cloud_migrations.models.MigrationCollection( 49 | items=[ 50 | oci.cloud_migrations.models.Migration( 51 | id="migration1", 52 | display_name="Migration 1", 53 | compartment_id="compartment1", 54 | lifecycle_state="RUNNING", 55 | ) 56 | ] 57 | ) 58 | mock_client.list_migrations.return_value = mock_list_response 59 | 60 | async with Client(mcp) as client: 61 | result = ( 62 | await client.call_tool( 63 | "list_migrations", 64 | { 65 | "compartment_id": "compartment1", 66 | }, 67 | ) 68 | ).structured_content["result"] 69 | 70 | assert len(result) == 1 71 | assert result[0]["id"] == "migration1" 72 | -------------------------------------------------------------------------------- /src/oci-migration-mcp-server/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "oracle.oci-migration-mcp-server" 3 | version = "1.0.1" 4 | description = "Add your description here" 5 | readme = "README.md" 6 | requires-python = ">=3.13" 7 | license = "UPL-1.0" 8 | license-files = ["LICENSE.txt"] 9 | authors = [ 10 | {name = "Oracle MCP", email = "237432095+oracle-mcp@users.noreply.github.com"}, 11 | ] 12 | dependencies = [ 13 | "fastmcp==2.12.2", 14 | "oci==2.160.0", 15 | ] 16 | 17 | classifiers = [ 18 | "License :: OSI Approved :: Universal Permissive License (UPL)", 19 | "Operating System :: OS Independent", 20 | "Programming Language :: Python", 21 | "Programming Language :: Python :: 3.13", 22 | ] 23 | 24 | [project.scripts] 25 | "oracle.oci-migration-mcp-server" = "oracle.oci_migration_mcp_server.server:main" 26 | 27 | [build-system] 28 | requires = ["hatchling"] 29 | build-backend = "hatchling.build" 30 | 31 | [tool.hatch.build.targets.wheel] 32 | packages = ["oracle"] 33 | 34 | [dependency-groups] 35 | dev = [ 36 | "pytest>=8.4.2", 37 | "pytest-asyncio>=1.2.0", 38 | "pytest-cov>=7.0.0", 39 | ] 40 | 41 | [tool.coverage.run] 42 | omit = [ 43 | "**/__init__.py", 44 | "**/tests/*", 45 | "dist/*", 46 | ".venv/*", 47 | ] 48 | 49 | [tool.coverage.report] 50 | precision = 2 51 | fail_under = 53.84 52 | 53 | 54 | -------------------------------------------------------------------------------- /src/oci-monitoring-mcp-server/.python-version: -------------------------------------------------------------------------------- 1 | 3.13 2 | -------------------------------------------------------------------------------- /src/oci-monitoring-mcp-server/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2025 Oracle and/or its affiliates. 2 | 3 | The Universal Permissive License (UPL), Version 1.0 4 | 5 | Subject to the condition set forth below, permission is hereby granted to any 6 | person obtaining a copy of this software, associated documentation and/or data 7 | (collectively the "Software"), free of charge and under any and all copyright 8 | rights in the Software, and any and all patent rights owned or freely 9 | licensable by each licensor hereunder covering either (i) the unmodified 10 | Software as contributed to or provided by such licensor, or (ii) the Larger 11 | Works (as defined below), to deal in both 12 | 13 | (a) the Software, and 14 | (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if 15 | one is included with the Software (each a "Larger Work" to which the Software 16 | is contributed by such licensors), 17 | 18 | without restriction, including without limitation the rights to copy, create 19 | derivative works of, display, perform, and distribute the Software and make, 20 | use, sell, offer for sale, import, export, have made, and have sold the 21 | Software and the Larger Work(s), and to sublicense the foregoing rights on 22 | either these or other terms. 23 | 24 | This license is subject to the following condition: 25 | The above copyright notice and either this complete permission notice or at 26 | a minimum a reference to the UPL must be included in all copies or 27 | substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 35 | SOFTWARE. -------------------------------------------------------------------------------- /src/oci-monitoring-mcp-server/README.md: -------------------------------------------------------------------------------- 1 | # OCI Monitoring MCP Server 2 | 3 | ## Overview 4 | 5 | This server provides tools for interacting with Oracle Cloud Infrastructure (OCI) Monitoring service. 6 | 7 | ## Running the server 8 | 9 | ```sh 10 | uv run oracle.oci-monitoring-mcp-server 11 | ``` 12 | 13 | ## Tools 14 | 15 | | Tool Name | Description | 16 | | --- | --- | 17 | | list_metrics | List metrics in the tenancy | 18 | | get_metric | Get metric by name | 19 | 20 | 21 | ⚠️ **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. 22 | 23 | ## Third-Party APIs 24 | 25 | 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. 26 | 27 | ## Disclaimer 28 | 29 | Users are responsible for their local environment and credential safety. Different language model selections may yield different results and performance. 30 | 31 | ## License 32 | 33 | Copyright (c) 2025 Oracle and/or its affiliates. 34 | 35 | Released under the Universal Permissive License v1.0 as shown at 36 | . 37 | -------------------------------------------------------------------------------- /src/oci-monitoring-mcp-server/oracle/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | -------------------------------------------------------------------------------- /src/oci-monitoring-mcp-server/oracle/oci_monitoring_mcp_server/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | 7 | __project__ = "oracle.oci-monitoring-mcp-server" 8 | __version__ = "1.0.1" 9 | -------------------------------------------------------------------------------- /src/oci-monitoring-mcp-server/oracle/oci_monitoring_mcp_server/server.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | 7 | import os 8 | from logging import Logger 9 | from typing import Annotated 10 | 11 | import oci 12 | from fastmcp import FastMCP 13 | from oci.monitoring.models import SummarizeMetricsDataDetails 14 | 15 | from . import __project__, __version__ 16 | 17 | logger = Logger(__name__, level="INFO") 18 | 19 | mcp = FastMCP(name=__project__) 20 | 21 | 22 | def get_monitoring_client(): 23 | logger.info("entering get_monitoring_client") 24 | config = oci.config.from_file( 25 | profile_name=os.getenv("OCI_CONFIG_PROFILE", oci.config.DEFAULT_PROFILE) 26 | ) 27 | user_agent_name = __project__.split("oracle.", 1)[1].split("-server", 1)[0] 28 | config["additional_user_agent"] = f"{user_agent_name}/{__version__}" 29 | 30 | private_key = oci.signer.load_private_key_from_file(config["key_file"]) 31 | token_file = config["security_token_file"] 32 | token = None 33 | with open(token_file, "r") as f: 34 | token = f.read() 35 | signer = oci.auth.signers.SecurityTokenSigner(token, private_key) 36 | return oci.monitoring.MonitoringClient(config, signer=signer) 37 | 38 | 39 | @mcp.tool 40 | def get_compute_metrics( 41 | compartment_id: str, 42 | start_time: str, 43 | end_time: str, 44 | metricName: Annotated[ 45 | str, 46 | "The metric that the user wants to fetch. Currently we only support:" 47 | "CpuUtilization, MemoryUtilization, DiskIopsRead, DiskIopsWritten," 48 | "DiskBytesRead, DiskBytesWritten, NetworksBytesIn," 49 | "NetworksBytesOut, LoadAverage, MemoryAllocationStalls", 50 | ], 51 | resolution: Annotated[ 52 | str, 53 | "The granularity of the metric. Currently we only support: 1m, 5m, 1h, 1d. Default: 1m.", 54 | ] = "1m", 55 | aggregation: Annotated[ 56 | str, 57 | "The aggregation for the metric. Currently we only support: " 58 | "mean, sum, max, min, count. Default: mean", 59 | ] = "mean", 60 | instance_id: Annotated[ 61 | str, 62 | "Optional compute instance OCID to filter by " "(maps to resourceId dimension)", 63 | ] = None, 64 | compartment_id_in_subtree: Annotated[ 65 | bool, 66 | "Whether to include metrics from all subcompartments of the specified compartment", 67 | ] = False, 68 | ) -> list[dict]: 69 | monitoring_client = get_monitoring_client() 70 | namespace = "oci_computeagent" 71 | filter_clause = f'{{resourceId="{instance_id}"}}' if instance_id else "" 72 | query = f"{metricName}[{resolution}]{filter_clause}.{aggregation}()" 73 | 74 | series_list = monitoring_client.summarize_metrics_data( 75 | compartment_id=compartment_id, 76 | summarize_metrics_data_details=SummarizeMetricsDataDetails( 77 | namespace=namespace, 78 | query=query, 79 | start_time=start_time, 80 | end_time=end_time, 81 | resolution=resolution, 82 | ), 83 | compartment_id_in_subtree=compartment_id_in_subtree, 84 | ).data 85 | 86 | result: list[dict] = [] 87 | for series in series_list: 88 | dims = getattr(series, "dimensions", None) 89 | points = [] 90 | for p in getattr(series, "aggregated_datapoints", []): 91 | points.append( 92 | { 93 | "timestamp": getattr(p, "timestamp", None), 94 | "value": getattr(p, "value", None), 95 | } 96 | ) 97 | result.append( 98 | { 99 | "dimensions": dims, 100 | "datapoints": points, 101 | } 102 | ) 103 | return result 104 | 105 | 106 | @mcp.tool 107 | def list_alarms( 108 | compartment_id: Annotated[ 109 | str, 110 | "The ID of the compartment containing the resources" 111 | "monitored by the metric that you are searching for.", 112 | ], 113 | ) -> list[dict]: 114 | monitoring_client = get_monitoring_client() 115 | response = monitoring_client.list_alarms(compartment_id=compartment_id) 116 | alarms = response.data 117 | result = [] 118 | for alarm in alarms: 119 | result.append( 120 | { 121 | "id": alarm.id, 122 | "display_name": alarm.display_name, 123 | "severity": alarm.severity, 124 | "lifecycle_state": alarm.lifecycle_state, 125 | "namespace": alarm.namespace, 126 | "query": alarm.query, 127 | } 128 | ) 129 | return result 130 | 131 | 132 | def main(): 133 | mcp.run() 134 | 135 | 136 | if __name__ == "__main__": 137 | main() 138 | -------------------------------------------------------------------------------- /src/oci-monitoring-mcp-server/oracle/oci_monitoring_mcp_server/tests/test_monitoring_tools.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | 7 | from unittest.mock import MagicMock, create_autospec, patch 8 | 9 | import oci 10 | import pytest 11 | from fastmcp import Client 12 | from oracle.oci_monitoring_mcp_server.server import mcp 13 | 14 | 15 | class TestMonitoringTools: 16 | @pytest.mark.asyncio 17 | @patch("oracle.oci_monitoring_mcp_server.server.get_monitoring_client") 18 | async def test_get_compute_metrics(self, mock_get_client): 19 | mock_client = MagicMock() 20 | mock_get_client.return_value = mock_client 21 | 22 | # Mock OCI summarize_metrics_data response with one series containing two points 23 | mock_summarize_response = create_autospec(oci.response.Response) 24 | series = MagicMock() 25 | series.dimensions = {"resourceId": "instance1"} 26 | series.aggregated_datapoints = [ 27 | MagicMock(timestamp="2023-01-01T00:00:00Z", value=42.0), 28 | MagicMock(timestamp="2023-01-01T00:01:00Z", value=43.5), 29 | ] 30 | mock_summarize_response.data = [series] 31 | mock_client.summarize_metrics_data.return_value = mock_summarize_response 32 | 33 | # Call the MCP tool 34 | async with Client(mcp) as client: 35 | result = ( 36 | await client.call_tool( 37 | "get_compute_metrics", 38 | { 39 | "compartment_id": "compartment1", 40 | "start_time": "2023-01-01T00:00:00Z", 41 | "end_time": "2023-01-01T01:00:00Z", 42 | "metricName": "CpuUtilization", 43 | "resolution": "1m", 44 | "aggregation": "mean", 45 | "instance_id": "instance1", 46 | "compartment_id_in_subtree": False, 47 | }, 48 | ) 49 | ).structured_content["result"] 50 | 51 | # Validate result structure and values 52 | assert isinstance(result, list) 53 | assert len(result) == 1 54 | assert result[0]["dimensions"] == {"resourceId": "instance1"} 55 | assert "datapoints" in result[0] 56 | assert len(result[0]["datapoints"]) == 2 57 | assert result[0]["datapoints"][0]["timestamp"] == "2023-01-01T00:00:00Z" 58 | assert result[0]["datapoints"][0]["value"] == pytest.approx(42.0) 59 | 60 | @pytest.mark.asyncio 61 | @patch("oracle.oci_monitoring_mcp_server.server.get_monitoring_client") 62 | async def test_list_alarms(self, mock_get_client): 63 | mock_client = MagicMock() 64 | mock_get_client.return_value = mock_client 65 | 66 | mock_alarm1 = oci.monitoring.models.Alarm( 67 | id="alarm1", 68 | display_name="Test Alarm 1", 69 | severity="CRITICAL", 70 | lifecycle_state="ACTIVE", 71 | namespace="oci_monitoring", 72 | query="CpuUtilization[1m].mean() > 80", 73 | ) 74 | mock_alarm2 = oci.monitoring.models.Alarm( 75 | id="alarm2", 76 | display_name="Test Alarm 2", 77 | severity="WARNING", 78 | lifecycle_state="ACTIVE", 79 | namespace="oci_monitoring", 80 | query="MemoryUtilization[1m].mean() > 90", 81 | ) 82 | 83 | mock_list_response = create_autospec(oci.response.Response) 84 | mock_list_response.data = [mock_alarm1, mock_alarm2] 85 | mock_client.list_alarms.return_value = mock_list_response 86 | 87 | async with Client(mcp) as client: 88 | result = ( 89 | await client.call_tool( 90 | "list_alarms", 91 | { 92 | "compartment_id": "compartment1", 93 | }, 94 | ) 95 | ).structured_content["result"] 96 | 97 | assert len(result) == 2 98 | assert result[0]["id"] == "alarm1" 99 | assert result[0]["display_name"] == "Test Alarm 1" 100 | assert result[1]["id"] == "alarm2" 101 | assert result[1]["display_name"] == "Test Alarm 2" 102 | -------------------------------------------------------------------------------- /src/oci-monitoring-mcp-server/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "oracle.oci-monitoring-mcp-server" 3 | version = "1.0.1" 4 | description = "OCI Monitoring Service MCP server" 5 | readme = "README.md" 6 | requires-python = ">=3.13" 7 | license = "UPL-1.0" 8 | license-files = ["LICENSE.txt"] 9 | authors = [ 10 | {name = "Oracle MCP", email = "237432095+oracle-mcp@users.noreply.github.com"}, 11 | ] 12 | dependencies = [ 13 | "fastmcp==2.12.2", 14 | "oci==2.160.0", 15 | ] 16 | 17 | classifiers = [ 18 | "License :: OSI Approved :: Universal Permissive License (UPL)", 19 | "Operating System :: OS Independent", 20 | "Programming Language :: Python", 21 | "Programming Language :: Python :: 3.13", 22 | ] 23 | 24 | [project.scripts] 25 | "oracle.oci-monitoring-mcp-server" = "oracle.oci_monitoring_mcp_server.server:main" 26 | 27 | [build-system] 28 | requires = ["hatchling"] 29 | build-backend = "hatchling.build" 30 | 31 | [tool.hatch.build.targets.wheel] 32 | packages = ["oracle"] 33 | 34 | [dependency-groups] 35 | dev = [ 36 | "pytest>=8.4.2", 37 | "pytest-asyncio>=1.2.0", 38 | "pytest-cov>=7.0.0", 39 | ] 40 | 41 | [tool.coverage.run] 42 | omit = [ 43 | "**/__init__.py", 44 | "**/tests/*", 45 | "dist/*", 46 | ".venv/*", 47 | ] 48 | 49 | [tool.coverage.report] 50 | precision = 2 51 | fail_under = 75 52 | 53 | 54 | -------------------------------------------------------------------------------- /src/oci-network-load-balancer-mcp-server/.python-version: -------------------------------------------------------------------------------- 1 | 3.13 2 | -------------------------------------------------------------------------------- /src/oci-network-load-balancer-mcp-server/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2025 Oracle and/or its affiliates. 2 | 3 | The Universal Permissive License (UPL), Version 1.0 4 | 5 | Subject to the condition set forth below, permission is hereby granted to any 6 | person obtaining a copy of this software, associated documentation and/or data 7 | (collectively the "Software"), free of charge and under any and all copyright 8 | rights in the Software, and any and all patent rights owned or freely 9 | licensable by each licensor hereunder covering either (i) the unmodified 10 | Software as contributed to or provided by such licensor, or (ii) the Larger 11 | Works (as defined below), to deal in both 12 | 13 | (a) the Software, and 14 | (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if 15 | one is included with the Software (each a "Larger Work" to which the Software 16 | is contributed by such licensors), 17 | 18 | without restriction, including without limitation the rights to copy, create 19 | derivative works of, display, perform, and distribute the Software and make, 20 | use, sell, offer for sale, import, export, have made, and have sold the 21 | Software and the Larger Work(s), and to sublicense the foregoing rights on 22 | either these or other terms. 23 | 24 | This license is subject to the following condition: 25 | The above copyright notice and either this complete permission notice or at 26 | a minimum a reference to the UPL must be included in all copies or 27 | substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 35 | SOFTWARE. -------------------------------------------------------------------------------- /src/oci-network-load-balancer-mcp-server/README.md: -------------------------------------------------------------------------------- 1 | # OCI Network Load Balancer MCP Server 2 | 3 | ## Overview 4 | 5 | This server provides tools to interact with the OCI Network Load Balancer resources. 6 | It includes tools to help with managing network load balancers. 7 | 8 | ## Running the server 9 | 10 | ```sh 11 | uv run oracle.oci-network-load-balancer-mcp-server 12 | ``` 13 | 14 | ## Tools 15 | 16 | | Tool Name | Description | 17 | | --- | --- | 18 | | list_network_load_balancers | List network load balancers in a given compartment | 19 | | get_network_load_balancer | Get network load balancer details | 20 | | list_network_load_balancer_listeners | List listeners in a given network load balancer | 21 | | get_network_load_balancer_listener | Get a listener with a given listener name from a network load balancer | 22 | | list_network_load_balancer_backend_sets | List backend sets in a given network load balancer | 23 | | get_network_load_balancer_backend_set | Get a backend set with a given backend set name from a network load balancer | 24 | | list_network_load_balancer_backends | List backends in a given backend set and network load balancer | 25 | | get_network_load_balancer_backend | Get a backend with a given backend name from a backend set and network load balancer | 26 | 27 | ⚠️ **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. 28 | 29 | ## Third-Party APIs 30 | 31 | 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. 32 | 33 | ## Disclaimer 34 | 35 | Users are responsible for their local environment and credential safety. Different language model selections may yield different results and performance. 36 | 37 | ## License 38 | 39 | Copyright (c) 2025 Oracle and/or its affiliates. 40 | 41 | Released under the Universal Permissive License v1.0 as shown at 42 | . 43 | -------------------------------------------------------------------------------- /src/oci-network-load-balancer-mcp-server/oracle/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | -------------------------------------------------------------------------------- /src/oci-network-load-balancer-mcp-server/oracle/oci_network_load_balancer_mcp_server/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | 7 | __project__ = "oracle.oci-network-load-balancer-mcp-server" 8 | __version__ = "1.0.1" 9 | -------------------------------------------------------------------------------- /src/oci-network-load-balancer-mcp-server/oracle/oci_network_load_balancer_mcp_server/server.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | 7 | import os 8 | from logging import Logger 9 | from typing import Annotated 10 | 11 | import oci 12 | from fastmcp import FastMCP 13 | 14 | from . import __project__ 15 | 16 | logger = Logger(__name__, level="INFO") 17 | 18 | mcp = FastMCP(name=__project__) 19 | 20 | 21 | def get_nlb_client(): 22 | logger.info("entering get_nlb_client") 23 | config = oci.config.from_file( 24 | profile_name=os.getenv("OCI_CONFIG_PROFILE", oci.config.DEFAULT_PROFILE) 25 | ) 26 | 27 | private_key = oci.signer.load_private_key_from_file(config["key_file"]) 28 | token_file = config["security_token_file"] 29 | token = None 30 | with open(token_file, "r") as f: 31 | token = f.read() 32 | signer = oci.auth.signers.SecurityTokenSigner(token, private_key) 33 | return oci.network_load_balancer.NetworkLoadBalancerClient(config, signer=signer) 34 | 35 | 36 | @mcp.tool( 37 | name="list_network_load_balancers", 38 | description="Lists the network load balancers from the given compartment", 39 | ) 40 | def list_network_load_balancers( 41 | compartment_id: Annotated[str, "compartment ocid"], 42 | ) -> list[dict]: 43 | nlb_client = get_nlb_client() 44 | nlbs = nlb_client.list_network_load_balancers(compartment_id).data.items 45 | return [ 46 | { 47 | "nlb_id": nlb.id, 48 | "display_name": nlb.display_name, 49 | "lifecycle_state": nlb.lifecycle_state, 50 | "public_ips": [ip.ip_address for ip in nlb.ip_addresses if ip.is_public], 51 | "private_ips": [ 52 | ip.ip_address for ip in nlb.ip_addresses if not ip.is_public 53 | ], 54 | } 55 | for nlb in nlbs 56 | ] 57 | 58 | 59 | @mcp.tool( 60 | name="get_network_load_balancer", description="Get network load balancer details" 61 | ) 62 | def get_network_load_balancer(network_load_balancer_id: Annotated[str, "nlb id"]): 63 | nlb_client = get_nlb_client() 64 | return nlb_client.get_network_load_balancer(network_load_balancer_id).data 65 | 66 | 67 | @mcp.tool(name="list_network_load_balancer_listeners") 68 | def list_listeners(network_load_balancer_id: str) -> list[dict]: 69 | """Lists the listeners from the given network load balancer""" 70 | nlb_client = get_nlb_client() 71 | listeners = nlb_client.list_listeners(network_load_balancer_id).data.items 72 | return [ 73 | { 74 | "name": listener.name, 75 | "ip_version": listener.ip_version, 76 | "protocol": listener.protocol, 77 | "port": listener.port, 78 | "is_ppv2_enabled": listener.is_ppv2_enabled, 79 | } 80 | for listener in listeners 81 | ] 82 | 83 | 84 | @mcp.tool(name="get_network_load_balancer_listener") 85 | def get_listener( 86 | network_load_balancer_id: str, 87 | listener_name: str, 88 | ): 89 | """Gets the listener with the given listener name 90 | from the given network load balancer""" 91 | nlb_client = get_nlb_client() 92 | return nlb_client.get_listener(network_load_balancer_id, listener_name).data 93 | 94 | 95 | @mcp.tool(name="list_network_load_balancer_backend_sets") 96 | def list_backend_sets(network_load_balancer_id: str) -> list[dict]: 97 | """Lists the backend sets from the given network load balancer""" 98 | nlb_client = get_nlb_client() 99 | backend_sets = nlb_client.list_backend_sets(network_load_balancer_id).data.items 100 | return [ 101 | { 102 | "name": backend_set.name, 103 | "ip_version": backend_set.ip_version, 104 | "is_preemptive": backend_set.are_operationally_active_backends_preferred, 105 | "load_balancing_policy": backend_set.policy, 106 | "number_of_backends": len(backend_set.backends), 107 | } 108 | for backend_set in backend_sets 109 | ] 110 | 111 | 112 | @mcp.tool(name="get_network_load_balancer_backend_set") 113 | def get_backend_set( 114 | network_load_balancer_id: str, 115 | backend_set_name: str, 116 | ): 117 | """Gets the backend set with the given backend set name 118 | from the given network load balancer""" 119 | nlb_client = get_nlb_client() 120 | return nlb_client.get_backend_set(network_load_balancer_id, backend_set_name).data 121 | 122 | 123 | @mcp.tool(name="list_network_load_balancer_backends") 124 | def list_backends( 125 | network_load_balancer_id: str, 126 | backend_set_name: str, 127 | ) -> list[dict]: 128 | """Lists the backends from the given backend set and network load balancer""" 129 | nlb_client = get_nlb_client() 130 | backends = nlb_client.list_backends( 131 | network_load_balancer_id, backend_set_name 132 | ).data.items 133 | return [ 134 | { 135 | "name": backend.name, 136 | "ip_address": backend.ip_address, 137 | "port": backend.port, 138 | "weight": backend.weight, 139 | "is_drain": backend.is_drain, 140 | "is_backup": backend.is_backup, 141 | "is_offline": backend.is_offline, 142 | } 143 | for backend in backends 144 | ] 145 | 146 | 147 | @mcp.tool(name="get_network_load_balancer_backend") 148 | def get_backend( 149 | network_load_balancer_id: str, 150 | backend_set_name: str, 151 | backend_name: str, 152 | ): 153 | """Gets the backend with the given backend name 154 | from the given backend set and network load balancer""" 155 | nlb_client = get_nlb_client() 156 | return nlb_client.get_backend( 157 | network_load_balancer_id, backend_set_name, backend_name 158 | ).data 159 | 160 | 161 | def main(): 162 | mcp.run() 163 | 164 | 165 | if __name__ == "__main__": 166 | main() 167 | -------------------------------------------------------------------------------- /src/oci-network-load-balancer-mcp-server/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "oracle.oci-network-load-balancer-mcp-server" 3 | version = "1.0.1" 4 | description = "OCI Network Load Balancer MCP server" 5 | readme = "README.md" 6 | requires-python = ">=3.13" 7 | license = "UPL-1.0" 8 | license-files = ["LICENSE.txt"] 9 | authors = [ 10 | {name = "Oracle MCP", email = "237432095+oracle-mcp@users.noreply.github.com"}, 11 | ] 12 | dependencies = [ 13 | "fastmcp==2.12.2", 14 | "oci==2.160.0", 15 | ] 16 | 17 | classifiers = [ 18 | "License :: OSI Approved :: Universal Permissive License (UPL)", 19 | "Operating System :: OS Independent", 20 | "Programming Language :: Python", 21 | "Programming Language :: Python :: 3.13", 22 | ] 23 | 24 | [project.scripts] 25 | "oracle.oci-network-load-balancer-mcp-server" = "oracle.oci_network_load_balancer_mcp_server.server:main" 26 | 27 | [build-system] 28 | requires = ["hatchling"] 29 | build-backend = "hatchling.build" 30 | 31 | [tool.hatch.build.targets.wheel] 32 | packages = ["oracle"] 33 | 34 | [dependency-groups] 35 | dev = [ 36 | "pytest>=8.4.2", 37 | "pytest-asyncio>=1.2.0", 38 | "pytest-cov>=7.0.0", 39 | ] 40 | 41 | [tool.coverage.run] 42 | omit = [ 43 | "**/__init__.py", 44 | "**/tests/*", 45 | "dist/*", 46 | ".venv/*", 47 | ] 48 | 49 | [tool.coverage.report] 50 | precision = 2 51 | fail_under = 66.66 52 | 53 | 54 | -------------------------------------------------------------------------------- /src/oci-networking-mcp-server/.python-version: -------------------------------------------------------------------------------- 1 | 3.13 2 | -------------------------------------------------------------------------------- /src/oci-networking-mcp-server/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2025 Oracle and/or its affiliates. 2 | 3 | The Universal Permissive License (UPL), Version 1.0 4 | 5 | Subject to the condition set forth below, permission is hereby granted to any 6 | person obtaining a copy of this software, associated documentation and/or data 7 | (collectively the "Software"), free of charge and under any and all copyright 8 | rights in the Software, and any and all patent rights owned or freely 9 | licensable by each licensor hereunder covering either (i) the unmodified 10 | Software as contributed to or provided by such licensor, or (ii) the Larger 11 | Works (as defined below), to deal in both 12 | 13 | (a) the Software, and 14 | (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if 15 | one is included with the Software (each a "Larger Work" to which the Software 16 | is contributed by such licensors), 17 | 18 | without restriction, including without limitation the rights to copy, create 19 | derivative works of, display, perform, and distribute the Software and make, 20 | use, sell, offer for sale, import, export, have made, and have sold the 21 | Software and the Larger Work(s), and to sublicense the foregoing rights on 22 | either these or other terms. 23 | 24 | This license is subject to the following condition: 25 | The above copyright notice and either this complete permission notice or at 26 | a minimum a reference to the UPL must be included in all copies or 27 | substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 35 | SOFTWARE. -------------------------------------------------------------------------------- /src/oci-networking-mcp-server/README.md: -------------------------------------------------------------------------------- 1 | # OCI Networking MCP Server 2 | 3 | ## Overview 4 | 5 | This server provides tools to interact with the OCI Networking resources. 6 | It includes tools to help with managing network configurations. 7 | 8 | ## Running the server 9 | 10 | ```sh 11 | uv run oracle.oci-networking-mcp-server 12 | ``` 13 | 14 | ## Tools 15 | 16 | | Tool Name | Description | 17 | | --- | --- | 18 | | list_vcns | List Virtual Cloud Networks (VCNs) in a given compartment | 19 | | get_vcn | Get a VCN with a given VCN OCID | 20 | | delete_vcn | Delete a VCN with a given VCN OCID | 21 | | create_vcn | Create a new VCN | 22 | | list_subnets | List subnets in a given compartment and VCN | 23 | | get_subnet | Get a subnet with a given subnet OCID | 24 | | create_subnet | Create a new subnet | 25 | | list_security_lists | List security lists in a given VCN and compartment | 26 | | get_security_list | Get a security list with a given security list OCID | 27 | | list_network_security_groups | List network security groups in a given compartment and VCN | 28 | | get_network_security_group | Get a network security group with a given NSG OCID | 29 | 30 | ⚠️ **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. 31 | 32 | ## Third-Party APIs 33 | 34 | 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. 35 | 36 | ## Disclaimer 37 | 38 | Users are responsible for their local environment and credential safety. Different language model selections may yield different results and performance. 39 | 40 | ## License 41 | 42 | Copyright (c) 2025 Oracle and/or its affiliates. 43 | 44 | Released under the Universal Permissive License v1.0 as shown at 45 | . 46 | -------------------------------------------------------------------------------- /src/oci-networking-mcp-server/oracle/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | -------------------------------------------------------------------------------- /src/oci-networking-mcp-server/oracle/oci_networking_mcp_server/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | 7 | __project__ = "oracle.oci-networking-mcp-server" 8 | __version__ = "1.0.1" 9 | -------------------------------------------------------------------------------- /src/oci-networking-mcp-server/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "oracle.oci-networking-mcp-server" 3 | version = "1.0.1" 4 | description = "OCI Networking Service MCP server" 5 | readme = "README.md" 6 | requires-python = ">=3.13" 7 | license = "UPL-1.0" 8 | license-files = ["LICENSE.txt"] 9 | authors = [ 10 | {name = "Oracle MCP", email = "237432095+oracle-mcp@users.noreply.github.com"}, 11 | ] 12 | dependencies = [ 13 | "fastmcp==2.12.2", 14 | "oci==2.160.0", 15 | ] 16 | 17 | classifiers = [ 18 | "License :: OSI Approved :: Universal Permissive License (UPL)", 19 | "Operating System :: OS Independent", 20 | "Programming Language :: Python", 21 | "Programming Language :: Python :: 3.13", 22 | ] 23 | 24 | [project.scripts] 25 | "oracle.oci-networking-mcp-server" = "oracle.oci_networking_mcp_server.server:main" 26 | 27 | [build-system] 28 | requires = ["hatchling"] 29 | build-backend = "hatchling.build" 30 | 31 | [tool.hatch.build.targets.wheel] 32 | packages = ["oracle"] 33 | 34 | [dependency-groups] 35 | dev = [ 36 | "pytest>=8.4.2", 37 | "pytest-asyncio>=1.2.0", 38 | "pytest-cov>=7.0.0", 39 | ] 40 | 41 | [tool.coverage.run] 42 | omit = [ 43 | "**/__init__.py", 44 | "**/tests/*", 45 | "dist/*", 46 | ".venv/*", 47 | ] 48 | 49 | [tool.coverage.report] 50 | precision = 2 51 | fail_under = 65.78 52 | 53 | 54 | -------------------------------------------------------------------------------- /src/oci-object-storage-mcp-server/.python-version: -------------------------------------------------------------------------------- 1 | 3.13 2 | -------------------------------------------------------------------------------- /src/oci-object-storage-mcp-server/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2025 Oracle and/or its affiliates. 2 | 3 | The Universal Permissive License (UPL), Version 1.0 4 | 5 | Subject to the condition set forth below, permission is hereby granted to any 6 | person obtaining a copy of this software, associated documentation and/or data 7 | (collectively the "Software"), free of charge and under any and all copyright 8 | rights in the Software, and any and all patent rights owned or freely 9 | licensable by each licensor hereunder covering either (i) the unmodified 10 | Software as contributed to or provided by such licensor, or (ii) the Larger 11 | Works (as defined below), to deal in both 12 | 13 | (a) the Software, and 14 | (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if 15 | one is included with the Software (each a "Larger Work" to which the Software 16 | is contributed by such licensors), 17 | 18 | without restriction, including without limitation the rights to copy, create 19 | derivative works of, display, perform, and distribute the Software and make, 20 | use, sell, offer for sale, import, export, have made, and have sold the 21 | Software and the Larger Work(s), and to sublicense the foregoing rights on 22 | either these or other terms. 23 | 24 | This license is subject to the following condition: 25 | The above copyright notice and either this complete permission notice or at 26 | a minimum a reference to the UPL must be included in all copies or 27 | substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 35 | SOFTWARE. -------------------------------------------------------------------------------- /src/oci-object-storage-mcp-server/README.md: -------------------------------------------------------------------------------- 1 | # OCI Object Storage MCP Server 2 | 3 | ## Overview 4 | 5 | This server provides tools to interact with the OCI Object Storage resources. 6 | It includes tools to help with managing object storage configurations. 7 | 8 | ## Running the server 9 | 10 | ```sh 11 | uv run oracle.oci-object-storage-mcp-server 12 | ``` 13 | 14 | ## Tools 15 | 16 | | Tool Name | Description | 17 | | --- | --- | 18 | | get_namespace | Get the object storage namespace for the tenancy | 19 | | list_buckets | List object storage buckets in a given compartment | 20 | | get_bucket_details | Get details for a specific object storage bucket | 21 | | list_objects | List objects in a given object storage bucket | 22 | | list_object_versions | List object versions in a given object storage bucket | 23 | | get_object | Get a specific object from an object storage bucket | 24 | | upload_object | Upload an object to an object storage bucket | 25 | 26 | ⚠️ **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. 27 | 28 | ## Third-Party APIs 29 | 30 | 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. 31 | 32 | ## Disclaimer 33 | 34 | Users are responsible for their local environment and credential safety. Different language model selections may yield different results and performance. 35 | 36 | ## License 37 | 38 | Copyright (c) 2025 Oracle and/or its affiliates. 39 | 40 | Released under the Universal Permissive License v1.0 as shown at 41 | . 42 | 43 | -------------------------------------------------------------------------------- /src/oci-object-storage-mcp-server/oracle/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | -------------------------------------------------------------------------------- /src/oci-object-storage-mcp-server/oracle/oci_object_storage_mcp_server/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | 7 | __project__ = "oracle.oci-object-storage-mcp-server" 8 | __version__ = "1.0.1" 9 | -------------------------------------------------------------------------------- /src/oci-object-storage-mcp-server/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "oracle.oci-object-storage-mcp-server" 3 | version = "1.0.1" 4 | description = "OCI Object Storage Service MCP server" 5 | readme = "README.md" 6 | authors = [ 7 | {name = "Oracle MCP", email = "237432095+oracle-mcp@users.noreply.github.com"}, 8 | ] 9 | requires-python = ">=3.13" 10 | dependencies = [ 11 | "fastmcp==2.12.2", 12 | "oci==2.160.0", 13 | ] 14 | 15 | classifiers = [ 16 | "License :: OSI Approved :: Universal Permissive License (UPL)", 17 | "Operating System :: OS Independent", 18 | "Programming Language :: Python", 19 | "Programming Language :: Python :: 3.13", 20 | ] 21 | 22 | [project.scripts] 23 | "oracle.oci-object-storage-mcp-server" = "oracle.oci_object_storage_mcp_server.server:main" 24 | 25 | [build-system] 26 | requires = ["hatchling"] 27 | build-backend = "hatchling.build" 28 | 29 | [tool.hatch.build.targets.wheel] 30 | packages = ["oracle"] 31 | 32 | [dependency-groups] 33 | dev = [ 34 | "pytest>=8.4.2", 35 | "pytest-asyncio>=1.2.0", 36 | "pytest-cov>=7.0.0", 37 | ] 38 | 39 | [tool.coverage.run] 40 | omit = [ 41 | "**/__init__.py", 42 | "**/tests/*", 43 | "dist/*", 44 | ".venv/*", 45 | ] 46 | 47 | [tool.coverage.report] 48 | precision = 2 49 | fail_under = 85.78 50 | 51 | -------------------------------------------------------------------------------- /src/oci-pricing-mcp-server/.dockerignore: -------------------------------------------------------------------------------- 1 | # VCS / OS 2 | .git 3 | .gitignore 4 | .DS_Store 5 | 6 | # Python 7 | __pycache__/ 8 | *.py[cod] 9 | *.pyo 10 | *.pyd 11 | *.egg-info/ 12 | .eggs/ 13 | .venv/ 14 | venv/ 15 | env/ 16 | pip-wheel-metadata/ 17 | 18 | # Tool caches 19 | .mypy_cache/ 20 | .ruff_cache/ 21 | .pytest_cache/ 22 | .cache/ 23 | 24 | # Build artifacts 25 | build/ 26 | dist/ 27 | 28 | # IDE 29 | .vscode/ 30 | .idea/ 31 | 32 | # Secrets & local env 33 | .env 34 | .env.* 35 | -------------------------------------------------------------------------------- /src/oci-pricing-mcp-server/.gitignore: -------------------------------------------------------------------------------- 1 | # OS / VCS 2 | .DS_Store 3 | Thumbs.db 4 | .git/ 5 | .git-* 6 | *.orig 7 | 8 | # Python bytecode 9 | __pycache__/ 10 | *.py[cod] 11 | *$py.class 12 | 13 | # Virtual env 14 | .venv/ 15 | venv/ 16 | env/ 17 | ENV/ 18 | .conda/ 19 | .mamba/ 20 | 21 | # Packaging / build 22 | build/ 23 | dist/ 24 | *.egg-info/ 25 | .eggs/ 26 | pip-wheel-metadata/ 27 | wheels/ 28 | *.egg 29 | MANIFEST 30 | 31 | # Test / coverage 32 | .pytest_cache/ 33 | .coverage 34 | .coverage.* 35 | htmlcov/ 36 | .cache/ 37 | .nox/ 38 | .tox/ 39 | 40 | # Type checking / linters 41 | .mypy_cache/ 42 | .ruff_cache/ 43 | .pyre/ 44 | 45 | # Logs / temp 46 | *.log 47 | logs/ 48 | *.pid 49 | *.tmp 50 | *.swp 51 | 52 | # Notebooks 53 | .ipynb_checkpoints/ 54 | 55 | # IDE 56 | .vscode/ 57 | .idea/ 58 | *.code-workspace 59 | 60 | # Secrets / local env 61 | .env 62 | .env.* 63 | *.pem 64 | *.key 65 | *.crt 66 | 67 | # Docker (repo 内で不要なローカル生成物) 68 | docker-compose.override.yml 69 | -------------------------------------------------------------------------------- /src/oci-pricing-mcp-server/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.11-slim 2 | WORKDIR /app 3 | COPY . /app 4 | RUN pip install -U pip && pip install fastmcp httpx babel pycountry 5 | CMD ["python", "oci-pricing-mcp-server.py"] 6 | -------------------------------------------------------------------------------- /src/oci-pricing-mcp-server/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2025 Oracle and/or its affiliates. 2 | 3 | The Universal Permissive License (UPL), Version 1.0 4 | 5 | Subject to the condition set forth below, permission is hereby granted to any 6 | person obtaining a copy of this software, associated documentation and/or data 7 | (collectively the "Software"), free of charge and under any and all copyright 8 | rights in the Software, and any and all patent rights owned or freely 9 | licensable by each licensor hereunder covering either (i) the unmodified 10 | Software as contributed to or provided by such licensor, or (ii) the Larger 11 | Works (as defined below), to deal in both 12 | 13 | (a) the Software, and 14 | (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if 15 | one is included with the Software (each a "Larger Work" to which the Software 16 | is contributed by such licensors), 17 | 18 | without restriction, including without limitation the rights to copy, create 19 | derivative works of, display, perform, and distribute the Software and make, 20 | use, sell, offer for sale, import, export, have made, and have sold the 21 | Software and the Larger Work(s), and to sublicense the foregoing rights on 22 | either these or other terms. 23 | 24 | This license is subject to the following condition: 25 | The above copyright notice and either this complete permission notice or at 26 | a minimum a reference to the UPL must be included in all copies or 27 | substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 35 | SOFTWARE. -------------------------------------------------------------------------------- /src/oci-pricing-mcp-server/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "oci-pricing-mcp-server" 3 | version = "0.1.0" 4 | description = "OCI Pricing MCP Server" 5 | readme = "README.md" 6 | license = "UPL-1.0" 7 | license-files = ["LICENSE.txt"] 8 | authors = [ 9 | {name = "Oracle MCP", email = "237432095+oracle-mcp@users.noreply.github.com"}, 10 | ] 11 | requires-python = ">=3.11" 12 | dependencies = [ 13 | "fastmcp>=2.0.0", 14 | "httpx>=0.27.0", 15 | "babel>=2.10", 16 | "pycountry>=22.3.5", 17 | ] 18 | 19 | classifiers = [ 20 | "License :: OSI Approved :: Universal Permissive License (UPL)", 21 | "Operating System :: OS Independent", 22 | "Programming Language :: Python", 23 | "Programming Language :: Python :: 3.11", 24 | "Programming Language :: Python :: 3.12", 25 | "Programming Language :: Python :: 3.13", 26 | ] 27 | 28 | [project.scripts] 29 | oci-pricing-mcp = "oci_pricing_mcp.entry:main" 30 | 31 | [tool.setuptools.package-dir] 32 | "" = "src" 33 | 34 | [tool.setuptools.packages.find] 35 | where = ["src"] 36 | include = ["oci_pricing_mcp*"] 37 | 38 | [tool.black] 39 | line-length = 100 40 | target-version = ["py311"] 41 | 42 | [tool.ruff] 43 | line-length = 100 44 | target-version = "py311" 45 | fix = true 46 | 47 | [tool.ruff.lint] 48 | select = ["E","F","I","UP","B"] 49 | ignore = ["E501"] 50 | -------------------------------------------------------------------------------- /src/oci-registry-mcp-server/.python-version: -------------------------------------------------------------------------------- 1 | 3.13 2 | -------------------------------------------------------------------------------- /src/oci-registry-mcp-server/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2025 Oracle and/or its affiliates. 2 | 3 | The Universal Permissive License (UPL), Version 1.0 4 | 5 | Subject to the condition set forth below, permission is hereby granted to any 6 | person obtaining a copy of this software, associated documentation and/or data 7 | (collectively the "Software"), free of charge and under any and all copyright 8 | rights in the Software, and any and all patent rights owned or freely 9 | licensable by each licensor hereunder covering either (i) the unmodified 10 | Software as contributed to or provided by such licensor, or (ii) the Larger 11 | Works (as defined below), to deal in both 12 | 13 | (a) the Software, and 14 | (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if 15 | one is included with the Software (each a "Larger Work" to which the Software 16 | is contributed by such licensors), 17 | 18 | without restriction, including without limitation the rights to copy, create 19 | derivative works of, display, perform, and distribute the Software and make, 20 | use, sell, offer for sale, import, export, have made, and have sold the 21 | Software and the Larger Work(s), and to sublicense the foregoing rights on 22 | either these or other terms. 23 | 24 | This license is subject to the following condition: 25 | The above copyright notice and either this complete permission notice or at 26 | a minimum a reference to the UPL must be included in all copies or 27 | substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 35 | SOFTWARE. -------------------------------------------------------------------------------- /src/oci-registry-mcp-server/README.md: -------------------------------------------------------------------------------- 1 | # OCI Registry MCP Server 2 | 3 | ## Overview 4 | 5 | This server provides tools to interact with the OCI Registry resources. 6 | It includes tools to help with managing container repositories. 7 | 8 | ## Running the server 9 | 10 | ```sh 11 | uv run oracle.oci-registry-mcp-server 12 | ``` 13 | 14 | ## Tools 15 | 16 | | Tool Name | Description | 17 | | --- | --- | 18 | | create_container_repository | Create a new container repository | 19 | | list_container_repositories | List container repositories in a given compartment | 20 | | get_container_repo_details | Get details for a specific container repository | 21 | | delete_container_repository | Delete a container repository | 22 | 23 | ⚠️ **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. 24 | 25 | ## Third-Party APIs 26 | 27 | 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. 28 | 29 | ## Disclaimer 30 | 31 | Users are responsible for their local environment and credential safety. Different language model selections may yield different results and performance. 32 | 33 | ## License 34 | 35 | Copyright (c) 2025 Oracle and/or its affiliates. 36 | 37 | Released under the Universal Permissive License v1.0 as shown at 38 | . 39 | -------------------------------------------------------------------------------- /src/oci-registry-mcp-server/oracle/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | -------------------------------------------------------------------------------- /src/oci-registry-mcp-server/oracle/oci_registry_mcp_server/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | 7 | __project__ = "oracle.oci-registry-mcp-server" 8 | __version__ = "1.0.1" 9 | -------------------------------------------------------------------------------- /src/oci-registry-mcp-server/oracle/oci_registry_mcp_server/server.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | 7 | import os 8 | from logging import Logger 9 | 10 | import oci 11 | from fastmcp import FastMCP 12 | 13 | from . import __project__, __version__ 14 | 15 | logger = Logger(__name__, level="INFO") 16 | 17 | mcp = FastMCP(name=__project__) 18 | 19 | 20 | def get_ocir_client(): 21 | config = oci.config.from_file( 22 | profile_name=os.getenv("OCI_CONFIG_PROFILE", oci.config.DEFAULT_PROFILE) 23 | ) 24 | 25 | config["additional_user_agent"] = f"{__project__}/{__version__}" 26 | 27 | private_key = oci.signer.load_private_key_from_file(config["key_file"]) 28 | token_file = config["security_token_file"] 29 | token = None 30 | with open(token_file, "r") as f: 31 | token = f.read() 32 | signer = oci.auth.signers.SecurityTokenSigner(token, private_key) 33 | return oci.artifacts.ArtifactsClient(config, signer=signer) 34 | 35 | 36 | @mcp.tool 37 | def create_container_repository( 38 | compartment_id: str, repository_name: str, is_public: bool = False 39 | ): 40 | ocir_client = get_ocir_client() 41 | create_repository_details = oci.artifacts.models.CreateContainerRepositoryDetails( 42 | compartment_id=compartment_id, display_name=repository_name, is_public=is_public 43 | ) 44 | try: 45 | repository = ocir_client.create_container_repository( 46 | create_repository_details 47 | ).data 48 | return { 49 | "repository_name": repository.display_name, 50 | "id": repository.id, 51 | "is_public": repository.is_public, 52 | } 53 | except oci.exceptions.ServiceError as e: 54 | logger.error(f"Failed to create container repository: {e}") 55 | return {"error": str(e)} 56 | 57 | 58 | @mcp.tool 59 | def list_container_repositories(compartment_id: str): 60 | ocir_client = get_ocir_client() 61 | try: 62 | repositories = ocir_client.list_container_repositories( 63 | compartment_id=compartment_id 64 | ).data.items 65 | return [ 66 | { 67 | "repository_name": repo.display_name, 68 | "id": repo.id, 69 | "is_public": repo.is_public, 70 | } 71 | for repo in repositories 72 | ] 73 | except oci.exceptions.ServiceError as e: 74 | logger.error(f"Failed to list container repositories: {e}") 75 | return {"error": str(e)} 76 | 77 | 78 | @mcp.tool 79 | def get_container_repo_details(repository_id: str): 80 | ocir_client = get_ocir_client() 81 | try: 82 | repository = ocir_client.get_container_repository( 83 | repository_id=repository_id 84 | ).data 85 | return { 86 | "repository_name": repository.display_name, 87 | "id": repository.id, 88 | "is_public": repository.is_public, 89 | "compartment_id": repository.compartment_id, 90 | "time_created": repository.time_created.isoformat(), 91 | } 92 | except oci.exceptions.ServiceError as e: 93 | logger.error(f"Failed to get container repository details: {e}") 94 | return {"error": str(e)} 95 | 96 | 97 | @mcp.tool 98 | def delete_container_repository(repository_id: str): 99 | ocir_client = get_ocir_client() 100 | try: 101 | ocir_client.delete_container_repository(repository_id=repository_id) 102 | return {"success": True} 103 | except oci.exceptions.ServiceError as e: 104 | logger.error(f"Failed to delete container repository: {e}") 105 | return {"error": str(e), "success": False} 106 | 107 | 108 | def main(): 109 | mcp.run() 110 | 111 | 112 | if __name__ == "__main__": 113 | main() 114 | -------------------------------------------------------------------------------- /src/oci-registry-mcp-server/oracle/oci_registry_mcp_server/tests/test_registry_tools.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | 7 | from unittest.mock import MagicMock, create_autospec, patch 8 | 9 | import oci 10 | import pytest 11 | from fastmcp import Client 12 | from oracle.oci_registry_mcp_server.server import mcp 13 | 14 | 15 | class TestRegistryTools: 16 | @pytest.mark.asyncio 17 | @patch("oracle.oci_registry_mcp_server.server.get_ocir_client") 18 | async def test_create_container_repository(self, mock_get_client): 19 | mock_client = MagicMock() 20 | mock_get_client.return_value = mock_client 21 | 22 | mock_create_response = create_autospec(oci.response.Response) 23 | mock_create_response.data = oci.artifacts.models.ContainerRepository( 24 | display_name="repo1", id="repo1_id", is_public=False 25 | ) 26 | mock_client.create_container_repository.return_value = mock_create_response 27 | 28 | async with Client(mcp) as client: 29 | result = ( 30 | await client.call_tool( 31 | "create_container_repository", 32 | { 33 | "compartment_id": "compartment1", 34 | "repository_name": "repo1", 35 | }, 36 | ) 37 | ).structured_content 38 | 39 | assert result["repository_name"] == "repo1" 40 | 41 | # @pytest.mark.asyncio 42 | # @patch("oracle.oci_registry_mcp_server.server.get_ocir_client") 43 | # async def test_list_container_repositories(self, mock_get_client): 44 | # mock_client = MagicMock() 45 | # mock_get_client.return_value = mock_client 46 | 47 | # mock_list_response = create_autospec(oci.response.Response) 48 | # mock_list_response.data = oci.artifacts.models.ContainerRepositoryCollection( 49 | # items=[MagicMock(display_name="repo1", id="repo1_id", is_public=False)] 50 | # ) 51 | # mock_client.list_container_repositories.return_value = mock_list_response 52 | 53 | # async with Client(mcp) as client: 54 | # result = ( 55 | # await client.call_tool( 56 | # "list_container_repositories", 57 | # { 58 | # "compartment_id": "compartment1", 59 | # }, 60 | # ) 61 | # ).structured_content 62 | 63 | # assert len(result) == 1 64 | # assert result[0]["repository_name"] == "repo1" 65 | 66 | @pytest.mark.asyncio 67 | @patch("oracle.oci_registry_mcp_server.server.get_ocir_client") 68 | async def test_get_container_repo_details(self, mock_get_client): 69 | mock_client = MagicMock() 70 | mock_get_client.return_value = mock_client 71 | 72 | mock_get_response = create_autospec(oci.response.Response) 73 | mock_get_response.data = MagicMock( 74 | display_name="repo1", 75 | id="repo1_id", 76 | is_public=False, 77 | compartment_id="compartment1", 78 | ) 79 | mock_client.get_container_repository.return_value = mock_get_response 80 | 81 | async with Client(mcp) as client: 82 | result = ( 83 | await client.call_tool( 84 | "get_container_repo_details", 85 | { 86 | "repository_id": "repo1_id", 87 | }, 88 | ) 89 | ).data 90 | 91 | assert result["repository_name"] == "repo1" 92 | 93 | @pytest.mark.asyncio 94 | @patch("oracle.oci_registry_mcp_server.server.get_ocir_client") 95 | async def test_delete_container_repository(self, mock_get_client): 96 | mock_client = MagicMock() 97 | mock_get_client.return_value = mock_client 98 | 99 | mock_delete_response = create_autospec(oci.response.Response) 100 | mock_client.delete_container_repository.return_value = mock_delete_response 101 | 102 | async with Client(mcp) as client: 103 | result = ( 104 | await client.call_tool( 105 | "delete_container_repository", 106 | { 107 | "repository_id": "repo1_id", 108 | }, 109 | ) 110 | ).data 111 | 112 | assert result["success"] 113 | -------------------------------------------------------------------------------- /src/oci-registry-mcp-server/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "oracle.oci-registry-mcp-server" 3 | version = "1.0.1" 4 | description = "OCI Registry Service MCP server" 5 | readme = "README.md" 6 | requires-python = ">=3.13" 7 | license = "UPL-1.0" 8 | license-files = ["LICENSE.txt"] 9 | authors = [ 10 | {name = "Oracle MCP", email = "237432095+oracle-mcp@users.noreply.github.com"}, 11 | ] 12 | dependencies = [ 13 | "fastmcp==2.12.2", 14 | "oci==2.160.0", 15 | ] 16 | 17 | classifiers = [ 18 | "License :: OSI Approved :: Universal Permissive License (UPL)", 19 | "Operating System :: OS Independent", 20 | "Programming Language :: Python", 21 | "Programming Language :: Python :: 3.13", 22 | ] 23 | 24 | [project.scripts] 25 | "oracle.oci-registry-mcp-server" = "oracle.oci_registry_mcp_server.server:main" 26 | 27 | [build-system] 28 | requires = ["hatchling"] 29 | build-backend = "hatchling.build" 30 | 31 | [tool.hatch.build.targets.wheel] 32 | packages = ["oracle"] 33 | 34 | [dependency-groups] 35 | dev = [ 36 | "pytest>=8.4.2", 37 | "pytest-asyncio>=1.2.0", 38 | "pytest-cov>=7.0.0", 39 | ] 40 | 41 | [tool.coverage.run] 42 | omit = [ 43 | "**/__init__.py", 44 | "**/tests/*", 45 | "dist/*", 46 | ".venv/*", 47 | ] 48 | 49 | [tool.coverage.report] 50 | precision = 2 51 | fail_under = 53 52 | -------------------------------------------------------------------------------- /src/oci-resource-search-mcp-server/.python-version: -------------------------------------------------------------------------------- 1 | 3.13 2 | -------------------------------------------------------------------------------- /src/oci-resource-search-mcp-server/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2025 Oracle and/or its affiliates. 2 | 3 | The Universal Permissive License (UPL), Version 1.0 4 | 5 | Subject to the condition set forth below, permission is hereby granted to any 6 | person obtaining a copy of this software, associated documentation and/or data 7 | (collectively the "Software"), free of charge and under any and all copyright 8 | rights in the Software, and any and all patent rights owned or freely 9 | licensable by each licensor hereunder covering either (i) the unmodified 10 | Software as contributed to or provided by such licensor, or (ii) the Larger 11 | Works (as defined below), to deal in both 12 | 13 | (a) the Software, and 14 | (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if 15 | one is included with the Software (each a "Larger Work" to which the Software 16 | is contributed by such licensors), 17 | 18 | without restriction, including without limitation the rights to copy, create 19 | derivative works of, display, perform, and distribute the Software and make, 20 | use, sell, offer for sale, import, export, have made, and have sold the 21 | Software and the Larger Work(s), and to sublicense the foregoing rights on 22 | either these or other terms. 23 | 24 | This license is subject to the following condition: 25 | The above copyright notice and either this complete permission notice or at 26 | a minimum a reference to the UPL must be included in all copies or 27 | substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 35 | SOFTWARE. -------------------------------------------------------------------------------- /src/oci-resource-search-mcp-server/README.md: -------------------------------------------------------------------------------- 1 | # OCI Resource Search MCP Server 2 | 3 | ## Overview 4 | 5 | This server provides tools for interacting with Oracle Cloud Infrastructure (OCI) Resource Search service. 6 | 7 | ## Running the server 8 | 9 | ```sh 10 | uv run oracle.oci-resource-search-mcp-server 11 | ``` 12 | 13 | ## Tools 14 | 15 | | Tool Name | Description | 16 | | --- | --- | 17 | | search_resources | Search for resources in the tenancy | 18 | 19 | 20 | ⚠️ **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. 21 | 22 | ## Third-Party APIs 23 | 24 | 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. 25 | 26 | ## Disclaimer 27 | 28 | Users are responsible for their local environment and credential safety. Different language model selections may yield different results and performance. 29 | 30 | ## License 31 | 32 | Copyright (c) 2025 Oracle and/or its affiliates. 33 | 34 | Released under the Universal Permissive License v1.0 as shown at 35 | . 36 | -------------------------------------------------------------------------------- /src/oci-resource-search-mcp-server/oracle/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | -------------------------------------------------------------------------------- /src/oci-resource-search-mcp-server/oracle/oci_resource_search_mcp_server/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | 7 | __project__ = "oracle.oci-resource-search-mcp-server" 8 | __version__ = "1.0.1" 9 | -------------------------------------------------------------------------------- /src/oci-resource-search-mcp-server/oracle/oci_resource_search_mcp_server/server.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | 7 | import os 8 | from logging import Logger 9 | from typing import Annotated 10 | 11 | import oci 12 | from fastmcp import FastMCP 13 | from oci.resource_search.models import FreeTextSearchDetails, StructuredSearchDetails 14 | 15 | from . import __project__, __version__ 16 | 17 | logger = Logger(__name__, level="INFO") 18 | 19 | mcp = FastMCP(name=__project__) 20 | 21 | 22 | def get_search_client(): 23 | logger.info("entering get_search_client") 24 | config = oci.config.from_file( 25 | profile_name=os.getenv("OCI_CONFIG_PROFILE", oci.config.DEFAULT_PROFILE) 26 | ) 27 | 28 | user_agent_name = __project__.split("oracle.", 1)[1].split("-server", 1)[0] 29 | config["additional_user_agent"] = f"{user_agent_name}/{__version__}" 30 | 31 | private_key = oci.signer.load_private_key_from_file(config["key_file"]) 32 | token_file = config["security_token_file"] 33 | token = None 34 | with open(token_file, "r") as f: 35 | token = f.read() 36 | signer = oci.auth.signers.SecurityTokenSigner(token, private_key) 37 | return oci.resource_search.ResourceSearchClient(config, signer=signer) 38 | 39 | 40 | @mcp.tool 41 | def list_all_resources(compartment_id: str) -> list[dict]: 42 | """Returns all resources""" 43 | search_client = get_search_client() 44 | structured_search = StructuredSearchDetails( 45 | type="Structured", 46 | query=f"query all resources where compartmentId = '{compartment_id}'", 47 | ) 48 | response = search_client.search_resources(structured_search).data 49 | return [ 50 | { 51 | "resource_id": resource.identifier, 52 | "compartment_id": compartment_id, 53 | "display_name": resource.display_name, 54 | "resource_type": resource.resource_type, 55 | "lifecycle_state": resource.lifecycle_state, 56 | "freeform_tags": resource.freeform_tags, 57 | "defined_tags": resource.defined_tags, 58 | } 59 | for resource in response.items 60 | ] 61 | 62 | 63 | @mcp.tool 64 | def search_resources( 65 | compartment_id: str, 66 | display_name: Annotated[str, "Full display name or display name substring"], 67 | ) -> list[dict]: 68 | """Searches for resources by display name""" 69 | search_client = get_search_client() 70 | structured_search = StructuredSearchDetails( 71 | type="Structured", 72 | query=( 73 | f"query all resources where compartmentId = '{compartment_id}' " 74 | f"&& displayName =~ '{display_name}'" 75 | ), 76 | ) 77 | response = search_client.search_resources(structured_search).data 78 | return [ 79 | { 80 | "resource_id": resource.identifier, 81 | "compartment_id": compartment_id, 82 | "display_name": resource.display_name, 83 | "resource_type": resource.resource_type, 84 | "lifecycle_state": resource.lifecycle_state, 85 | "freeform_tags": resource.freeform_tags, 86 | "defined_tags": resource.defined_tags, 87 | } 88 | for resource in response.items 89 | ] 90 | 91 | 92 | @mcp.tool 93 | def search_resources_free_form( 94 | compartment_id: str, 95 | text: Annotated[str, "Free-form search string"], 96 | ) -> list[dict]: 97 | """Searches for the presence of the search string in all resource fields""" 98 | search_client = get_search_client() 99 | freetext_search = FreeTextSearchDetails( 100 | type="FreeText", 101 | text=text, 102 | ) 103 | response = search_client.search_resources(freetext_search).data 104 | return [ 105 | { 106 | "resource_id": resource.identifier, 107 | "compartment_id": compartment_id, 108 | "display_name": resource.display_name, 109 | "resource_type": resource.resource_type, 110 | "lifecycle_state": resource.lifecycle_state, 111 | "freeform_tags": resource.freeform_tags, 112 | "defined_tags": resource.defined_tags, 113 | } 114 | for resource in response.items 115 | ] 116 | 117 | 118 | def search_resources_by_type(compartment_id: str, resource_type: str): 119 | """Search for resources by resource type""" 120 | search_client = get_search_client() 121 | structured_search = StructuredSearchDetails( 122 | type="Structured", 123 | query=( 124 | f"query all {resource_type} " 125 | f"resources where compartmentId = '{compartment_id}'" 126 | ), 127 | ) 128 | response = search_client.search_resources(structured_search).data 129 | return [ 130 | { 131 | "resource_id": resource.identifier, 132 | "compartment_id": compartment_id, 133 | "display_name": resource.display_name, 134 | "resource_type": resource.resource_type, 135 | "lifecycle_state": resource.lifecycle_state, 136 | "freeform_tags": resource.freeform_tags, 137 | "defined_tags": resource.defined_tags, 138 | } 139 | for resource in response.items 140 | ] 141 | 142 | 143 | @mcp.tool 144 | def list_resource_types() -> list[str]: 145 | """Returns a list of all supported OCI resource types""" 146 | search_client = get_search_client() 147 | resource_types = search_client.list_resource_types() 148 | return [x.name for x in resource_types.data] 149 | 150 | 151 | def main(): 152 | mcp.run() 153 | 154 | 155 | if __name__ == "__main__": 156 | main() 157 | -------------------------------------------------------------------------------- /src/oci-resource-search-mcp-server/oracle/oci_resource_search_mcp_server/tests/test_resource_search_tools.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | 7 | from unittest.mock import MagicMock, create_autospec, patch 8 | 9 | import oci 10 | import pytest 11 | from fastmcp import Client 12 | from oracle.oci_resource_search_mcp_server.server import mcp 13 | 14 | 15 | class TestResourceSearchTools: 16 | @pytest.mark.asyncio 17 | @patch("oracle.oci_resource_search_mcp_server.server.get_search_client") 18 | async def test_list_all_resources(self, mock_get_client): 19 | mock_client = MagicMock() 20 | mock_get_client.return_value = mock_client 21 | 22 | mock_search_response = create_autospec(oci.response.Response) 23 | mock_search_response.data = ( 24 | oci.resource_search.models.ResourceSummaryCollection( 25 | items=[ 26 | oci.resource_search.models.ResourceSummary( 27 | identifier="resource1", 28 | display_name="Resource 1", 29 | resource_type="instance", 30 | lifecycle_state="RUNNING", 31 | ) 32 | ] 33 | ) 34 | ) 35 | mock_client.search_resources.return_value = mock_search_response 36 | 37 | async with Client(mcp) as client: 38 | result = ( 39 | await client.call_tool( 40 | "list_all_resources", 41 | { 42 | "compartment_id": "compartment1", 43 | }, 44 | ) 45 | ).structured_content["result"] 46 | 47 | assert len(result) == 1 48 | assert result[0]["resource_id"] == "resource1" 49 | 50 | @pytest.mark.asyncio 51 | @patch("oracle.oci_resource_search_mcp_server.server.get_search_client") 52 | async def test_search_resources(self, mock_get_client): 53 | mock_client = MagicMock() 54 | mock_get_client.return_value = mock_client 55 | 56 | mock_search_response = create_autospec(oci.response.Response) 57 | mock_search_response.data = ( 58 | oci.resource_search.models.ResourceSummaryCollection( 59 | items=[ 60 | oci.resource_search.models.ResourceSummary( 61 | identifier="resource1", 62 | display_name="Resource 1", 63 | resource_type="instance", 64 | lifecycle_state="RUNNING", 65 | ) 66 | ] 67 | ) 68 | ) 69 | mock_client.search_resources.return_value = mock_search_response 70 | 71 | async with Client(mcp) as client: 72 | result = ( 73 | await client.call_tool( 74 | "search_resources", 75 | { 76 | "compartment_id": "compartment1", 77 | "display_name": "Resource", 78 | }, 79 | ) 80 | ).structured_content["result"] 81 | 82 | assert len(result) == 1 83 | assert result[0]["resource_id"] == "resource1" 84 | 85 | @pytest.mark.asyncio 86 | @patch("oracle.oci_resource_search_mcp_server.server.get_search_client") 87 | async def test_search_resources_free_form(self, mock_get_client): 88 | mock_client = MagicMock() 89 | mock_get_client.return_value = mock_client 90 | 91 | mock_search_response = create_autospec(oci.response.Response) 92 | mock_search_response.data = ( 93 | oci.resource_search.models.ResourceSummaryCollection( 94 | items=[ 95 | oci.resource_search.models.ResourceSummary( 96 | identifier="resource1", 97 | display_name="Resource 1", 98 | resource_type="instance", 99 | lifecycle_state="RUNNING", 100 | ) 101 | ] 102 | ) 103 | ) 104 | mock_client.search_resources.return_value = mock_search_response 105 | 106 | async with Client(mcp) as client: 107 | result = ( 108 | await client.call_tool( 109 | "search_resources_free_form", 110 | { 111 | "compartment_id": "compartment1", 112 | "text": "Resource", 113 | }, 114 | ) 115 | ).structured_content["result"] 116 | 117 | assert len(result) == 1 118 | assert result[0]["resource_id"] == "resource1" 119 | 120 | @pytest.mark.asyncio 121 | @patch("oracle.oci_resource_search_mcp_server.server.get_search_client") 122 | async def test_list_resource_types(self, mock_get_client): 123 | mock_client = MagicMock() 124 | mock_get_client.return_value = mock_client 125 | 126 | mock_list_response = create_autospec(oci.response.Response) 127 | mock_list_response.data = [ 128 | oci.resource_search.models.ResourceType(name="instance"), 129 | oci.resource_search.models.ResourceType(name="volume"), 130 | ] 131 | mock_client.list_resource_types.return_value = mock_list_response 132 | 133 | async with Client(mcp) as client: 134 | result = (await client.call_tool("list_resource_types", {})).data 135 | 136 | assert result == ["instance", "volume"] 137 | -------------------------------------------------------------------------------- /src/oci-resource-search-mcp-server/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "oracle.oci-resource-search-mcp-server" 3 | version = "1.0.1" 4 | description = "OCI Resource Search Service MCP server" 5 | readme = "README.md" 6 | requires-python = ">=3.13" 7 | license = "UPL-1.0" 8 | license-files = ["LICENSE.txt"] 9 | authors = [ 10 | {name = "Oracle MCP", email = "237432095+oracle-mcp@users.noreply.github.com"}, 11 | ] 12 | dependencies = [ 13 | "fastmcp==2.12.2", 14 | "oci==2.160.0", 15 | ] 16 | 17 | classifiers = [ 18 | "License :: OSI Approved :: Universal Permissive License (UPL)", 19 | "Operating System :: OS Independent", 20 | "Programming Language :: Python", 21 | "Programming Language :: Python :: 3.13", 22 | ] 23 | 24 | [project.scripts] 25 | "oracle.oci-resource-search-mcp-server" = "oracle.oci_resource_search_mcp_server.server:main" 26 | 27 | [build-system] 28 | requires = ["hatchling"] 29 | build-backend = "hatchling.build" 30 | 31 | [tool.hatch.build.targets.wheel] 32 | packages = ["oracle"] 33 | 34 | [dependency-groups] 35 | dev = [ 36 | "pytest>=8.4.2", 37 | "pytest-asyncio>=1.2.0", 38 | "pytest-cov>=7.0.0", 39 | ] 40 | 41 | [tool.coverage.run] 42 | omit = [ 43 | "**/__init__.py", 44 | "**/tests/*", 45 | "dist/*", 46 | ".venv/*", 47 | ] 48 | 49 | [tool.coverage.report] 50 | precision = 2 51 | fail_under = 67 52 | 53 | 54 | -------------------------------------------------------------------------------- /src/oci-usage-mcp-server/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2025 Oracle and/or its affiliates. 2 | 3 | The Universal Permissive License (UPL), Version 1.0 4 | 5 | Subject to the condition set forth below, permission is hereby granted to any 6 | person obtaining a copy of this software, associated documentation and/or data 7 | (collectively the "Software"), free of charge and under any and all copyright 8 | rights in the Software, and any and all patent rights owned or freely 9 | licensable by each licensor hereunder covering either (i) the unmodified 10 | Software as contributed to or provided by such licensor, or (ii) the Larger 11 | Works (as defined below), to deal in both 12 | 13 | (a) the Software, and 14 | (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if 15 | one is included with the Software (each a "Larger Work" to which the Software 16 | is contributed by such licensors), 17 | 18 | without restriction, including without limitation the rights to copy, create 19 | derivative works of, display, perform, and distribute the Software and make, 20 | use, sell, offer for sale, import, export, have made, and have sold the 21 | Software and the Larger Work(s), and to sublicense the foregoing rights on 22 | either these or other terms. 23 | 24 | This license is subject to the following condition: 25 | The above copyright notice and either this complete permission notice or at 26 | a minimum a reference to the UPL must be included in all copies or 27 | substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 35 | SOFTWARE. -------------------------------------------------------------------------------- /src/oci-usage-mcp-server/README.md: -------------------------------------------------------------------------------- 1 | # OCI Usage MCP Server 2 | 3 | ## Overview 4 | 5 | This server provides tools for interacting with Oracle Cloud Infrastructure (OCI) Usage service. 6 | 7 | ## Running the server 8 | 9 | ```sh 10 | uv run oracle.oci-usage-mcp-server 11 | ``` 12 | 13 | ## Tools 14 | 15 | | Tool Name | Description | 16 | | --- | --- | 17 | | list_usage_reports | List usage reports in the tenancy | 18 | | get_usage_report | Get usage report by ID | 19 | 20 | ⚠️ **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. 21 | 22 | ## Third-Party APIs 23 | 24 | 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. 25 | 26 | ## Disclaimer 27 | 28 | Users are responsible for their local environment and credential safety. Different language model selections may yield different results and performance. 29 | 30 | ## License 31 | 32 | Copyright (c) 2025 Oracle and/or its affiliates. 33 | 34 | Released under the Universal Permissive License v1.0 as shown at 35 | . 36 | -------------------------------------------------------------------------------- /src/oci-usage-mcp-server/oracle/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | -------------------------------------------------------------------------------- /src/oci-usage-mcp-server/oracle/oci_usage_mcp_server/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | 7 | __project__ = "oracle.oci-usage-mcp-server" 8 | __version__ = "1.0.1" 9 | -------------------------------------------------------------------------------- /src/oci-usage-mcp-server/oracle/oci_usage_mcp_server/server.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | 7 | import os 8 | from logging import Logger 9 | from typing import Annotated 10 | 11 | import oci 12 | from fastmcp import FastMCP 13 | from oci.usage_api.models import RequestSummarizedUsagesDetails 14 | 15 | from . import __project__, __version__ 16 | 17 | logger = Logger(__name__, level="INFO") 18 | 19 | mcp = FastMCP(name=__project__) 20 | 21 | 22 | def get_usage_client(): 23 | logger.info("entering get_monitoring_client") 24 | config = oci.config.from_file( 25 | profile_name=os.getenv("OCI_CONFIG_PROFILE", oci.config.DEFAULT_PROFILE) 26 | ) 27 | user_agent_name = __project__.split("oracle.", 1)[1].split("-server", 1)[0] 28 | config["additional_user_agent"] = f"{user_agent_name}/{__version__}" 29 | 30 | private_key = oci.signer.load_private_key_from_file(config["key_file"]) 31 | token_file = config["security_token_file"] 32 | token = None 33 | with open(token_file, "r") as f: 34 | token = f.read() 35 | signer = oci.auth.signers.SecurityTokenSigner(token, private_key) 36 | return oci.usage_api.UsageapiClient(config, signer=signer) 37 | 38 | 39 | @mcp.tool 40 | def get_summarized_usage( 41 | tenant_id: Annotated[str, "Tenancy OCID"], 42 | start_time: Annotated[ 43 | str, 44 | "The value to assign to the time_usage_started property of this RequestSummarizedUsagesDetails." 45 | "UTC date must have the right precision: hours, minutes, seconds, and second fractions must be 0", 46 | ], 47 | end_time: Annotated[ 48 | str, 49 | "The value to assign to the time_usage_ended property of this RequestSummarizedUsagesDetails." 50 | "UTC date must have the right precision: hours, minutes, seconds, and second fractions must be 0", 51 | ], 52 | group_by: Annotated[ 53 | list[str], 54 | "Aggregate the result by." 55 | "Allows values are “tagNamespace”, “tagKey”, “tagValue”, “service”," 56 | "“skuName”, “skuPartNumber”, “unit”, “compartmentName”, “compartmentPath”, “compartmentId”" 57 | "“platform”, “region”, “logicalAd”, “resourceId”, “tenantId”, “tenantName”", 58 | ], 59 | compartment_depth: Annotated[float, "The compartment depth level."], 60 | granularity: Annotated[ 61 | str, 62 | 'Allowed values for this property are: "HOURLY", "DAILY", "MONTHLY". Default: "DAILY"', 63 | ] = "DAILY", 64 | query_type: Annotated[ 65 | str, 66 | 'Allowed values are: "USAGE", "COST", "CREDIT", "EXPIREDCREDIT", "ALLCREDIT", "OVERAGE"' 67 | 'Default: "COST"', 68 | ] = "COST", 69 | is_aggregate_by_time: Annotated[ 70 | bool, 71 | "Specifies whether aggregated by time. If isAggregateByTime is true," 72 | "all usage or cost over the query time period will be added up.", 73 | ] = False, 74 | ) -> list[dict]: 75 | usage_client = get_usage_client() 76 | summarized_details = RequestSummarizedUsagesDetails( 77 | tenant_id=tenant_id, 78 | time_usage_started=start_time, 79 | time_usage_ended=end_time, 80 | granularity=granularity, 81 | is_aggregate_by_time=is_aggregate_by_time, 82 | query_type=query_type, 83 | group_by=group_by, 84 | compartment_depth=compartment_depth, 85 | ) 86 | 87 | response = usage_client.request_summarized_usages( 88 | request_summarized_usages_details=summarized_details 89 | ) 90 | # Convert UsageSummary objects to dictionaries for proper serialization 91 | summarized_usages = [ 92 | oci.util.to_dict(usage_summary) for usage_summary in response.data.items 93 | ] 94 | return summarized_usages 95 | 96 | 97 | def main(): 98 | mcp.run() 99 | 100 | 101 | if __name__ == "__main__": 102 | main() 103 | -------------------------------------------------------------------------------- /src/oci-usage-mcp-server/oracle/oci_usage_mcp_server/tests/test_usage_tools.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | 7 | from unittest.mock import MagicMock, create_autospec, patch 8 | 9 | import oci 10 | import pytest 11 | from fastmcp import Client 12 | from oracle.oci_usage_mcp_server.server import mcp 13 | 14 | 15 | class TestUsageTools: 16 | @pytest.mark.asyncio 17 | @patch("oracle.oci_usage_mcp_server.server.get_usage_client") 18 | async def test_get_summarized_usage(self, mock_get_client): 19 | mock_client = MagicMock() 20 | mock_get_client.return_value = mock_client 21 | 22 | mock_request_summarized_response = create_autospec(oci.response.Response) 23 | mock_request_summarized_response.data = oci.usage_api.models.QueryCollection( 24 | items=[ 25 | oci.usage_api.models.UsageSummary( 26 | compartment_id="test_compartment_id", 27 | compartment_name="test_compartment_name", 28 | computed_amount=6.731118997232, 29 | computed_quantity=69.842410393953, 30 | service="Database", 31 | ) 32 | ] 33 | ) 34 | 35 | mock_client.request_summarized_usages.return_value = ( 36 | mock_request_summarized_response 37 | ) 38 | print("mock response", mock_request_summarized_response) 39 | async with Client(mcp) as client: 40 | result = ( 41 | await client.call_tool( 42 | "get_summarized_usage", 43 | { 44 | "tenant_id": "test_tenant_id", 45 | "start_time": "2023-01-01T00:00:00Z", 46 | "end_time": "2023-01-02T00:00:00Z", 47 | "group_by": ["compartment"], 48 | "compartment_depth": 1.0, 49 | }, 50 | ) 51 | ).structured_content["result"] 52 | 53 | assert len(result) == 1 54 | assert result[0]["compartment_id"] == "test_compartment_id" 55 | assert result[0]["service"] == "Database" 56 | assert result[0]["computed_amount"] == 6.731118997232 57 | -------------------------------------------------------------------------------- /src/oci-usage-mcp-server/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "oracle.oci-usage-mcp-server" 3 | version = "1.0.1" 4 | description = "OCI Usage MCP server" 5 | readme = "README.md" 6 | license = "UPL-1.0" 7 | license-files = ["LICENSE.txt"] 8 | authors = [ 9 | {name = "Oracle MCP", email = "237432095+oracle-mcp@users.noreply.github.com"}, 10 | ] 11 | requires-python = ">=3.13" 12 | dependencies = [ 13 | "fastmcp==2.12.2", 14 | "oci==2.160.0", 15 | ] 16 | 17 | classifiers = [ 18 | "License :: OSI Approved :: Universal Permissive License (UPL)", 19 | "Operating System :: OS Independent", 20 | "Programming Language :: Python", 21 | "Programming Language :: Python :: 3.13", 22 | ] 23 | 24 | [project.scripts] 25 | "oracle.oci-usage-mcp-server" = "oracle.oci_usage_mcp_server.server:main" 26 | 27 | [build-system] 28 | requires = ["hatchling"] 29 | build-backend = "hatchling.build" 30 | 31 | [tool.hatch.build.targets.wheel] 32 | packages = ["oracle"] 33 | 34 | [dependency-groups] 35 | dev = [ 36 | "pytest>=8.4.2", 37 | "pytest-asyncio>=1.2.0", 38 | "pytest-cov>=7.0.0", 39 | ] 40 | 41 | [tool.coverage.run] 42 | omit = [ 43 | "**/__init__.py", 44 | "**/tests/*", 45 | "dist/*", 46 | ".venv/*", 47 | ] 48 | 49 | [tool.coverage.report] 50 | precision = 2 51 | fail_under = 58.81 52 | 53 | 54 | -------------------------------------------------------------------------------- /src/oracle-db-doc-mcp-server/.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | index* 3 | *.egg-info 4 | -------------------------------------------------------------------------------- /src/oracle-db-doc-mcp-server/Dockerfile: -------------------------------------------------------------------------------- 1 | # 2 | # Since: August 2025 3 | # Author: Gerald Venzl 4 | # Name: Dockerfile 5 | # Description: Dockerfile to build Docker image 6 | # 7 | # Copyright 2025 Oracle Corporation and/or its affiliates. 8 | # 9 | # Licensed under the Apache License, Version 2.0 (the "License"); 10 | # you may not use this file except in compliance with the License. 11 | # You may obtain a copy of the License at 12 | # 13 | # http://www.apache.org/licenses/LICENSE-2.0 14 | # 15 | # Unless required by applicable law or agreed to in writing, software 16 | # distributed under the License is distributed on an "AS IS" BASIS, 17 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | # See the License for the specific language governing permissions and 19 | # limitations under the License. 20 | # 21 | FROM alpine 22 | 23 | COPY oracle-db-doc-mcp-server.py fastmcp.json requirements.txt ./ 24 | 25 | RUN apk --update --no-cache add python3 py3-pip curl && \ 26 | pip install -r requirements.txt --break-system-packages && \ 27 | rm requirements.txt && \ 28 | mkdir /input && \ 29 | curl -L -o /input/dbdoc.zip https://docs.oracle.com/en/database/oracle/oracle-database/26/zip/oracle-database_26.zip && \ 30 | python3 oracle-db-doc-mcp-server.py -log-level DEBUG idx -path /input/dbdoc.zip && \ 31 | rm -r /input && \ 32 | apk del curl && \ 33 | rm -rf /var/cache/apk/* /tmp/* 34 | 35 | LABEL org.opencontainers.image.source=https://github.com/oracle/mcp 36 | LABEL org.opencontainers.image.description="Oracle Database Documentation MCP Server" 37 | LABEL org.opencontainers.image.licenses=Apache-2.0 38 | 39 | ENTRYPOINT [ "python3", "oracle-db-doc-mcp-server.py", "mcp" ] 40 | -------------------------------------------------------------------------------- /src/oracle-db-doc-mcp-server/fastmcp.json: -------------------------------------------------------------------------------- 1 | { 2 | "entrypoint": "oracle-db-doc-mcp-server.py", 3 | "environment": { 4 | "dependencies": [ 5 | "beautifulsoup4 >= 4.9.0", 6 | "markdownify >= 1.2.0", 7 | "fastmcp >= 2.11.3", 8 | "pocketsearch >= 0.40.0" 9 | ] 10 | } 11 | } -------------------------------------------------------------------------------- /src/oracle-db-doc-mcp-server/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "oracle-db-doc-mcp-server" 3 | version = "1.0.0" 4 | description = "The Oracle Database Documentation MCP Server" 5 | readme = "README.md" 6 | requires-python = ">=3.13" 7 | dependencies = [ 8 | "beautifulsoup4>=4.9.0", 9 | "fastmcp>=2.11.3", 10 | "markdownify>=1.2.0", 11 | "pocketsearch>=0.40.0", 12 | "pydantic>=2.12.3" 13 | ] 14 | -------------------------------------------------------------------------------- /src/oracle-db-doc-mcp-server/requirements.txt: -------------------------------------------------------------------------------- 1 | beautifulsoup4 >= 4.9.0 2 | markdownify >= 1.2.0 3 | fastmcp >= 2.11.3 4 | pocketsearch >= 0.40.0 5 | pydantic>=2.12.3 6 | -------------------------------------------------------------------------------- /tests/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2025 Oracle and/or its affiliates. 2 | 3 | The Universal Permissive License (UPL), Version 1.0 4 | 5 | Subject to the condition set forth below, permission is hereby granted to any 6 | person obtaining a copy of this software, associated documentation and/or data 7 | (collectively the "Software"), free of charge and under any and all copyright 8 | rights in the Software, and any and all patent rights owned or freely 9 | licensable by each licensor hereunder covering either (i) the unmodified 10 | Software as contributed to or provided by such licensor, or (ii) the Larger 11 | Works (as defined below), to deal in both 12 | 13 | (a) the Software, and 14 | (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if 15 | one is included with the Software (each a "Larger Work" to which the Software 16 | is contributed by such licensors), 17 | 18 | without restriction, including without limitation the rights to copy, create 19 | derivative works of, display, perform, and distribute the Software and make, 20 | use, sell, offer for sale, import, export, have made, and have sold the 21 | Software and the Larger Work(s), and to sublicense the foregoing rights on 22 | either these or other terms. 23 | 24 | This license is subject to the following condition: 25 | The above copyright notice and either this complete permission notice or at 26 | a minimum a reference to the UPL must be included in all copies or 27 | substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 35 | SOFTWARE. -------------------------------------------------------------------------------- /tests/README.md: -------------------------------------------------------------------------------- 1 | # End-to-End Tests for OCI MCP Servers 2 | 3 | ## Introduction 4 | 5 | This directory contains end-to-end tests for the OCI MCP Servers using the Behave framework. 6 | 7 | ## Prerequisites 8 | 9 | 1. Ensure you have the necessary OCI configuration set up on your system. 10 | 11 | ## Configuration 12 | 13 | 1. In the e2e directory, copy `.env.template` to `.env`. 14 | 2. Fill in the required environment variables in `.env`: 15 | - TENANCY_OCID: Your Oracle Cloud tenancy OCID. 16 | - TENANCY_NAME: Your Oracle Cloud tenancy name. 17 | - COMPARTMENT_OCID: The OCID of the compartment to test against (defaults to TENANCY_OCID if not set). 18 | - USER_OCID: Your Oracle Cloud user OCID. 19 | - USER_NAME: Your Oracle Cloud user name. 20 | - REGION: Your home region name (defaults to us-ashburn-1 if not set) 21 | - MODEL: LLM model that you are running (defaults to got-oss:20b if not set) 22 | 23 | You can copy the following into a `.env` file 24 | ```bash 25 | TENANCY_OCID= 26 | TENANCY_NAME= 27 | COMPARTMENT_OCID= 28 | USER_OCID= 29 | USER_NAME= 30 | REGION= 31 | MODEL= 32 | 33 | ## Running the Tests 34 | 35 | 1. Ensure the `ollama` is installed and started. 36 | 2. Following the instructions in the [Getting Started - MCPHost](https://github.com/shrug-labs/oci-mcp#mcphost) section. 37 | 2. Run the tests using the command: 38 | ```bash 39 | cd tests/e2e 40 | behave 41 | 42 | ## Notes 43 | 44 | - The tests use the configuration from the `.env` file. 45 | - The `mcphost.json` file is used to configure the MCP server. 46 | 47 | 48 | ---- 49 | Copyright (c) 2025, Oracle and/or its affiliates. Licensed under the [Universal Permissive License v1.0](https://oss.oracle.com/licenses/upl). 50 | 51 | -------------------------------------------------------------------------------- /tests/e2e/features/.env.template: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, Oracle and/or its affiliates. 2 | # Licensed under the Universal Permissive License v1.0 as shown at 3 | # https://oss.oracle.com/licenses/upl. 4 | 5 | 6 | MODEL= 7 | REGION= 8 | TENANCY_OCID= 9 | TENANCY_NAME= 10 | COMPARTMENT_OCID= 11 | USER_OCID= 12 | USER_NAME= 13 | -------------------------------------------------------------------------------- /tests/e2e/features/environment.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | 7 | import json 8 | import os 9 | import subprocess 10 | import time 11 | 12 | 13 | def set_default(obj, attribute, value): 14 | if attribute not in obj or not obj[attribute]: 15 | obj[attribute] = value 16 | 17 | 18 | try: 19 | config_path = os.path.join(os.path.dirname(__file__), ".env") 20 | mcp_host_file = os.path.join(os.path.dirname(__file__), "mcphost.json") 21 | config = {} 22 | with open(config_path, "r") as config_file: 23 | for line in config_file: 24 | line = line.strip() 25 | if line and "=" in line: 26 | key, value = line.split("=", 1) 27 | config[key.strip()] = value.strip() 28 | 29 | # set defaults 30 | set_default(config, "MCP_HOST_FILE", mcp_host_file) 31 | set_default(config, "URL", "http://localhost:8000/api/chat") 32 | set_default(config, "MODEL", "gpt-oss:20b") 33 | set_default(config, "COMPARTMENT_OCID", config["TENANCY_OCID"]) 34 | set_default(config, "USER_NAME", "") 35 | set_default(config, "REGION", "us-ashburn-1") 36 | 37 | except FileNotFoundError: 38 | raise EnvironmentError( 39 | print( 40 | "\nPlease provide the environment configuration through the .env file.\n" 41 | "You can copy .env.template and fill with data\n\n" 42 | ) 43 | ) 44 | 45 | _system_prompt = f"""You are an Oracle Cloud Infrastructure expert generative chat assistant. Limit your answers to OCI. OCID is synonymous with ID. The logged in user's OCID is '{config["USER_OCID"]}', and the display name is {config["USER_NAME"]}. The tenancy OCID is '{config["TENANCY_OCID"]}', which is also called the root compartment. The active (current) tenancy name is {config["TENANCY_NAME"]}. The active (current) region is {config["REGION"]}. The active (current) compartment is '{config["COMPARTMENT_OCID"]}'. If the user makes a request that relies on a tool that requires a compartment id, and the user doesn't specify one, don't ask the user for the compartment id and use the root compartment instead. If I ask you for a list of things, prefer either a tabular or text-based approach over dumping them in a code block. When formatting your response, don't use bullets or lists within tables. When a user makes a request, you must first attempt to fulfill it by using the available MCP tools. These tools are connected to our live data sources and provide the most accurate and real-time information. Only after exhausting the capabilities of the MCP tools should you resort to other methods, such as using a general web search, if the MCP tools cannot provide the necessary information. If there is an error in calling the run_oci_command tool, then try to use the get_oci_command_help tool to get more information on the command and retry with the updated information. Don't send back emojis in the responses.""" # noqa ES501 46 | 47 | 48 | def set_mcp_servers(context): 49 | try: 50 | context.mcp_servers = [] 51 | with open(mcp_host_file, "r") as f: 52 | mcp_hosts = json.load(f) 53 | for key in mcp_hosts["mcpServers"]: 54 | context.mcp_servers.append(key.replace("-", "_")) 55 | 56 | print("Configured servers: ", ", ".join(sorted(context.mcp_servers))) 57 | except FileNotFoundError: 58 | raise EnvironmentError( 59 | f"{mcp_host_file} could not be found. Provide one to configure the MCP servers" 60 | ) 61 | 62 | 63 | def before_all(context): 64 | """Start the MCP bridge before running any prompts""" 65 | try: 66 | # set the current configured mcp servers 67 | set_mcp_servers(context) 68 | 69 | # load the MCP servers 70 | context.bridge_proc = subprocess.Popen( 71 | ["uvx", "ollama-mcp-bridge", "--config", config["MCP_HOST_FILE"]] 72 | ) 73 | print("Waiting for servers to start...", flush=True) 74 | time.sleep( 75 | 2 * len(context.mcp_servers or 10) 76 | ) # Give the server and bridge time to start 2s per server seems to be good. 77 | 78 | if context.bridge_proc.poll() is not None: 79 | raise RuntimeError("Process failed to start") 80 | 81 | # add global defaults to the context 82 | context.system_message = {"role": "system", "content": _system_prompt} 83 | context.url = config["URL"] 84 | context.model = config["MODEL"] 85 | 86 | print("\n\n Starting tests...\n\n") 87 | except FileNotFoundError as e: 88 | raise EnvironmentError( 89 | f"Command not found: {e.filename}. Ensure it's installed and in your PATH." 90 | ) 91 | 92 | 93 | def after_all(context): 94 | """Terminate the MCP bridge""" 95 | print("Checking and terminating process...") 96 | # Poll the process to get its return code 97 | return_code = context.bridge_proc.poll() 98 | 99 | if return_code is None: 100 | # Process is still running, terminate it 101 | print("Process is still running. Terminating...") 102 | context.bridge_proc.terminate() 103 | # Optionally, check again to see if it terminated cleanly 104 | context.bridge_proc.wait(timeout=5) 105 | print("Process terminated.") 106 | elif return_code != 0: 107 | # Process exited with an error code, meaning it failed 108 | stdout, stderr = context.bridge_proc.communicate() 109 | error_message = f"Process closed prematurely with exit code {return_code}\n" 110 | error_message += f"Stdout: {stdout}\nStderr: {stderr}" 111 | raise RuntimeError(error_message) 112 | else: 113 | # Process exited cleanly (with code 0) but was not expected to 114 | raise RuntimeError("Process closed unexpectedly but cleanly.") 115 | -------------------------------------------------------------------------------- /tests/e2e/features/general-prompts.feature: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, Oracle and/or its affiliates. 2 | # Licensed under the Universal Permissive License v1.0 as shown at 3 | # https://oss.oracle.com/licenses/upl. 4 | 5 | 6 | Feature: OCI MCP Servers 7 | Scenario: List the tools available in the agent 8 | Given the MCP server is running with OCI tools 9 | And the ollama model with the tools is properly working 10 | When I send a request with the prompt "What tools do you have? List all by name" 11 | Then the response should contain a list of tools available 12 | 13 | Scenario: List the instances in the root compartment 14 | Given the MCP server is running with OCI tools 15 | And the ollama model with the tools is properly working 16 | When I send a request with the prompt "list my instances in the root compartment and limit to 5" 17 | Then the response should contain a list of instances 18 | 19 | -------------------------------------------------------------------------------- /tests/e2e/features/mcphost.json: -------------------------------------------------------------------------------- 1 | { 2 | "mcpServers": { 3 | "oracle-datetime-helper-mcp-server": { 4 | "disabled": false, 5 | "timeout": 60, 6 | "type": "stdio", 7 | "command": "uv", 8 | "args": [ 9 | "run", 10 | "oracle.datetime-helper-mcp-server" 11 | ] 12 | }, 13 | "oracle-oci-api-mcp-server": { 14 | "disabled": false, 15 | "timeout": 60, 16 | "type": "stdio", 17 | "command": "uv", 18 | "args": [ 19 | "run", 20 | "oracle.oci-api-mcp-server" 21 | ] 22 | }, 23 | "oracle-oci-compute-instance-agent-mcp-server": { 24 | "disabled": false, 25 | "timeout": 60, 26 | "type": "stdio", 27 | "command": "uv", 28 | "args": [ 29 | "run", 30 | "oracle.oci-compute-instance-agent-mcp-server" 31 | ] 32 | }, 33 | "oracle-oci-compute-mcp-server": { 34 | "disabled": false, 35 | "timeout": 60, 36 | "type": "stdio", 37 | "command": "uv", 38 | "args": [ 39 | "run", 40 | "oracle.oci-compute-mcp-server" 41 | ] 42 | }, 43 | "oracle-oci-identity-mcp-server": { 44 | "disabled": false, 45 | "timeout": 60, 46 | "type": "stdio", 47 | "command": "uv", 48 | "args": [ 49 | "run", 50 | "oracle.oci-identity-mcp-server" 51 | ] 52 | }, 53 | "oracle-oci-migration-mcp-server": { 54 | "disabled": false, 55 | "timeout": 60, 56 | "type": "stdio", 57 | "command": "uv", 58 | "args": [ 59 | "run", 60 | "oracle.oci-migration-mcp-server" 61 | ] 62 | }, 63 | "oracle-oci-monitoring-mcp-server": { 64 | "disabled": false, 65 | "timeout": 60, 66 | "type": "stdio", 67 | "command": "uv", 68 | "args": [ 69 | "run", 70 | "oracle.oci-monitoring-mcp-server" 71 | ] 72 | }, 73 | "oracle-oci-network-load-balancer-mcp-server": { 74 | "disabled": false, 75 | "timeout": 60, 76 | "type": "stdio", 77 | "command": "uv", 78 | "args": [ 79 | "run", 80 | "oracle.oci-network-load-balancer-mcp-server" 81 | ] 82 | }, 83 | "oracle-oci-networking-mcp-server": { 84 | "disabled": false, 85 | "timeout": 60, 86 | "type": "stdio", 87 | "command": "uv", 88 | "args": [ 89 | "run", 90 | "oracle.oci-networking-mcp-server" 91 | ] 92 | }, 93 | "oracle-oci-object-storage-mcp-server": { 94 | "disabled": false, 95 | "timeout": 60, 96 | "type": "stdio", 97 | "command": "uv", 98 | "args": [ 99 | "run", 100 | "oracle.oci-object-storage-mcp-server" 101 | ] 102 | }, 103 | "oracle-oci-registry-mcp-server": { 104 | "disabled": false, 105 | "timeout": 60, 106 | "type": "stdio", 107 | "command": "uv", 108 | "args": [ 109 | "run", 110 | "oracle.oci-registry-mcp-server" 111 | ] 112 | }, 113 | "oracle-oci-resource-search-mcp-server": { 114 | "disabled": false, 115 | "timeout": 60, 116 | "type": "stdio", 117 | "command": "uv", 118 | "args": [ 119 | "run", 120 | "oracle.oci-resource-search-mcp-server" 121 | ] 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /tests/e2e/features/oci-api-mcp-server.feature: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, Oracle and/or its affiliates. 2 | # Licensed under the Universal Permissive License v1.0 as shown at 3 | # https://oss.oracle.com/licenses/upl. 4 | 5 | 6 | Feature: OCI API MCP Server 7 | Scenario: List the tools available in the agent 8 | Given the MCP server is running with OCI tools 9 | And the ollama model with the tools is properly working 10 | When I send a request with the prompt "What tools do you have" 11 | Then the response should contain a list of tools available 12 | 13 | Scenario: List the instances in the root compartment 14 | Given the MCP server is running with OCI tools 15 | And the ollama model with the tools is properly working 16 | When I send a request with the prompt "list my instances and limit to 2" 17 | Then the response should contain a list of all instances 18 | 19 | Scenario: Generate Terraform for Stable Diffusion GPU infrastructure 20 | Given the MCP server is running with OCI tools 21 | And the ollama model with the tools is properly working 22 | When I send a request with the prompt "Create TF for me to create and configure all resources needed to run stable diffusion in a webUI on an OCI GPU. I want to make sure i'm using OCI Gen AI services as much as possible" 23 | Then the response should contain terraform configuration 24 | And the response should mention GPU instances 25 | And the response should mention OCI Gen AI services -------------------------------------------------------------------------------- /tests/e2e/features/oci-compute-mcp-server.feature: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, Oracle and/or its affiliates. 2 | # Licensed under the Universal Permissive License v1.0 as shown at 3 | # https://oss.oracle.com/licenses/upl. 4 | 5 | 6 | Feature: OCI Compute MCP Server 7 | Scenario: List the tools available in the agent 8 | Given the MCP server is running with OCI tools 9 | And the ollama model with the tools is properly working 10 | When I send a request with the prompt "What tools do you have" 11 | Then the response should contain a list of compute tools available 12 | 13 | Scenario: Security review of compute instances in specific region 14 | Given the MCP server is running with OCI tools 15 | And the ollama model with the tools is properly working 16 | When I send a request with the prompt "Can you review the security configuration of my compute instances in San Jose and let me know if there are any recommended improvements or best practices to strengthen their security posture?" 17 | Then the response should contain security analysis 18 | And the response should mention security best practices 19 | And the response should reference regional considerations -------------------------------------------------------------------------------- /tests/e2e/features/oci-object-storage-mcp-server.feature: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, Oracle and/or its affiliates. 2 | # Licensed under the Universal Permissive License v1.0 as shown at 3 | # https://oss.oracle.com/licenses/upl. 4 | 5 | 6 | Feature: OCI Object Storage MCP Server 7 | Scenario: Get the namespace 8 | Given the MCP server is running with OCI tools 9 | And the ollama model with the tools is properly working 10 | When I send a request with the prompt "get my namespace" 11 | Then the response should contain a the tenancy namespace 12 | 13 | Scenario: List buckets 14 | Given the MCP server is running with OCI tools 15 | And the ollama model with the tools is properly working 16 | When I send a request with the prompt "list my buckets" 17 | Then the response should contain a list of buckets available 18 | 19 | -------------------------------------------------------------------------------- /tests/e2e/features/steps/general-prompts.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | 7 | import requests 8 | from behave import given, then, when 9 | 10 | 11 | @given("the MCP server is running with OCI tools") 12 | def step_impl(context): 13 | assert context.bridge_proc.poll() is None, "Process is not running!!" 14 | 15 | 16 | @given("the ollama model with the tools is properly working") 17 | def step_impl_ollama_model(context): 18 | try: 19 | # Check if ollama is running and has the model 20 | response = requests.get("http://localhost:8000/health") 21 | response.raise_for_status() 22 | except requests.exceptions.RequestException as e: 23 | raise ConnectionError( 24 | f"Could not connect to Ollama or model not found: {e}. Is Ollama running?" 25 | ) 26 | 27 | 28 | @when('I send a request with the prompt "{prompt}"') 29 | def step_impl_prompt(context, prompt): 30 | # Send a request to the bridge (which is configured to talk to Ollama) 31 | payload = { 32 | "model": context.model, 33 | "options": {"temperature": 0.7, "top_p": 0.9}, 34 | "messages": [context.system_message, {"role": "user", "content": prompt}], 35 | "stream": False, 36 | "thinking": True, 37 | } 38 | 39 | context.response = requests.post(context.url, json=payload, stream=False) 40 | context.response.raise_for_status() 41 | 42 | # check if all thinking is really done... 43 | result = context.response.json() 44 | thinking = result["message"]["thinking"] 45 | content = result["message"]["content"] 46 | print("thinking & content", thinking, content, flush=True) 47 | if content is None and thinking is not None: 48 | print("Getting the next response...") 49 | context.response = requests.post(context.url, json=payload, stream=False) 50 | context.response.raise_for_status() 51 | 52 | 53 | @then("the response should contain a list of tools available") 54 | def step_impl_tools_available(context): 55 | result = context.response.json() 56 | print("available tools", result) 57 | assert "content" in result["message"], "Response does not contain a content key." 58 | 59 | for tool_server in context.mcp_servers: 60 | assert ( 61 | tool_server in result["message"]["content"] 62 | ), f"{tool_server} is missing from tools." 63 | 64 | 65 | @then("the response should contain a list of instances") 66 | def step_impl_list_instances(context): 67 | result = context.response.json() 68 | print("Instances", result) 69 | assert "content" in result["message"], "Response does not contain a content key." 70 | assert ( 71 | "ocid1.instance" in result["message"]["content"] 72 | ), "tools could not be queried." 73 | -------------------------------------------------------------------------------- /tests/e2e/features/steps/oci-api-mcp-server-steps.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | 7 | from behave import then 8 | 9 | 10 | @then("the response should contain terraform configuration") 11 | def step_impl_terraform_configuration(context): 12 | response_json = context.response.json() 13 | assert ( 14 | "content" in response_json["message"] 15 | ), "Response does not contain a content key." 16 | content = response_json["message"]["content"].lower() 17 | assert any( 18 | keyword in content 19 | for keyword in ["terraform", "resource", "provider", ".tf", "infrastructure"] 20 | ), "Terraform configuration could not be generated." 21 | 22 | 23 | @then("the response should mention GPU instances") 24 | def step_impl_gpu_instances(context): 25 | response_json = context.response.json() 26 | content = response_json["message"]["content"].lower() 27 | assert any( 28 | keyword in content 29 | for keyword in ["gpu", "bm.gpu", "vm.gpu", "a10", "v100", "graphics"] 30 | ), "GPU instances were not mentioned in the response." 31 | 32 | 33 | @then("the response should mention OCI Gen AI services") 34 | def step_impl_oci_gen_ai(context): 35 | response_json = context.response.json() 36 | content = response_json["message"]["content"].lower() 37 | assert any( 38 | keyword in content 39 | for keyword in [ 40 | "gen ai", 41 | "generative ai", 42 | "ai service", 43 | "llama", 44 | "cohere", 45 | "model", 46 | ] 47 | ), "OCI Gen AI services were not mentioned in the response." 48 | -------------------------------------------------------------------------------- /tests/e2e/features/steps/oci-compute-mcp-server-steps.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | 7 | from behave import then 8 | 9 | 10 | @then("the response should contain a list of compute tools available") 11 | def step_impl_compute_tools_available(context): 12 | response_json = context.response.json() 13 | assert ( 14 | "content" in response_json["message"] 15 | ), "Response does not contain a content key." 16 | content = response_json["message"]["content"].lower() 17 | assert any( 18 | tool in content 19 | for tool in [ 20 | "list_instances", 21 | "get_instance", 22 | "launch_instance", 23 | "list_images", 24 | "instance_action", 25 | ] 26 | ), "Compute tools could not be queried." 27 | 28 | 29 | @then("the response should contain security analysis") 30 | def step_impl_security_analysis(context): 31 | response_json = context.response.json() 32 | assert ( 33 | "content" in response_json["message"] 34 | ), "Response does not contain a content key." 35 | content = response_json["message"]["content"].lower() 36 | assert any( 37 | keyword in content 38 | for keyword in ["security", "configuration", "analysis", "review", "assessment"] 39 | ), "Security analysis could not be performed." 40 | 41 | 42 | @then("the response should mention security best practices") 43 | def step_impl_security_best_practices(context): 44 | response_json = context.response.json() 45 | content = response_json["message"]["content"].lower() 46 | assert any( 47 | keyword in content 48 | for keyword in [ 49 | "best practice", 50 | "recommendation", 51 | "improve", 52 | "strengthen", 53 | "security group", 54 | "firewall", 55 | "ssh", 56 | "encryption", 57 | ] 58 | ), "Security best practices were not mentioned in the response." 59 | 60 | 61 | @then("the response should reference regional considerations") 62 | def step_impl_regional_considerations(context): 63 | response_json = context.response.json() 64 | content = response_json["message"]["content"].lower() 65 | assert any( 66 | keyword in content 67 | for keyword in ["san jose", "us-phoenix-1", "region", "regional", "location"] 68 | ), "Regional considerations were not mentioned in the response." 69 | -------------------------------------------------------------------------------- /tests/e2e/features/steps/oci-object-storage-mcp-server-steps.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2025, Oracle and/or its affiliates. 3 | Licensed under the Universal Permissive License v1.0 as shown at 4 | https://oss.oracle.com/licenses/upl. 5 | """ 6 | 7 | from behave import then 8 | 9 | 10 | @then("the response should contain a the tenancy namespace") 11 | def step_impl_namespace(context): 12 | result = context.response.json() 13 | print("buckets", result) 14 | assert "content" in result["message"], "Response does not contain a content key." 15 | # assert "bucket" in result["message"]["content"] 16 | 17 | 18 | @then("the response should contain a list of buckets available") 19 | def step_impl_list_buckets(context): 20 | result = context.response.json() 21 | print("buckets", result) 22 | assert "content" in result["message"], "Response does not contain a content key." 23 | # assert "bucket" in result["message"]["content"] 24 | -------------------------------------------------------------------------------- /tests/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "oracle.oci-e2e-tests" 3 | version = "0.1.0" 4 | description = "OCI MCP Servers e2e tests" 5 | readme = "README.md" 6 | requires-python = ">=3.13" 7 | license = "UPL-1.0" 8 | license-files = ["LICENSE.txt"] 9 | dependencies = [ 10 | "fastmcp==2.12.2", 11 | "oci==2.160.0" 12 | ] 13 | 14 | [dependency-groups] 15 | dev = [ 16 | "pytest>=8.4.2", 17 | "pytest-asyncio>=1.2.0", 18 | "pytest-bdd>=6.1.1", 19 | "pytest-cov>=7.0.0", 20 | "behave>=1.2.6" 21 | ] 22 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | isolated_build = True 3 | 4 | [isort] 5 | profile = black 6 | extend_skip = 7 | src/dbtools-mcp-server/, 8 | src/mysql-mcp-server/, 9 | src/oci-pricing-mcp-server, 10 | src/oracle-db-doc-mcp-server 11 | 12 | [flake8] 13 | ; to match Black 14 | max-line-length = 110 15 | extend-exclude = 16 | venv, 17 | .venv, 18 | venv, 19 | src/dbtools-mcp-server, 20 | src/mysql-mcp-server, 21 | src/oci-pricing-mcp-server, 22 | src/oracle-db-doc-mcp-server 23 | src/database-mcp-server 24 | 25 | [testenv] 26 | deps = 27 | black==25.1.0 28 | flake8==7.3.0 29 | isort==6.0.1 30 | setenv = 31 | PYTHON = python3 32 | 33 | [testenv:lint] 34 | commands = 35 | isort -c {posargs:{toxinidir}} 36 | black --force-exclude 'src/dbtools-mcp-server|mysql-mcp-server|oci-pricing-mcp-server' --check {posargs:{toxinidir}} 37 | flake8 {posargs:{toxinidir}} 38 | 39 | [testenv:format] 40 | commands = 41 | isort {posargs:{toxinidir}} 42 | black --force-exclude 'src/dbtools-mcp-server|mysql-mcp-server|oci-pricing-mcp-server' {posargs:{toxinidir}} 43 | flake8 {posargs:{toxinidir}} 44 | --------------------------------------------------------------------------------