M cenaly.ru
🔗 Integrations

⚡ MCP API Reference (for AI/GPT)

Complete protocol reference, tool schemas, and authentication for bot integrations

Documentation

cenaly.ru MCP Server — AI / GPT Integration Reference

This document is designed for AI assistants, GPT bots, and automated integrations. It provides exact protocol details, tool schemas, and authentication flow.

Server Information#

Property Value
Server Name meni-user-data-mcp
Protocol MCP 2024-11-05 (Streamable HTTP)
Transport HTTP POST (stateless)
Base URL https://api.cenaly.ru/mcp
Content-Type application/json
Wire Format JSON-RPC 2.0

Authentication#

All tool calls require an Authorization header.

Authorization: Bearer mk_XXXXXXXXXXXX...  (64 hex characters)

Scoped to a specific user account. The bot sees only that user's data.

Option 2: Cognito JWT Token#

Authorization: Bearer eyJraWQi...  (JWT id_token)

Obtained via POST /auth/login. Expires in 1 hour.

Option 3: Admin API Key#

Authorization: Bearer <admin_api_key>

Full access to all data. Only for system administrators.

Obtaining a JWT Token#

POST https://api.cenaly.ru/mcp/auth/login
Content-Type: application/json

{
  "email": "user@example.com",
  "password": "password123"
}

Response:

{
  "idToken": "eyJraWQi...",
  "accessToken": "eyJraWQi...",
  "refreshToken": "eyJjdHki...",
  "expiresIn": 3600,
  "tokenType": "Bearer"
}

MCP Protocol#

Initialize#

POST https://api.cenaly.ru/mcp
Authorization: Bearer <token>
Content-Type: application/json

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "initialize",
  "params": {
    "protocolVersion": "2024-11-05",
    "capabilities": {},
    "clientInfo": { "name": "my-bot", "version": "1.0" }
  }
}

Response:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2024-11-05",
    "capabilities": { "tools": {} },
    "serverInfo": { "name": "meni-user-data-mcp", "version": "1.0.0" }
  }
}

List Tools#

{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/list",
  "params": {}
}

Call Tool#

{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "tools/call",
  "params": {
    "name": "tool_name",
    "arguments": { ... }
  }
}

Response on success:

{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "content": [
      { "type": "text", "text": "{\"key\": \"value\"}" }
    ]
  }
}

Response on error:

{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "content": [
      { "type": "text", "text": "error message" }
    ],
    "isError": true
  }
}

Endpoints#

Method Path Auth Description
GET / No Server info + tool list
POST / Yes MCP JSON-RPC protocol
GET /health No Health check → {"status":"ok"}
POST /auth/login No Login → JWT tokens
GET /api/keys JWT or own MCP key List user's API keys
POST /api/keys JWT or own MCP key Generate new API key
DELETE /api/keys/{keyId} JWT or own MCP key Revoke API key

/api/keys is authorized on behalf of a user: either a Cognito JWT or your own 64-hex MCP key works. The administrator key does not — it carries no user identity, so the server answers 403 user identity required.

All paths are relative to https://api.cenaly.ru/mcp.


Complete Tool Reference#

Access Levels#

  • USER — Available to all authenticated users (data scoped to own account)
  • ADMIN — Available only to administrators (full access)

Self-Service Tools#

whoami#

Access: USER — Arguments: none
Returns: userId, email, userRole, authMethod

my_profile#

Access: USER — Arguments: none
Returns: full user profile from S3

update_my_profile#

Access: USER

Argument Type Required Description
fields object yes Key-value pairs to update in profile

my_locations#

Access: USER — Arguments: none
Returns: array of user's locations

my_orders#

Access: USER

Argument Type Required Description
limit integer no Maximum number of results

my_images#

Access: USER

Argument Type Required Description
type string no Enum: all, menu-photos, category-photos, locations

User Profiles#

list_users#

Access: ADMIN

Argument Type Required Description
limit integer no Maximum number of results

