Skip to main content
Glama

Partelisto MCP

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.

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.

Related MCP server: Hostaway MCP

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.esk8s/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 instead.

  • request.Scheme read http behind the TLS-terminating ingress, so /.well-known/oauth-protected-resource reported "resource": "http://mcp.partelisto.es". Fixed with UseForwardedHeaders.

Also hit and fixed as part of this rollout, outside this repo: cert-manager 1.18.2 in this cluster couldn't issue any new TLS certificate (an upstream bug with ingress-nginx's strict path validation — cert-manager#7791). Patched by adding --feature-gates=ACMEHTTP01IngressPathTypeExact=false to the cert-manager Deployment's args in the cert-manager namespace — the documented workaround, reverting to pre-1.18 behavior. This was blocking certificate issuance cluster-wide, not just for this service.

Verified live over real HTTPS: /healthz, /.well-known/oauth-protected-resource (correct https:// resource and both scopes listed), and the MCP initialize handshake.

Listed in the official MCP registry

io.github.TargetGrps/partelisto-mcp is live and active at registry.modelcontextprotocol.io — verify with curl "https://registry.modelcontextprotocol.io/v0.1/servers?search=partelisto-mcp". Published by .github/workflows/publish-mcp-registry.yml on every push to main that touches server.json, via GitHub Actions OIDC — no login, no stored token, nobody approves anything by hand. The namespace has to match the org's exact casing (TargetGrps, not targetgrps) or the registry's OIDC check 403s.

What's NOT done yet (manual follow-ups)

  • Not submitted to the ChatGPT App directory. Unlike the MCP registry, there's no OIDC/CI path for this — OpenAI's submission flow is a human review process behind a developer-account login: verify the production /mcp URL, verify the domain, provide reviewer credentials for the OAuth flow, write test cases, submit for a 5-10 business day review (submission guidelines). That needs someone who owns (or will own) the org's OpenAI developer account — logging into or creating one isn't something to automate.

  • Not actually connected from ChatGPT — the redirect URI is registered but nobody has completed ChatGPT's connector-add flow against this server yet, unlike Claude.ai (see the Keycloak section above, verified end to end).

  • Only Claude.ai's and ChatGPT's redirect URIs are registered on the partelisto-mcp Keycloak client. Add more as other clients (Copilot, etc.) actually get connected.

Local development

dotnet build                       # builds src/*.sln
dotnet test                        # 8 unit tests, ResponseShaper + GatewayQueries PII guard
dotnet run --project src/TargetGrps.Partelisto.Mcp.Api -- --stdio   # MCP over stdin/stdout (Glama introspection)
docker compose build targetgrps-partelisto-mcp
docker compose up -d
curl http://localhost:5207/healthz
curl http://localhost:5207/.well-known/oauth-protected-resource
docker compose down

appsettings.Development.json points Gateway:BaseUrl at http://localhost:5201 — the api-gateway port from the workspace compose stack (see the partelisto local-dev-startup notes for how to bring that up). The Docker Compose file instead uses http://host.docker.internal:5201, since this service's own container isn't on that stack's docker network.

Manually exercising a tool without going through a real MCP client

tools/list needs no token. tools/call needs an access token minted for the partelisto-mcp client with partelisto:read/partelisto:write in its scope — a token from partelisto-spa (e.g. copied from the SPA's dev tools) will not work, RequireScope rejects it. The client has consentRequired: true, so it won't hand out a token via password grant (no browser to show consent to) unless that's toggled off in the Keycloak admin console first — fine for one-off local testing, but flip it back afterward.

Available Tools

8 tools
create_bookingAInspect

Creates a new booking (a check-in workflow) for one of the host's properties. Requires the write permission granted separately during sign-in. Ask the host to confirm the property and dates before calling this. Does not email the guest — call send_guest_checkin_link afterwards if a link should go out now.

ParametersJSON Schema
NameRequiredDescriptionDefault
checkInYesCheck-in date, yyyy-MM-dd.
checkOutYesCheck-out date, yyyy-MM-dd.
guestNameNoGuest name, optional.
guestEmailNoGuest email, optional.
guestPhoneNoGuest phone, optional.
propertyIdYesThe property id, from list_properties.
templateIdNoCheck-in template id. Omit if the property has exactly one active (non-archived) template — it is picked automatically; otherwise this is required.

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark readOnlyHint=false and destructiveHint=false, but the description adds meaningful behavioral context: the operation requires separately granted write permission, should only be invoked after host confirmation, and will not send an email to the guest. This goes beyond the annotations and helps set expectations for side effects.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three focused sentences with no filler: purpose first, then permission, then confirmation requirement, then the send_guest_checkin_link follow-up. Every sentence earns its place and the most important operational constraints are front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a mutation tool with 7 parameters, no output schema, and sibling send_guest_checkin_link, the description plus a fully documented schema gives an agent everything needed to invoke the tool correctly. It covers permission, confirmation, side effects, and the relevant alternative/follow-up behavior.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents every parameter thoroughly, including the templateId logic. The description adds only general context around property and dates rather than parameter-level detail. A baseline of 3 is appropriate because the schema is doing the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Creates a new booking (a check-in workflow) for one of the host's properties.' It clearly separates this from siblings like send_guest_checkin_link and list_bookings by defining what the tool itself accomplishes. The parenthetical clarifies the domain meaning of 'booking' rather than leaving it ambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit preconditions: write permission is required, and the host should confirm property and dates before calling. It also provides a when-not/what-next rule by stating it does not email the guest and directing the agent to send_guest_checkin_link if a link should go out. This is actionable guidance, not just context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_attention_requiredA
Read-onlyIdempotent
Inspect

Scans the signed-in host's most recent bookings (up to 50) and returns only what needs action right now: stays that are imminent or under way where the guest has not completed check-in, and bookings whose SES.HOSPEDAJES submission failed. Empty list means nothing needs attention within the window. No guest PII.

ParametersJSON Schema
NameRequiredDescriptionDefault
arrivalWindowDaysNoHow many days ahead counts as "imminent" (a negative gap means the stay already started). Defaults to 3.

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and idempotentHint=true, so the description's job is lighter. It still adds meaningful behavioral context: the 50-booking scan window, the signed-in host scope, empty-list semantics, and the explicit 'No guest PII' guarantee. The exact return shape and ordering are not disclosed, but this is not critical for a read-only tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences with no filler. It front-loads the tool's action and outcome, then compactly lists the criteria and key behavioral facts (empty-list meaning, PII exclusion). Every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only tool with one optional parameter and no output schema, the description covers the input semantics, output selection criteria, empty-list behavior, and privacy boundary. The main unstated detail is the exact response structure, but the described behavior is sufficient for an agent to invoke it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The single parameter arrivalWindowDays is fully documented in the schema with a default value and an explanation of the negative-gap meaning, giving a baseline of 3. The description itself does not add further parameter detail, but none is needed given the schema's complete coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: it scans the signed-in host's recent bookings and returns only actionable items. It then enumerates the exact inclusion criteria (imminent/in-progress stays with no guest check-in, and failed SES.HOSPEDAJES submissions), which clearly distinguishes it from list_bookings and status-related siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description clearly communicates when this tool is appropriate: it is for surfacing only items that need immediate action, and an empty list means nothing requires attention. However, it does not explicitly mention alternatives such as list_bookings for full booking history or get_guest_form_status for individual form status, so the exclusion guidance is implied rather than stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_guest_form_statusA
Read-onlyIdempotent
Inspect

Whether the guest has completed the check-in form for a booking the host owns (None or Submitted). No form content.

ParametersJSON Schema
NameRequiredDescriptionDefault
bookingIdYesThe booking id.

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint and idempotentHint, so the safety profile is covered. The description adds useful behavioral detail by stating the possible outcomes (None or Submitted) and explicitly clarifying that form content is not returned, which goes beyond the structured metadata.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single sentence that front-loads the primary result and includes a scope qualifier and an explicit exclusion ('No form content'). There is no filler or redundant restating of the tool name.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a one-parameter, read-only status tool with rich annotations, the description is largely complete: it gives the possible values, the ownership constraint, and what is not included. It does not describe error behavior for non-owned bookings or invalid IDs, but that is a minor gap given the simplicity of the tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the bookingId parameter is documented as 'The booking id.' The description adds that the booking must be one the host owns, but it does not provide additional format, constraints, or usage details, so the baseline of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly identifies the resource (guest check-in form status), the scope (booking the host owns), and the expected output values (None or Submitted). It lacks an explicit imperative verb like 'Get' or 'Returns', but the tool name plus description make the purpose unambiguous, and 'No form content' helps distinguish it from content-retrieval tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies when to use the tool by scoping it to host-owned bookings and excluding form content. However, it does not explicitly mention alternatives or state when not to use it, such as when the caller is not the host or when form content is needed.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_usage_summaryA
Read-onlyIdempotent
Inspect

The signed-in host's plan tier, trial status, and this month's usage against plan limits (properties, templates, bookings).

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A3.5/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and idempotentHint=true, so the safety profile is covered. The description adds useful behavioral context by specifying that the data is scoped to the signed-in host and reflects the current month's usage, which implies time-dependent data. However, it does not describe response structure, potential absence of plan limits, or any edge behavior such as what happens when the host has no plan.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single compact sentence that front-loads the subject (the signed-in host) and quickly enumerates the three key result categories: plan tier, trial status, and usage against plan limits. Every phrase earns its place; there is no repetition, filler, or schema duplication.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter, read-only summary tool, the description is adequately complete. It describes what the response covers and the scope ('signed-in host'), and the annotations cover the operational safety. The absence of an output schema is mitigated by the explicit enumeration of the result content, though a note on the format of usage limits would make it fully self-contained.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has zero parameters, so parameter disambiguation is unnecessary. The description correctly focuses entirely on the output semantics, which is the appropriate baseline for a parameterless read-only tool. No parameter-related ambiguity exists.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly identifies the tool's purpose: retrieving the signed-in host's plan tier, trial status, and current usage against plan limits. It names the specific resource (usage summary) and the data domains (properties, templates, bookings), which distinguishes it from sibling listing tools. It lacks an explicit verb like 'retrieves' or 'gets', but the tool name and content specification make the purpose unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives such as list_bookings or list_properties. It implies it is for account-level usage/limit checking, but does not state explicit conditions, exclusions, or comparison with sibling tools. An agent would need to infer from the tool name that this is for plan usage rather than operational data.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_bookingsA
Read-onlyIdempotent
Inspect

Lists the signed-in host's bookings (newest first), paged. Returns id, property id, check-in/check-out dates, status, and whether a check-in link and guest contact exist — never the guest's email, phone, or documents.

ParametersJSON Schema
NameRequiredDescriptionDefault
skipNoRows to skip, for paging. Defaults to 0.
takeNoRows to return, max 50. Defaults to 20.

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the readOnlyHint and idempotentHint annotations, the description adds valuable behavioral context: results are newest first, paged, and explicitly never include guest email, phone, or documents. This privacy guarantee is important for an agent deciding whether this tool fits a request.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two compact sentences cover scope, ordering, paging, return fields, and exclusions. Every phrase carries information, and the core action is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple list tool with a fully documented schema and safety annotations, the description is complete. It explains what is returned, what is never returned, and the paging behavior, so an agent has everything needed to invoke it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema already fully documents skip and take, including defaults and max value, so the baseline is 3. The description only adds that results are paged, which reinforces the schema without adding new parameter-level detail.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool lists the signed-in host's bookings, with explicit ordering and paging. It distinguishes itself from sibling resources like list_properties and send_guest_checkin_link by naming the exact resource and scope.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description makes clear this is for retrieving the signed-in host's bookings and that results are paginated. It does not explicitly state when to avoid this tool or prefer a sibling, but the resource and scope are specific enough for an agent to select it correctly.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_propertiesA
Read-onlyIdempotent
Inspect

Lists the signed-in host's properties: id, name, address, municipality/province, and whether it is archived. No guest data.

ParametersJSON Schema
NameRequiredDescriptionDefault
includeArchivedNoInclude archived properties. Defaults to false.

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint and idempotentHint, so the safety profile is covered. The description adds meaningful context about scope (signed-in host) and data boundaries, without contradicting annotations. Minor gaps like ordering or pagination are not critical for this simple read-only list.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, front-loaded sentence that states the operation, scope, and returned fields without wasted words. The 'No guest data' exclusion is concise and valuable.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple read-only listing tool with one optional parameter, the description is complete: it names the resource, scope, included fields, and exclusion. The output schema is absent, but the description enumerates the return fields sufficiently, and annotations cover behavioral safety.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema fully documents the single optional includeArchived parameter with its default and meaning, so the description does not need to add parameter details. The description adds no extra parameter-level semantics, but the high schema coverage keeps this at baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb ('Lists') and resource ('signed-in host's properties') and enumerates the returned fields. It also draws a clear boundary with 'No guest data,' distinguishing it from guest-related sibling tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description clearly establishes when to use the tool: to list the signed-in host's properties. The explicit 'No guest data' note provides a useful when-not signal, though it does not name alternative sibling tools for guest-specific operations.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_ses_statusesA
Read-onlyIdempotent
Inspect

SES.HOSPEDAJES (police registration) submission status for a set of bookings the host owns: status, attempts, last error, and the official reference once accepted. Bookings with no submission yet are omitted.

ParametersJSON Schema
NameRequiredDescriptionDefault
bookingIdsYesBooking ids to check, up to 50.

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already establish read-only and idempotent behavior. The description adds non-obvious behavioral context: bookings without a submission are omitted, and the response includes attempts, last error, and official reference once accepted. This goes beyond what the annotations and schema provide.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences with no filler. The description front-loads the domain and purpose, then adds the important omission caveat. Every sentence contributes useful information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a one-parameter, read-only tool with no output schema, the description covers purpose, scope, returned fields, and the omission behavior. It does not specify response formatting or possible status values, but an agent has enough information to select and invoke the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The single parameter is fully documented in the schema ('Booking ids to check, up to 50'), so the baseline applies. The description reinforces that the ids refer to host-owned bookings, but adds no additional syntax or constraints beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names the resource (SES.HOSPEDAJES police-registration submissions) and the action (checking status for host-owned bookings), and lists the returned fields. It is clearly distinct from list_bookings, but it does not explicitly differentiate from the sibling get_guest_form_status, so it stops short of a 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The use case is implied—check SES submission status for a set of bookings the host owns—and the host-ownership scope is stated. However, there is no explicit when-to-use guidance, no mention of alternatives, and no condition distinguishing it from get_guest_form_status.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 8 tool updatesv0.1.0
    • First observedcreate_booking
    • First observedget_attention_required
    • First observedget_guest_form_status
    • First observedget_usage_summary
    • First observedlist_bookings
    • First observedlist_properties
    • First observedlist_ses_statuses
    • First observedsend_guest_checkin_link

TDQS

A4.2/5.0

Scored across 8 tools

Disambiguation5/5

Each tool targets a distinct resource or action: usage/plan, bookings, guest link sending, police registration status, guest form status, and properties. Aggregating tools like get_attention_required clearly complement rather than duplicate the individual status-checking tools.

Naming Consistency5/5

All tool names use lowercase snake_case with a consistent verb-first pattern: get_, list_, create_, send_. The naming is uniform and predictable, making it easy to infer each tool's purpose from its name alone.

Tool Count5/5

Eight tools is well-scoped for a check-in workflow MCP server. Each tool covers a meaningful operation without redundancy, and the count feels neither thin nor bloated.

Completeness4/5

The core workflow is well covered: create a booking, send a check-in link, check guest form completion, check police registration status, and get an attention-required summary. Minor gaps exist around booking updates/cancellations and property management, but these appear outside the server's stated focus.

Maintenance

ActivityNo data
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    Not graded
    maintenance
    Enables AI assistants to interact with Hostaway's property management platform through standardized MCP tools. Provides access to listings, bookings, guest communication, and availability checking for vacation rental management.
    -
  • A
    license
    B
    quality
    B
    maintenance
    A read-only hospitality-focused MCP server that enables users to retrieve reservation details, listing briefs, and guest conversation contexts from Hostaway. It simplifies hospitality workflows by providing specialized tools for searching threads and viewing reservation data through natural language interfaces.
    6
    58 npm
    MIT
  • A
    license
    A
    quality
    C
    maintenance
    Connects AI assistants to the Hostaway property management API via 10 read-only tools covering listings, reservations, calendars, guest conversations, and owner statements.
    10
    779 npm
    2
    MIT
  • A
    license
    Not graded
    quality
    F
    maintenance
    Connects AI agents to RealtyCalendar accounts, allowing users to query bookings, availability, and check-ins via natural language, with local-first privacy and read-only access.
    MIT