Metadata-Version: 2.4
Name: d1-mcp-mint
Version: 0.1.0
Summary: DelhiveryOne MCP auto-mints access tokens for AI tools
Author-email: Delhivery Engineering <integrations@delhivery.com>
License-Expression: MIT
Keywords: auth,delhivery,mcp,proxy,token
Requires-Python: >=3.11
Requires-Dist: httpx<1.0.0,>=0.27.0
Requires-Dist: mcp<2.0.0,>=1.0.0
Provides-Extra: dev
Requires-Dist: pytest-asyncio<1,>=0.23; extra == 'dev'
Requires-Dist: pytest<9,>=8.0; extra == 'dev'
Requires-Dist: respx<1,>=0.21; extra == 'dev'
Description-Content-Type: text/markdown

# d1-mcp-mint

**DelhiveryOne MCP Mint** — Connect your AI IDE (Kiro, Cursor, Claude Desktop) to DelhiveryOne APIs in 2 steps. No manual token management.

## How It Works

This package runs as a local MCP server (stdio) that:
1. Takes your Auth `client_id` and `client_secret`
2. Auto-mints and caches access tokens (refreshes before expiry)
3. Proxies all MCP tool calls to the live D1 MCP Gateway with a fresh Bearer token

You never touch tokens manually. They're minted, cached, and refreshed automatically.

Get your ClientID and Secret from:

```
curl --location --request POST 'https://<your-auth-domain>/p/api/account/client' \
--header 'Authorization: Bearer <your-auth-token>'
```

```mermaid
flowchart TD
    A[AI IDE - Kiro Cursor Claude] -->|stdio| B[d1-mcp-mint local proxy]
    B -->|client_credentials grant| C[Auth]
    C -->|access_token| B
    B -->|Bearer token + headers| D[D1 MCP Gateway]
    D -->|tool results| B
    B -->|tool results| A
```

---

## Repository Structure

```
d1-mcp-mint/
├── src/
│   └── d1_mcp_mint/
│       ├── __init__.py          # Package version
│       ├── server.py            # MCP stdio server + D1 gateway proxy
│       └── token_manager.py     # Auth token caching & auto-refresh
├── tests/                       # Test suite
├── pyproject.toml               # Package metadata & dependencies
├── README.md                    # This file
└── uv.lock                      # Locked dependencies
```

---

## Prerequisites

| Requirement | How to get it |
|-------------|---------------|
| **Python 3.11+** | Bundled with `uv` |
| **uv** (Python package runner) | See install instructions below |
| **Auth credentials** | Provided by Delhivery (client_id + client_secret) |

### Install uv (one-time)

```bash
# macOS (Homebrew)
brew install uv

# or via pip
pip install uv

# or via curl
curl -LsSf https://astral.sh/uv/install.sh | sh
```

Verify it works:
```bash
uvx --version
```

---

## Setup (2 Steps)

### Step 1: Add MCP Config to Your IDE

**Kiro** (`.kiro/settings/mcp.json`):
```json
{
  "mcpServers": {
    "delhivery-one": {
      "command": "uvx",
      "args": ["d1-mcp-mint@latest"],
      "env": {
        "D1_CLIENT_ID": "<your-auth-client-id>",
        "D1_CLIENT_SECRET": "<your-auth-client-secret>",
        "D1_AUTH_URL": "https://<your-auth-domain>",
        "D1_REALM": "<your-realm>",
        "D1_CLIENT_CMS": "<your-client-cms-id>",
        "D1_MCP_URL": "https://<your-mcp-gateway>/delhivery-one/c/<your-client-path>/mcp"
      }
    }
  }
}
```

**Cursor** (`.cursor/mcp.json`):
```json
{
  "mcpServers": {
    "delhivery-one": {
      "command": "uvx",
      "args": ["d1-mcp-mint@latest"],
      "env": {
        "D1_CLIENT_ID": "<your-auth-client-id>",
        "D1_CLIENT_SECRET": "<your-auth-client-secret>",
        "D1_AUTH_URL": "https://<your-auth-domain>",
        "D1_REALM": "<your-realm>",
        "D1_CLIENT_CMS": "<your-client-cms-id>",
        "D1_MCP_URL": "https://<your-mcp-gateway>/delhivery-one/c/<your-client-path>/mcp"
      }
    }
  }
}
```

**Claude Desktop** (`claude_desktop_config.json`):
```json
{
  "mcpServers": {
    "delhivery-one": {
      "command": "uvx",
      "args": ["d1-mcp-mint@latest"],
      "env": {
        "D1_CLIENT_ID": "<your-auth-client-id>",
        "D1_CLIENT_SECRET": "<your-auth-client-secret>",
        "D1_AUTH_URL": "https://<your-auth-domain>",
        "D1_REALM": "<your-realm>",
        "D1_CLIENT_CMS": "<your-client-cms-id>",
        "D1_MCP_URL": "https://<your-mcp-gateway>/delhivery-one/c/<your-client-path>/mcp"
      }
    }
  }
}
```

#### Using System Environment Variables (recommended for security)

