Metadata-Version: 2.4
Name: maximo-enterprise-mcp
Version: 1.0.0
Summary: An MCP server for IBM Maximo Asset Management, by Maxis Technology — stable tool surface for MCP clients and hosted API use.
License: Apache-2.0
Keywords: maximo,mcp,ibm,asset-management,oslc
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: fastmcp>=2.0.0
Requires-Dist: fastapi>=0.135.0
Requires-Dist: httpx>=0.27.0
Requires-Dist: pydantic>=2.0.0
Requires-Dist: pydantic-settings>=2.0.0
Requires-Dist: redis>=5.0.0
Requires-Dist: starlette<2.0.0,>=0.49.1
Requires-Dist: PyYAML>=6.0
Requires-Dist: python-dateutil>=2.9.0
Requires-Dist: uvicorn>=0.30.0
Provides-Extra: ai
Requires-Dist: chromadb>=0.5.0; extra == "ai"
Requires-Dist: openai>=1.40.0; extra == "ai"
Requires-Dist: sentence-transformers>=3.0.0; extra == "ai"
Provides-Extra: exports
Requires-Dist: openpyxl>=3.1.0; extra == "exports"
Requires-Dist: reportlab>=4.0.0; extra == "exports"
Provides-Extra: dev
Requires-Dist: pytest>=9.0.3; extra == "dev"
Requires-Dist: pytest-asyncio>=1.3.0; extra == "dev"
Requires-Dist: python-dotenv>=1.0.0; extra == "dev"
Requires-Dist: ruff>=0.15.12; extra == "dev"
Dynamic: license-file

﻿# Maximo Enterprise MCP

<!-- mcp-name: io.github.MaxisTechnology-Dev/maximo-mcp -->

A production-focused integration that brings IBM Maximo Asset Management into AI workflows through the Model Context Protocol.

