Add oracle-data-studio-mcp-server#223
Open
tsikinov wants to merge 5 commits intooracle:mainfrom
Open
Conversation
A Python MCP server providing 60 task-oriented composite tools for three Oracle Data Studio services: Essbase, ADP (Autonomous Database Data Platform), and Data Transforms. Features: - 60 high-level composite tools (30 Essbase, 15 ADP, 15 Data Transforms) plus 1 prompt template — each tool combines multiple SDK calls into a single LLM-friendly operation. - Oracle 23ai annotation-aware query routing: a new adp_get_annotations tool reads ALL_ANNOTATIONS_USAGE; the adp_sql_with_annotations prompt teaches the assistant to fetch annotations first and use them as semantic hints (units, aggregations, join keys, time grain, PII). - Annotation-driven cube/AV/table routing: tables can declare `cube='<app>.<db>'` and `analytic_view='<av>'` annotations to tell the LLM which query source to use for aggregate questions — deterministic, no name-matching. - Three access profiles (viewer / analyst / admin) with verb-based filtering plus explicit deny lists for tools that need finer control (calc-script content, log access, pipeline execution). - Server-level instructions advertised on MCP handshake — every compliant client (Claude Desktop, Cursor, Codex) injects them into the LLM's system context. Security/safety: - Error messages sanitised through a shared safe_err helper — strips DSN passwords, URL userinfo, Bearer tokens, OCID tails, and absolute filesystem paths. - Reconnect rate-limit (3 attempts / 60s, 30s cooldown) and per-context lock around credential reuse. - streamable-http binds 127.0.0.1 by default (no built-in auth). Validation: A/B tested on Oracle Autonomous Database 23.26 with the MovieLens dataset — annotation-aware SQL generation beat naive generation 5/5 across realistic failure modes (UNIT mismatch, GRAIN mismatch, AGGREGATE choice, JOIN_HINT, PII avoidance). Tests: 109 unit tests covering config loading, profile filtering, credential store, helpers, error sanitisation, reconnect rate-limit and locking, tool registration, and tool dispatch (mocked SDK). Signed-off-by: Alexander Tsikinovsky <alexander.tsikinovsky@oracle.com>
CI runs `uv run pytest --cov=. --cov-branch --cov-report=...`, which fails to parse `--cov` flags without the pytest-cov plugin. - pyproject.toml: add `pytest-cov>=7.0.0` to [dependency-groups].dev - pyproject.toml: drop `fail_under` (informational coverage only for now; ~24% line coverage today, will be raised in follow-up PRs) - uv.lock: regenerated to include pytest-cov + coverage transitively Verified locally with the exact CI command: exit code 0, 109 tests passing, HTML + term-missing reports generated. Signed-off-by: Alexander Tsikinovsky <alexander.tsikinovsky@oracle.com>
Adds 111 new tests (109 → 220 total) across:
- cli_config: 0% → 90% — argparse builder + each sub-command handler
(set with/without password prompt, server-no-password path, list,
remove)
- credential_store: 28% → 81% — store/remove/list/load round-trips
with tmp-path-isolated config files; password never lands on disk;
keyring fallback when keyring module unavailable
- server.py lifespan: 29% → 75% — covers each branch of the startup
context manager (no-config, Essbase token vs. user/password, ADP
login success and failure path)
- adp_tools: 26% → 54% — bulk parametrised dispatch for every
manage_* action (list/get/create/delete/etc.) per tool
- essbase_tools: 21% → 35% — bulk dispatch for application,
database, files, locks, sessions, variables, scripts, connections,
filters, jobs, datasources, drill_through, users
- dt_tools: 25% → 30% — schedule, variables, connection actions
Pattern: a small _adp_dispatch / _dt_dispatch / _ess_dispatch helper
takes (tool, kwargs, sdk_path) tuples and verifies the SDK method was
called for that action — prevents the param-leak class of bug
(B1, B2, M7 from earlier audit) from regressing.
Total: 220 tests, 44.20% line coverage, 17.61% branch coverage.
Verified locally with the exact CI command:
uv run pytest --cov=. --cov-branch \
--cov-report=html:htmlcov/oracle-data-studio-mcp-server \
--cov-report=term-missing
→ 220 passed, exit code 0
Signed-off-by: Alexander Tsikinovsky <alexander.tsikinovsky@oracle.com>
Adds 95 more tests (256 → 351 total) covering bigger composite-tool bodies and the auto-reconnect path: - _adp_connect: 65% → 95% — full run_adp paths (success, no-client, string-result formatter, expired-then-reconnect, non-expired error goes through safe_err, proactive reconnect on expired token, reconnect-already-done dedup) - adp_tools: 54% → 72% — adp_search include_ddl walks DDL probes, adp_load_from_cloud full flow + progress-only path, adp_build_analytic_view all 4 SDK calls, adp_analyze_analytic_view walks quality + dimensions + measures, adp_generate_insights polls status + collects graph - dt_tools: 36% → 63% — dt_describe_project full body (3 list calls), dt_describe_connection (details + test + schemas), dt_check_health walks all connections, dt_run_pipeline (dataflow), dt_browse_data with schema filter, dt_create_pipeline create-project-when-missing branch, dt_manage_dataload create with all load_types (truncate / append / recreate), dt_manage_workflow get, dt_manage_data_entities import - essbase_tools: 35% → 66% — essbase_run_calculation inline calc flow, essbase_load_data dataload payload, essbase_describe_database multi-call, essbase_manage_security user + group paths, essbase_manage_filters create + update + auto-validate, essbase_manage_drill_through create with payload, essbase_manage_db_settings 'all' + per-category, essbase_outline_metadata category dispatch, essbase_browse_outline recursive walk, essbase_search_members ancestor enrichment, essbase_manage_users provision_app_role / provision_service_role, essbase_edit_outline BOE payload shape Total: 351 tests, 70.52% line coverage, 25.83% branch coverage, exit code 0 with the exact CI command. Signed-off-by: Alexander Tsikinovsky <alexander.tsikinovsky@oracle.com>
…ew feedback Two pre-emptive review-friendly tweaks: - pyproject.toml: set fail_under = 75 — a regression gate slightly below current line coverage (79.25%) so a future PR can't silently lower it. The previous "no gate" was stylistically suspect. - README.md: new section 'About the oracle-data-studio dependency' explaining the PyPI dep is the official Oracle Data Studio SDK maintained by the same team contributing this server, and that version 1.0.26+ is required for the annotation guidance and reconnect-safety features. Test additions (155 more — 351 → 506 total): - credential_store: 81% → 89% — keyring success/delete/missing paths - adp_tools: 72% → 81% — full multi-call composite walks for load_from_cloud, build_analytic_view, analyze_analytic_view, generate_insights, search-with-DDL; bulk validation-error coverage for every manage_* tool's missing-arg branches - dt_tools: 63% → 75% — schedule create across all 5 frequencies (immediate / hourly / daily / weekly / monthly), workflow check_exists, dataload create with all 3 load_types, browse_data with/without schema filter, full describe_project / describe_ connection / check_health walks, plus bulk validation-error coverage - essbase_tools: 66% → 75% — manage_filters create/update with validate, manage_drill_through create/update/execute, manage_ database update/copy, manage_groups add_users / remove_users / add_subgroups, manage_users provision_app/service + deprovision + update + create, edit_outline payloads (add/remove/move), manage_files upload/download/copy/move, manage_db_settings 'all' + per-category, outline_metadata categories incl. export_xml + member, manage_jobs status/rerun, manage_locks unlock, manage_sessions kill/kill_all + bulk validation-error coverage - server.py: 75% → 78% — Essbase login failure caught, DT config cached for lazy connect Total: 506 tests, 79.25% line coverage, 23.58% branch coverage, exit code 0 with the exact CI command + the new fail_under gate. Signed-off-by: Alexander Tsikinovsky <alexander.tsikinovsky@oracle.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #222.
A Python MCP server providing 60 task-oriented composite tools for
three Oracle Data Studio services: Essbase, ADP (Autonomous Database
Data Platform), and Data Transforms.
Highlights
Transforms — plus 1 prompt template. Each tool combines multiple SDK
calls into a single LLM-friendly operation rather than exposing raw
REST endpoints.
adp_get_annotationsreads
ALL_ANNOTATIONS_USAGE; theadp_sql_with_annotationspromptteaches the assistant to use them as semantic hints (units,
aggregations, join keys, time grain, PII).
cube='<app>.<db>'andanalytic_view='<av>'annotations thatdeterministically route the LLM to the right query source. No
name-matching, no guessing.
viewer/analyst/adminwithverb-based filtering plus explicit deny lists.
instructionsadvertised on MCP handshake — everycompliant client (Claude Desktop, Cursor, Codex) injects them into
the LLM's system context.
Safety
safe_errhelper — strips DSNpasswords, URL userinfo, Bearer tokens, OCID tails, absolute paths.
per-context lock around credential reuse.
streamable-httpbinds127.0.0.1by default; logs a warning whenbound to
0.0.0.0.arbitrary SQL.
Validation
credential store, error sanitisation, reconnect rate-limit and
locking, tool registration, mocked SDK dispatch.
MovieLens dataset and an Essbase cube of the same name.
Annotation-aware SQL beat naive generation 5/5 across realistic
failure modes (UNIT mismatch, GRAIN mismatch, AGGREGATE choice,
JOIN_HINT, PII avoidance).
Test plan
uv sync --all-extrasuv run pytest oracle/data_studio_mcp_server/tests/test_unit.py→ 109 passedREADME.md)