Skip to content

Rcv prompt updates v3 - #403

Open
gsharini wants to merge 2 commits into
oracle:mainfrom
gsharini:rcv_promptupdates_v3
Open

Rcv prompt updates v3#403
gsharini wants to merge 2 commits into
oracle:mainfrom
gsharini:rcv_promptupdates_v3

Conversation

@gsharini

Copy link
Copy Markdown
Member

Description

This change delivers Recovery MCP Server v3.0.0, expanded Recovery Service and Database Service read coverage, and guided operational workflows for Cloud Protect onboarding.

Fixes # (issue)

Type of change

Please delete options that are not relevant.

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How Has This Been Tested?

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

Added targeted unit tests covering:
Guidance-tool availability and input validation.
Recovery and Recovery Database tool behavior, including legacy coverage retained during test-suite restructuring.Multi-Tenant OAuth authentication and tenancy header routing.

Onboard testing :
Prompt
codex> "Using recovery service mcp server onboard database DB0729 with ip 100.102.44.215 to recovery service."

Final Result:
DB0729 is onboarded to Recovery Service.

  • Protected database: db0729_xxm_iad
  • Status: ACTIVE
  • Policy: Bronze, 14-day retention
  • Recovery Service subnet: the OCID you supplied
  • Scheduled Cloud Protect backup task: every 15 minutes
    The initial health is WARNING — Waiting for archive logs, which is expected immediately after onboarding; the first scheduled task is due at 13:20 UTC. Real-time redo remains disabled. I did not enable it because that is a separate configuration change and requires a

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

@oracle-contributor-agreement oracle-contributor-agreement Bot added the OCA Verified All contributors have signed the Oracle Contributor Agreement. label Jul 31, 2026
@gsharini gsharini closed this Jul 31, 2026
@gsharini gsharini reopened this Jul 31, 2026

@dustin-sale dustin-sale left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review by @dustin-sale via Codex.

Requested changes

  • server.py:4340 — [P1] Do not expose profile credentials through unauthenticated HTTP.
  • server.py:802 — [P1] Preserve the Recovery invocation authorization scope.
  • server.py:799 — [P1] Require a valid public OAuth base URL.
  • server.py:527 — [P1] Use the shared caller-scoped authentication path.

Additional review notes

  • test_legacy_recovery_tools.py:357 — [P2] Assert the exact user agent for every auth path.
  • CHANGELOG.md:3 — [P2] Document the 3.0.0 breaking changes.

Validation

make lint, scoped tests, lock validation, and package build passed. Tests reported 132 passed, 9 xfailed, and 90.01% coverage; git diff --check found four whitespace errors.

See the inline comments in this review for evidence, impact, and suggested remediation.

oauth_port = int(port or "8000")
logger.info("Running FastMCP over streamable HTTP with OCI IAM OAuth at http://%s:%s", oauth_host, oauth_port)
mcp.run(transport="http", host=oauth_host, port=oauth_port)
elif host and port:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment from @dustin-sale via Codex.

[P1] Do not expose profile credentials through unauthenticated HTTP

Evidence: _build_auth_provider() returns None for session and apikey, but this branch starts an HTTP listener for those modes. A session-mode probe confirms mcp.auth is None; the prior implementation instead rejected HTTP startup without IDCS configuration.

Impact: any caller able to reach the configured bind address can invoke the server's OCI tools using the operator's API-key or session-token credentials.

Requested change: disallow profile-backed HTTP or attach an authentication provider before listening, and restore a regression test proving HTTP cannot start unauthenticated.

base_url = _first_env("ORACLE_MCP_BASE_URL", "MCP_BASE_URL", default="http://localhost:8000")
storage_root = _first_env("ORACLE_MCP_OAUTH_STORAGE_DIR", default=_default_oauth_storage_root())
redirect_path = _first_env("ORACLE_MCP_OAUTH_REDIRECT_PATH", default="/auth/callback")
scopes = (_first_env("ORACLE_MCP_OAUTH_SCOPES", default="openid offline_access") or "").split()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment from @dustin-sale via Codex.

[P1] Preserve the Recovery invocation authorization scope

Evidence: the hosted OAuth default was openid profile email oci_mcp.recovery.invoke; it is now only openid offline_access.

Impact: the server no longer requires the Recovery-specific authorization scope, so an authenticated identity can reach Recovery tools without the invocation entitlement previously enforced by this server.

Requested change: retain oci_mcp.recovery.invoke or an explicitly documented equivalent, preserve compatible scope configuration, and add a negative test for a token missing that scope.

return None

registry = _get_registry()
base_url = _first_env("ORACLE_MCP_BASE_URL", "MCP_BASE_URL", default="http://localhost:8000")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment from @dustin-sale via Codex.

[P1] Require a public OAuth base URL for hosted mode

Evidence: missing configuration silently becomes http://localhost:8000, while the new hosted OAuth README instructions require only the auth method and tenancy registry. Authorization metadata and per-tenant callback URLs are derived from this value.

Impact: a remote deployment following the documentation advertises localhost/plain-HTTP authorization and callback URLs, so clients redirect to the wrong machine and login cannot complete correctly.