Built by [Maxis Technology](https://maxistechnology.com) as part of **Alchemize** — a state-of-the-art enterprise data management platform capable of doing in hours what others do in days. Want to know more? Head over to [alchemize.io](https://alchemize.io/).

This project now exposes:

- A stable MCP server for Claude Desktop, Cursor, and other MCP clients.
- A hosted HTTP/SSE mode for remote MCP access.
- A FastAPI tool layer for OpenAI, Gemini, Grok, and custom orchestrators.

The current stable surface is `69` public tools across assets, asset reliability (failure classes, meter readings, criticality, warranty status), work orders, work order planning (job plan detail, actuals vs planned, schedule calendar, cost estimate, cost breakdown), service requests, job plans, inventory (item master, storerooms, valuation, critical-spares check), purchasing (POs, requisitions, vendors, spend analysis), labor (crafts, available-technician finder), locations, reporting (failure Pareto, bad actor assets, Excel + PDF export), AI intelligence (anomaly detection, root cause, health scoring), compliance & EHS (calibrations due, inspections due, permits, certifications expiring, incidents, compliance dashboard), schema discovery, and administration.

## Responsible Use

This server speaks to a live IBM Maximo instance and exposes its data — and,
when explicitly enabled, its mutating operations — to a language model. Before
deploying:

- Run hosted HTTP/SSE behind an authenticated gateway. Per-request identity
  comes from `MCP_AUTH_MODE=jwt` (OIDC) or static + gateway-injected
  `X-MCP-*` headers. Never expose the FastAPI tool API to untrusted callers
  without an identity solution in front.
- TLS at the edge (or in-process via `MCP_SSL_*`) is mandatory for any
  non-stdio deployment. The app does not terminate TLS itself.
- Keep all write tools `# DISABLED` in [server.py](server.py) until you have
  reviewed the RBAC policy and audit posture for your environment.
- Stamp `MAXIMO_ENV=dev|staging|prod` per deployment so audit records and
  `/healthz` make it obvious which Maximo a container is talking to.
- Read [SECURITY.md](SECURITY.md) and
  [PRODUCT_GAPS_BEFORE_DEPLOY.md](PRODUCT_GAPS_BEFORE_DEPLOY.md) before
  pushing to a public registry; the latter documents the exact controls
  required for `https://github.com/mcp`-style listings.

## Architecture

```text
Local MCP clients        -> stdio MCP server -> Maximo OSLC
Remote MCP clients       -> HTTP gateway -> hosted MCP SSE -> Maximo OSLC
OpenAI / Gemini / Grok   -> FastAPI tool API -> shared executor -> Maximo OSLC
```

## Installation

### Local MCP for Claude Desktop / Claude Code / Cursor

You have two ways to install: `uvx` (recommended — no manual install) or `pip install`.

#### Option A — `uvx` (recommended)

Install [`uv`](https://docs.astral.sh/uv/getting-started/installation/) once, then point your MCP client at `uvx maximo-enterprise-mcp`. `uvx` downloads, caches, and runs the package on demand.

#### Option B — `pip install`

```bash
pip install maximo-enterprise-mcp
```

Then in the configs below, replace:

```json
"command": "uvx",
"args": ["maximo-enterprise-mcp"]
```

with:

```json
"command": "maximo-enterprise-mcp",
"args": []
```

#### Claude Desktop

Edit `%APPDATA%\Claude\claude_desktop_config.json` (Windows) or `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS):

```json
{
  "mcpServers": {
    "maximo": {
      "command": "uvx",
      "args": ["maximo-enterprise-mcp"],
      "env": {
        "MAXIMO_URL": "https://your-maximo-host.com/maximo/oslc",
        "MAXIMO_HOST": "https://your-maximo-host.com",
        "AUTH_MODE": "basic",
        "MAXIMO_USERNAME": "your-username",
        "MAXIMO_PASSWORD": "your-password",
        "CURRENT_USER_ROLE": "readonly"
      }
    }
  }
}
```

Restart Claude Desktop. The hammer icon appears once tools load.

#### Claude Code

Add to project-level `.mcp.json` or global `~/.claude.json`:

```json
{
  "mcpServers": {
    "maximo": {
      "command": "uvx",
      "args": ["maximo-enterprise-mcp"],
      "env": {
        "MAXIMO_URL": "https://your-maximo-host.com/maximo/oslc",
        "MAXIMO_HOST": "https://your-maximo-host.com",
        "AUTH_MODE": "basic",
        "MAXIMO_USERNAME": "your-username",
        "MAXIMO_PASSWORD": "your-password",
        "CURRENT_USER_ROLE": "readonly"
      }
    }
  }
}
```

Run `/mcp` in Claude Code to verify the connection.

#### Cursor

Add to `~/.cursor/mcp.json` (global) or `.cursor/mcp.json` (per project):

```json
{
  "mcpServers": {
    "maximo": {
      "command": "uvx",
      "args": ["maximo-enterprise-mcp"],
      "env": {
        "MAXIMO_URL": "https://your-maximo-host.com/maximo/oslc",
        "MAXIMO_HOST": "https://your-maximo-host.com",
        "AUTH_MODE": "basic",
        "MAXIMO_USERNAME": "your-username",
        "MAXIMO_PASSWORD": "your-password",
        "CURRENT_USER_ROLE": "readonly"
      }
    }
  }
}
```

In Cursor: Settings → MCP → Refresh to load.

### Hosted MCP over HTTP/SSE

Hosted mode is intended for trusted network or gateway-protected deployments. It now fails closed unless `MCP_ACCESS_TOKEN` is set.

```bash
python server.py --http --host 0.0.0.0 --port 8080
```

Remote MCP clients should connect to:

- MCP SSE endpoint: `http://host:8080/sse`
- Health endpoint: `http://host:8080/healthz`

Example remote MCP config:

```json
{
  "mcpServers": {
    "maximo": {
      "type": "sse",
      "url": "http://localhost:8080/sse",
      "headers": {
        "Authorization": "Bearer <your MCP_ACCESS_TOKEN>"
      }
    }
  }
}
```

### FastAPI Tool API

Hosted HTTP mode also exposes a tool API for non-MCP platforms:

- `GET /healthz`
- `GET /v1/tools`
- `POST /v1/tools/{tool_name}`
- `GET /v1/providers/openai-tools`
- `GET /v1/providers/gemini-tools`
- `GET /v1/providers/grok-tools`

Example invocation:

```bash
curl -X POST http://localhost:8080/v1/tools/list_assets \
  -H "Authorization: Bearer $MCP_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d "{\"site_id\":\"BEDFORD\",\"page_size\":10}"
```

## AI Platform Usage

### OpenAI

Use `GET /v1/providers/openai-tools` to retrieve OpenAI-compatible tool definitions, then execute the selected tool via `POST /v1/tools/{tool_name}`.

### Gemini

Use `GET /v1/providers/gemini-tools` to retrieve Gemini function declarations from the same shared tool registry.

### Grok

Use `GET /v1/providers/grok-tools`. The payload is OpenAI-compatible so the same orchestration pattern works.

## Optional Dependencies

Core installation uses `requirements.txt`.

Optional extras are defined in [`pyproject.toml`](pyproject.toml):

- `pip install ".[ai]"` for OpenAI, ChromaDB, and sentence-transformers.
- `pip install ".[exports]"` for Excel and PDF export dependencies.
- `pip install ".[dev]"` for local test and lint tooling.

## Environment Variables

See [`.env.example`](.env.example) for the complete set. The most important variables are:

| Variable | Required | Description |
|---|---|---|
| `MAXIMO_URL` | Yes | Full Maximo OSLC base URL |
| `MAXIMO_HOST` | Yes | Maximo host root URL |
| `AUTH_MODE` | Yes | `basic`, `apikey`, or `oauth` |
| `MAXIMO_USERNAME` / `MAXIMO_PASSWORD` | Basic auth | Maximo credentials |
| `MCP_ACCESS_TOKEN` | Hosted HTTP | Required bearer token for hosted MCP/API mode |
| `CURRENT_USER_ROLE` | Local only | Session role for local or trusted deployments |
| `REDIS_URL` | No | Redis cache connection string |
| `VPN_SAFE_MODE` | No | Enables safer default payload sizes |
| `DEFAULT_PAGE_SIZE` | No | Default page size when safe mode is enabled |

## Docker

### Build

```bash
docker build -t maximo-enterprise-mcp .
```

### Run

```bash
docker run -d ^
  -p 8080:8080 ^
  -e TRANSPORT_MODE=http ^
  -e MCP_ACCESS_TOKEN=change-me ^
  -e MAXIMO_URL=https://your-maximo-host.example.com/maximo/oslc ^
  -e MAXIMO_HOST=https://your-maximo-host.example.com ^
  -e AUTH_MODE=basic ^
  -e MAXIMO_USERNAME=your-maximo-username ^
  -e MAXIMO_PASSWORD=your-maximo-password ^
  maximo-enterprise-mcp
```

Use [`docker-compose.yml`](docker-compose.yml) if you want Redis included.

## Deployment Guidance

The server does NOT terminate TLS itself. Every non-stdio deployment
MUST terminate TLS either at the edge or in-process via
`MCP_SSL_CERTFILE` / `MCP_SSL_KEYFILE`. See [SECURITY.md](SECURITY.md).

### AWS

- Recommended first target: ECS Fargate or App Runner.
- Store secrets in AWS Secrets Manager.
- **Required:** put ALB or API Gateway in front for TLS and access control.
- Keep Maximo connectivity private when possible.

### Azure

- Recommended first target: Azure Container Apps or App Service.
- Store secrets in Key Vault.
- **Required:** put Application Gateway or Front Door in front for TLS and access control.

### Environment Separation

Run one container image, three deployments, three secret stores. Stamp
`MAXIMO_ENV=dev|staging|prod` per deployment — the value lands in every
audit record and on `/healthz`, so an operator can confirm at a glance
which Maximo a given container is pointed at.

Recommended pattern:

| Deployment | `MAXIMO_ENV` | Maximo target | Token scope |
|---|---|---|---|
| dev      | `dev`     | dev Maximo     | dev `MCP_ACCESS_TOKEN` / OIDC tenant |
| staging  | `staging` | staging Maximo | staging token / OIDC tenant |
| prod     | `prod`    | prod Maximo    | prod token / OIDC tenant |

Never reuse a token across environments — a leaked dev token must not
unlock prod, and a misrouted dev container must not write to prod data.

### Public Internet

Exposing the raw hosted MCP to the public internet requires ALL of the
following — no exceptions:

- bearer or OIDC inbound authentication (`MCP_AUTH_MODE`)
- TLS at the edge or in-process (the app serves plaintext by default)
- explicit CORS allowlist (`MCP_ALLOWED_ORIGINS`) — do NOT use `*`
- rate limiting (`RATE_LIMIT_PER_MINUTE`) and a separate edge limiter
- audit logging with durable forwarding
- private Maximo connectivity or strict network controls

## Development

### Run unit tests

```bash
pytest -m "not integration"
```

### Run integration tests

Integration tests hit a real Maximo instance configured in `.env`. Two suites:

- `tests/integration_test_tools.py` — tool-by-tool smoke against a single live Maximo
- `tests/integration/test_smoke_wave[1-4].py` — per-wave smoke runs that gate every public tool added in waves 1–4/6

```bash
# Run every integration test (skipped automatically if MAXIMO_URL is unset)
pytest tests/integration -m integration -v

# Run a single wave's smoke
pytest tests/integration/test_smoke_wave2.py -m integration -v

# Or run a wave standalone for ad-hoc debugging
python tests/integration/test_smoke_wave2.py
```

### List registered MCP tools

```bash
python server.py --test
```

## Security Notes

- Do not commit real `.env`, `.mcp.json`, or `.cursor/mcp.json` values.
- Use example configs from the `*.example` files and keep secrets in local-only files or a secret manager.
- Hosted mode requires `MCP_ACCESS_TOKEN`.
- The env-based role model is suitable for local or trusted deployments, not multi-tenant public hosting.

---

*IBM and Maximo are trademarks of International Business Machines Corp., used here for descriptive purposes only. This project is not affiliated with IBM.*
