Agent Skills / maison-features

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-features

Maison — Feature plans and entitlements (Maison staff)

Control what a hotel's plan includes: read the caller's per-feature access snapshot for a hotel, list and change the hotel's entitled features (grant/revoke in one call), push a feature to every child property, and manage plan templates (create, update, assign, apply with optional pruning, drift report, per-client overrides, plan history), Maison's payment gateway fees and the feature catalogue. Each plan feature is on or locked (shown to the hotel locked, with the plan's message); a feature left out is off. Use when a hotel upgrades or downgrades, when a tool answers 403 not_entitled, or when standardising plans across a group.

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

  • A tool returned not_entitled — get_client_access shows what the plan lacks; set_client_features fixes it.
  • Roll out a plan — set_client_plan (assign + apply) or apply_plan_template.
  • Who changed a plan and when — list_plan_template_history / list_client_plan_history.
  • Invoice hotels for payments — get_gateway_fee_totals with from/to (optionally clientId).

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
apply_plan_templateSync the client's features to its assigned template: grant missing features, optionally revoke extras.POST /api/v1/client/{clientId}/plan/applyclient-feature-management WRITE (global)
assign_plan_templateAssign or remove the client's plan template (pass null to unassign).PUT /api/v1/client/{clientId}/planclient-feature-management WRITE (global)
clear_client_feature_overrideRemove the client's override for one feature so it follows the plan template again, and reconcile its features.DELETE /api/v1/client/{clientId}/plan/override/{feature}client-feature-management WRITE (global); destructive
clear_client_gateway_feeRemove the hotel's own fee for one gateway so its plan's fee applies again.DELETE /api/v1/client/{clientId}/gatewayfee/{gateway}clients WRITE (global); destructive
clear_plan_gateway_feeRemove a plan template's fee for one gateway; its clients without a fee of their own then pay none.DELETE /api/v1/featureplan/{templateId}/gatewayfee/{gateway}clients WRITE (global); destructive
create_featureAdd a feature to the catalogue that grants (policy rules) and plans name.POST /api/v1/featuremaison-roles WRITE (global)
create_plan_templateCreate a new plan template.POST /api/v1/featureplanclient-feature-management WRITE (global)
delete_plan_templateSoft-delete a plan template.DELETE /api/v1/featureplan/{templateId}client-feature-management WRITE (global); destructive
deprecate_featureMark a catalogue feature deprecated: it leaves the catalogue offered to grants and plans and every client's eligibility.DELETE /api/v1/feature/{featureId}maison-roles WRITE (global); destructive
get_client_accessFor every feature in the catalogue, returns whether the caller is entitled (plan), and whether they may read, write or execute it on this client; plus lockedFeatures (features the plan shows locked — offered as an upgrade, not hidden) and lockedMessage (the plan's locked copy, or the default).GET /api/v1/client/{clientId}/accessclients READ (client); read-only
get_client_planReturn the client's assigned plan template, its overrides ([{ feature, state }]), the effective entitlement (effective), the features shown locked (locked) and the drift: features the client has that its plan and overrides don't call for (extra), and effective features it is missing (missing).GET /api/v1/client/{clientId}/planclient-feature-management READ (global); read-only
get_gateway_fee_totalsPaid payments and the Maison fees recorded on them for an inclusive date range, per client, gateway and currency (amounts in minor units), optionally for one client.GET /api/v1/gatewayfees/totalsclients READ (global); read-only
get_plan_templateReturn one plan template by id, including its features with their states, locked message and counts.GET /api/v1/featureplan/{templateId}client-feature-management READ (global); read-only
grant_client_featureAdd a single feature to the client's plan.POST /api/v1/client/{clientId}/featureclient-feature-management WRITE (global)
grant_feature_to_childrenAdd a feature to every child property's plan.POST /api/v1/client/{clientId}/children/featureclient-feature-management WRITE (global)
list_client_featuresReturns the feature strings currently in the client's plan (layer-1 entitlements).GET /api/v1/client/{clientId}/featuresclient-feature-management READ (global); read-only
list_client_gateway_feesMaison's fee per payment gateway (stripe, elavon) for one hotel as it applies: the client's own fee, else its plan's, else none (source: client | template | null).GET /api/v1/client/{clientId}/gatewayfeesupdate-client READ (client); read-only
list_client_plan_historyA client's plan history, newest first: the plans it was assigned and its feature override changes.GET /api/v1/client/{clientId}/plan/historyclient-feature-management READ (global); read-only
list_plan_gateway_feesThe Maison fees a plan template sets per gateway; every client on the plan without its own fee pays these.GET /api/v1/featureplan/{templateId}/gatewayfeesclients READ (global); read-only
list_plan_template_clientsThe active clients on one plan template (id and name), as the plan page lists them.GET /api/v1/featureplan/{templateId}/clientsclient-feature-management READ (global); read-only
list_plan_template_historyA plan template's change history, newest first: its own field and feature-state changes, its creation and deletion, and clients assigned to it or moved off it.GET /api/v1/featureplan/{templateId}/historyclient-feature-management READ (global); read-only
list_plan_templatesList all non-deleted plan templates with their features ([{ feature, state }], state "on" or "locked"), locked message and counts (client_count, on_count, locked_count).GET /api/v1/featureplansclient-feature-management READ (global); read-only
revoke_client_featureRemove a single feature from the client's plan.DELETE /api/v1/client/{clientId}/feature/{feature}client-feature-management WRITE (global); destructive
set_client_feature_overrideSet the client's own state for one feature ("on", "off" or "locked"), winning over its plan template, and reconcile its features.PUT /api/v1/client/{clientId}/plan/override/{feature}client-feature-management WRITE (global)
set_client_featuresGrant and/or revoke a set of features.PUT /api/v1/client/{clientId}/featuresclient-feature-management WRITE (global); composite of grant_client_feature, revoke_client_feature
set_client_gateway_feeSet the hotel's own Maison fee for one gateway, overriding its plan's fee; recorded on each later payment for invoicing.PUT /api/v1/client/{clientId}/gatewayfee/{gateway}clients WRITE (global)
set_client_planAssign a template, set the client's overrides (each { feature, state } with state "on", "off" or "locked"; a plain name means on) and apply it.PUT /api/v1/client/{clientId}/plan/setclient-feature-management WRITE (global); composite of assign_plan_template, set_client_feature_override, apply_plan_template
set_plan_gateway_feeSet a plan template's Maison fee for one gateway; it applies to every client on the plan that has no fee of its own.PUT /api/v1/featureplan/{templateId}/gatewayfee/{gateway}clients WRITE (global)
update_featureRename a catalogue feature or change its description; at least one field.PUT /api/v1/feature/{featureId}maison-roles WRITE (global)
update_plan_templateUpdate the name, description, locked message or features (with their states) of an existing plan template; changing the features reconciles every client on the plan.PUT /api/v1/featureplan/{templateId}client-feature-management WRITE (global)

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

Recommended workflows

Upgrade a hotel to a plan template

  1. list_plan_templates → pick the template id.
  2. set_client_plan with templateId and prune: false (keeps extra grants) or true (exact match).
  3. get_client_plan to review drift afterwards.

Give one hotel an exception to its plan

  1. set_client_feature_override with state "on", "off" or "locked" — it wins over the plan and the hotel's features are reconciled at once.
  2. clear_client_feature_override returns the feature to the plan default.
  3. get_client_plan lists the hotel's overrides and its locked features.

Tips

  • get_client_access is the fastest way to answer 'what can I do for this hotel?' — it merges plan entitlement with the caller's grants.
  • Plan history pages by offset (limit, offset) and returns total.
  • Gateway fees: a client's own fee wins over its plan's fee (source says which applies); setting and clearing fees is Maison staff only (global clients WRITE).
  • create_feature / update_feature / deprecate_feature change the platform feature catalogue (global maison-roles WRITE) — prefer an existing feature.

Pitfalls

  • All plan tools except get_client_access need the GLOBAL client-feature-management grant (Maison staff).
  • apply_plan_template with prune: true revokes features not in the template — confirm with the user first.
  • A Maison-only feature cannot be locked (400) — use off instead.
  • delete_plan_template answers 409 while any hotel is on the plan — list_plan_template_clients lists them; move them to another plan first.

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>/plan/apply" -H "x-api-key: $MAISON_API_KEY" -H "content-type: application/json" -d '{}'
json
// MCP (https://maison-labs.com/mcp, Streamable HTTP): tools/call
{ "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "apply_plan_template", "arguments": {} } }
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": "apply_plan_template", "input": {} } }] } } }

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.