Skip to main content
Glama
hackbansu

GoldenPi Bonds MCP Server

by hackbansu
README.md
# GoldenPi Bonds MCP Server

A [Model Context Protocol](https://modelcontextprotocol.io) server that exposes GoldenPi's reverse-engineered bond discovery APIs.

**Tools:**

- `goldenpi_list_bonds` — filtered, paginated bond listing via `POST /v0/bonds/list`
- `goldenpi_search_bonds` — free-text bond search via `POST /v0/bonds/search`

## Installation

```bash
cd goldenpi-mcp
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
cp .env.example .env
```

## Configuration

Copy `.env.example` to `.env` and edit as needed:

```bash
cp .env.example .env
```

Key variables:

| Variable | Default | Purpose |
|---|---|---|
| `GOLDENPI_BASE_URL` | `https://api.goldenpi.com` | GoldenPi API base URL |
| `GOLDENPI_CLIENT_TOKEN` | *(none)* | Optional static token. If unset or rejected, the server falls back to `/v0/auth/handshake`. |
| `GOLDENPI_PARTNER_ID` | `GoldenPi-Securities` | Partner ID sent during handshake |
| `GOLDENPI_SEND_DEPOSITORY_HEADER` | `0` | Set to `1` to send `x-gpi-client-depositoryid` on POSTs. Off by default because the live API rejects it on bond endpoints. |
| `GOLDENPI_MCP_TRANSPORT` | `stdio` | `stdio` for OpenCode/Claude Desktop, `sse` for ChatGPT apps |
| `GOLDENPI_MCP_HOST` / `GOLDENPI_MCP_PORT` | `0.0.0.0` / `8080` | SSE server bind address |

Auth behavior:

1. Uses `GOLDENPI_CLIENT_TOKEN` if set.
2. If the static token fails with an auth/header error, automatically calls `POST /v0/auth/handshake` to obtain a guest token and retries.
3. If handshake also fails, the server exits immediately with a clear error.

**Note:** As of the latest test, the embedded static token from the frontend bundle is rejected by the live API. The handshake guest token works, so leaving `GOLDENPI_CLIENT_TOKEN` unset (or commented out) is the most reliable default.

**Header note:** The frontend only sends `x-gpi-client-token` on POST requests. Sending `x-gpi-client-depositoryid` on `POST /v0/bonds/list` causes an "invalid header" error, so this server does **not** send it by default. Set `GOLDENPI_SEND_DEPOSITORY_HEADER=1` only if you specifically need it.

## Running locally (stdio / OpenCode / Claude Desktop)

```bash
python -m goldenpi_mcp.server
```

OpenCode / Claude Desktop config:

```json
{
  "mcpServers": {
    "goldenpi-bonds": {
      "command": "python",
      "args": ["-m", "goldenpi_mcp.server"],
      "env": {
        "GOLDENPI_DEPOSITORY_ID": "GoldenPi"
      }
    }
  }
}
```

## Running for ChatGPT / SSE clients

```bash
python -m goldenpi_mcp.server --transport sse --host 0.0.0.0 --port 8080
```

Your ChatGPT app should connect to:

```
http://localhost:8080/sse
```

## Tool reference

### `goldenpi_list_bonds`

Filtered, paginated bond discovery via `POST /v0/bonds/list`. **Does not support free-text search** — use `goldenpi_search_bonds` for name/ISIN/issuer queries.

#### Pagination & sorting

| Parameter | Type | Description |
|---|---|---|
| `sort_by` | enum | How to sort. Default: `yield-high-to-low`. |
| `limit` | int | Results per page. Range: 1–50. Default: 10. |
| `offset` | int | 1-based page number. Default: 1. |

#### Core filters

| Parameter | Type | Description |
|---|---|---|
| `asset_classes` | list | Instrument types: `NCD`, `NCD-IPO`, `GSEC`, `SDL`, `CGTB`, `SGB-IPO`. Defaults to `NCD`, `NCD-IPO`. |
| `credit_ratings` | list | `aaa`, `aa`, `a`, `sovereign`. `sovereign` matches government securities. |
| `min_yield` / `max_yield` | number | YTMC % range. Omit either side for open-ended. |
| `min_investment_inr` / `max_investment_inr` | number | Settlement amount per lot in INR. |
| `payment_frequencies` | list | `annual`, `half-yearly`, `quarterly`, `monthly`, `thrice-yearly`, `on-maturity`. |
| `issuer_types` | list | `nbfc`, `corporate`, `psu`, `psb`, `bank`, `government`, `gsec`, `sdl`, `rbi`. `gsec`/`sdl` also enable government asset classes. |
| `min_tenure_months` / `max_tenure_months` | int | Remaining tenure in whole months. Ignored if `tenure_preset` is set. |
| `tenure_preset` | enum | Shortcut: `less-than-1y`, `1-5y`, `5-10y`, `more-than-10y`, `short-term-3y`. |
| `investment_purpose` | enum | Strategy preset applying multiple filters at once, e.g. `highest-safety`, `tax-free-investment`, `invest-short-time`. |

#### Boolean flags

| Parameter | Description |
|---|---|
| `tax_free_only` | Tax-free bonds only. Mutually exclusive with `taxable_only`. |
| `taxable_only` | Taxable bonds only. |
| `nri_eligible_only` | NRI-eligible bonds only. |
| `secured_only` / `unsecured_only` | Secured or unsecured only. Mutually exclusive. |
| `perpetual_only` / `non_perpetual_only` | Perpetual or non-perpetual only. Mutually exclusive. |
| `call_option_only` / `no_call_option_only` | With or without call option. Mutually exclusive. |
| `pledge_for_fno_only` | Accepted as pledge for F&O margin. |
| `huf_tax_exemption_only` | HUF tax exemption available. |
| `spotlight_only` | Featured/spotlight bonds only. |

#### Advanced filters

| Parameter | Type | Description |
|---|---|---|
| `issuer_mode` | enum | `public` (Public Placement) or `private` (Private Placement). |
| `face_values` | list | `1000`, `10000`, `100000`, `200000`, `1000000`, `above-10-lacs`. Combined into a range. |
| `bond_price_level` | enum | `discount`, `par`, `premium`. |
| `bank_bond_tier` | enum | `tier_i`, `tier_ii`, `tier_iii`. |
| `seniority` | enum | `senior` or `subordinate`. |
| `depository_listing` | enum | `nsdl`, `cdsl`, `both`. |
| `listed` | list | Override listing filter. `[1]` = active deals, `[0]` = primary/IPO, `[0,1]` = both. |
| `include_marketing_details` | bool | Include featured/UTSAV campaign metadata. |

Output:

```json
{
  "totalCount": 123,
  "filteredCount": 45,
  "hasMore": true,
  "bonds": [ /* full instList rows */ ]
}
```

### `goldenpi_search_bonds`

Free-text search across bonds/FDs/IPOs via `POST /v0/bonds/search`.

| Parameter | Required | Description |
|---|---|---|
| `search_filter` | yes | Name, ISIN, or issuer text. Minimum 2 characters. |
| `sort_by` | no | `yield-high-to-low` (default) or `yield-low-to-high`. |
| `limit` | no | Results per page. Range: 1–50. Default: 10. |
| `offset` | no | 1-based page number. Default: 1. |

## Testing

```bash
pytest
```

## Legal / risks

This is an unofficial reverse-engineered integration. GoldenPi may change their API without notice. Use at your own risk and respect their terms of service.