pik-mcp
# 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
Scored across 35 tools
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.
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.
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.
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.