{
    "$schema": "https://modelcontextprotocol.io/schemas/draft/server-card.json",
    "serverInfo": {
        "name": "com.openajan/openajan",
        "title": "OpenAjan",
        "version": "1.3.0",
        "description": "Open gateway between AI assistants and local shops (restaurants, cafés, barbers, beauty, florists, clinics). Find a shop, read its live menu, prices, hours and free booking times, and place an order or booking after the user says yes. Payment happens at the shop; OpenAjan never handles money.",
        "websiteUrl": "https://openajan.com",
        "documentationUrl": "https://openajan.com/agents.php"
    },
    "transport": {
        "type": "streamable-http",
        "endpoint": "https://openajan.com/mcp"
    },
    "capabilities": {
        "tools": {
            "listChanged": false
        }
    },
    "authentication": {
        "required": true,
        "schemes": [
            "oauth2"
        ],
        "type": "oauth2",
        "protectedResourceMetadata": "https://openajan.com/.well-known/oauth-protected-resource",
        "authorizationServerMetadata": "https://openajan.com/.well-known/oauth-authorization-server",
        "scopesSupported": [
            "shops:read",
            "orders:write"
        ]
    },
    "tools": [
        {
            "name": "find_shops",
            "title": "Find shops",
            "annotations": {
                "readOnlyHint": true,
                "destructiveHint": false,
                "idempotentHint": true,
                "openWorldHint": true,
                "title": "Find shops"
            },
            "description": "Search local shops on OpenAjan by name, city, zip or type (restaurant, cafe, barber, beauty, florist, repair, clinic, shop). Returns slug, name, type, city, whether the shop takes orders or bookings, and verified (true = OpenAjan has checked phone, opening hours, catalog freshness and order handling). Prices include VAT.",
            "inputSchema": {
                "type": "object",
                "properties": {
                    "query": {
                        "type": "string",
                        "description": "Free text: shop name, city, type, e.g. \"pizza Aarhus\" or \"Rebæk\""
                    },
                    "country": {
                        "type": "string",
                        "description": "DK, DE or TR (optional)"
                    },
                    "limit": {
                        "type": "integer",
                        "default": 5
                    }
                },
                "required": [
                    "query"
                ]
            },
            "outputSchema": {
                "type": "object",
                "properties": {
                    "shops": {
                        "type": "array",
                        "items": {
                            "type": "object",
                            "properties": {
                                "slug": {
                                    "type": "string"
                                },
                                "name": {
                                    "type": "string"
                                },
                                "type": {
                                    "type": "string"
                                },
                                "city": {
                                    "type": "string"
                                },
                                "zip": {
                                    "type": "string"
                                },
                                "country": {
                                    "type": "string"
                                },
                                "accepts": {
                                    "type": "array",
                                    "items": {
                                        "type": "string"
                                    }
                                },
                                "verified": {
                                    "type": "boolean"
                                },
                                "url": {
                                    "type": "string"
                                }
                            },
                            "required": []
                        }
                    }
                },
                "required": [
                    "shops"
                ]
            }
        },
        {
            "name": "get_shop",
            "title": "Get shop card",
            "annotations": {
                "readOnlyHint": true,
                "destructiveHint": false,
                "idempotentHint": true,
                "openWorldHint": true,
                "title": "Get shop card"
            },
            "description": "Get a shop's full card: address, phone, opening hours, and catalog with item ids and prices (including VAT). Orders and bookings refer to these item ids.",
            "inputSchema": {
                "type": "object",
                "properties": {
                    "slug": {
                        "type": "string",
                        "description": "Shop slug, e.g. \"rebaek-pizza\""
                    }
                },
                "required": [
                    "slug"
                ]
            },
            "outputSchema": {
                "type": "object",
                "properties": {
                    "openajan_version": {
                        "type": "string"
                    },
                    "merchant": {
                        "type": "object"
                    },
                    "hours": {
                        "type": "array"
                    },
                    "catalog": {
                        "type": "array",
                        "items": {
                            "type": "object",
                            "properties": {
                                "id": {
                                    "type": "integer"
                                },
                                "name": {
                                    "type": "string"
                                },
                                "price": {
                                    "type": "number"
                                },
                                "currency": {
                                    "type": "string"
                                },
                                "category": {
                                    "type": [
                                        "string",
                                        "null"
                                    ]
                                },
                                "duration_min": {
                                    "type": [
                                        "integer",
                                        "null"
                                    ]
                                }
                            },
                            "required": []
                        }
                    },
                    "ordering": {
                        "type": "object"
                    }
                },
                "required": [
                    "merchant",
                    "catalog",
                    "ordering"
                ]
            }
        },
        {
            "name": "place_order",
            "title": "Place order",
            "annotations": {
                "readOnlyHint": false,
                "destructiveHint": false,
                "idempotentHint": true,
                "openWorldHint": true,
                "title": "Place order"
            },
            "description": "Places an order or booking at a shop on the user's behalf, in two calls. The first call (without quote) places nothing: it returns status \"quote\" with the exact items, quantities, total and time, and a quote code valid for 15 minutes. The order is placed by a second call with the same items, time and that quote, made after the user has approved the quoted summary. Items are referenced by the item ids on the shop card. confirmed=true states that the user explicitly approved the exact items, quantities, total price (incl. VAT) and pickup/appointment time. The same idempotency_key always returns the same order, so retries are safe. For kind=booking, wanted_at is required and must be one of the shop's free times; otherwise the result is slot_not_available with free_slots. If the user set a maximum amount per order when connecting, orders above it (also when split within 30 minutes) are rejected with spending_limit_exceeded; if the user set a monthly budget, orders beyond it are rejected with monthly_budget_exceeded. Payment happens at the shop unless the response says online. The shop confirms by phone or email. The result includes a receipt signed by OpenAjan (Ed25519) that the shop can verify.",
            "inputSchema": {
                "type": "object",
                "properties": {
                    "slug": {
                        "type": "string"
                    },
                    "kind": {
                        "type": "string",
                        "enum": [
                            "order",
                            "booking"
                        ],
                        "default": "order"
                    },
                    "items": {
                        "type": "array",
                        "items": {
                            "type": "object",
                            "properties": {
                                "id": {
                                    "type": "integer"
                                },
                                "qty": {
                                    "type": "integer",
                                    "default": 1
                                }
                            },
                            "required": [
                                "id"
                            ]
                        }
                    },
                    "customer_name": {
                        "type": "string",
                        "description": "Required unless the user gave it at sign-in"
                    },
                    "customer_phone": {
                        "type": "string",
                        "description": "Required unless the user gave it at sign-in"
                    },
                    "customer_email": {
                        "type": "string",
                        "description": "Optional; order confirmations are emailed here."
                    },
                    "wanted_at": {
                        "type": "string",
                        "description": "ISO 8601 pickup/appointment time, optional"
                    },
                    "note": {
                        "type": "string"
                    },
                    "agent": {
                        "type": "string",
                        "description": "Name of the agent placing the order, e.g. Claude, ChatGPT"
                    },
                    "confirmed": {
                        "type": "boolean",
                        "description": "Must be true: the user explicitly approved items, total and time."
                    },
                    "quote": {
                        "type": "string",
                        "description": "Quote code from the first call. Without it, no order is placed and a quote is returned."
                    },
                    "idempotency_key": {
                        "type": "string",
                        "description": "Unique key per intended order (e.g. a UUID). Retrying with the same key returns the same order instead of creating a new one."
                    }
                },
                "required": [
                    "slug",
                    "items",
                    "confirmed"
                ]
            },
            "outputSchema": {
                "type": "object",
                "properties": {
                    "ok": {
                        "type": "boolean"
                    },
                    "order_id": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "status": {
                        "type": "string"
                    },
                    "quote": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "user_confirmation_required": {
                        "type": "boolean"
                    },
                    "shop": {
                        "type": "string"
                    },
                    "items": {
                        "type": "array",
                        "items": {
                            "type": "object"
                        }
                    },
                    "kind": {
                        "type": "string"
                    },
                    "total": {
                        "type": "number"
                    },
                    "currency": {
                        "type": "string"
                    },
                    "payment": {
                        "type": "string",
                        "enum": [
                            "at_merchant",
                            "online"
                        ]
                    },
                    "wanted_at": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "receipt": {
                        "type": [
                            "object",
                            "null"
                        ]
                    },
                    "message": {
                        "type": "string"
                    }
                },
                "required": [
                    "ok",
                    "status",
                    "total",
                    "currency"
                ]
            }
        },
        {
            "name": "get_availability",
            "title": "Free booking times",
            "annotations": {
                "readOnlyHint": true,
                "destructiveHint": false,
                "idempotentHint": true,
                "openWorldHint": true,
                "title": "Free booking times"
            },
            "description": "Free appointment/table times at a shop that takes bookings, for one date (shop local time). Service item ids set the duration. If the date is full, next_available gives the next free day. The returned slots are valid wanted_at values for a booking.",
            "inputSchema": {
                "type": "object",
                "properties": {
                    "slug": {
                        "type": "string"
                    },
                    "date": {
                        "type": "string",
                        "description": "YYYY-MM-DD in the shop's local time. Default: today."
                    },
                    "items": {
                        "type": "array",
                        "items": {
                            "type": "integer"
                        },
                        "description": "Item ids of the services to book. Optional."
                    }
                },
                "required": [
                    "slug"
                ]
            },
            "outputSchema": {
                "type": "object",
                "properties": {
                    "shop": {
                        "type": "string"
                    },
                    "date": {
                        "type": "string"
                    },
                    "timezone": {
                        "type": "string"
                    },
                    "duration_min": {
                        "type": "integer"
                    },
                    "slot_minutes": {
                        "type": "integer"
                    },
                    "min_notice_min": {
                        "type": "integer"
                    },
                    "slots": {
                        "type": "array",
                        "items": {
                            "type": "string"
                        }
                    },
                    "next_available": {
                        "type": [
                            "object",
                            "null"
                        ]
                    },
                    "how_to_book": {
                        "type": "string"
                    },
                    "duration_source": {
                        "type": "string"
                    },
                    "pickup_orders": {
                        "type": "string"
                    }
                },
                "required": [
                    "shop",
                    "date",
                    "slots"
                ]
            }
        },
        {
            "name": "find_options",
            "title": "Find options across shops",
            "annotations": {
                "readOnlyHint": true,
                "destructiveHint": false,
                "idempotentHint": true,
                "openWorldHint": true,
                "title": "Find options across shops"
            },
            "description": "Searches all OpenAjan shops at once by what, where and when — for any trade (restaurants, cafés, barbers, beauty, florists, repair shops, clinics, shops), without knowing a shop name. Returns matching shops with the matching items (ids, prices incl. VAT, durations) and, for shops that take bookings, free start times in the requested window; for order shops, when they are open for pickup that day. If nothing is free in the window, next_available lists the next free day at up to three shops. Item names are matched in the shop's own language (e.g. Danish \"herreklip\", German \"Herrenschnitt\").",
            "inputSchema": {
                "type": "object",
                "properties": {
                    "service": {
                        "type": "string",
                        "description": "What: a product, service or trade word, e.g. \"herreklip\", \"Margherita\", \"buket\", \"dækskifte\"."
                    },
                    "where": {
                        "type": "string",
                        "description": "City, area or postal code, e.g. \"Roskilde\" or \"2100\"."
                    },
                    "type": {
                        "type": "string",
                        "enum": [
                            "restaurant",
                            "cafe",
                            "barber",
                            "beauty",
                            "florist",
                            "repair",
                            "clinic",
                            "shop",
                            "other"
                        ],
                        "description": "Trade. Optional."
                    },
                    "country": {
                        "type": "string",
                        "description": "DK, DE or TR. Optional."
                    },
                    "date": {
                        "type": "string",
                        "description": "YYYY-MM-DD (shop local time). Default: today."
                    },
                    "after": {
                        "type": "string",
                        "description": "Earliest time HH:MM. Optional."
                    },
                    "before": {
                        "type": "string",
                        "description": "Latest start time HH:MM (exclusive). Optional."
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Max shops, 1–10. Default 5."
                    }
                },
                "required": []
            },
            "outputSchema": {
                "type": "object",
                "properties": {
                    "query": {
                        "type": "object"
                    },
                    "count": {
                        "type": "integer"
                    },
                    "options": {
                        "type": "array",
                        "items": {
                            "type": "object"
                        }
                    },
                    "next_available": {
                        "type": "array",
                        "items": {
                            "type": "object"
                        }
                    },
                    "note": {
                        "type": "string"
                    }
                },
                "required": [
                    "count",
                    "options"
                ]
            }
        },
        {
            "name": "order_status",
            "title": "Order status",
            "annotations": {
                "readOnlyHint": true,
                "destructiveHint": false,
                "idempotentHint": true,
                "openWorldHint": true,
                "title": "Order status"
            },
            "description": "Check the status of an order placed via OpenAjan: new (waiting for the shop), confirmed (shop accepted), done (ready / handed over), cancelled (shop declined). Without order_id it returns the user's latest orders.",
            "inputSchema": {
                "type": "object",
                "properties": {
                    "order_id": {
                        "type": "string",
                        "description": "e.g. oa_ord_12. Optional."
                    }
                },
                "required": []
            },
            "outputSchema": {
                "type": "object",
                "properties": {
                    "orders": {
                        "type": "array",
                        "items": {
                            "type": "object",
                            "properties": {
                                "order_id": {
                                    "type": "string"
                                },
                                "shop": {
                                    "type": "string"
                                },
                                "status": {
                                    "type": "string"
                                },
                                "status_text": {
                                    "type": "string"
                                },
                                "total": {
                                    "type": "number"
                                },
                                "currency": {
                                    "type": "string"
                                },
                                "wanted_at": {
                                    "type": [
                                        "string",
                                        "null"
                                    ]
                                },
                                "placed_at": {
                                    "type": "string"
                                }
                            },
                            "required": []
                        }
                    }
                },
                "required": [
                    "orders"
                ]
            }
        },
        {
            "name": "search",
            "title": "Search shops",
            "annotations": {
                "readOnlyHint": true,
                "destructiveHint": false,
                "idempotentHint": true,
                "openWorldHint": true,
                "title": "Search shops"
            },
            "description": "Search OpenAjan shops. Returns results with id (slug), title and url.",
            "inputSchema": {
                "type": "object",
                "properties": {
                    "query": {
                        "type": "string"
                    }
                },
                "required": [
                    "query"
                ]
            }
        },
        {
            "name": "fetch",
            "title": "Fetch shop card",
            "annotations": {
                "readOnlyHint": true,
                "destructiveHint": false,
                "idempotentHint": true,
                "openWorldHint": true,
                "title": "Fetch shop card"
            },
            "description": "Fetch a shop card by id (slug).",
            "inputSchema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string"
                    }
                },
                "required": [
                    "id"
                ]
            }
        }
    ],
    "resources": [],
    "prompts": []
}