get_user_profile#

Access: USER (own) / ADMIN (any)

Argument Type Required Description
userId string yes The user ID

update_user_profile#

Access: USER/ADMIN — userId is required by the schema, but for a non-admin the server always substitutes the caller's own id, so another user's profile cannot be changed with it.

Argument Type Required Description
userId string yes The user ID
fields object yes Key-value pairs to update

search_user_by_email#

Access: ADMIN

Argument Type Required Description
email string yes Email address to search

Locations#

list_locations#

Access: USER (own) / ADMIN (any)

Argument Type Required Description
userId string yes Cognito user sub

get_location_profile#

Access: USER (own) / ADMIN (any)

Argument Type Required Description
userId string no User ID (admin only, auto-resolved for regular users)
locationId string yes Location ID

Returns: status, displayName, phone, address, facebookUrl, instagramUrl, domainName, settings (currency, country, defaultLanguage, publicMenuEnabled, serviceChargeEnabled), workingHours.

update_location_profile#

Access: USER (own) / ADMIN (any)

Argument Type Required Description
userId string no User ID (admin only, auto-resolved for regular users)
locationId string yes Location ID
fields object yes Fields to update: displayName, phone, address, facebookUrl, instagramUrl, status, settings, workingHours

Changes are synced to CDN automatically. Do NOT use this to change domainName — use set_location_domain instead.

get_location_menu#

Access: USER (own) / ADMIN (any)

Argument Type Required Description
userId string no User ID (admin only, auto-resolved for regular users)
locationId string yes Location ID
language string no Language code (e.g. en, ru, ka) for localized names. Omit for all translations

Returns full menu with categories and enriched items (names, prices, translations).


list_menu_items#

Access: USER (own) / ADMIN (any)

Argument Type Required Description
userId string no User ID (admin only, auto-resolved for regular users)
categoryId string no Category ID — recommended for detailed item data

With categoryId: returns full item data (name, price, translations). Without: returns item/category ID pairs.

get_menu_item#

Access: USER (own) / ADMIN (any)

Argument Type Required Description
userId string no User ID (admin only, auto-resolved for regular users)
categoryId string no Category ID (optional — omit to search all categories)
itemId string yes Menu item ID

Returns full details: name, description, price, translations, tags, variantGroups, addons, image info.

update_menu_item#

Access: USER (own) / ADMIN (any)

Argument Type Required Description
userId string no User ID (admin only, auto-resolved for regular users)
categoryId string no Category ID (optional — omit to auto-find)
itemId string yes Menu item ID
fields object yes Fields to merge: name, description, price, status, tags, variantGroups, addons, nameTranslations, descriptionTranslations, locationPrices, sortOrder

Changes sync automatically to CDN and userprofile.json.

create_menu_item#

Access: USER (own) / ADMIN (any)

Argument Type Required Description
userId string no User ID (admin only, auto-resolved for regular users)
locationId string yes Location ID
categoryId string yes Category ID to put the item in
itemId string yes Unique item ID
name string yes Item name (primary language)
price number yes Price
nameTranslations object no Translations: {ka, ru, uk, ...}
description string no Item description
status string no Enum: active, paused, archived (default: active)
sortOrder number no Sort order (auto-assigned if omitted)

create_menu_category#

Access: USER (own) / ADMIN (any)

Argument Type Required Description
userId string no User ID (admin only, auto-resolved for regular users)
locationId string yes Location ID
categoryId string yes Unique category ID
name string yes Category name (primary language)
nameTranslations object no Translations: {ka, ru, uk, ...}
status string no Enum: active, paused, archived (default: active)
sortOrder number no Sort order (auto-assigned if omitted)

update_menu_category#

Access: USER (own) / ADMIN (any)

Argument Type Required Description
userId string no User ID (admin only, auto-resolved for regular users)
locationId string yes Location ID
categoryId string yes Category ID to update
name string no New category name
nameTranslations object no Translations to merge: {ka, ru, uk, ...}
status string no Enum: active, paused, archived
sortOrder number no New sort order

