MCP Server Quickstart
The Owning MCP (Model Context Protocol) server lets any MCP-compatible AI client — Claude Desktop, GPT, Cursor, or any custom agent — search, browse, create, and manage listings on Owning.pro without writing HTTP code. It wraps the REST API in 10 simple tools exposed over JSON-RPC 2.0.
What is the MCP Server?
The MCP server is a thin layer that translates MCP protocol requests into HTTP calls to the Owning REST API. Instead of constructing HTTP requests with headers, URLs, and JSON bodies, an AI agent simply calls a tool like search_listings or create_listing with structured arguments.
Simpler for agents — tools have typed parameters and descriptions, so the LLM knows exactly what to pass.
No HTTP boilerplate — the server handles auth headers, URL construction, and response parsing.
Structured results — results come back as text content (JSON or Markdown) ready for the LLM to reason about.
Architecture
MCP Client (Claude Desktop, GPT, Cursor, custom agent)
| MCP protocol (JSON-RPC 2.0 over HTTP)
v
MCP Server (https://mcp.owning.pro)
| HTTP calls to api.owning.pro
v
Owning API (https://api.owning.pro)Connecting to the MCP Server
Server URL
| Endpoint | Method | Purpose |
|---|---|---|
https://mcp.owning.pro/mcp | POST | JSON-RPC 2.0 request → response |
https://mcp.owning.pro/mcp/sse | GET | SSE keepalive (for clients that expect SSE) |
https://mcp.owning.pro/health | GET | Health check + tool list |
Protocol
The server implements the MCP Streamable HTTP transport (spec 2025-03-26). Each POST /mcp request is a complete JSON-RPC 2.0 request → response cycle. No persistent connection is needed.
Authentication
Pass your Owning API key as a Bearer token in the Authorization header:
Authorization: Bearer own_aBcD123eFgH456iJkL789mNoP012qRsT345uVwX678yZ- Read tools (search, get, categories, asset types) — API key optional. Without a key, requests are anonymous (subject to public rate limits: 100 req/min per IP).
- Write tools (create, upload, publish, manage) — API key required with write permission.
- contact_seller — API key optional (public endpoint, rate limited per IP).
Step 1: Initialize
curl -X POST https://mcp.owning.pro/mcp \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {}
}'
# Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2024-11-05",
"capabilities": { "tools": {} },
"serverInfo": { "name": "owning-mcp", "version": "0.2.0" }
}
}Step 2: List available tools
curl -X POST https://mcp.owning.pro/mcp \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/list",
"params": {}
}'
# Response: array of 10 tool definitions with name, description, and inputSchemaStep 3: Call a tool
curl -X POST https://mcp.owning.pro/mcp \
-H "Content-Type: application/json" \
-H "Authorization: Bearer own_aBcD123eFgH..." \
-d '{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "search_listings",
"arguments": {
"query": "bavaria",
"category": "boats",
"limit": 5
}
}
}'
# Response:
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"content": [{ "type": "text", "text": "{ \"results\": [...], \"pagination\": {...} }" }]
}
}Read Tools (5)
Read-only tools for searching and browsing listings. API key is optional — without one, requests are anonymous.
1. search_listings
Search for listings with filters. Returns matching listings with title, price, location, images, and key attributes.
Parameters
| Param | Type | Required | Default | Description |
|---|---|---|---|---|
query | string | No | — | Full-text search across title, description, tags, and attributes |
category | string | No | — | Category slug (e.g. boats, cars) |
brand | string | No | — | Filter by brand (passed as attr[brand]) |
min_price | number | No | — | Minimum price filter |
max_price | number | No | — | Maximum price filter |
location | string | No | — | Filter by location (country or city) |
limit | integer | No | 20 | Results per page (max 100) |
offset | integer | No | 0 | Pagination offset |
# Example: search for Bavaria boats under 150k
{
"name": "search_listings",
"arguments": {
"query": "bavaria",
"category": "boats",
"max_price": 150000,
"limit": 10
}
}2. get_listing
Get full details of a specific listing by ID or slug. Returns all available information including description, specifications, all images, pricing, location, and attributes.
Parameters
| Param | Type | Required | Description |
|---|---|---|---|
id_or_slug | string | Yes | Listing ID (ULID) or slug (e.g. azimut-95-magellano-2024) |
3. get_listing_markdown
Get a listing in Markdown format — optimized for agents and AI consumption. Includes all listing data (title, price, description, specifications, images, attributes) in a structured, readable Markdown document with YAML frontmatter.
Parameters
| Param | Type | Required | Description |
|---|---|---|---|
id_or_slug | string | Yes | Listing ID (ULID) or slug |
# Example response content:
---
title: "Lagoon 400 S2"
price: 295000
currency: "EUR"
condition: "good"
---
## Description
Gebrauchtboot; Baujahr 2016
## Specifications
- **Brand**: lagoon
- **Year**: 2016
- **Length**: 11.97 m4. list_categories
List all available categories on Owning.pro with their listing counts. Returns a hierarchical tree of categories (parent and subcategories) with slug names and item counts. No parameters required.
5. get_asset_type
Get the attribute template for a specific category. Shows what fields/attributes are available for listings in that category (e.g. brand, model, year, length for boats).
Parameters
| Param | Type | Required | Description |
|---|---|---|---|
category | string | Yes | Category slug / asset type ID (e.g. boats, cars) |
Write Tools (5)
Write tools for creating, publishing, and managing listings. All require an API key with write permission, except contact_seller which is public.
6. create_listing
Create a new listing on Owning.pro. The listing is created in draft status — use publish_listing to make it visible publicly. Rate limit: 10 listings per day per user.
Parameters
| Param | Type | Required | Description |
|---|---|---|---|
title | string | Yes | 5–120 characters |
description | string | Yes | 20–5000 characters |
category_id | string | Yes | Category ID (use list_categories to find available) |
condition | enum | Yes | new, like_new, good, fair, poor, refurbished |
type | enum | No | sale (default) or wanted |
price | object | Yes | { amount, currency?, negotiable? } — currency defaults to EUR |
location | object | Yes | { country, city, postal_code?, lat?, lng?, shipping? } |
images | array | No | Up to 10: [{ url, alt? }]}. Use upload_image first. |
attributes | object | No | Category-specific attributes (use get_asset_type to discover) |
tags | array | No | Up to 10 tags, each 1–50 characters |
{
"name": "create_listing",
"arguments": {
"title": "Apple iPhone 13 128GB Blue",
"description": "Apple iPhone 13 in blue, 128GB. Good condition, battery health 89%.",
"category_id": "electronics",
"condition": "good",
"price": { "amount": 399, "currency": "EUR", "negotiable": true },
"location": { "country": "ES", "city": "Madrid", "shipping": true },
"tags": ["iphone", "apple", "smartphone"]
}
}7. upload_image
Upload an image to Owning.pro. Pass the image as base64-encoded data. If listing_id is provided, the image is attached to that listing (requires ownership). If omitted, a standalone upload returns a URL for use in create_listing. Rate limit: 50 images per day. Supported formats: jpg, png, webp, heic, heif, avif. Max size: 10 MB.
Parameters
| Param | Type | Required | Description |
|---|---|---|---|
image_data | string | Yes | Base64-encoded image data (without data: prefix) |
filename | string | Yes | Original filename including extension (e.g. photo.jpg) |
listing_id | string | No | Listing ID or slug. If provided, attaches to that listing. |
8. publish_listing
Publish a draft listing, making it publicly visible on Owning.pro. Moves the listing from draft to active status. Only the listing owner can publish.
Parameters
| Param | Type | Required | Description |
|---|---|---|---|
id_or_slug | string | Yes | Listing ID or slug of the draft listing to publish |
9. contact_seller
Contact the seller of a listing by sending a message. The seller's email is never exposed — the API relays the message via email and the seller can reply to your email. No API key required (public endpoint). Rate limit: 5 contacts per hour per IP.
Parameters
| Param | Type | Required | Description |
|---|---|---|---|
id_or_slug | string | Yes | Listing ID or slug |
name | string | Yes | Your name (shown to the seller, 1–100 chars) |
email | string | Yes | Your email (the seller can reply to this) |
message | string | Yes | Your message (1–2000 characters) |
10. manage_listing
Manage an existing listing — update its fields, change its status, or delete it. Only the listing owner can perform these actions. Supports three actions:
Parameters
| Param | Type | Required | Description |
|---|---|---|---|
id_or_slug | string | Yes | Listing ID or slug to manage |
action | enum | Yes | update, change_status, or delete |
status | enum | For change_status | active, paused, or sold |
title, description, price, etc. | various | For update | Any listing field to update (see create_listing for the full list) |
# Example: pause a listing
{
"name": "manage_listing",
"arguments": {
"id_or_slug": "apple-iphone-13-128gb-blue",
"action": "change_status",
"status": "paused"
}
}
# Example: update the price
{
"name": "manage_listing",
"arguments": {
"id_or_slug": "apple-iphone-13-128gb-blue",
"action": "update",
"price": { "amount": 350, "currency": "EUR", "negotiable": false }
}
}
# Example: delete a listing
{
"name": "manage_listing",
"arguments": {
"id_or_slug": "apple-iphone-13-128gb-blue",
"action": "delete"
}
}Rate Limits
The MCP server forwards all requests to the Owning REST API, so the API's rate limits apply:
| Tool | Limit | Scope |
|---|---|---|
| Read tools (no API key) | 100 req/min | per IP |
| Read tools (with API key) | 300 req/min | per key |
create_listing | 10 req/day | per user |
upload_image | 50 req/day | per user |
contact_seller | 5 req/hour | per IP |
Error Handling
Tool errors are returned as MCP results with isError: true and an error message in the content:
{
"jsonrpc": "2.0",
"id": 4,
"result": {
"content": [{ "type": "text", "text": "Search failed: Rate limit exceeded (status 429)" }],
"isError": true
}
}Invalid arguments (schema validation failures) are also returned as isError results with a description of which fields failed.
Health Check
curl https://mcp.owning.pro/health
# Response:
{
"status": "ok",
"service": "owning-mcp",
"version": "0.2.0",
"timestamp": "2026-07-11T16:17:44.333Z",
"apiBaseUrl": "https://api.owning.pro",
"tools": [
"search_listings", "get_listing", "get_listing_markdown",
"list_categories", "get_asset_type",
"create_listing", "upload_image", "publish_listing",
"contact_seller", "manage_listing"
]
}Check out the MCP server integration example for a complete end-to-end walkthrough in Python and JavaScript.