Requested change: fail fast unless hosted mode has an explicit validated HTTPS public base URL. Keep localhost only behind an explicit local-development mode, and document the per-tenant callback paths.

_ENV_IDCS_CLIENT_ID = ("ORACLE_MCP_IDCS_CLIENT_ID", "IDCS_CLIENT_ID")
_ENV_IDCS_CLIENT_SECRET = ("ORACLE_MCP_IDCS_CLIENT_SECRET", "IDCS_CLIENT_SECRET")

_oauth_signer_cache: dict[str, Any] = {}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment from @dustin-sale via Codex.

[P1] Use the repository's caller-scoped authentication path

Evidence: repository rules require oracle-mcp-common for credential resolution and IDCS request-token exchange and explicitly prohibit globally cached HTTP signers. This package does not declare that dependency, duplicates the authentication logic, and stores token-exchange signers in this process-wide cache; tests assert that the same signer is reused across requests.

Impact: shared validation and secret-handling fixes are bypassed, and mutable signer state outlives the request context that established the caller identity.

Requested change: use oracle-mcp-common>=0.1.0,<0.2.0 and its request-scoped auth contexts, extending the shared implementation for registry routing if necessary. Construct each HTTP signer and OCI client inside the current request and remove the global signer cache.

)
loaded = server._load_oci_config_for_server()
assert loaded["region"] == "PROFILE2"
assert loaded["additional_user_agent"].startswith("oci-recovery-mcp/")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment from @dustin-sale via Codex.

[P2] Assert the exact user agent on every authentication path

Evidence: this assertion accepts any version beginning with oci-recovery-mcp/, and the new API-key, security-token, and OAuth client-factory tests do not assert the exact additional_user_agent.

Impact: a stale version or a client path that omits telemetry can pass while violating the repository's OCI client-construction contract.

Requested change: assert the exact derived value oci-recovery-mcp/3.0.0 for every supported API-key, security-token, and HTTP/token-exchange client-construction path.

Comment thread src/oci-recovery-mcp-server/CHANGELOG.md Outdated
@gsharini gsharini closed this Aug 12, 2026
@gsharini
gsharini force-pushed the rcv_promptupdates_v3 branch from 54843e9 to 5f3b79c Compare August 12, 2026 07:12
@gsharini

Copy link
Copy Markdown
Member Author

Addressed all the review comments. Thank you for reviewing this.

@gsharini gsharini reopened this Aug 13, 2026

@dustin-sale dustin-sale left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review by @dustin-sale via Codex.

Requested changes

  • server.py:876 — [P1] Route hosted HTTP authentication through oracle-mcp-common.

Additional review notes

  • README.md:73 — [P2] Remove unsupported profile-backed HTTP instructions.
  • onboard_database_to_recovery_service.txt:186 — [P3] Clear the remaining whitespace failures.

Validation

make lint, scoped tests (132 passed, 90.42% coverage), lock validation, package build, and GitHub CI passed. git diff --check found three whitespace errors.

See the inline comments in this review for evidence, impact, and suggested remediation.

domain_kwargs["oci_domain_id"] = entry.idcs_domain.split(".")[0]

try:
signer = TokenExchangeSigner(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment from @dustin-sale via Codex.

[P1] Route hosted HTTP authentication through oracle-mcp-common

Evidence: profile authentication now uses build_auth_context(), but the hosted path still constructs TokenExchangeSigner directly here and builds MultiTenantOCIAuth/OCIProvider itself. Repository rules require provider configuration through build_idcs_http_auth(required_scopes) and request-scoped OCI credentials through context_for(access_token.token).

Impact: the hosted path continues to bypass shared authentication validation, secret-handling fixes, and lifecycle guarantees.

Requested change: construct a shared IDCS HTTP-auth object for each configured tenancy and use its context_for() result for caller-specific OCI clients. If registry routing is not supported yet, extend the shared implementation rather than duplicating the authentication path in this server.

```

For HTTP transport, start the server with:
To run a local HTTP listener for `session` or `apikey` mode, set both values below. This listener uses the server's local OCI credentials, so expose it only on a trusted network.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment from @dustin-sale via Codex.

[P2] Remove unsupported profile-backed HTTP instructions

Evidence: this section says session and apikey can use a local HTTP listener, but main() now rejects any non-OAuth listener and the 3.0.0 changelog correctly describes those modes as stdio-only. The environment-variable table repeats the unsupported local-listener exception.

Impact: operators following the README receive a startup error and may believe an unsafe credential-exposure model is supported.

Requested change: document session/apikey as stdio-only, reserve ORACLE_MCP_HOST and ORACLE_MCP_PORT for OAuth mode, and update the matching _effective_auth_method() docstring.

• DNS configuration;
• IAM policies;
• authentication configuration;
• database wallet/encryption requirements, only for on-premise database;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment from @dustin-sale via Codex.

[P3] Clear the remaining whitespace failures

Evidence: git diff --check reports trailing whitespace on this line and line 286, plus a new blank line at EOF in test_recovery_coverage.py.

Impact: the patch does not pass the repository's clean-diff validation.

Requested change: remove all three whitespace errors and rerun git diff --check.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

OCA Verified All contributors have signed the Oracle Contributor Agreement.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants