Skip to main content
Glama
dkasipovic

pik-mcp

by dkasipovic
README.md
# pik-mcp

An [MCP](https://modelcontextprotocol.io) server that exposes the
[OLX.ba](https://olx.ba) marketplace API (base URL `https://api.olx.ba`,
[documentation](https://api-documentation.olx.ba/)) as tools an LLM client can call:
authenticate, browse and manage listings, read categories/attributes/locations, and
run sponsorship/discount actions.

## Setup

```bash
npm install
npm run build
```

Copy `.env.example` to `.env` and fill in your OLX credentials:

```
OLX_USERNAME=your-username-or-email
OLX_PASSWORD=your-password
OLX_DEVICE_NAME=pik-mcp          # optional
OLX_BASE_URL=https://api.olx.ba  # optional
```

The server logs in with these credentials on the first tool call, caches the bearer
token in memory, and automatically re-authenticates if the token expires (HTTP 401).
Credentials are never written to stdout (the MCP transport); logs go to stderr.

## Running

`pik-mcp` speaks MCP over **stdio**. Point any MCP client at `node dist/index.js`.

### Claude Desktop / Claude Code config

```json
{
  "mcpServers": {
    "olx": {
      "command": "node",
      "args": ["C:/Users/dkasi/Documents/Projects/pik-mcp/dist/index.js"],
      "env": {
        "OLX_USERNAME": "your-username-or-email",
        "OLX_PASSWORD": "your-password"
      }
    }
  }
}
```

### Inspect / debug

```bash
npm run inspect   # opens @modelcontextprotocol/inspector against the server
```

## Tools

| Group | Tools |
|-------|-------|
| Auth | `whoami`, `login_status` |
| Listings (read) | `search_listings`, `get_listing`, `get_user_listings` |
| Categories | `list_categories`, `get_category_children`, `get_category`, `get_category_attributes`, `get_category_brands`, `get_category_models`, `suggest_category`, `find_category` |
| Locations | `list_countries`, `list_cities`, `get_city`, `list_country_states`, `get_canton_cities` |
| Listings (write) | `create_listing`, `update_listing`, `publish_listing`, `refresh_listing`, `get_refresh_limits`, `get_listing_limits`, `finish_listing`, `hide_listing`, `unhide_listing`, `delete_listing` |
| Images | `upload_listing_image`, `delete_listing_image`, `set_main_listing_image` |
| Sponsored / discount | `get_sponsor_price`, `sponsor_listing`, `set_listing_discount`, `finish_listing_discount` |

Destructive tools (`delete_listing`, `finish_listing`, image delete) and paid tools
(`sponsor_listing`, `set_listing_discount`) are flagged via MCP annotations and their
descriptions. `refresh_listing` may consume a paid refresh once the free quota is
exhausted — check `get_refresh_limits` first.

### Searching listings

`search_listings` performs full-text search over OLX (`GET /search`). It is
**public and works without credentials**, so you can browse even before setting up
login. It accepts typed filters — `q`, `category_id`, `brand_id`, `city_id`,
`price_from`/`price_to`, `state` (condition id, e.g. `2` = used), `created_gte`
(e.g. `"-24 hours"`), `per_page`, `page`, `sort_by`/`sort_order` — plus an
`extra_params` object passed through verbatim for advanced keys such as attribute
filters (`attr`, `attr_encoded`).

By default it returns a **compact** summary per listing (id, title, price,
category/brand/city ids, condition, date, cover image, and a
`https://olx.ba/artikal/{id}` URL) alongside pagination `meta` and category
`aggregations`. Pass `raw: true` to get the full untrimmed API payload.

### Typical create-and-publish flow

1. `suggest_category` / `find_category` → pick a `category_id`
2. `get_category_attributes` → see required attributes; `get_category_brands` / `get_category_models` if applicable
3. `get_city` (or `list_cities`) → pick a `city_id`
4. `create_listing` → returns a DRAFT listing id
5. `upload_listing_image` → attach photos; `set_main_listing_image` for the cover
6. `publish_listing` → makes it visible in search

## Notes / limitations

- The documented API exposes no generic "search all listings" endpoint. Browsing is
  done via categories + a user's listings (`get_user_listings`).
- Some success messages from OLX are in Bosnian (e.g. *"Oglas je uspjesno objavljen"*)
  and are passed through as-is.

## Project layout

```
src/
  index.ts          entry point (stdio transport)
  server.ts         builds McpServer, registers all tool groups
  config.ts         env-based configuration
  olx/
    client.ts       HTTP client: auth, token cache, 401 retry, error mapping
    types.ts        response shapes
  tools/            one file per resource group
  util/             shared zod schemas + result formatting
```

TDQS

A3.8/5.0

Scored across 35 tools

Disambiguation5/5

Each tool has a clear, distinct purpose: listing CRUD, images, categories, locations, search, user info, etc. Even with 35 tools, there is no ambiguity; for example, listing lifecycle tools (create, update, publish, finish, hide, etc.) are all uniquely named and described.

Naming Consistency4/5

Most tools follow a verb_noun pattern (e.g., get_listing, create_listing, upload_listing_image). Minor inconsistencies: 'whoami' and 'login_status' deviate, and some use different ordering (finish_listing vs. finish_listing_discount). Overall, the pattern is recognizable and predictable.

Tool Count4/5

35 tools is on the high side, but they cover a wide range of features for a listing marketplace (CRUD, images, sponsorship, discounts, categories, locations, search). The count is justified by the domain complexity and each tool earns its place.

Completeness5/5

The tool surface covers the full listing lifecycle and supporting operations: CRUD, image management, refresh, sponsorship, discounts, limits, categories with attributes and brands, location hierarchy, search, and user authentication. No obvious gaps for the stated purpose of managing OLX listings.

Maintenance

ActivityStale
ResponsivenessNo issues