Skip to main content
Glama
README.md
# ai-credits-mcp

MCP server that exposes AI credit usage data from OpenMeter to the TAIS AI chat service. Queries are automatically scoped to the calling tenant and restricted to admin users.

---

## Tools

All tools require the caller to be in the `Administrators` group. Each tool returns a markdown table (for the LLM to summarise) and a `[Download Excel](url)` link pointing to a temporary `.xlsx` file served at `/download/<token>`. The link expires after **10 minutes**. They are automatically scoped to the calling user's tenant — no tenant parameter is exposed.

If the request exceeds 50 rows in the text preview, the table is truncated with a note to see the Excel file for the full dataset.

### `get_credit_usage_by_tenant`

Returns total credits consumed by the tenant as a single aggregated number.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `from_date` | string | No | ISO 8601 start, e.g. `"2026-01-01T00:00:00Z"` |
| `to_date` | string | No | ISO 8601 end (defaults to now) |

**Output columns:** `tenant`, `credits`

**Example prompts:**
- *"How many AI credits has my tenant used?"*
- *"What's our total credit spend this month?"*

---

### `get_credit_usage_summary`

Returns credits broken down by user, module, product, and skill — useful for identifying who or what is consuming the most credits.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `from_date` | string | No | ISO 8601 start |
| `to_date` | string | No | ISO 8601 end (defaults to now) |

**Output columns:** `user`, `module`, `product`, `tenant`, `skill`, `credits`

**Example prompts:**
- *"Show me credit usage broken down by user."*
- *"Which product or skill is using the most credits?"*
- *"Give me a credit usage summary for Q1 2026."*

---

### `get_credit_events`

Returns individual raw credit events — the lowest level of detail, one row per event.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `from_date` | string | No | ISO 8601 start |
| `to_date` | string | No | ISO 8601 end (defaults to now) |

**Output columns:** `time`, `user`, `module`, `product`, `tenant`, `credits`

**Example prompts:**
- *"Show me all credit events from last week."*
- *"What happened on January 15th in terms of AI usage?"*

---

### How the AI decides which tool to call

When you ask about credit usage in the AI chat, the model picks the appropriate tool automatically:

- Totals / "how much overall" → `get_credit_usage_by_tenant`
- Breakdowns by user / module / skill → `get_credit_usage_summary`
- Individual events / audit trail → `get_credit_events`

If no date range is specified, the last 7 days are used by default. To change the range, phrase your question naturally: *"...for January 2026"* or *"...since last month"* — the model will translate this to ISO 8601 parameters.

---

## Security

| Invariant | Enforcement |
|---|---|
| Admin-only access | `X-User-UserRole` checked on every call; accepted values: `admin`, `Administrators` |
| Tenant-scoped | `X-Tenant-Name` header used as filter; callers cannot override it |
| Tenant header absent | Returns an error — no data is exposed |
| `OPENMETER_API_KEY` never exposed | Only used inside `query_credits._get()`; never returned to callers |

The TAIS chatbot-agent-service forwards both headers automatically on every MCP connection.

---

## Running locally

**Prerequisites:** Python 3.11+, `uv`

```bash
cd ai-credits-mcp
uv sync                        # install dependencies
cp .env.example .env           # add your OPENMETER_API_KEY
uv run main.py
# Server starts at http://localhost:8765
```

Health check:
```bash
curl http://localhost:8765/health
# {"status": "ok"}
```

---

## AI chat integration

Use the registration script to register the tool and wire it to a TAIS session:

```bash
bash scripts/register.sh
```

The script reads `TAIS_JWT` from `.env`, decodes the tenant and user automatically, registers the tool against the local TAIS API, and PATCHes the session. If `TAIS_SESSION_ID` is not set in `.env` it will prompt you interactively.

**Note:** registered tools expire after ~1 hour. Re-run the script when the tool stops responding.

To wire to a session manually:

```bash
PATCH http://localhost:5001/api/v2/sessions-service/{sessionId}
Authorization: Bearer <token>
Content-Type: application/json

{"toolIds": ["<tool-id-from-registration>"]}
```

---

## Environment variables

| Variable | Required | Description |
|---|---|---|
| `OPENMETER_API_KEY` | Yes | OpenMeter API key |
| `MCP_PORT` | No | Port to listen on (default: `8765`) |
| `TAIS_JWT` | No | JWT for `scripts/register.sh` — not used by the server at runtime |
| `TAIS_SESSION_ID` | No | Session to wire the tool to; script prompts if absent |
| `TENANT_OVERRIDE` | No | Dev only — overrides `X-Tenant-Name` header |
| `ROLE_OVERRIDE` | No | Dev only — overrides `X-User-UserRole` header |

---

## Project structure

```
ai-credits-mcp/
├── server.py            # FastMCP server, tools, middleware, download endpoint
├── main.py              # uvicorn entry point
├── scripts/
│   └── register.sh      # registers tool with TAIS and wires it to a session
├── pyproject.toml       # dependencies (mcp, uvicorn, openpyxl, python-dotenv)
└── .env.example         # environment variable template
```

`server.py` imports `query_credits` from the sibling `ai-credit-usage/` directory, which handles all OpenMeter API calls.

---

## Aspire registration

Registered in `apphost.cs` as:

```csharp
var aiCreditsMcp = builder.AddPythonApp("ai-credits-mcp", "/Users/a.demers/dev/ai-credits-mcp", "main.py")
    .WithUv()
    .WithEnvironment("PYTHONPATH", ".")
    .WithHttpEndpoint(port: 8765, env: "MCP_PORT", isProxied: false)
    .WithHttpHealthCheck("/health")
    .WithEnvironment("OPENMETER_API_KEY", Environment.GetEnvironmentVariable("OPENMETER_API_KEY") ?? "");
```

Add `OPENMETER_API_KEY=<your-key>` to the workspace-root `.env` file.