Salta ai contenuti

MCP server

Questi contenuti non sono ancora disponibili nella tua lingua.

GuestCraft lets an AI assistant work with an instance through the Model Context Protocol. Every public operation that an integration may call is an MCP tool, generated from the instance’s own OpenAPI document, and a few composed tools cover common front-desk tasks. The assistant acts with the credential you give it, so it can do only what that credential allows, and every destructive tool asks for a confirmation before it changes anything. How tools are generated, named and marked is described in the package README.

There are two ways to run it:

  • Built into every instance, at https://<your instance>/api/mcp, on Vercel and Docker alike. Nothing to install: give your MCP client the URL. It signs in with OAuth, or takes an API key or organization token.
  • From a checkout of this repository, over stdio or as a local Streamable HTTP endpoint, with an API key or organization token (Running the package yourself). The package is not published to npm.

The endpoint speaks Streamable HTTP, protocol revision 2026-07-28, and serves 2025-era clients statelessly as well. It keeps no session: each request is authenticated on its own, which is why it runs on serverless hosts. The examples use https://hotel.example.com for your instance.

A client that supports MCP authorization needs the URL only; never put a credential in its configuration.

  1. Its first request is answered 401 with WWW-Authenticate: Bearer resource_metadata="https://hotel.example.com/.well-known/oauth-protected-resource/api/mcp".
  2. The client reads that protected-resource metadata (RFC 9728), finds the instance’s authorization server, registers itself (dynamic client registration) and opens the consent page in your browser.
  3. You sign in, choose the workspace, the properties and the permissions the assistant gets, and approve. The application never receives more than you hold yourself.
  4. The client receives a token for https://hotel.example.com/api/mcp only: it is refused at the REST API and at any other instance. Revoking the application in the workspace’s settings ends its access at the next request.
  5. A tool call or resource read that needs a permission the token’s scopes do not name is answered 403 before it runs, with WWW-Authenticate: Bearer error="insufficient_scope", scope="rates.read", resource_metadata="…" (RFC 6750). The scope lists the permissions the operation takes, one of which is enough. A client that supports step-up authorization asks for those scopes with the ones it has, the consent page opens again, and the call is retried once you approve.

Client by client:

Client Add the server Then
Claude Code claude mcp add --transport http guestcraft https://hotel.example.com/api/mcp Run /mcp inside Claude Code and choose Authenticate.
Claude Desktop Settings → Connectors → Add custom connector, with the URL. Connect opens the sign-in.
Cursor In ~/.cursor/mcp.json: { "mcpServers": { "guestcraft": { "url": "https://hotel.example.com/api/mcp" } } } Cursor shows Needs login next to the server: select it.
VS Code In .vscode/mcp.json: { "servers": { "guestcraft": { "type": "http", "url": "https://hotel.example.com/api/mcp" } } } Start the server and allow the sign-in.
MCP Inspector Transport Streamable HTTP, the URL, Connect. The Inspector runs the OAuth flow in its browser tab.

A client that sends headers can use an integration’s credential instead: in Settings → API keys, create a key with only the permissions the assistant needs, then add Authorization: Bearer gc_live_… to the server’s entry, for example claude mcp add --transport http guestcraft https://hotel.example.com/api/mcp --header "Authorization: Bearer gc_live_…". With an organization token, add GuestCraft-Workspace-Id: ws_… to choose the default workspace; a tool’s workspace_id argument chooses another one for a single call. In a shared project file, refer to the secret through the client’s variables instead of writing it.

Client sessions (gc_cst_…) and the mobile app’s device tokens are refused: they are not an integration’s delegation for this endpoint.

The server authenticates each request with the instance’s own credential gateway and calls the API in the same process with your principal. It never forwards your token to the REST API and never uses a credential of its own, so the API’s permission checks, property scopes, the live ceiling of the person behind the credential and the audit log apply to every tool call exactly as to your own requests: the audit entry names your API key, organization token or application.

Each MCP request is admitted once against your credential’s budget, like any other request. The API calls a tool then makes in process are not admitted again: a composed tool such as availability_and_quotes makes one call per room type within that single admission.

