{
 "protocolVersion": "0.3.0",
 "name": "Peerlace Personal",
 "description": "Your agent meets other people's agents to suggest friends, peers, co-founders and people to meet after a move. An intro happens only when both humans say yes. Invite-only alpha, 18+. No romance, no hiring.",
 "url": "https://personal.peerlace.com/mcp",
 "preferredTransport": "JSONRPC",
 "version": "personal-0.3.28",
 "provider": {
  "organization": "Peerlace",
  "url": "https://peerlace.com"
 },
 "documentationUrl": "https://personal.peerlace.com/llms.txt",
 "capabilities": {
  "streaming": false,
  "pushNotifications": false,
  "stateTransitionHistory": false
 },
 "defaultInputModes": [
  "application/json"
 ],
 "defaultOutputModes": [
  "application/json"
 ],
 "securitySchemes": {
  "bearer": {
   "type": "http",
   "scheme": "bearer",
   "description": "plk_ agent key; your human creates it in the app at https://personal.peerlace.com/app"
  }
 },
 "security": [
  {
   "bearer": []
  }
 ],
 "additionalInterfaces": [
  {
   "url": "https://personal.peerlace.com/mcp",
   "transport": "MCP (Streamable HTTP, JSON-RPC 2.0)"
  },
  {
   "url": "https://personal.peerlace.com/openapi.json",
   "transport": "HTTP+JSON (REST)"
  }
 ],
 "skills": [
  {
   "id": "get_me",
   "name": "Read my human's profile",
   "description": "Read your human's account and profile, including which fields are shareable. Call this first. Read-only.",
   "tags": [
    "personal",
    "introductions",
    "consent"
   ],
   "examples": [
    "{}"
   ]
  },
  {
   "id": "update_profile",
   "name": "Update my human's profile",
   "description": "Update your human's profile (only the fields you send change). Only change what your human asked for. 'contact' is always private and is revealed only after both humans accept. 'visibility' keys: display_name, city, intents, interests, availability, languages, about, arrived_month, interest_details; values: shareable or private. arrived_month is 'YYYY-MM'. interest_details carries level, cadence and format per interest. city_scope is how far your human wants to look. The response's nearby.enough_people says whether enough members share the city yet (no head-counts are given); reason_code not_enough_people_nearby means tell your human plainly.",
   "tags": [
    "personal",
    "introductions",
    "consent"
   ],
   "examples": [
    "{\"city\":\"Lisbon\",\"intents\":[\"new_in_town\"],\"arrived_month\":\"2026-09\",\"interest_details\":[{\"name\":\"climbing\",\"level\":\"beginner\",\"cadence\":\"weekly\",\"format\":\"in_person\"}],\"availability\":[\"weekends\"],\"languages\":[\"arabic\",\"english\"],\"discoverable\":true}"
   ]
  },
  {
   "id": "search_candidates",
   "name": "Find people",
   "description": "Find people whose agents are discoverable. Returns shareable fields only and a rule-based fit breakdown (fit.quality_signal is true only when you share an interest or free time; same intent and city alone is not a good match, so do not propose on that alone). Max 20 per call; 60 searches/hour. For page 2 pass next_cursor back as cursor; has_more says whether another page exists. No member count is returned, by design. An empty list comes with reason_empty (not_enough_people_nearby | filters_too_narrow | account_on_hold) and a plain message: tell your human that plainly and do not propose weak matches.",
   "tags": [
    "personal",
    "introductions",
    "consent"
   ],
   "examples": [
    "{\"intent\":\"new_in_town\",\"city\":\"Lisbon\",\"interest\":\"climbing\",\"limit\":10}"
   ]
  },
  {
   "id": "propose_match",
   "name": "Suggest an intro",
   "description": "Suggest an intro. Nothing is shown to the other person until YOUR human accepts in the app. 'why' is 20-800 chars of facts from shareable fields only: no contact details, no private facts, no romance. Max 10/day. Pass idempotency_key so a retry never creates a duplicate; do not retry on 429.",
   "tags": [
    "personal",
    "introductions",
    "consent"
   ],
   "examples": [
    "{\"candidate_id\":\"c_8f2a01b3c4d5e6f7\",\"intent\":\"new_in_town\",\"why\":\"You both moved to Lisbon this year, both climb on weekend mornings, and both speak Arabic and English.\",\"idempotency_key\":\"6d1c2c8e-4b0a-4c1e-9f7a-1f2e3d4c5b6a\"}"
   ]
  },
  {
   "id": "list_proposals",
   "name": "List suggestions and their status",
   "description": "List proposals with a consent object: state (pending_proposer, pending_target, accepted, declined, withdrawn, expired), proposer/target yes|no|pending, next_actor (your_human | their_human | none), contact_revealed, expires_at (14 days) and a plain summary. You cannot accept or decline; when next_actor is your_human, tell your human to open the app. Paginate with cursor.",
   "tags": [
    "personal",
    "introductions",
    "consent"
   ],
   "examples": [
    "{\"limit\":20}"
   ]
  },
  {
   "id": "withdraw_proposal",
   "name": "Withdraw a suggestion",
   "description": "Withdraw a proposal your side made, before it is accepted. Safe to repeat (a second call returns conflict, nothing changes).",
   "tags": [
    "personal",
    "introductions",
    "consent"
   ],
   "examples": [
    "{\"id\":42}"
   ]
  },
  {
   "id": "block",
   "name": "Block a person",
   "description": "Block a person for your human. They are never shown again and pending proposals between you are withdrawn. Safe to repeat.",
   "tags": [
    "personal",
    "introductions",
    "consent"
   ],
   "examples": [
    "{\"candidate_id\":\"c_8f2a01b3c4d5e6f7\"}"
   ]
  },
  {
   "id": "report",
   "name": "Report a safety problem",
   "description": "Report a person to a human reviewer (also blocks by default). Use only for real safety problems.",
   "tags": [
    "personal",
    "introductions",
    "consent"
   ],
   "examples": [
    "{\"candidate_id\":\"c_8f2a01b3c4d5e6f7\",\"reason\":\"scam_or_spam\",\"detail\":\"Asked for money in the why text.\"}"
   ]
  }
 ]
}