Skip to main content
Glama
README.md
# Fusion MCP — Oracle Fusion ERP Cloud MCP Server

A **local stdio MCP server** (Python, FastMCP) that gives an LLM client (Claude
Desktop / Claude Code) **read-only access** to an Oracle Fusion / ERP Cloud database —
discover objects, describe tables, read source, and run SELECT queries — all via the
**BI Publisher SOAP API** (no direct DB connection required).

## Architecture

```
Claude Desktop / Claude Code  (MCP stdio)
        │
        ▼
Fusion MCP Server (Python, FastMCP)
  Tools ──► SQL guard ──► BIP client (requests + SOAP)
               │
          Catalog SQL builders (ALL_OBJECTS, ALL_TAB_COLUMNS, …)
        │
        ▼
Oracle Fusion — BI Publisher web services
  ExternalReportWSSService  (runReport → base64 CSV)
        │
        ▼
FUSION schema  +  ALL_* data dictionary
```

## Prerequisites

### 1 — Fusion BIP service account

Create (or identify) a Fusion user that:
- Has the **BI Publisher role** (`BIPAdministrator` or a custom role with BIP access).
- Has **read-only access** on the FUSION schema and the Oracle data dictionary
  (`SELECT_CATALOG_ROLE` equivalent, or appropriate Fusion data roles).
- Will be used as `FUSION_USER` / `FUSION_PASSWORD` in `.env`.

This is the primary security boundary — the app-layer SQL guard enforces
`SELECT`/`WITH` only, but the BIP service account must also be read-only at
the database level.

### 2 — Python 3.11+

