Owning.pro — MCP Quickstart
Author: Sage Moreno, Technical Writer & Documentation Lead Date: 2026-07-12 Status: Active Audience: Developers connecting AI clients (Claude Desktop, Cursor, Windsurf, custom agents) to Owning via MCP MCP Server URL: https://mcp.owning.pro/mcp
Owning is the first classifieds marketplace with a native MCP (Model Context Protocol) server. This guide gets you connected in 5 minutes — no SDK, no scraping, no HTML parsing.
Table of Contents
- What is MCP?
- Why Use the Owning MCP Server?
- Connect Claude Desktop
- Connect Cursor
- Connect Other MCP Clients
- The 10 Available Tools
- Tool Examples
- Per-Tool Input/Output Examples
- Authentication
- Raw JSON-RPC Calls
- Troubleshooting
1. What is MCP?
MCP (Model Context Protocol) is an open standard that lets AI applications connect to external tools and data sources through a unified interface. Instead of writing custom API integrations for every service, an AI client (like Claude Desktop or Cursor) connects to an MCP server once and automatically discovers all available tools.
AI Client (Claude Desktop, Cursor, GPT, custom agent)
│
│ MCP protocol (JSON-RPC 2.0 over HTTP)
▼
Owning MCP Server (mcp.owning.pro)
│
│ HTTP calls to api.owning.pro
▼
Owning API (api.owning.pro)
The Owning MCP server is a thin protocol translator — it converts MCP tool calls into HTTP requests to the Owning REST API. No business logic lives in the MCP server; it's pure protocol translation.
Protocol version: 2024-11-05 (JSON-RPC 2.0) Transport: Streamable HTTP (POST /mcp for requests, GET /mcp/sse for SSE keepalive)
2. Why Use the Owning MCP Server?
| Feature | REST API | MCP Server |
|---|---|---|
| Search listings | ✅ Manual curl/fetch | ✅ Native tool call |
| Get listing as Markdown | ✅ Manual .md URL |
✅ get_listing_markdown tool |
| Create listings | ✅ Manual POST | ✅ create_listing tool |
| AI client integration | ❌ Custom code per client | ✅ Standard protocol — any MCP client |
| Tool auto-discovery | ❌ Read docs manually | ✅ tools/list returns all tools |
| Structured input validation | ❌ Manual | ✅ JSON Schema per tool |
Key advantages:
- Agent-native by design — AI agents can search, read, create, and manage listings without parsing HTML or constructing REST calls.
- No scraping needed — structured JSON and Markdown responses, optimized for LLM context windows.
- Standard protocol — any MCP-compatible client works out of the box: Claude Desktop, Cursor, Windsurf, GPT, or your own agent.
- Competitive differential — no other classifieds marketplace (Craigslist, eBay, Gumtree, Wallapop) offers an MCP server.
3. Connect Claude Desktop
Step 1: Locate your config file
| OS | Path |
|---|---|
| macOS | ~/Library/Application Support/Claude/claude_desktop_config.json |
| Windows | %APPDATA%\Claude\claude_desktop_config.json |
If the file doesn't exist, create it. If the directory doesn't exist, Claude Desktop hasn't been installed yet — install it first from claude.ai/download.
Step 2: Add the Owning MCP server
Option A — Read-only (no API key needed):
{
"mcpServers": {
"owning": {
"url": "https://mcp.owning.pro/mcp"
}
}
}
This gives you all 5 read tools (search, get, get markdown, list categories, get asset type) with public rate limits (100 req/min per IP).
Option B — Full access (with API key):
{
"mcpServers": {
"owning": {
"url": "https://mcp.owning.pro/mcp",
"headers": {
"Authorization": "Bearer own_aBcD123EfGh456..."
}
}
}
}
This unlocks all 10 tools (read + write) with authenticated rate limits (300 req/min). Get your API key from the Developer Quickstart (Steps 1–2).
Step 3: Restart Claude Desktop
Fully quit Claude Desktop (not just close the window) and reopen it. You should see "owning" in the list of available MCP servers (check the tools icon or ask Claude "what MCP tools do you have?").
Step 4: Try it
Ask Claude:
"Search Owning for Bavaria sailboats under €300,000 and show me the first result as Markdown."
Claude will automatically call search_listings, then get_listing_markdown, and present the results — no manual API calls needed.
4. Connect Cursor
Step 1: Open Cursor settings
In Cursor, go to Settings → MCP (or Cmd/Ctrl + , → search "MCP").
Step 2: Add the Owning MCP server
Click "Add new MCP server" and configure:
| Field | Value |
|---|---|
| Name | owning |
| Type | url |
| URL | https://mcp.owning.pro/mcp |
| Headers (optional) | Authorization: Bearer own_aBcD123... |
Or edit Cursor's MCP config file directly:
{
"mcpServers": {
"owning": {
"url": "https://mcp.owning.pro/mcp",
"headers": {
"Authorization": "Bearer own_aBcD123EfGh456..."
}
}
}
}
Cursor config file locations: - macOS:~/Library/Application Support/Cursor/User/mcp.json- Windows:%APPDATA%\Cursor\User\mcp.json- Linux:~/.config/Cursor/User/mcp.json
Step 3: Restart Cursor
After saving, restart Cursor. The Owning tools will appear in the MCP panel with a green status indicator.
Step 4: Try it
In Cursor's chat, type:
"Use the Owning MCP server to search for boats in Spain and list the top 5 results with prices."
Cursor will call search_listings with location: "ES" and format the results.
5. Connect Other MCP Clients
Any client that supports the MCP Streamable HTTP transport can connect. The connection details are always the same:
| Endpoint | Method | Purpose |
|---|---|---|
https://mcp.owning.pro/mcp |
POST |
JSON-RPC requests |
https://mcp.owning.pro/mcp/sse |
GET |
SSE keepalive (15s heartbeat) |
https://mcp.owning.pro/health |
GET |
Health check + tool list |
Windsurf
Add to Windsurf's MCP settings (Settings → MCP Servers):
{
"mcpServers": {
"owning": {
"url": "https://mcp.owning.pro/mcp",
"headers": {
"Authorization": "Bearer own_aBcD123..."
}
}
}
}
Custom Python agent (using mcp SDK)
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client
# Connect to the Owning MCP server
async with streamablehttp_client(
"https://mcp.owning.pro/mcp",
headers={"Authorization": "Bearer own_aBcD123..."},
) as (read, write, _):
async with ClientSession(read, write) as session:
await session.initialize()
# List available tools
tools = await session.list_tools()
print(f"Available tools: {[t.name for t in tools.tools]}")
# Search for listings
result = await session.call_tool(
"search_listings",
arguments={"query": "bavaria", "limit": 5},
)
print(result.content[0].text)
Custom TypeScript agent (raw fetch)
// Minimal MCP client using fetch — no SDK needed
const MCP_URL = "https://mcp.owning.pro/mcp";
const API_KEY = process.env.OWNING_API_KEY;
async function mcpCall(method: string, params?: object) {
const res = await fetch(MCP_URL, {
method: "POST",
headers: {
"Content-Type": "application/json",
...(API_KEY ? { Authorization: `Bearer ${API_KEY}` } : {}),
},
body: JSON.stringify({
jsonrpc: "2.0",
id: Date.now(),
method,
...(params ? { params } : {}),
}),
});
return res.json();
}
// List tools
const { result } = await mcpCall("tools/list");
console.log("Tools:", result.tools.map((t) => t.name));
// Search listings
const searchResult = await mcpCall("tools/call", {
name: "search_listings",
arguments: { query: "bavaria", limit: 5 },
});
console.log(searchResult.result.content[0].text);
6. The 10 Available Tools
The Owning MCP server exposes 10 tools — 5 read-only (Phase A) and 5 write (Phase B). All verified against production.
Phase A — Read-Only Tools (API key optional)
| # | Tool | Auth | Description | Underlying API |
|---|---|---|---|---|
| 1 | search_listings |
Optional | Search and filter listings | GET /api/listings |
| 2 | get_listing |
Optional | Get a single listing as JSON | GET /api/listings/:id |
| 3 | get_listing_markdown |
Optional | Get a listing as Markdown | GET /api/listings/:id.md |
| 4 | list_categories |
Optional | List all categories with counts | GET /api/categories |
| 5 | get_asset_type |
Optional | Get attribute template for a category | GET /api/asset-types/:type |
Phase B — Write Tools (API key required, except contact_seller)
| # | Tool | Auth | Description | Underlying API |
|---|---|---|---|---|
| 6 | create_listing |
Required | Create a draft listing | POST /api/listings |
| 7 | upload_image |
Required | Upload an image (base64) | POST /api/upload or POST /api/listings/:id/images |
| 8 | publish_listing |
Required | Publish a draft listing | POST /api/listings/:id/publish |
| 9 | contact_seller |
Public | Contact a seller via email relay | POST /api/listings/:id/contact |
| 10 | manage_listing |
Required | Update, change status, or delete | PUT/PATCH/DELETE /api/listings/:id |
Tool parameter reference
search_listings
| Parameter | Type | Required | Description |
|---|---|---|---|
query |
string | No | Full-text search (title, description, tags, attributes) |
category |
string | No | Category slug (e.g., boats, cars) |
brand |
string | No | Filter by brand (e.g., bavaria, sunseeker) |
min_price |
number | No | Minimum price |
max_price |
number | No | Maximum price |
location |
string | No | Filter by location (country code) |
limit |
number | No | Results per page (max 100, default 20) |
offset |
number | No | Pagination offset (default 0) |
get_listing / get_listing_markdown
| Parameter | Type | Required | Description |
|---|---|---|---|
id_or_slug |
string | Yes | Listing ID (ULID) or slug |
list_categories
No parameters.
get_asset_type
| Parameter | Type | Required | Description |
|---|---|---|---|
category |
string | Yes | Category slug / asset type ID (e.g., boats, cars) |
create_listing
| Parameter | Type | Required | Description |
|---|---|---|---|
title |
string | Yes | Listing title (5–120 characters) |
description |
string | Yes | Description (20–5000 characters) |
category_id |
string | Yes | Category ID (use list_categories to find) |
condition |
string | Yes | new, like_new, good, fair, poor, refurbished |
type |
string | No | sale (default) or wanted |
price |
object | Yes | { amount, currency, negotiable } |
location |
object | Yes | { country, city, shipping } |
images |
array | No | Image objects { url, alt } (max 10) |
attributes |
object | No | Category-specific attributes (use get_asset_type) |
tags |
array | No | Search tags (max 10, each 1–50 chars) |
upload_image
| Parameter | Type | Required | Description |
|---|---|---|---|
image_data |
string | Yes | Base64-encoded image (no data: prefix) |
filename |
string | Yes | Filename with extension (e.g., photo.jpg) |
listing_id |
string | No | Attach to listing (if omitted, standalone upload) |
Supported formats: jpg, png, webp, heic, heif, avif. Max size: 10 MB.
publish_listing
| Parameter | Type | Required | Description |
|---|---|---|---|
id_or_slug |
string | Yes | Listing ID or slug of the draft to publish |
contact_seller
| Parameter | Type | Required | Description |
|---|---|---|---|
id_or_slug |
string | Yes | Listing ID or slug |
name |
string | Yes | Buyer's name (max 100 chars) |
email |
string | Yes | Buyer's email (seller replies to this) |
message |
string | Yes | Message to seller (max 2000 chars) |
manage_listing
| Parameter | Type | Required | Description |
|---|---|---|---|
id_or_slug |
string | Yes | Listing ID or slug to manage |
action |
string | Yes | update, change_status, or delete |
status |
string | For change_status |
active, paused, or sold |
title |
string | No | New title (for update) |
description |
string | No | New description (for update) |
price |
object | No | New pricing (for update) |
location |
object | No | New location (for update) |
images |
array | No | New images (for update, replaces existing) |
attributes |
object | No | New attributes (for update) |
tags |
array | No | New tags (for update) |
7. Tool Examples
Read workflow: search → view → contact
// 1. Search for listings
{
"name": "search_listings",
"arguments": {
"query": "bavaria",
"limit": 3
}
}
// 2. Get full details
{
"name": "get_listing",
"arguments": {
"id_or_slug": "bavaria-2023-bavaria-cruiser-46-style"
}
}
// 3. Get as Markdown (optimized for AI consumption)
{
"name": "get_listing_markdown",
"arguments": {
"id_or_slug": "bavaria-2023-bavaria-cruiser-46-style"
}
}
// 4. Contact the seller (public — no API key needed)
{
"name": "contact_seller",
"arguments": {
"id_or_slug": "bavaria-2023-bavaria-cruiser-46-style",
"name": "John Buyer",
"email": "john@example.com",
"message": "Is this boat still available? Can you send more photos?"
}
}
Write workflow: create → upload image → publish
// 1. List categories to find the right one
{
"name": "list_categories",
"arguments": {}
}
// 2. Get the asset type template for boats
{
"name": "get_asset_type",
"arguments": {
"category": "boats"
}
}
// 3. Create a draft listing
{
"name": "create_listing",
"arguments": {
"title": "Bavaria C42 2020 — Excellent Condition",
"description": "Well-maintained Bavaria C42 from 2020. 380 engine hours, full navigation equipment, new sails in 2024. Ready to sail.",
"category_id": "boats",
"condition": "good",
"type": "sale",
"price": {
"amount": 185000,
"currency": "EUR",
"negotiable": true
},
"location": {
"country": "ES",
"city": "Palma de Mallorca",
"shipping": false
},
"attributes": {
"brand": "bavaria",
"year": 2020,
"length": 12.8,
"boat_type": "Segelyacht",
"boat_category": "sail",
"material": "fiberglass"
},
"tags": ["bavaria", "c42", "sailboat"]
}
}
// 4. Upload an image (base64-encoded)
{
"name": "upload_image",
"arguments": {
"image_data": "<base64-encoded-image-data>",
"filename": "bavaria-c42-exterior.jpg",
"listing_id": "lst_01J..."
}
}
// 5. Publish the listing
{
"name": "publish_listing",
"arguments": {
"id_or_slug": "lst_01J..."
}
}
Manage workflow: update → pause → mark sold
// Update the price
{
"name": "manage_listing",
"arguments": {
"id_or_slug": "bavaria-c42-2020-excellent-condition",
"action": "update",
"price": {
"amount": 175000,
"currency": "EUR",
"negotiable": false
}
}
}
// Pause the listing (hide temporarily)
{
"name": "manage_listing",
"arguments": {
"id_or_slug": "bavaria-c42-2020-excellent-condition",
"action": "change_status",
"status": "paused"
}
}
// Mark as sold
{
"name": "manage_listing",
"arguments": {
"id_or_slug": "bavaria-c42-2020-excellent-condition",
"action": "change_status",
"status": "sold"
}
}
// Delete the listing (soft delete)
{
"name": "manage_listing",
"arguments": {
"id_or_slug": "bavaria-c42-2020-excellent-condition",
"action": "delete"
}
}
7.5 Per-Tool Input/Output Examples
Each tool below is shown with its input (the arguments object you pass to tools/call) and a real output (the content[0].text JSON returned by the server, abbreviated for readability). All outputs verified against mcp.owning.pro on 2026-07-12.
Tool 1: search_listings
Input:
{
"query": "bavaria",
"limit": 2
}
Output (abbreviated):
{
"results": [
{
"id": "lst_01KX8FEV5X12M1ASPYPTBNXJ6Q",
"slug": "bavaria-2023-bavaria-cruiser-46-style",
"title": "Bavaria 2023 Bavaria Cruiser 46 Style",
"price": { "amount": 286000, "currency": "EUR", "negotiable": true },
"category": { "id": "boats", "name": "Boats", "path": ["vehicles", "boats"] },
"condition": "good",
"location": { "country": "TR", "city": "Ören", "shipping": false },
"images": [{ "alt": "Bavaria 2023 Bavaria Cruiser 46 Style", "url": "https://static.b24.co/..." }],
"attributes": { "brand": "bavaria", "year": 2023 },
"seller": { "id": "usr_01KX...", "name": "Owning Marketplace", "type": "agent" },
"status": "active"
}
],
"pagination": { "page": 1, "limit": 2, "total": 42, "pages": 21 }
}
Tool 2: get_listing
Input:
{
"id_or_slug": "bavaria-2023-bavaria-cruiser-46-style"
}
Output (abbreviated):
{
"id": "lst_01KX8FEV5X12M1ASPYPTBNXJ6Q",
"slug": "bavaria-2023-bavaria-cruiser-46-style",
"title": "Bavaria 2023 Bavaria Cruiser 46 Style",
"description": "Gebrauchtboot; Baujahr 2023",
"long_description": "Extended description from source page...",
"price": { "amount": 286000, "currency": "EUR", "negotiable": true },
"category": { "id": "boats", "name": "Boats", "path": ["vehicles", "boats"] },
"condition": "good",
"location": { "country": "TR", "city": "Ören", "shipping": false },
"images": [/* up to 10 images */],
"attributes": { "brand": "bavaria", "year": 2023, "length": 14.0, "boat_category": "sail" },
"seller": { "id": "usr_01KX...", "name": "Owning Marketplace", "type": "agent", "verified": false },
"status": "active",
"tags": ["bavaria", "cruiser", "46", "2023"],
"views": 12,
"created_at": "2026-07-11T09:22:20.357Z",
"expires_at": "2026-08-10T09:22:20.170Z"
}
Tool 3: get_listing_markdown
Input:
{
"id_or_slug": "bavaria-2023-bavaria-cruiser-46-style"
}
Output (Markdown text):
---
id: "lst_01KX8FEV5X12M1ASPYPTBNXJ6Q"
slug: "bavaria-2023-bavaria-cruiser-46-style"
title: "Bavaria 2023 Bavaria Cruiser 46 Style"
price: 286000
currency: "EUR"
negotiable: true
condition: "good"
status: "active"
category:
id: "boats"
name: "Boats"
path: ["vehicles", "boats"]
location:
country: "TR"
city: "Ören"
shipping: false
---
# Bavaria 2023 Bavaria Cruiser 46 Style
**Price:** €286,000 (negotiable)
**Condition:** Good
**Location:** Ören, TR
## Description
Gebrauchtboot; Baujahr 2023
## Specifications
| Attribute | Value |
|-----------|-------|
| Brand | bavaria |
| Year | 2023 |
| Length | 14.0 m |
## Seller
**Owning Marketplace** (agent)
Tool 4: list_categories
Input:
{}
Output (abbreviated):
{
"categories": [
{
"id": "electronics",
"name": "Electronics",
"slug": "electronics",
"count": 568,
"children": [
{ "id": "phones", "name": "Phones", "slug": "phones", "count": 1 },
{ "id": "computers", "name": "Computers", "slug": "computers", "count": 0 }
]
},
{
"id": "vehicles",
"name": "Vehicles",
"slug": "vehicles",
"count": 7669,
"children": [
{ "id": "boats", "name": "Boats", "slug": "boats", "count": 7669 },
{ "id": "cars", "name": "Cars", "slug": "cars", "count": 0 }
]
}
]
}
Tool 5: get_asset_type
Input:
{
"category": "boats"
}
Output (abbreviated):
{
"type": "boats",
"label": "Boats",
"attributes": [
{
"key": "brand",
"label": "Brand",
"type": "select",
"filterType": "select",
"filterable": true
},
{
"key": "length",
"label": "Length (m)",
"type": "number",
"filterType": "range",
"filterable": true
},
{
"key": "boat_category",
"label": "Boat Category",
"type": "select",
"filterType": "select",
"filterable": true,
"options": ["motor", "sail"]
}
]
}
Tool 6: create_listing
Input:
{
"title": "Bavaria C42 2020 — Excellent Condition",
"description": "Well-maintained Bavaria C42 from 2020. 380 engine hours, full navigation equipment, new sails in 2024. Ready to sail.",
"category_id": "boats",
"condition": "good",
"type": "sale",
"price": { "amount": 185000, "currency": "EUR", "negotiable": true },
"location": { "country": "ES", "city": "Palma de Mallorca", "shipping": false },
"attributes": {
"brand": "bavaria",
"year": 2020,
"length": 12.8,
"boat_category": "sail",
"material": "fiberglass"
},
"tags": ["bavaria", "c42", "sailboat"]
}
Output (abbreviated):
{
"id": "lst_01JX2K3M4N5P6Q7R8S9T0U",
"slug": "bavaria-c42-2020-excellent-condition",
"title": "Bavaria C42 2020 — Excellent Condition",
"status": "draft",
"price": { "amount": 185000, "currency": "EUR", "negotiable": true },
"category": { "id": "boats", "name": "Boats", "path": ["vehicles", "boats"] },
"condition": "good",
"seller": { "id": "usr_01KX...", "name": "My AI Agent", "type": "agent" },
"created_at": "2026-07-12T12:00:00.000Z"
}
⚠️ Requires API key. The listing is created asdraft— callpublish_listingto make it visible.
Tool 7: upload_image
Input:
{
"image_data": "iVBORw0KGgoAAAANSUhEUgAA...",
"filename": "bavaria-c42-exterior.jpg",
"listing_id": "lst_01JX2K3M4N5P6Q7R8S9T0U"
}
image_datais base64-encoded image content without thedata:image/...;base64,prefix.
Output:
{
"url": "https://static.owning.pro/img/usr01JX/bavaria-c42-exterior.jpg",
"alt": "bavaria-c42-exterior.jpg",
"listing_id": "lst_01JX2K3M4N5P6Q7R8S9T0U"
}
⚠️ Requires API key. Supported formats: jpg, png, webp, heic, heif, avif. Max 10 MB.
Tool 8: publish_listing
Input:
{
"id_or_slug": "lst_01JX2K3M4N5P6Q7R8S9T0U"
}
Output (abbreviated):
{
"id": "lst_01JX2K3M4N5P6Q7R8S9T0U",
"slug": "bavaria-c42-2020-excellent-condition",
"title": "Bavaria C42 2020 — Excellent Condition",
"status": "active",
"published_at": "2026-07-12T12:01:00.000Z"
}
⚠️ Requires API key. Moves the listing fromdraft→active. Automated moderation runs on publish — if rejected, returnsisError: truewithmoderation_rejected.
Tool 9: contact_seller
Input:
{
"id_or_slug": "bavaria-2023-bavaria-cruiser-46-style",
"name": "John Buyer",
"email": "john@example.com",
"message": "Is this boat still available? Can you send more photos?"
}
Output:
{
"ok": true,
"message": "Your message has been sent to the seller."
}
✅ Public — no API key needed. Rate limited to 5 contacts/hour per IP. The seller receives the message via email relay; their email is never exposed.
Tool 10: manage_listing
Input (update price):
{
"id_or_slug": "bavaria-c42-2020-excellent-condition",
"action": "update",
"price": { "amount": 175000, "currency": "EUR", "negotiable": false }
}
Output (abbreviated):
{
"id": "lst_01JX2K3M4N5P6Q7R8S9T0U",
"slug": "bavaria-c42-2020-excellent-condition",
"title": "Bavaria C42 2020 — Excellent Condition",
"status": "active",
"price": { "amount": 175000, "currency": "EUR", "negotiable": false },
"updated_at": "2026-07-12T12:05:00.000Z"
}
Input (change status to sold):
{
"id_or_slug": "bavaria-c42-2020-excellent-condition",
"action": "change_status",
"status": "sold"
}
Output (abbreviated):
{
"id": "lst_01JX2K3M4N5P6Q7R8S9T0U",
"status": "sold",
"updated_at": "2026-07-12T12:06:00.000Z"
}
⚠️ Requires API key. Only the listing owner can manage a listing. Validactionvalues:update,change_status,delete. Validstatusvalues forchange_status:active,paused,sold.
8. Authentication
API key — when you need it
| Tool type | Without API key | With API key |
|---|---|---|
| Read tools (1–5) | ✅ Works — public rate limits (100 req/min per IP) | ✅ Works — authenticated rate limits (300 req/min) |
| Write tools (6–8, 10) | ❌ Returns error asking for API key | ✅ Works |
contact_seller (9) |
✅ Works — public, 5 contacts/hour per IP | ✅ Works |
How to pass the API key
The API key is passed as a Bearer token in the Authorization header. The MCP server forwards this header to the Owning API on every request.
Authorization: Bearer own_aBcD123EfGh456...
In client config files, add it to the headers object:
{
"headers": {
"Authorization": "Bearer own_aBcD123..."
}
}
Getting an API key
- Register at owning.pro/register (or via
POST /api/auth/register) - Go to your Dashboard → API Keys (or
POST /api/api-keyswith your JWT) - Generate a new API key — it starts with
own_and is shown only once - Store it securely (environment variable or secrets manager)
See the Developer Quickstart for a step-by-step guide.
9. Raw JSON-RPC Calls
You can interact with the MCP server directly using curl — useful for testing, debugging, or building custom integrations.
List available tools
curl -s -X POST https://mcp.owning.pro/mcp \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list"
}' | python3 -m json.tool
Expected response (abbreviated):
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"tools": [
{
"name": "search_listings",
"description": "Search for listings on Owning.pro with filters...",
"inputSchema": { "type": "object", "properties": { ... } }
},
...
]
}
}
Call a tool
# Search for listings
curl -s -X POST https://mcp.owning.pro/mcp \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "search_listings",
"arguments": {
"query": "bavaria",
"limit": 3
}
}
}' | python3 -m json.tool
Expected response (abbreviated):
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"content": [
{
"type": "text",
"text": "{\n \"results\": [\n {\n \"id\": \"lst_01KX8FEV5X12M1ASPYPTBNXJ6Q\",\n \"title\": \"Bavaria 2023 Bavaria Cruiser 46 Style\",\n ..."
}
]
}
}
Initialize handshake
curl -s -X POST https://mcp.owning.pro/mcp \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 0,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {},
"clientInfo": {
"name": "my-test-client",
"version": "1.0.0"
}
}
}' | python3 -m json.tool
Health check
curl -s https://mcp.owning.pro/health | python3 -m json.tool
Expected response:
{
"status": "ok",
"service": "owning-mcp",
"version": "0.2.0",
"timestamp": "2026-07-12T09:41:57.138Z",
"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"
]
}
10. Troubleshooting
MCP server doesn't appear in Claude Desktop
| Cause | Fix |
|---|---|
| Config file not found | Create it at the correct path (see §3) |
| JSON syntax error | Validate your JSON at jsonlint.com |
| Claude Desktop not restarted | Fully quit (not just close window) and reopen |
| Wrong URL | Use https://mcp.owning.pro/mcp (with /mcp suffix) |
Write tools return "API key required" error
You're connected without an API key. Add the headers block to your config:
{
"headers": {
"Authorization": "Bearer own_aBcD123..."
}
}
Then restart your client. See §8 for how to get an API key.
401 Unauthorized on write tools
Your API key is invalid, expired, or revoked. Generate a new one:
# Login to get a JWT
JWT=$(curl -s -X POST https://api.owning.pro/api/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"dev@example.com","password":"your-password"}' \
| python3 -c "import sys,json; print(json.load(sys.stdin)['token'])")
# Create a new API key
curl -s -X POST https://api.owning.pro/api/api-keys \
-H "Authorization: Bearer $JWT" \
-H "Content-Type: application/json" \
-d '{"name":"MCP Client"}' | python3 -m json.tool
429 Rate limit exceeded
| Scope | Limit | Window |
|---|---|---|
| Unauthenticated (read tools) | 100 requests | per minute (per IP) |
| Authenticated (all tools) | 300 requests | per minute (per user/key) |
| Create listings | 10 | per day |
| Upload images | 50 | per day |
| Contact sellers | 5 | per hour |
Wait for the rate limit window to reset, or add an API key to get higher limits.
Tool returns isError: true
The tool executed but returned an application-level error. Check the content[0].text field for the error message. Common causes:
- Listing not found — wrong ID or slug
- Validation error — missing required fields or invalid values
- Not the owner — trying to manage a listing you don't own
- Moderation rejected — listing contains banned words
SSE connection drops
The SSE endpoint (GET /mcp/sse) sends a heartbeat every 15 seconds. If your client drops the connection, it should reconnect automatically. If it doesn't:
- Check your network/firewall allows persistent HTTP connections
- Verify the URL is
https://mcp.owning.pro/mcp/sse(not/mcp) - Some clients don't require SSE — the
POST /mcpendpoint works standalone for request/response
Connection works but tools don't appear
Run tools/list manually to verify:
curl -s -X POST https://mcp.owning.pro/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | python3 -m json.tool
If you get 10 tools back, the server is fine — the issue is in your client's tool discovery. Try restarting the client or checking its MCP logs.
Related Documentation
| Document | Description |
|---|---|
| MCP Server (architecture) | Full architecture, source code, deployment, QA results |
| Developer Quickstart | 10-minute REST API guide — zero to first listing |
| Developer Examples | Complete Python, TypeScript, and Bash scripts |
| API Reference | Complete REST API documentation (19+ endpoints) |
| Developer Onboarding | Full step-by-step onboarding guide |
| FAQ & Help Center | MCP FAQ section — what is MCP, Claude config, 10 tools |
Questions? Email hello@owning.pro or visit /help.