Instead of hardcoding secrets in JSON, export them in your shell profile (`~/.zshrc`, `~/.bashrc`):

```bash
export D1_CLIENT_ID="your-client-id"
export D1_CLIENT_SECRET="your-client-secret"
export D1_AUTH_URL="https://<your-auth-domain>"
export D1_REALM="your-realm"
export D1_CLIENT_CMS="cms::client::your-uuid"
export D1_MCP_URL="https://<your-mcp-gateway>/delhivery-one/c/<your-client-path>/mcp"
```

Then your MCP config passes them through (no secrets in the file):

```json
{
  "mcpServers": {
    "delhivery-one": {
      "command": "uvx",
      "args": ["d1-mcp-mint@latest"],
      "env": {
        "D1_CLIENT_ID": "${D1_CLIENT_ID}",
        "D1_CLIENT_SECRET": "${D1_CLIENT_SECRET}",
        "D1_AUTH_URL": "${D1_AUTH_URL}",
        "D1_REALM": "${D1_REALM}",
        "D1_CLIENT_CMS": "${D1_CLIENT_CMS}",
        "D1_MCP_URL": "${D1_MCP_URL}"
      }
    }
  }
}
```

This way you can safely commit `mcp.json` to version control — it contains no secrets.

### Step 2: Fill In Your Credentials

| Variable | What it is | Example |
|----------|-----------|---------|
| `D1_CLIENT_ID` | Auth confidential client ID | `d1-mcp-client-acme` |
| `D1_CLIENT_SECRET` | Auth client secret | `aB3x...k9Yz` |
| `D1_AUTH_URL` | Auth server base URL | `https://<your-auth-domain>` |
| `D1_REALM` | Auth realm name | `<your-realm-id>` |
| `D1_CLIENT_CMS` | Client CMS identifier | `cms::client::<your-uuid>` |
| `D1_MCP_URL` | D1 MCP Gateway endpoint | `https://<your-mcp-gateway>/delhivery-one/c/<path>/mcp` |

**Where do I get these?** Your Delhivery account manager or engineering contact will provide all six values.

---

## Restart and Verify

### Kiro
1. Open Command Palette (`Cmd+Shift+P`)
2. Search for **"MCP: Restart Server"** or **"MCP: List Servers"**
3. You should see `delhivery-one` listed with status **running**

### Cursor
1. Open Settings → MCP
2. You should see `delhivery-one` listed
3. Click the refresh icon if it's not connected
4. Status should show a green dot (connected)

---

## What You Can Do

Once connected, ask your AI assistant things like:

- "Show me my recent shipments"
- "What's the status of waybill WB12345?"
- "Get my wallet balance"
- "List my support tickets"
- "What does my dashboard look like?"

The available tools depend on what's configured on the D1 MCP Gateway for your account.

---

## How Token Management Works

```
┌─────────────────────────────────────────────────────────────┐
│                    Token Lifecycle                          │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. First tool call → mint token via client_credentials     │
│  2. Cache token in memory                                   │
│  3. Subsequent calls → use cached token                     │
│  4. 30 seconds before expiry → auto-refresh                 │
│  5. Token failure → re-mint immediately                     │
│                                                             │
│  You never see or manage tokens. It just works.             │
│                                                             │
└─────────────────────────────────────────────────────────────┘
```

The `TokenManager` class:
1. On the first `get_token()` call, mints a token via `client_credentials` grant
2. Caches the token + expiry time in memory
3. Returns the cached token on subsequent calls if still valid
4. Re-mints only when the token is within 30 seconds of expiry

Auth is only hit once per token lifetime (typically every ~5 minutes), not on every API call.

---

## Environment Variables Reference

| Variable | Required | Description |
|----------|----------|-------------|
| `D1_CLIENT_ID` | Yes | Auth confidential client ID |
| `D1_CLIENT_SECRET` | Yes | Auth client secret |
| `D1_AUTH_URL` | Yes | Auth base URL |
| `D1_REALM` | Yes | Auth realm name |
| `D1_CLIENT_CMS` | Yes | Client CMS identifier for D1 |
| `D1_MCP_URL` | Yes | D1 MCP Gateway endpoint URL |
| `D1_USER_EMAIL` | No | User email (defaults to `--`) |

---

## For Developers: Local Development

### Clone and install

```bash
git clone <repo-url>
cd d1-mcp-mint
uv sync
```

### Run the server locally

```bash
# Set env vars
export D1_CLIENT_ID="your-client-id"
export D1_CLIENT_SECRET="your-client-secret"
export D1_AUTH_URL="https://<your-auth-domain>"
export D1_REALM="<your-realm-id>"
export D1_CLIENT_CMS="cms::client::<your-uuid>"
export D1_MCP_URL="https://<your-mcp-gateway>/delhivery-one/c/<your-client-path>/mcp"

# Run the server (stdio mode — accepts JSON-RPC on stdin)
uv run d1-mcp-mint
```

### Point your IDE at local source (instead of PyPI)