Install [uv](https://docs.astral.sh/uv/) or use pip.

## Setup (local development)

```powershell
# Clone the repo
git clone https://github.com/ramesharavapally/FUSION-MCP.git
cd FUSION-MCP

# Install (editable + dev deps)
uv pip install -e ".[dev]"

# Copy and fill in credentials
cp .env.example .env
# Edit .env: set FUSION_BASE_URL, FUSION_USER, FUSION_PASSWORD
```

## Running the server

```powershell
# From a local clone
uv run fusion-mcp

# Or directly from GitHub without cloning (production use)
uvx --from git+https://github.com/ramesharavapally/FUSION-MCP.git fusion-mcp
```

### Deploying the SQL-runner report

The server does **not** deploy any BIP artifacts — you set up the report
manually in the BI Publisher catalog before running the server.

The query is sent as a **base64-encoded bind parameter** named `query1` (not a
lexical `&query1`). This is deliberate: passing raw SQL as a lexical value trips
BIP's SQL-injection guard (`SQLInjection Error: Invalid parameter value …`), and
on Fusion SaaS that guard can't be disabled. Base64-encoding keeps the parameter
value free of SQL keywords, and a PL/SQL data model decodes it and opens a cursor.

Create a CSV-output report over a data model whose dataset is this PL/SQL block:

```sql
DECLARE
    TYPE refcursor IS REF CURSOR;
    xdo_cursor REFCURSOR;
    l_query    VARCHAR2(32000);

    FUNCTION get_query(p_query IN VARCHAR2) RETURN VARCHAR2 IS
    BEGIN
        RETURN utl_raw.cast_to_varchar2(
                   utl_encode.base64_decode(utl_raw.cast_to_raw(p_query)));
    END;
BEGIN
    l_query := get_query(:query1);
    OPEN :xdo_cursor FOR l_query;
END;
```

The server base64-encodes each query and strips any trailing `;` before sending
(the decoded statement must not carry a semicolon, since it is opened as a
cursor). Then point the server at the report:

```ini
# .env
FUSION_REPORT_PATH=/your/existing/report/path.xdo
```

## Tests

```powershell
# Unit tests — no Fusion connection required
uv run pytest

# Single test file
uv run pytest tests/test_sql_guard.py
```

## MCP Inspector (interactive tool testing)

```powershell
npx @modelcontextprotocol/inspector uv run fusion-mcp
```

## Register with Claude Desktop

Add to `claude_desktop_config.json` (typically at
`%APPDATA%\Claude\claude_desktop_config.json` on Windows or
`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):

```json
{
  "mcpServers": {
    "fusion-mcp": {
      "command": "uvx",
      "args": [
        "--from",
        "git+https://github.com/ramesharavapally/FUSION-MCP.git",
        "fusion-mcp"
      ],
      "env": {
        "FUSION_BASE_URL": "https://<pod>.fa.ocs.oraclecloud.com",
        "FUSION_USER": "your_bip_service_user",
        "FUSION_PASSWORD": "your_password",
        "FUSION_MAX_ROWS": "100",
        "LOG_LEVEL": "INFO"
      }
    }
  }
}
```

`uvx` fetches the package directly from GitHub and runs it in an isolated
environment — no local clone or `pip install` needed.  Claude Desktop
re-uses the cached environment on subsequent starts; to pick up a new
commit, restart Claude Desktop (uvx re-checks the git ref on each cold
start).

> **Tip:** pin to a specific commit or tag for stability:
> ```
> "git+https://github.com/ramesharavapally/FUSION-MCP.git@v1.0.0"
> ```

## Available MCP tools

| Tool | Description |
|---|---|
| `search_objects` | Search `ALL_OBJECTS` by name pattern (tables, views, packages, …) |
| `search_tables` | Find tables/views by name or comment |
| `search_columns` | Find tables by column name or column comment |
| `search_source` | Full-text search across `ALL_SOURCE` |
| `describe_table` | Full column/PK/index/stats description of a table or view |
| `read_object_source` | Read full source of a procedure/function/package from `ALL_SOURCE` |
| `get_procedure_signature` | Discover argument names, types, and directions from `ALL_ARGUMENTS` |
| `list_package_contents` | List all subprograms inside a package |
| `execute_query` | Run a read-only `SELECT`/`WITH` query; returns CSV-parsed rows |

> **Note:** `call_procedure` is not available in Fusion MCP. Oracle BIP executes
> SELECT data models only — anonymous PL/SQL blocks are not supported.
> Use `get_procedure_signature` and `read_object_source` for procedure discovery.

## Security model

1. **SQL guard** (`safety/sql_guard.py`) — rejects anything that is not a single
   `SELECT`/`WITH`; blocks `;` chaining; validates identifiers used in catalog SQL.
   This is the app-layer boundary.
2. **BIP data model** — the deployed report decodes the base64 `query1` bind
   parameter and opens it as a cursor (`OPEN … FOR`), which only executes a single
   query; multi-statement/DML text cannot be smuggled through this path.
3. **Service account** — the BIP user should have read-only database grants (see
   prerequisites above). This is the ultimate security boundary.

## Configuration reference

| Variable | Default | Description |
|---|---|---|
| `FUSION_BASE_URL` | — | Fusion pod URL, e.g. `https://<pod>.fa.ocs.oraclecloud.com` |
| `FUSION_USER` | — | BIP service account username |
| `FUSION_PASSWORD` | — | BIP service account password |
| `FUSION_REPORT_PATH` | `/Custom/py_sql/SampleReport.xdo` | BIP catalog path for the manually-deployed report |
| `FUSION_MAX_ROWS` | `100` | Maximum rows returned per query |
| `FUSION_REQUEST_TIMEOUT_S` | `120` | HTTP timeout for BIP calls (seconds) |
| `LOG_LEVEL` | `INFO` | Logging level (DEBUG, INFO, WARNING, ERROR) |

TDQS

A3.9/5.0

Scored across 9 tools

Disambiguation5/5

Each tool has a clearly distinct purpose: describe_table for table metadata, execute_query for read-only SQL, get_procedure_signature for argument details, list_package_contents for package subprograms, read_object_source for source code, and multiple search tools for different search scopes (columns, objects, source, tables). No two tools overlap in functionality.

Naming Consistency5/5

All tool names follow a consistent verb_noun pattern in snake_case (e.g., describe_table, execute_query, search_columns). The verbs (describe, execute, get, list, read, search) are intuitive and match the action. No mixing of styles or ambiguous names.

Tool Count5/5

With 9 tools, the server is well-scoped for its purpose of exploring and querying an Oracle Fusion database. Each tool earns its place without being overwhelming or too sparse.

Completeness4/5

The tool set covers most essential operations: discovery (search tools), description (describe_table), query execution (execute_query), and code examination (read_object_source, list_package_contents, get_procedure_signature). However, there is no simple 'list all tables' tool without a keyword, so users must search even for a broad listing. This minor gap prevents a perfect score.

Maintenance

ActivityMaintained
ResponsivenessSyncing