Updates group-item.json (global + user), menu.location.json, and userprofile.json.

move_menu_item#

Access: USER (own) / ADMIN (any)

Argument Type Required Description
userId string no User ID (admin only, auto-resolved for regular users)
locationId string yes Location ID
itemId string yes Item ID to move
fromCategoryId string yes Source category ID
toCategoryId string yes Destination category ID

merge_categories#

Access: USER (own) / ADMIN (any)

Argument Type Required Description
userId string no User ID (admin only, auto-resolved for regular users)
locationId string yes Location ID
sourceCategoryId string yes Category to merge FROM (deleted after merge)
targetCategoryId string yes Category to merge INTO (receives all items)
keepSourceName boolean no If true, use source category name (default: keep target name)

Atomic operation: moves all items, merges nameTranslations, deletes source category.

delete_menu_category#

Access: USER (own) / ADMIN (any)

Argument Type Required Description
userId string no User ID (admin only, auto-resolved for regular users)
locationId string yes Location ID
categoryId string yes Category ID to delete
force boolean no If true, also delete all items (default: false — fail if has items)

Orders#

list_orders#

Access: USER (own) / ADMIN (any)

Argument Type Required Description
userId string no User ID (reads from data.meni)
domain string no Domain name (reads from o.cenaly.ru)
limit integer no Max orders (default 50)

get_order#

Access: USER (own domain) / ADMIN (any)

Argument Type Required Description
domain string no Domain name (e.g. UKRAINOCHKA)
locationId string no Location ID — used to resolve domain if domain is not provided
orderId string yes Order ID

Domains#

check_domain_availability#

Access: USER

Argument Type Required Description
domainName string yes Domain name to check (e.g. my-restaurant)
currentDomainName string no Current domain of this location (own domain is always available)

Returns available: true/false with reason. Validates format: 3-63 chars, lowercase alphanumeric and hyphens.

set_location_domain#

Access: USER (own) / ADMIN (any)

Argument Type Required Description
locationId string yes Location ID
domainName string yes New domain name (3-63 chars, lowercase alphanumeric and hyphens)

Validates availability, updates profile, renames CDN files, and updates domain mappings.

list_domains#

Access: ADMIN

Argument Type Required Description
prefix string no Filter domains by prefix

resolve_domain#

Access: USER

Argument Type Required Description
domain string yes The domain to resolve

CDN#

get_cdn_profile#

Access: USER

Argument Type Required Description
domain string yes The domain

get_cdn_menu#

Access: USER

Argument Type Required Description
domain string yes The domain
language string yes Language code (e.g., en, ru, ka)

list_cdn_files#

Access: USER

Argument Type Required Description
domain string yes The domain

invalidate_cdn_cache#

Access: ADMIN

Argument Type Required Description
paths array of strings yes CDN paths, e.g. ["/locations/DOMAIN/*"]

Images#

list_user_images#

Access: USER (own) / ADMIN (any)

Argument Type Required Description
userId string yes Cognito user sub
type string no Enum: all, menu-photos, category-photos, locations

get_image_upload_url#

Access: USER

Argument Type Required Description
type string yes Enum: menu-photos, category-photos, locations
itemId string no Menu item ID or category ID (required for menu-photos, category-photos)
locationId string no Location ID (required for locations type — hero/logo images)
filename string no Filename (default: original.jpg)
contentType string no Enum: image/jpeg, image/png, image/webp (default: image/jpeg)

Returns a presigned URL valid for 15 minutes. After uploading, the image processing pipeline automatically generates thumbnails and syncs to CDN.

delete_image#

Access: USER (own) / ADMIN (any)

Argument Type Required Description
key string yes Full S3 key in i.cenaly.ru, e.g. users/{userId}/menu-photos/{itemId}/original.jpg

S3 (Low-level Storage)#

s3_read#

Access: USER (own prefix) / ADMIN (any)