```json
{
  "mcpServers": {
    "delhivery-one": {
      "command": "uv",
      "args": ["run", "--directory", "/absolute/path/to/d1-mcp-mint", "d1-mcp-mint"],
      "env": {
        "D1_CLIENT_ID": "...",
        "D1_CLIENT_SECRET": "...",
        "D1_AUTH_URL": "https://<your-auth-domain>",
        "D1_REALM": "...",
        "D1_CLIENT_CMS": "...",
        "D1_MCP_URL": "https://<your-mcp-gateway>/delhivery-one/c/<your-client-path>/mcp"
      }
    }
  }
}
```

### Key source files

| File | Purpose |
|------|---------|
| `src/d1_mcp_mint/server.py` | Entry point. Registers MCP handlers, builds proxy, routes tool calls to the D1 gateway. |
| `src/d1_mcp_mint/token_manager.py` | Handles Auth `client_credentials` grant. Caches tokens in memory and auto-refreshes 30s before expiry. |
| `src/d1_mcp_mint/__init__.py` | Package version (`__version__`). |
| `pyproject.toml` | Build config (hatchling), dependencies, CLI entry point (`d1-mcp-mint` → `server:main`). |

### Run tests

```bash
uv sync --dev
uv run pytest tests/ -v
```

---

## Publishing to PyPI

Publishing is automated via GitHub Actions. Push a tag to trigger the workflow:

```bash
# Bump version in pyproject.toml and src/d1_mcp_mint/__init__.py
# Then tag and push:
git tag d1-mcp-mint-v0.2.0
git push origin d1-mcp-mint-v0.2.0
```

The CI pipeline will:
1. Run tests across Python 3.11, 3.12, and 3.13
2. Build the package
3. Publish to PyPI using trusted publishing (OIDC — no API tokens needed)

### Manual publish (fallback)

```bash
cd d1-mcp-mint
uv build
uv publish --token <your-pypi-api-token>
```

### Publish to TestPyPI first (recommended for new versions)

```bash
uv publish --publish-url https://test.pypi.org/legacy/ --token <your-test-pypi-token>

# Verify it works
uvx --index-url https://test.pypi.org/simple/ d1-mcp-mint@0.1.0
```

### Bumping the version

Update the version in two places:
1. `pyproject.toml` → `version = "X.Y.Z"`
2. `src/d1_mcp_mint/__init__.py` → `__version__ = "X.Y.Z"`

---

## Troubleshooting

| Error | Cause | Fix |
|-------|-------|-----|
| `D1_CLIENT_ID is required` | Missing env var | Add to your MCP config `env` block |
| `401 Unauthorized` from Auth | Wrong client_id/secret | Verify credentials in Auth admin |
| `403 Forbidden` from D1 Gateway | Client not authorized | Contact Delhivery to enable access |
| `Connection refused` | MCP gateway down or wrong URL | Verify `D1_MCP_URL` is correct |
| `uvx: command not found` | uv not installed | Install via `brew install uv` or `pip install uv` |
| Server shows "disconnected" | Bad credentials | Test token manually (see below) |
| "No tools available" | Tools not configured for client | Contact Delhivery engineering |

### Quick credential test

```bash
curl -X POST "https://<your-auth-domain>/realms/<your-realm>/protocol/openid-connect/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials&client_id=<your-client-id>&client_secret=<your-client-secret>"
```

If this returns JSON with `access_token`, your credentials are correct.

---

## Security Notes

- Client secrets are stored in your local MCP config — **never commit secrets to version control**
- Tokens are cached in-memory only (not persisted to disk)
- Token lifetime is controlled by your Auth client configuration
- Add to your `.gitignore`:
  ```
  .kiro/settings/mcp.json
  .cursor/mcp.json
  ```
- If credentials are compromised, disable the Auth client immediately

---

## For Delhivery Admins: Client Setup

To onboard a new customer/developer:

1. Create a **confidential client** in the appropriate Auth realm
2. Enable **Service Accounts** (client_credentials grant)
3. Assign required **roles/scopes** for D1 API access
4. Provide the customer with:
   - `client_id`
   - `client_secret`
   - `realm` name
   - `auth_url`
   - `client_cms`
   - `mcp_url`

---

## FAQ

**Q: Do I need Python installed?**
A: You need `uv` (which bundles its own Python). If you have `brew install uv`, you're good.

**Q: Does this work offline?**
A: No. It needs network access to reach Auth (for tokens) and the D1 MCP Gateway (for API calls).

**Q: Can I use this in CI/CD?**
A: It's designed for local IDE use. For CI/CD, mint tokens directly via the Auth token endpoint.

**Q: What APIs can I access?**
A: Whatever tools are configured on the D1 MCP Gateway for your client. Typically: shipments, orders, wallets, tickets, dashboards, and more.

**Q: Can multiple people use the same client_id?**
A: Yes, but for audit/security reasons, each developer should ideally have their own credentials.

**Q: How do I update to the latest version?**
A: `uvx` always pulls `@latest` by default. Just restart the MCP server. No manual update needed.

---

## License

MIT
