pik-mcp
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@pik-mcp search for used cars in Sarajevo under 5000 KM"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
pik-mcp
An MCP server that exposes the
OLX.ba marketplace API (base URL https://api.olx.ba,
documentation) as tools an LLM client can call:
authenticate, browse and manage listings, read categories/attributes/locations, and
run sponsorship/discount actions.
Setup
npm install
npm run buildCopy .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 # optionalThe 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.
Related MCP server: meloqa-mcp
Running
pik-mcp speaks MCP over stdio. Point any MCP client at node dist/index.js.
Claude Desktop / Claude Code config
{
"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
npm run inspect # opens @modelcontextprotocol/inspector against the serverTools
Group | Tools |
Auth |
|
Listings (read) |
|
Categories |
|
Locations |
|
Listings (write) |
|
Images |
|
Sponsored / 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
suggest_category/find_category→ pick acategory_idget_category_attributes→ see required attributes;get_category_brands/get_category_modelsif applicableget_city(orlist_cities) → pick acity_idcreate_listing→ returns a DRAFT listing idupload_listing_image→ attach photos;set_main_listing_imagefor the coverpublish_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 formattingAvailable Tools
35 toolscreate_listingCreate listing (draft)A
Create a new listing in DRAFT status (POST /listings). Only title is required. The listing is NOT visible until you call publish_listing. Resolve category_id via the category tools and city_id via the location tools first.
Inputs: title (required), price, state, city_id, +10 more.
delete_listingDelete listing (permanent)ADestructive
PERMANENTLY delete a listing (DELETE /listings/:id). This is irreversible — confirm with the user before calling.
Inputs: id (required).
delete_listing_imageDelete listing imageADestructive
Remove one image from a listing (POST /listings/:id/image-delete).
Inputs: id (required), imageId (required).
find_categoryFind category by nameARead-only
Find categories matching a name, with their hierarchical path (GET /categories/find?name=).
Inputs: name (required).
finish_listingFinish listing (mark sold)ADestructive
Mark a listing as completed/sold (POST /listings/:id/finish). This ends the active listing; it moves to the user's finished listings.
Inputs: id (required).
finish_listing_discountFinish listing discountA
End an active discount early and restore the original price (POST /listings/:id/discount/finish).
Inputs: id (required).
get_canton_citiesGet cities in a cantonARead-only
Return the cities within a canton (GET /cantons/:id/cities).
Inputs: id (required).
get_categoryGet category detailARead-only
Return a single category with detailed properties such as base_listing_price and top_category status (GET /category/:id).
Inputs: id (required).
get_category_attributesGet category attributesARead-only
Return the attributes for a category (GET /categories/:id/attributes), including input_type, options and whether each is required. These define the attributes you can set when creating a listing in this category.
Inputs: id (required).
get_category_brandsGet category brandsBRead-only
Return the brands available for a category (GET /categories/:id/brands).
Inputs: id (required).
get_category_childrenGet child categoriesARead-only
Return the child categories of a category (GET /categories/:id). Use this to walk the category tree down to a leaf before creating a listing.
Inputs: id (required).
get_category_modelsGet brand modelsARead-only
Return the models for a brand within a category (GET /categories/:id/brands/:brand_id/models).
Inputs: id (required), brand_id (required).
get_cityGet city detailARead-only
Return a single city with coordinates, zip_code, country_id and canton_id (GET /cities/:id). Use the id as city_id when creating a listing.
Inputs: id (required).
get_listingGet listingARead-only
Retrieve a single listing by its id (GET /listings/:id). Returns the full listing object: title, price, location, status, images and owner details.
Inputs: id (required).
get_listing_limitsGet listing limitsARead-only
Return per-category listing limits (cars, real-estate, other) with current counts (GET /listing-limits).
Inputs: no named parameters.
get_refresh_limitsGet refresh limitsARead-only
Return refresh quota: free_limit, free_count, paid_count, listing_count (GET /listing/refresh/limits).
Inputs: no named parameters.
get_sponsor_priceGet sponsorship price quoteARead-only
Get a price quote for sponsoring a listing (GET /listings/:id/sponsore/price). Read-only — ALWAYS call this and show the quote to the user before sponsor_listing.
Inputs: id (required), days (required), type (required), refresh_every (required), +1 more.
get_user_listingsGet a user's listingsARead-only
List a user's listings, filtered by state (GET /users/:user/listings and its finished/inactive/expired/hidden variants). Paginated. Use state: active for the public/visible listings. The user is a username for active listings and a user id for the other states, matching the OLX API.
Inputs: user (required), page, state.
hide_listingHide listingA
Hide a listing from search; it stays visible on the user profile (POST /listings/:id/hide).
Inputs: id (required).
list_categoriesList top-level categoriesARead-only
Return all top-level categories (GET /categories).
Inputs: no named parameters.
list_citiesList citiesARead-only
Return all cities with their cantons (GET /cities).
Inputs: no named parameters.
list_countriesList countriesARead-only
Return all countries with id, name and code (GET /countries).
Inputs: no named parameters.
list_country_statesList country states / cantonsBRead-only
Return country states with their cantons (GET /country-states).
Inputs: no named parameters.
login_statusLogin statusARead-only
Force a fresh login with the configured credentials and report success. Useful for diagnosing authentication problems.
Inputs: no named parameters.
publish_listingPublish listingA
Activate a DRAFT listing so it becomes visible in search (POST /listings/:id/publish).
Inputs: id (required).
refresh_listingRefresh listingA
Bump a listing's rank by refreshing its timestamp (PUT /listings/:id/refresh). Subject to quota — check get_refresh_limits. May consume a paid refresh once the free quota is exhausted.
Inputs: id (required).
search_listingsSearch listingsARead-only
Full-text search across OLX listings (GET /search). Public — works without credentials. Combine a text query with filters (category, brand, city, price range, condition, recency). Returns a compact summary per listing plus pagination meta and category aggregations. Set raw: true for the full untrimmed payload. Use extra_params for advanced/rare query keys such as attribute filters (attr, attr_encoded) or custom sorting.
Inputs: q, raw, page, state, +10 more.
set_listing_discountSet listing discount (PAID/impactful)ADestructive
Set a temporary discounted price on a listing (POST /listings/:id/discount). This changes the live price shown to buyers for the given period. Confirm with the user first.
Inputs: id (required), days (required), price (required).
set_main_listing_imageSet main listing imageA
Set a listing's primary/cover image (POST /listings/:id/image-main).
Inputs: id (required), imageId (required).
sponsor_listingSponsor listing (PAID)ADestructive
Purchase sponsorship/promotion for a listing (POST /listings/:id/sponsore). THIS SPENDS OLX CREDITS. Call get_sponsor_price first, present the total to the user, and only proceed after explicit confirmation.
Inputs: id (required), days (required), type (required), refresh_every (required), +1 more.
suggest_categorySuggest category from titleBRead-only
Suggest categories for a listing title/keyword (GET /categories/suggest?keyword=). Handy for auto-selecting a category when creating a listing.
Inputs: keyword (required).
unhide_listingUnhide listingA
Restore a hidden listing's visibility (POST /listings/:id/unhide).
Inputs: id (required).
update_listingUpdate listingA
Update fields on an existing listing (PUT /listings/:id). Provide only the fields you want to change alongside the listing id.
Inputs: id (required), price, state, title, +11 more.
upload_listing_imageUpload listing image(s)A
Attach image(s) to a listing (POST /listings/:id/image-upload). Provide either image_url (the API fetches it) and/or an images array of image URLs. Returns the created image objects with their ids and sizes.
Inputs: id (required), images, image_url.
whoamiWho am IARead-only
Return the currently authenticated OLX user (GET /me). Also confirms that login and token caching are working.
Inputs: no named parameters.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
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.
Maintenance
Related MCP Connectors
Pay-per-use tool marketplace for AI agents. Search, price-check, and call APIs via MCP.
100+ MCP tools for AI agents: content metadata, trade intelligence, business-expertise analysis.
The OpenRouter for tools. One MCP connection gives any AI agent 254 hosted tools, pay per call.
214 tools for AI agents over one MCP endpoint: image, video, audio, 3D, data, storage, mail, GPUs.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceMCP server for managing OLX.ba / PIK.ba shops, enabling listing management, category/location queries, sponsor operations, and image uploads via natural language.-
- AlicenseCqualityCmaintenanceExposes every operation from the meloQA v1 API as MCP tools, enabling LLM clients to read and manage meloQA projects, test cases, cycles, executions, bugs, links, and reference data.8346 npmMIT
- AlicenseAqualityDmaintenanceExposes the Loyverse API as MCP tools to manage stores, products, inventory, customers, receipts, and more from AI assistants.54MIT
- AlicenseNot gradedqualityCmaintenanceMCP server for the OLX.ba API that enables searching, publishing, editing, and managing listings (ads), including image handling, sponsorships, categories, locations, and user account operations through 36 tools covering all official API endpoints.8 npm7MIT