Argument Type Required Description
bucket string yes Enum: data.meni, cdn.cenaly.ru, i.cenaly.ru, o.cenaly.ru
key string yes S3 object key

s3_write#

Access: ADMIN

Argument Type Required Description
bucket string yes Enum: data.meni, cdn.cenaly.ru, o.cenaly.ru
key string yes S3 object key
data object yes JSON data to write

s3_list#

Access: USER (own prefix) / ADMIN (any)

Argument Type Required Description
bucket string yes Enum: data.meni, cdn.cenaly.ru, i.cenaly.ru, o.cenaly.ru
prefix string yes Key prefix to list
limit integer no Max keys (default 100)

s3_delete#

Access: ADMIN

Argument Type Required Description
bucket string yes Enum: data.meni, cdn.cenaly.ru, o.cenaly.ru
key string yes S3 object key

Cognito (User Management)#

cognito_list_users#

Access: ADMIN

Argument Type Required Description
filter string no Cognito filter expression
limit integer no Maximum number of results

cognito_get_user#

Access: ADMIN

Argument Type Required Description
username string yes Cognito username (sub UUID)

System#

get_system_stats#

Access: ADMIN — Arguments: none
Returns: user count, location count, domain count, etc.


S3 Bucket Reference#

Bucket Purpose Example Keys
data.meni Private user data users/{userId}/profile.json
cdn.cenaly.ru Published CDN data {domain}/menu-en.json
i.cenaly.ru Images users/{userId}/menu-photos/...
o.cenaly.ru Orders {domain}/orders/{orderId}.json

Access Control#

  1. Regular users can only access their own data (enforced by userId)
  2. S3 access for regular users is restricted to users/{userId}/ prefix
  3. Admin-only tools: list_users, search_user_by_email, list_domains, invalidate_cdn_cache, s3_write, s3_delete, cognito_list_users, cognito_get_user, get_system_stats
  4. For location/menu tools, userId is auto-resolved for regular users (only admins need to specify it)
  5. update_user_profile is available to a regular user too — the server forces the caller's own id
  6. API key management (/api/keys) requires a user identity: a Cognito JWT or your own MCP key (the administrator key is not accepted)

Error Handling#

HTTP Status Meaning
200 Success (check result.isError for tool-level errors)
400 Invalid JSON or missing method
401 Missing or invalid authentication
403 user identity required/api/keys called without a user identity (i.e. with the administrator key)
404 Unknown path
405 Wrong HTTP method
500 Internal server error

Tool Error Messages#

Error Meaning
🔒 admin access required Tool requires admin role
🔒 access denied: you can only access your own data User tried to access another user's data
missing required argument: <name> Required parameter not provided
unknown tool: <name> Tool name not recognized

Example Session#

→ POST /  {"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"bot","version":"1.0"}}}
← 200  {"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"2024-11-05","capabilities":{"tools":{}},"serverInfo":{"name":"meni-user-data-mcp","version":"1.0.0"}}}

→ POST /  {"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"whoami","arguments":{}}}
← 200  {"jsonrpc":"2.0","id":2,"result":{"content":[{"type":"text","text":"{\"userId\":\"abc-123\",\"email\":\"user@example.com\"}"}]}}

Client Configuration#

Claude Desktop#

{
  "mcpServers": {
    "meni": {
      "url": "https://api.cenaly.ru/mcp",
      "headers": {
        "Authorization": "Bearer <API_KEY>"
      }
    }
  }
}

cURL#

curl -X POST https://api.cenaly.ru/mcp \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <API_KEY>" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"whoami","arguments":{}}}'

Python#

import requests

resp = requests.post("https://api.cenaly.ru/mcp",
    headers={"Authorization": "Bearer <API_KEY>", "Content-Type": "application/json"},
    json={"jsonrpc": "2.0", "id": 1, "method": "tools/call",
          "params": {"name": "my_profile", "arguments": {}}})
print(resp.json()["result"]["content"][0]["text"])