pifini
Real events, reviewed places, and ticket checkout across the Caribbean and Latin America.
¿Debería usar esto?
Calidad y seguridad
Basado en el análisis automatizado de las definiciones de herramientas y el cumplimiento del protocolo.
Costo de contexto
Este es el número aproximado de tokens que se consumen cada vez que las herramientas del servidor se cargan en el contexto de un modelo. Los recuentos más altos reducen la atención disponible para otras tareas.
Instalar
Instalación con un clic
Agrega esto a tu archivo `claude_desktop_config.json`:
{
"mcpServers": {
"pifini": {
"url": "https://pifini.net/api/mcp"
}
}
}Puntos de conexión remotos
https://pifini.net/api/mcpstreamable-httpQué puede hacer
Inventario de herramientas
Herramientas (6)
🟢search_events(query, country, city, category, entry_model, ...)
Search upcoming events (festivals, carnivals, concerts, food + cultural events) across the Caribbean, Latin America, and beyond. Returns event names, dates, locations, category, price (when known), and page URLs. Strongest coverage: Barbados, Trinidad, Jamaica, Bahamas, Mexico.
Esquema de entrada
{
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Free-text search over title and description"
},
"country": {
"type": "string",
"description": "ISO-3166 alpha-2 country code, e.g. BB, TT, JM"
},
"city": {
"type": "string",
"description": "City name filter"
},
"category": {
"type": "string",
"enum": [
"music",
"arts",
"culture",
"festival",
"sports",
"food",
"business",
"nightlife"
],
"description": "Filter by event category"
},
"entry_model": {
"type": "string",
"enum": [
"free",
"ticketed",
"external",
"mixed",
"unknown"
],
"description": "Filter by how someone gets in: 'free' = confirmed free entry, 'ticketed' = Pifini sells tickets, 'external' = paid but sold elsewhere, 'mixed' = umbrella event with both free and paid components, 'unknown' = not yet confirmed either way."
},
"starts_after": {
"type": "string",
"description": "Earliest start. A bare date ('2026-08-01') matches the event's LOCAL calendar date in its own timezone and is inclusive — this is what you want for 'what's on this weekend'. A full ISO timestamp ('2026-08-01T18:00:00Z') is compared as an exact UTC instant instead."
},
"starts_before": {
"type": "string",
"description": "Latest start, same rules as starts_after. A bare date is inclusive of that whole local day, so starts_after='2026-08-13' with starts_before='2026-08-13' returns everything happening on the 13th where it happens."
},
"include_past": {
"type": "boolean",
"description": "Include past events (default false)"
},
"near_lat": {
"type": "number",
"description": "Latitude to search near (pair with near_lng)"
},
"near_lng": {
"type": "number",
"description": "Longitude to search near (pair with near_lat)"
},
"radius_km": {
"type": "number",
"description": "Search radius in km around near_lat/near_lng (default 25, max 500)"
},
"limit": {
"type": "number",
"description": "Max results, 1-50 (default 10)"
},
"offset": {
"type": "number",
"description": "Skip this many matching results (for paging past the limit)"
}
}
}Esquema de salida
{
"type": "object",
"properties": {
"count": {
"type": "number",
"description": "Number of events in this page of results"
},
"total": {
"type": "number",
"description": "Total events matching the filters, across all pages. Use this before claiming how many exist."
},
"has_more": {
"type": "boolean",
"description": "True when more matches exist beyond this page."
},
"next_offset": {
"type": [
"number",
"null"
],
"description": "Pass as `offset` to fetch the next page. Null when this is the last page."
},
"events": {
"type": "array",
"items": {
"type": "object",
"properties": {
"title": {
"type": "string"
},
"slug": {
"type": "string"
},
"url": {
"type": "string"
},
"summary": {
"type": [
"string",
"null"
]
},
"starts_at": {
"type": "string",
"description": "Exact start instant, ISO-8601 UTC. Do NOT format this for a human — it is the wrong calendar day in most of the region. Use local_date / local_time."
},
"timezone": {
"type": [
"string",
"null"
],
"description": "IANA timezone of the venue, e.g. America/Mexico_City. Null when unknown."
},
"local_date": {
"type": "string",
"description": "The date the event actually happens where it happens, YYYY-MM-DD. Quote this one."
},
"local_time": {
"type": [
"string",
"null"
],
"description": "Local start time, HH:MM 24h. Null when start_time_known is false — say nothing about the time in that case."
},
"start_time_known": {
"type": "boolean",
"description": "False when only the date is known and the stored hour is a placeholder. Never present a start time when this is false."
},
"ends_at": {
"type": [
"string",
"null"
]
},
"city": {
"type": [
"string",
"null"
]
},
"country": {
"type": [
"string",
"null"
]
},
"category": {
"type": [
"string",
"null"
]
},
"entry_model": {
"type": "string"
},
"price": {
"type": [
"object",
"null"
],
"properties": {
"min": {
"type": "number"
},
"max": {
"type": [
"number",
"null"
]
},
"currency": {
"type": "string"
},
"note": {
"type": [
"string",
"null"
]
}
}
},
"organizer_name": {
"type": [
"string",
"null"
]
},
"cover_image_url": {
"type": [
"string",
"null"
]
},
"attendee_count": {
"type": "number"
},
"distance_km": {
"type": [
"number",
"null"
],
"description": "Only present when near_lat/near_lng were given"
}
}
}
}
},
"required": [
"count",
"total",
"has_more",
"events"
]
}🟢get_event(slug)
Full details for one event by slug: description, venue, date/time, and available ticket types with prices and remaining stock. Use the slug from search_events.
Esquema de entrada
{
"type": "object",
"properties": {
"slug": {
"type": "string",
"description": "Event slug from search_events"
}
},
"required": [
"slug"
]
}Esquema de salida
{
"type": "object",
"properties": {
"title": {
"type": "string"
},
"slug": {
"type": "string"
},
"url": {
"type": "string"
},
"summary": {
"type": [
"string",
"null"
]
},
"description": {
"type": [
"string",
"null"
]
},
"starts_at": {
"type": "string",
"description": "Exact start instant, ISO-8601 UTC. Do NOT format this for a human — it is the wrong calendar day in most of the region. Use local_date / local_time."
},
"timezone": {
"type": [
"string",
"null"
],
"description": "IANA timezone of the venue, e.g. America/Mexico_City. Null when unknown."
},
"local_date": {
"type": "string",
"description": "The date the event actually happens where it happens, YYYY-MM-DD. Quote this one."
},
"local_time": {
"type": [
"string",
"null"
],
"description": "Local start time, HH:MM 24h. Null when start_time_known is false — say nothing about the time in that case."
},
"start_time_known": {
"type": "boolean",
"description": "False when only the date is known and the stored hour is a placeholder. Never present a start time when this is false."
},
"ends_at": {
"type": [
"string",
"null"
]
},
"location_name": {
"type": [
"string",
"null"
]
},
"city": {
"type": [
"string",
"null"
]
},
"country": {
"type": [
"string",
"null"
]
},
"category": {
"type": [
"string",
"null"
]
},
"entry_model": {
"type": "string"
},
"price": {
"type": [
"object",
"null"
]
},
"organizer_name": {
"type": [
"string",
"null"
]
},
"organizer_url": {
"type": [
"string",
"null"
]
},
"cover_image_url": {
"type": [
"string",
"null"
]
},
"attendee_count": {
"type": "number"
},
"currency": {
"type": "string"
},
"website": {
"type": [
"string",
"null"
]
},
"ticket_types": {
"type": "array",
"items": {
"type": "object",
"properties": {
"ticket_type_id": {
"type": "string"
},
"name": {
"type": "string"
},
"description": {
"type": [
"string",
"null"
]
},
"price": {
"type": "number"
},
"currency": {
"type": "string"
},
"remaining": {
"type": [
"number",
"null"
]
},
"sales_end_at": {
"type": [
"string",
"null"
]
}
},
"required": [
"ticket_type_id",
"name",
"price",
"currency"
]
}
}
}
}🟢search_places(query, entity_type, category, country, city, ...)
Search Pifini's places directory across the Caribbean and Latin America — restaurants, bars, beaches, attractions, venues, hotels, tour operators, professionals, and services. Every result carries listing_type: 'curated' is a small, editorially reviewed set of flagship entries; 'directory' is the much larger set sourced from open map data (name, category, location, contact info) that has no reviews yet — say so rather than implying a recommendation the data doesn't back up. Category is a specific Overture taxonomy value (e.g. caribbean_restaurant, church_cathedral), not a broad bucket — call list_categories first if unsure of the exact value. Results marked is_sponsored are paid placements — disclose that when recommending.
Esquema de entrada
{
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Free-text search over name and summary"
},
"entity_type": {
"type": "string",
"enum": [
"venue",
"place",
"attraction",
"business",
"professional",
"service",
"city",
"country",
"experience",
"government",
"region",
"transport"
],
"description": "Filter by broad type of place"
},
"category": {
"type": "string",
"description": "Filter by exact category value (e.g. 'caribbean_restaurant'). Use list_categories to discover valid values — there are 1,000+, not a small fixed set."
},
"country": {
"type": "string",
"description": "ISO-3166 alpha-2 country code"
},
"city": {
"type": "string",
"description": "City name filter"
},
"near_lat": {
"type": "number",
"description": "Latitude to search near (pair with near_lng)"
},
"near_lng": {
"type": "number",
"description": "Longitude to search near (pair with near_lat)"
},
"radius_km": {
"type": "number",
"description": "Search radius in km around near_lat/near_lng (default 25, max 500)"
},
"limit": {
"type": "number",
"description": "Max results, 1-50 (default 10)"
},
"offset": {
"type": "number",
"description": "Skip this many matching results (for paging past the limit)"
}
}
}Esquema de salida
{
"type": "object",
"properties": {
"count": {
"type": "number",
"description": "Number of places in this page of results"
},
"total": {
"type": "number",
"description": "Total places matching the filters, across all pages. Use this before claiming how many exist."
},
"has_more": {
"type": "boolean",
"description": "True when more matches exist beyond this page."
},
"next_offset": {
"type": [
"number",
"null"
],
"description": "Pass as `offset` to fetch the next page. Null when this is the last page."
},
"places": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"slug": {
"type": "string"
},
"type": {
"type": "string"
},
"listing_type": {
"type": "string",
"enum": [
"curated",
"directory"
]
},
"url": {
"type": "string"
},
"summary": {
"type": [
"string",
"null"
]
},
"city": {
"type": [
"string",
"null"
]
},
"country": {
"type": [
"string",
"null"
]
},
"category": {
"type": [
"string",
"null"
]
},
"price_tier": {
"type": [
"string",
"null"
]
},
"avg_rating": {
"type": [
"number",
"null"
]
},
"review_count": {
"type": "number"
},
"is_verified": {
"type": "boolean"
},
"is_sponsored": {
"type": "boolean"
},
"distance_km": {
"type": [
"number",
"null"
]
}
}
}
}
},
"required": [
"count",
"total",
"has_more",
"places"
]
}🟢get_place(slug)
Full details for one place by slug, including its most recent published reviews if any exist. listing_type distinguishes a curated entry from an unreviewed directory listing (see search_places) — recent_reviews is often an empty array, which means no reviews yet, not a low-quality place. Use the slug from search_places.
Esquema de entrada
{
"type": "object",
"properties": {
"slug": {
"type": "string",
"description": "Place slug from search_places"
}
},
"required": [
"slug"
]
}Esquema de salida
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"slug": {
"type": "string"
},
"type": {
"type": "string"
},
"listing_type": {
"type": "string",
"enum": [
"curated",
"directory"
]
},
"url": {
"type": "string"
},
"summary": {
"type": [
"string",
"null"
]
},
"description": {
"type": [
"string",
"null"
]
},
"city": {
"type": [
"string",
"null"
]
},
"country": {
"type": [
"string",
"null"
]
},
"address": {
"type": [
"string",
"null"
]
},
"category": {
"type": [
"string",
"null"
]
},
"price_tier": {
"type": [
"string",
"null"
]
},
"website": {
"type": [
"string",
"null"
]
},
"avg_rating": {
"type": [
"number",
"null"
]
},
"review_count": {
"type": "number"
},
"is_verified": {
"type": "boolean"
},
"is_sponsored": {
"type": "boolean"
},
"recent_reviews": {
"type": "array",
"items": {
"type": "object",
"properties": {
"rating": {
"type": "number"
},
"title": {
"type": [
"string",
"null"
]
},
"body": {
"type": [
"string",
"null"
]
},
"verified_attendee": {
"type": "boolean"
},
"verification_basis": {
"type": "string",
"enum": [
"ticket_scan",
"transaction",
"rsvp",
"geo_checkin",
"manual",
"none"
],
"description": "How the reviewer's visit was established. ticket_scan and transaction are strong evidence, rsvp and geo_checkin are weaker, manual is self-declared and none is an unverified opinion. Describe the review accordingly."
},
"date": {
"type": "string"
}
},
"required": [
"rating",
"verified_attendee",
"date"
]
}
}
}
}🟢list_categories(query, country, limit)
Discover valid category values for search_places. Pifini's places directory uses Overture Maps' taxonomy — over 1,000 specific values like caribbean_restaurant, church_cathedral, landmark_and_historical_building — rather than broad buckets, so guessing a category string will usually miss. Call this first with a rough query (e.g. 'coffee' or 'beach') to find the exact value, then pass it to search_places' category parameter.
Esquema de entrada
{
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Rough term to match against category values, e.g. 'coffee', 'beach'"
},
"country": {
"type": "string",
"description": "ISO-3166 alpha-2 country code — only return categories present in that country"
},
"limit": {
"type": "number",
"description": "Max results, 1-100 (default 30)"
}
}
}Esquema de salida
{
"type": "object",
"properties": {
"count": {
"type": "number"
},
"categories": {
"type": "array",
"items": {
"type": "object",
"properties": {
"category": {
"type": "string",
"description": "Exact value to pass to search_places' category parameter"
},
"label": {
"type": "string",
"description": "Human-readable label"
},
"count": {
"type": "number",
"description": "How many active places have this category"
}
}
}
}
},
"required": [
"count",
"categories"
]
}🟡create_ticket_checkout(event_slug, items, buyer_email, buyer_name)
Create a secure Stripe-hosted payment link for event tickets. Returns a checkout URL — give it to the human to complete payment themselves; each ticket is then emailed with its QR code and its own link, which opens on any phone and can be saved to WhatsApp. Get ticket_type_id values from get_event. Always confirm the exact tickets and total with the human before calling this.
Esquema de entrada
{
"type": "object",
"properties": {
"event_slug": {
"type": "string",
"description": "Event slug"
},
"items": {
"type": "array",
"description": "Ticket selections",
"items": {
"type": "object",
"properties": {
"ticket_type_id": {
"type": "string",
"description": "Ticket type id from get_event"
},
"quantity": {
"type": "number",
"description": "1-20"
}
},
"required": [
"ticket_type_id",
"quantity"
]
}
},
"buyer_email": {
"type": "string",
"description": "Email to deliver tickets to (required — ask the human)"
},
"buyer_name": {
"type": "string",
"description": "Buyer's name (optional)"
}
},
"required": [
"event_slug",
"items",
"buyer_email"
]
}Esquema de salida
{
"type": "object",
"properties": {
"checkout_url": {
"type": "string"
},
"order_id": {
"type": "string"
},
"event": {
"type": "string"
},
"total": {
"type": "number"
},
"currency": {
"type": "string"
},
"instructions": {
"type": "string"
}
}
}Prompts recomendados
search_eventssearch_eventsget_eventget_eventlist_categoriesComunidad
Evidencia