Skip to content

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

  1. What is MCP?
  2. Why Use the Owning MCP Server?
  3. Connect Claude Desktop
  4. Connect Cursor
  5. Connect Other MCP Clients
  6. The 10 Available Tools
  7. Tool Examples
  8. Per-Tool Input/Output Examples
  9. Authentication
  10. Raw JSON-RPC Calls
  11. 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 as draft — call publish_listing to make it visible.

Tool 7: upload_image

Input:

{
  "image_data": "iVBORw0KGgoAAAANSUhEUgAA...",
  "filename": "bavaria-c42-exterior.jpg",
  "listing_id": "lst_01JX2K3M4N5P6Q7R8S9T0U"
}
image_data is base64-encoded image content without the data: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 from draftactive. Automated moderation runs on publish — if rejected, returns isError: true with moderation_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. Valid action values: update, change_status, delete. Valid status values for change_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

  1. Register at owning.pro/register (or via POST /api/auth/register)
  2. Go to your Dashboard → API Keys (or POST /api/api-keys with your JWT)
  3. Generate a new API key — it starts with own_ and is shown only once
  4. 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:

  1. Check your network/firewall allows persistent HTTP connections
  2. Verify the URL is https://mcp.owning.pro/mcp/sse (not /mcp)
  3. Some clients don't require SSE — the POST /mcp endpoint 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.


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.