MCP server setup
The OpenApp MCP server lets coding and operator agents discover organizations and entities, resolve doors by name, inspect audit and policies, and run controlled writes (propose_action / confirm_action, invites). It comes in two forms with different tool sets and different guardrails:
| Hosted MCP | Local MCP (@openapp/mcp-server) | |
|---|---|---|
| Where it runs | Inside the OpenApp API: POST /api/v1/mcp | Your machine: stdio (openapp-mcp) or streamable HTTP (openapp-mcp-http) |
| Auth | OAuth access token (client openapp-mcp) or API key (X-API-Key) | API key in OPENAPP_API_KEY, sent as X-API-Key |
| Org | X-Org header on every call; tools act only on that org | OPENAPP_ORG_ID, sent as X-Org |
| Write gate | Credential roles, agent tool allow-list, agent confirmation mode | OPENAPP_MCP_ALLOW_WRITES=1, then the same server-side checks |
| Scripting | Never | stdio only, with OPENAPP_MCP_ALLOW_SCRIPTING=1 |
Source: packages/openapp-mcp (@openapp/mcp-server on npm) and apps/backend/local_server/src/handlers/mcp.rs (hosted).
Hosted MCP
Section titled “Hosted MCP”Point your MCP client at the API host:
- Endpoint:
POST https://openapp.house/api/v1/mcp(JSON-RPC over HTTP). - Auth: an OAuth access token from the
openapp-mcpHydra client (client credentials for a named Agent, or authorization code for user consent), or an API key inX-API-Key. Protected-resource metadata:/.well-known/oauth-protected-resource. - Org: send
X-Orgwith every call. A tool call without it fails withX-Org is required. Every tool acts only on resources owned by that org; a resource in another org is reported as not found (404), never forbidden. - Permissions: each tool runs the HTTP handler it mirrors, so it needs the same permission, writes the same audit events, and returns the same response body. Invite tools also count against the invitation API rate limit.
- Guardrails: there is no
OPENAPP_MCP_ALLOW_WRITESswitch on hosted MCP. What an agent can do is bounded by its credential’s roles and scope, the agent’s tool allow-list (a tool outside it returnsTool is not allowed on hosted MCP), and the agent’s confirmation mode (always,physical_only, ornever), which decides whenopenapp_confirm_actionneeds a preview token. initializereportsserverInfo.versionas the backend version (the same value/statusreports).
Trimmed OpenAPI for Custom GPTs: openapp-openapi-agent.json (resolve, preview/execute, invites, audit — not the full spec).
Hosted tools
Section titled “Hosted tools”| Tool | Maps to | Notes |
|---|---|---|
openapp_list_orgs | — | Returns the X-Org org only; hosted MCP is org-scoped |
openapp_list_entities | GET /entities | First 50 by name; needs entities:list |
openapp_resolve | POST /orgs/{org_id}/resolve | query, optional resource_type |
openapp_list_audit_events | GET /orgs/{org_id}/audit/events | Filters: event_type, target_id, actor_kind, org_scope, limit |
openapp_list_policies | GET /orgs/{org_id}/policies | |
openapp_list_webhooks | GET /orgs/{org_id}/webhooks | |
openapp_audit_export | POST /orgs/{org_id}/audit/exports | Starts the job; poll it over HTTP |
openapp_list_invites | GET /integrations/{id}/access-invites | integration_id required; kind=share for shares |
openapp_revoke_invite | POST /integrations/{id}/access-invites/{invite_link_id}/revoke | integration_id and invite_id required |
openapp_propose_action | POST /entities/{id}/actions/{action_id}/preview | Dry run; returns a preview_token when confirmation is required |
openapp_confirm_action | POST /entities/{id}/actions/{action_id} with X-OpenApp-Confirm | confirm_token required; optional idempotency_key |
Local MCP (stdio and HTTP)
Section titled “Local MCP (stdio and HTTP)”Environment variables
Section titled “Environment variables”| Variable | Required | Description |
|---|---|---|
OPENAPP_API_KEY | Yes | API key (sent as X-API-Key), preferably an Agent credential |
OPENAPP_API_BASE | No | Default https://openapp.house/api/v1 |
OPENAPP_ORG_ID | For every tool except openapp_list_orgs, openapp_get_entity, and openapp_describe_action | Organization ULID (X-Org) |
OPENAPP_MCP_ALLOW_WRITES | For write tools | Set to 1 only after org policy review. Local server only. |
OPENAPP_MCP_ALLOW_SCRIPTING | For openapp_scripting_execute | Set to 1 and enable writes. stdio only; ignored by openapp-mcp-http. |
OPENAPP_MCP_HTTP_PORT | No | openapp-mcp-http port, default 8787 |
OPENAPP_MCP_HTTP_HOST | No | openapp-mcp-http bind address, default 127.0.0.1 |
Never commit keys to mcp.json — use env vars or your client’s secret store.
Local read tools
Section titled “Local read tools”| Tool | Maps to |
|---|---|
openapp_list_orgs | GET /orgs (every org the key can access) |
openapp_list_devices | GET /devices |
openapp_list_entities | GET /entities |
openapp_get_entity | GET /entities/{id} |
openapp_resolve | POST /orgs/{org_id}/resolve |
openapp_list_audit_events | GET /orgs/{org_id}/audit/events — filters: event_type, outcome, resource_type, resource_id, actor_user_id, actor_kind, correlation_id, occurred_after, occurred_before, cursor, limit |
openapp_list_policies | GET /orgs/{org_id}/policies |
openapp_list_webhooks | GET /orgs/{org_id}/webhooks |
openapp_list_invites | GET /integrations/{id}/access-invites |
openapp_describe_action | Static catalog of switchable.* actions |
openapp_propose_action | POST /entities/{id}/actions/{action_id}/preview |
Local write tools
Section titled “Local write tools”Refused unless OPENAPP_MCP_ALLOW_WRITES=1. The API still applies roles, credential scope, policies, and the agent’s confirmation mode.
| Tool | Maps to | Notes |
|---|---|---|
openapp_confirm_action | POST /entities/{id}/actions/{action_id} + X-OpenApp-Confirm | Two-phase physical write |
openapp_execute_entity_action | POST /entities/{id}/actions/{action_id}; optional Idempotency-Key | Local only. Prefer propose then confirm |
openapp_create_invitation | POST /integrations/{id}/access-invites | Local only. expires_in, or valid_from + valid_to, required |
openapp_revoke_invite | POST /integrations/{id}/access-invites/{invite_link_id}/revoke | |
openapp_audit_export | POST /orgs/{org_id}/audit/exports | Starts the job |
openapp_scripting_execute | POST /scripting/executions, then polls GET /scripting/executions/{id} | stdio only, with OPENAPP_MCP_ALLOW_SCRIPTING=1. Fails for scoped credentials, which can’t run scripting |
See Agent-relevant API and Query access and audit activity.
Run it
Section titled “Run it”npx -y @openapp/mcp-serverFrom the repository:
cd packages/openapp-mcpnpm installnpm run buildOPENAPP_API_KEY='https://openapp.house_openapp_…' OPENAPP_ORG_ID='01H…' npm startLocal streamable HTTP (never exposes scripting). It listens on http://127.0.0.1:8787/mcp and answers GET /health:
OPENAPP_API_KEY='…' OPENAPP_ORG_ID='…' npm run start:httpCursor mcp.json example
Section titled “Cursor mcp.json example”{ "mcpServers": { "openapp": { "command": "npx", "args": ["-y", "@openapp/mcp-server"], "env": { "OPENAPP_API_BASE": "https://openapp.house/api/v1", "OPENAPP_API_KEY": "<agent credential from dashboard>", "OPENAPP_ORG_ID": "<ulid>" } } }}Add "OPENAPP_MCP_ALLOW_WRITES": "1" only when operators approve physical actions from agents.
Installable job skills (STR checkout, guest invite, audit investigation) live in packages/openapp-skills/ and .cursor/skills/.
Safety
Section titled “Safety”- Read-only tools still reveal org structure and recent audit events — scope credentials minimally, and give agents an
allowed_entity_idslist. - Write tools unlock doors, create guest links, or run scripts — keep a human in the loop in agent UIs.
- Every
switchable.*action is audited (entity.action.succeeded/entity.action.denied), attributed to the agent. - Physical unlocks: Build an access-control agent.