Agent Skills / maison-apps
Install this skill alone, or read it below. Raw file: SKILL.md · references/tools.md
npx skills add https://docs.maison-labs.com --skill maison-appsMaison — 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(orrevoke_oauth_appas 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_appundoesrevoke_oauth_app.
Before you start
- Send
x-api-key: <key>on every call; the key only reaches/api/v1. GET /api/v1/tools(or MCPtools/list) returns the tools THIS key may run — if a tool below is missing there, you lack a grant; do not retry it.- Client-scoped tools take
clientId(a hotel id).whoamilists the ids you can act on.
Tools
| Tool | What it does | REST | Needs |
|---|---|---|---|
create_client_app | Register 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}/app | oauth-apps WRITE (client); plan: oauth-apps |
get_client_app | One 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_analytics | How 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}/analytics | oauth-apps READ (client); plan: oauth-apps; read-only |
list_client_app_audit | Every 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}/audit | oauth-apps READ (client); plan: oauth-apps; read-only |
list_client_app_requests | The 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}/requests | oauth-apps READ (client); plan: oauth-apps; read-only |
list_client_apps | The 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}/apps | oauth-apps READ (client); plan: oauth-apps; read-only |
list_oauth_apps | Maison 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/oauthapps | oauth-apps WRITE (global); read-only |
reinstate_client_app | Bring a revoked app back. | POST /api/v1/client/{clientId}/app/{appId}/reinstate | oauth-apps WRITE (client); plan: oauth-apps |
reinstate_oauth_app | Maison staff: bring a revoked app back; consents stay revoked. | POST /api/v1/oauthapp/{appId}/reinstate | oauth-apps WRITE (global) |
revoke_client_app | Stop 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_app | Maison 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_app | Maison 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}/suspend | oauth-apps WRITE (global); destructive |
unsuspend_oauth_app | Maison staff: lift a suspension; the app works again with the consents it had. | POST /api/v1/oauthapp/{appId}/unsuspend | oauth-apps WRITE (global) |
unverify_oauth_app | Maison staff: remove a live app's verified mark; the consent screen warns again. | POST /api/v1/oauthapp/{appId}/unverify | oauth-apps WRITE (global) |
update_client_app | Change 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_app | Maison staff: mark a live app verified — the consent screen drops its "Unverified app" warning. | POST /api/v1/oauthapp/{appId}/verify | oauth-apps WRITE (global) |
Full input fields for every tool: references/tools.md.
Recommended workflows
Register an app
create_client_appwith 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.- 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.
- 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
revoke_client_apprevokes the app and fans out to revoke every person's grant to it; access tokens are refused within 30 seconds.reinstate_client_appbrings the app back, but consents stay revoked — people connect again.- Maison staff use
suspend_oauth_appfor a temporary stop that keeps consents (tokens already issued run out within 15 minutes);unsuspend_oauth_applifts 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 withincludeRevokedorstatus: revoked.
Pitfalls
- Only a live app can be edited; reinstate a revoked app first.
- Reinstating answers 409
client_id_in_usewhen 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-appsplan entitlement (403not_entitled) as well as theoauth-appsgrant;canWriteon 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.
# 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": … }'// 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": … } } }// 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.