Agent Skills / maison-apps

Install this skill alone, or read it below. Raw file: SKILL.md · references/tools.md

bash
npx skills add https://docs.maison-labs.com --skill maison-apps

Maison — Developer apps

Manage the developer apps (OAuth clients) a hotel registers to call the Maison public API on its behalf: register, read, edit, revoke and reinstate apps, read each app's analytics, request log and audit trail; and, for Maison staff, verify, suspend, revoke or reinstate any app on the platform. Use when a hotel wants its own software or a partner to call the API, or when an app must be stopped.

Part of the Maison public API. Read the maison-public-api skill first for authentication, discovery and transport details (https://docs.maison-labs.com/skills/maison-public-api/SKILL.md).

When to use

  • Register an app for a hotel's own integration — create_client_app.
  • See a hotel's apps or change one — list_client_apps, get_client_app, update_client_app (name, redirect URIs, scopes; live apps only).
  • Stop an app and everyone connected through it — revoke_client_app (or revoke_oauth_app as Maison staff).
  • Audit what an app did and who changed it — get_client_app_analytics, list_client_app_requests, list_client_app_audit.
  • Review apps across the platform (Maison staff) — list_oauth_apps, verify_oauth_app, suspend_oauth_app; reinstate_oauth_app undoes revoke_oauth_app.

Before you start

  1. Send x-api-key: <key> on every call; the key only reaches /api/v1.
  2. GET /api/v1/tools (or MCP tools/list) returns the tools THIS key may run — if a tool below is missing there, you lack a grant; do not retry it.
  3. Client-scoped tools take clientId (a hotel id). whoami lists the ids you can act on.

Tools

ToolWhat it doesRESTNeeds
create_client_appRegister an OAuth app for a hotel: name, redirect URIs (https, or http on localhost), the scopes it may ask for, and its type — public (PKCE, no secret) or confidential (a client secret).POST /api/v1/client/{clientId}/appoauth-apps WRITE (client); plan: oauth-apps
get_client_appOne of a hotel's developer apps, revoked or not, with its registration, state, actors and usage.GET /api/v1/client/{clientId}/app/{appId}oauth-apps READ (client); plan: oauth-apps; read-only
get_client_app_analyticsHow an app is used over a window of UTC days (from/to inclusive, at most 92 days; default the last 30 days): requests per day split ok / error (error = status 400 and above), totals (requests, errors, median duration, active users, last use), the top tools, transports, people and sources, and consents (active now, granted / revoked per day).GET /api/v1/client/{clientId}/app/{appId}/analyticsoauth-apps READ (client); plan: oauth-apps; read-only
list_client_app_auditEvery change to the app and every consent to it, newest first (oauth_app_* events: created, updated, scopes / redirects changed, revoked, grants revoked, reinstated, suspended, verified, consent granted / revoked), each with the actor's name and the detail.GET /api/v1/client/{clientId}/app/{appId}/auditoauth-apps READ (client); plan: oauth-apps; read-only
list_client_app_requestsThe app's access log, newest first: every tool call and token exchange with its tool, transport, status, error code, duration, the person it ran as, the hotel it named and where it came from.GET /api/v1/client/{clientId}/app/{appId}/requestsoauth-apps READ (client); plan: oauth-apps; read-only
list_client_appsThe OAuth apps a hotel registered to call the Maison API on its behalf, newest first: registration fields, verified / suspended state, who created, changed or revoked each, last_used_at and requests_30d.GET /api/v1/client/{clientId}/appsoauth-apps READ (client); plan: oauth-apps; read-only
list_oauth_appsMaison staff: every OAuth app on the platform, oldest first — hotel portal apps, Claude / ChatGPT style CIMD and DCR registrations, and first-party apps — with the portal fields, is_first_party and the redirect URI count.GET /api/v1/oauthappsoauth-apps WRITE (global); read-only
reinstate_client_appBring a revoked app back.POST /api/v1/client/{clientId}/app/{appId}/reinstateoauth-apps WRITE (client); plan: oauth-apps
reinstate_oauth_appMaison staff: bring a revoked app back; consents stay revoked.POST /api/v1/oauthapp/{appId}/reinstateoauth-apps WRITE (global)
revoke_client_appStop a hotel's app and everyone connected through it: the app is revoked (never deleted) and every person's consent to it is revoked too (access tokens are refused within 30 seconds).DELETE /api/v1/client/{clientId}/app/{appId}oauth-apps WRITE (client); plan: oauth-apps; destructive
revoke_oauth_appMaison staff: revoke any app on the platform (any registration type) and every person's consent to it; access tokens are refused within 30 seconds.DELETE /api/v1/oauthapp/{appId}oauth-apps WRITE (global); destructive
suspend_oauth_appMaison staff: a temporary stop that keeps consents — authorize and token requests are refused, and access tokens already issued run out within 15 minutes.POST /api/v1/oauthapp/{appId}/suspendoauth-apps WRITE (global); destructive
unsuspend_oauth_appMaison staff: lift a suspension; the app works again with the consents it had.POST /api/v1/oauthapp/{appId}/unsuspendoauth-apps WRITE (global)
unverify_oauth_appMaison staff: remove a live app's verified mark; the consent screen warns again.POST /api/v1/oauthapp/{appId}/unverifyoauth-apps WRITE (global)
update_client_appChange a live app's name, logo, home page, redirect URIs or scopes (send only what changes).PUT /api/v1/client/{clientId}/app/{appId}oauth-apps WRITE (client); plan: oauth-apps
verify_oauth_appMaison staff: mark a live app verified — the consent screen drops its "Unverified app" warning.POST /api/v1/oauthapp/{appId}/verifyoauth-apps WRITE (global)

Full input fields for every tool: references/tools.md.

Recommended workflows

Register an app

  1. create_client_app with a name, redirect URIs, the scopes it needs and its client type (public, or confidential with a client secret). Use a user's own API key: an OAuth access token is refused, so one app can never register another.
  2. A confidential app's client secret is returned once in the response and can never be read again — hand it over straight away. There is no secret rotation: revoke the app and register a new one.
  3. The app starts unverified; people can still approve it, with an "Unverified app" warning on the consent screen until Maison verifies it.

Stop an app

  1. revoke_client_app revokes the app and fans out to revoke every person's grant to it; access tokens are refused within 30 seconds.
  2. reinstate_client_app brings the app back, but consents stay revoked — people connect again.
  3. Maison staff use suspend_oauth_app for a temporary stop that keeps consents (tokens already issued run out within 15 minutes); unsuspend_oauth_app lifts it.

Tips

  • An app is never deleted: revoke is the delete, and every change and every access is kept for audits.
  • Verification (verify_oauth_app / unverify_oauth_app) is a consent-screen badge only; it never gates the flow.
  • Scopes cap what an app may ask for; each person's own grants still cap what a token can do.
  • list_oauth_apps (Maison staff) includes Claude / ChatGPT style CIMD and DCR registrations; revoked apps join the list only with includeRevoked or status: revoked.

Pitfalls

  • Only a live app can be edited; reinstate a revoked app first.
  • Reinstating answers 409 client_id_in_use when another live app now holds the same OAuth client id.
  • Never log or echo a client secret.
  • The per-hotel tools need the hotel's oauth-apps plan entitlement (403 not_entitled) as well as the oauth-apps grant; canWrite on the reads says whether you may change the hotel's apps.

Calling conventions

Same tool, three transports — pick whichever your runtime already speaks. Always send x-api-key.

bash
# REST
curl -X POST "https://maison-labs.com/api/v1/client/<clientId>/app" -H "x-api-key: $MAISON_API_KEY" -H "content-type: application/json" -d '{ "name": …, "redirectUris": …, "requestedScopes": …, "clientType": … }'
json
// MCP (https://maison-labs.com/mcp, Streamable HTTP): tools/call
{ "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "create_client_app", "arguments": { "name": …, "redirectUris": …, "requestedScopes": …, "clientType": … } } }
json
// A2A (https://maison-labs.com/a2a): tasks/send with a data part
{ "jsonrpc": "2.0", "id": 1, "method": "tasks/send", "params": { "message": { "role": "user", "parts": [{ "type": "data", "data": { "tool": "create_client_app", "input": { "name": …, "redirectUris": …, "requestedScopes": …, "clientType": … } } }] } } }

Errors are the same everywhere: 401 no/invalid key; 403 forbidden with details.missing (the grants you lack — fall back to the composite's parts or stop); 403 not_entitled (the hotel's plan lacks the feature); 404, 409, 413 too_large, 503. Inputs that fail validation return 400 invalid_input with the Zod issues — fix and retry once.