Skip to main content
ClaudeWave

MCP server for Spanish vacation-rental guest check-in and SES.HOSPEDAJES. Connect Claude, ChatGPT and AI agents to bookings, guest-form status and SES submissions.

MCP ServersRegistry oficial0 estrellas0 forksC#Actualizado today
ClaudeWave Trust Score
70/100
· OK
Passed
  • Actively maintained (<30d)
  • Clear description
  • Topics declared
  • Documented (README)
Flags
  • !No standard license detected
Last scanned: 9/3/2026
Install in Claude Code / Claude Desktop
Method: Manual
Claude Code CLI
git clone https://github.com/TargetGrps/partelisto-mcp
1. Run the command above in your terminal (Claude Code), or paste the JSON config into claude_desktop_config.json (Claude Desktop).
2. Replace any <placeholder> values with your API keys or paths.
3. Restart Claude. The MCP server and its tools appear automatically.
💡 Clone https://github.com/TargetGrps/partelisto-mcp and follow its README for install instructions.
Casos de uso

Resumen de MCP Servers

# Partelisto MCP

SES.HOSPEDAJES and guest check-in for Spanish vacation rentals, exposed to AI agents.

A remote [MCP](https://modelcontextprotocol.io) 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](#tools-v1) 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)](#tools-v1) below.

```
Claude / ChatGPT / Copilot
        │  MCP over HTTP, Bearer token from Keycloak OAuth
        ▼
partelisto-mcp  (this service)
        │  same GraphQL call the SPA would make, same Bearer token forwarded as-is
        ▼
api-gateway  →  backoffice / booking / guestdocs
```

## 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
   standard `AddJwtBearer` handler in `Program.cs` — this service does real JWT verification, it does not
   trust an unverified claim. This is what lets an OAuth consent screen offer "read my data" separately
   from "send email on my behalf."
2. **Ownership/tenant**, enforced by the api-gateway on every call, same as for the web app: the raw
   bearer token is forwarded unchanged, and the gateway's `OwnerAccess` policy decides what data that
   specific user may see. A valid `partelisto:write` scope does not by itself grant access to any
   particular booking — the gateway still checks the caller owns it.

RFC 9728 protected-resource metadata is published at `/.well-known/oauth-protected-resource`, pointing
`authorization_servers` at Keycloak's realm and listing both scopes, so a spec-compliant MCP client can
discover how to obtain a token without a human pasting one in.

## Keycloak setup (done)

The `partelisto` realm has a client `partelisto-mcp` (uuid `f5a1cb7f-d6f9-474c-818a-183584dbec30`):
public client, `standardFlowEnabled` (authorization_code + PKCE), `consentRequired: true`,
`directAccessGrantsEnabled: true`. Two optional client scopes are assigned and shown on the consent
screen: `partelisto:read` and `partelisto:write` (both `display.on.consent.screen: true`). Two access
token audience mappers are attached to the client — one adding `partelisto-mcp` (so this service accepts
the token), one adding `api-gateway` (so the same token, forwarded unchanged, is also accepted by the
gateway; the first mapper alone replaces the audience rather than extending it, which silently broke the
gateway hop — worth remembering if another audience mapper gets added here later).

Registered redirect URIs: `https://claude.ai/api/mcp/auth_callback` and
`https://chatgpt.com/connector_platform_oauth_redirect`. Add more (Claude Code's local callback, etc.)
as each client actually gets connected — Keycloak needs the exact URI before that client's OAuth flow
will complete.

Two more fixes were needed, found only by testing against a real signed-in Claude.ai session (browser,
not curl) with a real (non-e2e) Partelisto account:
- **`fullScopeAllowed` was `false` on the `partelisto-mcp` client** (Keycloak's default for a
  client created via the Admin API). With it off, the issued token's `realm_access.roles` contained only
  `offline_access` — none of the user's actual roles — regardless of what the user actually had. Fixed
  by setting it to `true` (already `true` on `partelisto-spa`; brings this client in line with that).
- **Missing the `oidc-usermodel-realm-role-mapper` protocol mapper** (name "realm roles", claim name
  `roles`) that `partelisto-spa` has directly on the client. `TargetGrps.BuildingBlocks.Bootstrapper`'s
  JWT setup sets `RoleClaimType = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role"` and
  never maps `realm_access.roles` into that claim type itself (confirmed by decompiling the installed
  NuGet package — its `OnTokenValidated` handler only logs claims) — so `RequireRole(...)` policies like
  `OwnerAccess` fail for *any* client missing this exact mapper, no matter what roles the user has or
  what `realm_access` contains. Copied verbatim from `partelisto-spa`'s mapper config onto `partelisto-mcp`.

**Verified end to end with a real signed-in Claude.ai session**, not just curl: added the custom
connector, completed the full browser OAuth + consent flow (both scopes shown and granted separately,
confirming the two-scope design renders correctly), had `list_properties` fail twice with the two bugs
above, fixed both live, reconnected, and got a real answer back from backoffice through the whole chain
(gateway → backoffice → GraphQL → this service → Claude). This is now the most-verified path in the
whole project — the only thing left unverified is a ChatGPT connection specifically.

## Deployed

Live at `https://mcp.partelisto.es` — `k8s/deployment.yaml` applied directly (`kubectl apply -f k8s/`,
not Helm; see that file's header comment for why), image `ghcr.io/targetgrps/partelisto-mcp`, namespace
`targetgrps-microservices`. CI (`.github/workflows/build-publish.yml`) builds, tests, and pushes on
every push to `main`. Bump the `image:` tag in `k8s/deployment.yaml` and re-apply for future releases.

CI is self-contained — it does **not** call `targetgrps/reusable-workflows` the way every sibling
service's `build-publish.yml` does. That repo is private, and this one is deliberately public (see
"Made public" below); a public repository cannot call a reusable workflow in a private one at all —
GitHub rejects it at dispatch time ("workflow was not found"), independent of that repo's access-level
setting. The reusable workflow's other features (npm/nuget client publish, a Mongo image, Slack notify)
don't apply to this service anyway, so a small inline workflow was the right call, not a workaround.
Also needed `GH_TOKEN_TARGETGRPS` (not `secrets.GITHUB_TOKEN`) to log in to GHCR — the package was first
pushed with a personal token during initial rollout, so this repo's own Actions identity was never on
its "Manage Actions access" list (a GHCR setting with no REST API to fix remotely).

Two bugs found and fixed only by actually deploying, not by local `docker run`/`docker compose`:
- `dotnet publish --no-build -o /app` was publishing into the same directory the source tree already
  occupied, which silently drops Content items (`appsettings.json`). The image had no config at all and
  crashed on startup with `Keycloak:Authority is not configured`. Fixed by publishing to `/out`
aiai-agentschatgptclaudecsharpdotnetguest-checkinguest-registrationhospitalitykeycloakmcpmcp-servermodel-context-protocoloauthproperty-managementses-hospedajesshort-term-rentalspainvacation-rental

Lo que la gente pregunta sobre partelisto-mcp

¿Qué es TargetGrps/partelisto-mcp?

+

TargetGrps/partelisto-mcp es mcp servers para el ecosistema de Claude AI. MCP server for Spanish vacation-rental guest check-in and SES.HOSPEDAJES. Connect Claude, ChatGPT and AI agents to bookings, guest-form status and SES submissions. Tiene 0 estrellas en GitHub y su última actualización registrada es del 2026-09-02.

¿Cómo se instala partelisto-mcp?

+

Puedes instalar partelisto-mcp clonando el repositorio (https://github.com/TargetGrps/partelisto-mcp) o siguiendo las instrucciones del README en GitHub. ClaudeWave también te ofrece bloques de instalación rápida en esta misma página.

¿Es seguro usar TargetGrps/partelisto-mcp?

+

Nuestro agente de seguridad ha analizado TargetGrps/partelisto-mcp y le ha asignado un Trust Score de 70/100 (tier: OK). Revisa el desglose completo de comprobaciones superadas y flags en esta página.

¿Quién mantiene TargetGrps/partelisto-mcp?

+

TargetGrps/partelisto-mcp es mantenido por TargetGrps. La última actividad registrada en GitHub es del 2026-09-02, con 0 issues abiertos.

¿Hay alternativas a partelisto-mcp?

+

Sí. En ClaudeWave puedes explorar mcp servers similares en /categories/mcp, ordenados por popularidad o actividad reciente.

Despliega partelisto-mcp en tu cloud

Lleva este repo a producción en minutos. Cada plataforma genera su propio entorno con variables de entorno editables.

¿Mantienes este repo? Añade un badge a tu README

Pega el badge en tu README de GitHub para mostrar que está auditado por ClaudeWave. Cada badge enlaza de vuelta a esta página y muestra el Trust Score actual.

Featured on ClaudeWave: TargetGrps/partelisto-mcp
[![Featured on ClaudeWave](https://claudewave.com/api/badge/targetgrps-partelisto-mcp)](https://claudewave.com/repo/targetgrps-partelisto-mcp)
<a href="https://claudewave.com/repo/targetgrps-partelisto-mcp"><img src="https://claudewave.com/api/badge/targetgrps-partelisto-mcp" alt="Featured on ClaudeWave: TargetGrps/partelisto-mcp" width="320" height="64" /></a>

Más MCP Servers

Alternativas a partelisto-mcp