Web pages may call the endpoint only from the instance’s own origin and the origins in GUESTCRAFT_TRUSTED_ORIGINS: those get CORS answers, without cookies; any other origin is refused. Native clients, which send no Origin, are not affected.

  • One tool per operation that an API key or organization token may call, named after its operationId (reservation_rooms_check_in), with its summary, description, required permission and arguments. The operation’s permissions are also in its x-guestcraft-permissions in the OpenAPI document: every call needs one of them at least. Reads without required query parameters are also resources (guestcraft://v1/…).
  • Composed tools, each over several public operations:
Tool What it does Changes data
availability_and_quotes Free rooms per room type and night of a stay, and each rate plan’s price, with the reasons a plan is not bookable. No
find_reservation Reservations by confirmation code or guest name, arrival or departure date, or a night in house. No
change_booking One booked room’s dates, room type, unit or number of guests; new dates are priced with the room’s rate plan. Yes, after confirmation
check_in_readiness Whether each room can be checked in now, or why not: unconfirmed, not expected, the night audit not run for an arrival that has come (night_audit.required), a business date outside the stay (check_in.outside_stay), no unit for tonight, a dirty unit. Room blocks and a required inspection are not checked. No
check_out_readiness What checking out each in-house room would leave on the folio, and whether it must be settled, or the night audit run (night_audit.required), first. No
room_status The housekeeping status of the rooms, with a count per status. No

Write tools say “Writes data” at the start of their description and carry readOnlyHint: false. Each tool follows the effect its operation declares in the API (x-guestcraft-effect): only a purely additive creation is destructiveHint: false; updates and replacements, state transitions and deletions carry destructiveHint: true. Some clients limit how many tools they enable at once: enable only those you need in the client’s tool list.

Every tool whose operation updates, transitions or deletes (a cancellation, a check-in, a payment, a booking, which takes rooms out of inventory), and change_booking, changes nothing on its first call. It answers a preview of what it would do: the request it would send, or for change_booking what GuestCraft’s own dry run says the reservation would become. A change the dry run refuses is refused at once.

  • Clients with form elicitation (they declare elicitation with form in their capabilities) show you the preview and ask Make this change. Only yes runs the tool. No, or dismissing the question, leaves everything as it is.
  • Other clients receive a confirmation_token with the preview. The assistant must show you the preview and, only if you agree, call the same tool again with the same arguments and that token.

Either way the confirmation is issued by the server, valid for ten minutes, bound to your credential and workspace choice, the tool and its exact arguments (including the if_match version), and used once across every instance of the deployment. A retry of a used confirmation answers what happened the first time (identifiers and status only) and never acts twice. The tool still runs with your live permissions: a permission removed in the meantime refuses it.

An elicitation answer is your client’s report of what you chose; it is not proof that a person, rather than software, answered. Keep assistants’ credentials to the permissions they need.

  • Each tool call ends within 25 seconds. If a destructive call is cut off, the API may still have completed it: a retry of its confirmation then says the outcome is unknown, and you should read the resource to see whether the change happened.
  • Only an OAuth token’s missing scope is an insufficient_scope challenge. Everything else a credential may not do answers the API’s 403 auth.forbidden as the tool’s error result: an API key’s or organization token’s permissions, a property outside the grant, and a permission the member no longer holds, which signing in again cannot give back. A composed tool that answers in parts (prices, a unit’s status, a balance) reports a refused part in its result; only the operations it always calls are challenged.
  • The budgets of credentials apply per instance, as for the REST API.
  • Agents read text written by guests, such as messages and notes: treat their suggestions with the care you would give an email from a stranger.
What you see Why
HTTP 401 with WWW-Authenticate: Bearer … resource_metadata="…" No credential, or one the endpoint does not accept (expired, revoked, a client session or device token, a token for another resource). OAuth clients sign in again.
HTTP 403 before any tool runs The request’s Origin is not allowed.
HTTP 403 with WWW-Authenticate: Bearer error="insufficient_scope", scope="…" The OAuth token’s scopes do not name a permission the call needs: approve the scopes listed, one of which is enough, and retry.
HTTP 429 The credential’s budget is spent: retry after the Retry-After delay.
A result with confirmation_required Nothing changed yet: confirm and call again with the token.
A result with confirmation: "refused" The token or answer was for other arguments, another tool or caller, or expired: call again without it.
A tool result with isError and auth.forbidden The credential, or the person behind it, lacks the permission or property; the tool’s description names the permission.
A version error (412) Read the resource again and pass its current version as if_match.

The same server runs from a checkout of this repository, for local development or an instance without the built-in endpoint. It authenticates with API keys and organization tokens only.

  1. A credential. In Settings → API keys, a member with api_keys.manage creates a key with only the permissions the assistant needs, for example reservations.read for questions about bookings. Its secret (gc_live_…, or gc_test_… in a sandbox workspace) is shown once. Try a sandbox workspace first. See API keys and webhooks.

  2. The server. Node.js 24 and a checkout with its dependencies installed:

    Terminal window
    git clone <your GuestCraft repository> guestcraft && cd guestcraft
    pnpm install
    node packages/mcp/src/main.ts --help

    The examples below use /path/to/guestcraft for that checkout and https://hotel.example.com for your instance. Replace gc_live_… with your key; never commit it.

Over stdio the process serves one assistant and keeps its confirmations in memory; a confirmation token works only with the process that issued it.

Add the server to claude_desktop_config.json (Settings → Developer → Edit Config), then restart Claude Desktop:

{
"mcpServers": {
"guestcraft": {
"command": "node",
"args": ["/path/to/guestcraft/packages/mcp/src/main.ts"],
"env": {
"GUESTCRAFT_BASE_URL": "https://hotel.example.com",
"GUESTCRAFT_API_KEY": "gc_live_…"
}
}
}
}

If Claude Desktop does not find node, give its absolute path as command. With an organization token, set GUESTCRAFT_ORGANIZATION_TOKEN instead of GUESTCRAFT_API_KEY, and GUESTCRAFT_WORKSPACE_ID to the default workspace (ws_…); a tool’s workspace_id argument chooses another one for a single call.

Over stdio:

Terminal window
claude mcp add guestcraft \
--env GUESTCRAFT_BASE_URL=https://hotel.example.com \
--env GUESTCRAFT_API_KEY=gc_live_… \
-- node /path/to/guestcraft/packages/mcp/src/main.ts

Over HTTP, with the server started as in Streamable HTTP:

Terminal window
claude mcp add --transport http guestcraft http://127.0.0.1:3100/mcp \
--header "Authorization: Bearer gc_live_…"

Add --header "GuestCraft-Workspace-Id: ws_…" to choose the default workspace of an organization token. claude mcp list shows the server; /mcp inside Claude Code shows its tools. In a shared project file (--scope project, .mcp.json), refer to the key as ${GUESTCRAFT_API_KEY} instead of writing it.

In ~/.cursor/mcp.json, or .cursor/mcp.json of a project:

{
"mcpServers": {
"guestcraft": {
"command": "node",
"args": ["/path/to/guestcraft/packages/mcp/src/main.ts"],
"env": {
"GUESTCRAFT_BASE_URL": "https://hotel.example.com",
"GUESTCRAFT_API_KEY": "gc_live_…"
}
}
}
}

Over HTTP, the entry is { "url": "http://127.0.0.1:3100/mcp", "headers": { "Authorization": "Bearer gc_live_…" } }.

In .vscode/mcp.json, VS Code asks for the key once and stores it as a secret:

{
"inputs": [
{
"type": "promptString",
"id": "guestcraft-key",
"description": "GuestCraft API key",
"password": true
}
],
"servers": {
"guestcraft": {
"type": "stdio",
"command": "node",
"args": ["/path/to/guestcraft/packages/mcp/src/main.ts"],
"env": {
"GUESTCRAFT_BASE_URL": "https://hotel.example.com",
"GUESTCRAFT_API_KEY": "${input:guestcraft-key}"
}
}
}
}

Over HTTP, the server entry is { "type": "http", "url": "http://127.0.0.1:3100/mcp", "headers": { "Authorization": "Bearer ${input:guestcraft-key}" } }.

The MCP Inspector lists the tools and resources and calls them by hand; use a sandbox key (gc_test_…):

Terminal window
npx @modelcontextprotocol/inspector \
-e GUESTCRAFT_BASE_URL=https://hotel.example.com \
-e GUESTCRAFT_API_KEY=gc_test_… \
node /path/to/guestcraft/packages/mcp/src/main.ts

For the HTTP endpoint, choose the Streamable HTTP transport, the URL http://127.0.0.1:3100/mcp and an Authorization: Bearer gc_test_… header, and connect through the Inspector’s proxy, its default.

Terminal window
GUESTCRAFT_BASE_URL=https://hotel.example.com \
node /path/to/guestcraft/packages/mcp/src/main.ts --http --port 3100

One server serves several people: it holds no credential, and each request acts with the bearer credential it carries. It listens on 127.0.0.1 by default; another host (--host) needs TLS in front of it. Requests from web pages are refused unless their origin is allowed with --allow-origin https://app.example.com, which also gives that origin CORS answers. Its confirmations live in the process’s memory: a confirmation token works only with the process that issued it. The command exits with status 2 when a setting is missing or wrong, and says which.