Partelisto MCP
以下摘录自该仓库的 README(片段) · 在 GitHub 读完整 README →
SES.HOSPEDAJES and guest check-in for Spanish vacation rentals, exposed to AI agents.
A remote MCP server that lets Claude, ChatGPT, or any MCP-compatible
AI agent answer operational questions about a signed-in host's Spanish accommodation — which arrivals
still have an incomplete guest form, which bookings failed SES.HOSPEDAJES (police registration)
submission, how close the account is to its plan limit — and, with a separately granted permission,
resend a guest's check-in link. It adds no business logic of its own: every tool is a thin wrapper over
one query or mutation that already exists on the api-gateway, gated exactly the way the web app is.
**Tools:** list_properties · list_bookings · get_guest_form_status · list_ses_statuses ·
get_usage_summary · get_attention_required · send_guest_checkin_link · create_booking (the last
two need the extra partelisto:write scope — see the Tools table below for what each one
wraps).
**Example prompts:** "What needs my attention today?" · "Which of today's arrivals still have an
incomplete guest form?" · "Show me bookings where SES.HOSPEDAJES submission failed." · "Create a booking
for Casa Sol, 12–15 September, guest Ana García." · "Resend the check-in link for booking X."
No guest PII (email, phone, passport/DNI, date of birth, nationality, document content) is ever
selected or returned by any tool — see Tools (v1) below.
Why it deviates from the usual service-structure template
Every other TargetGrps service owns data (MongoDB, tenancy middleware, ApiServiceBootstrapper). This
one doesn't — it has no Domain layer and no database. It's a client of the gateway, not a peer of it.
The project layout keeps Application (DTOs, the fixed GraphQL documents, and the pure
response-shaping/redaction logic) and Infrastructure (the gateway HTTP client) for the same testability
reasons the template exists, but skips Mongo/multitenancy bootstrap because there's nothing to bootstrap.
Tools (v1)
| Tool | Scope | Wraps |
|---|---|---|
| list_properties | partelisto:read | properties |
| list_bookings | partelisto:read | bookingsPage (skip/take only — no filter yet, see below) |
| get_guest_form_status | partelisto:read | submissionStatus |
| list_ses_statuses | partelisto:read | sesSubmissionStatuses |
| get_usage_summary | partelisto:read | partelistoUsageInfo |
| get_attention_required | partelisto:read | bookingsPage + sesSubmissionStatuses, composed client-side — no new query. Scans the 50 most recent bookings; imminent/current stays with an incomplete guest form, plus any failed SES submission. |
| send_guest_checkin_link | partelisto:write | sendGuestLink mutation — emails the guest, rotates their link |
| create_booking | partelisto:write | createBooking mutation. Auto-resolves templateId via templates(propertyId) when the property has exactly one active template; otherwise asks the caller to pick one. Does not send the check-in link — call send_guest_checkin_link separately for that. |
None of these ever select or return guest email, phone, passport/DNI, date of birth, nationality, or
document content — see GatewayQueries (what's selected) and ResponseShaper (what's mapped into the
DTO). GatewayQueriesTests fails the build if a query is ever widened to select a field that looks like
PII, as a second line of defense.
list_bookings doesn't yet expose BookingsQuery.BookingFilter (propertyId/date range/status) because
its GraphQL input type name is generated by HotChocolate's mutation-conventions and wasn't worth
guessing blind — add it once the gateway schema can be introspected against directly.
Authorization — two independent layers
1. **Scope**, checked in this service (PartelistoTools.RequireScope): the bearer token's JWT scope
claim must contain partelisto:read for the five read tools, partelisto:write additionally for
send_guest_checkin_link. The token is validated (signature, issuer, expiry) against Keycloak by the