Skip to content

Commit 37c12e8

Browse files
os-zhuangclaude
andauthored
docs: add Connect-MCP and Actions guides — the two missing landing-promise pages (#3093)
The docs audit found the two worst feature-point gaps: - "Every object and action doubles as a governed MCP tool" is the site's core promise, but there was no page that gets a customer connected in 10 minutes — the connect instructions were buried in agents.mdx. - Actions had no hands-on page at all (two table rows and a forms aside), and shipped AI-generated dead buttons in production because the register-a-handler step was undocumented. Both pages are grounded in source (endpoints, auth tracks, exposure rules, tool names, failure modes verified in packages/runtime, packages/mcp, packages/spec) and real bundled examples (app-todo, app-showcase, app-crm): - ai/connect-mcp.mdx — one-command Claude Code connect (localhost + prod), Claude Desktop/claude.ai, .mcp.json, API keys (mint + 3 header forms), the 10 generated tools, security model (caller identity, OAuth scopes, trusted action bodies, TLS rule), verification question, and a symptom→fix troubleshooting table (404/501/401/403/missing-action). - ui/actions.mdx — honest type table (script/flow/url/modal; api+form flagged as not wired), define → two server-behavior paths (inline body vs registered handler, incl. the "dead button" trap), locations + by-name bindings, params/confirm/resultDialog, dual-surface requiredPermissions, fail-closed visible CEL gotchas, REST invocation, ai.exposed opt-in, troubleshooting. Nav: added to ai/ and ui/ meta.json; cross-links from agents.mdx and views.mdx rowActions/bulkActions. Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent 84b92b0 commit 37c12e8

6 files changed

Lines changed: 413 additions & 2 deletions

File tree

content/docs/ai/agents.mdx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,13 @@ instead — see the callout in the [AI Overview](/docs/ai).)
4343

4444
## Connect your AI (BYO-AI over MCP)
4545

46+
<Callout type="info">
47+
Step-by-step client setup (Claude Code, Claude Desktop, `.mcp.json`, API keys)
48+
with verification and troubleshooting lives in
49+
[Connect an MCP Client](/docs/ai/connect-mcp). The summary below covers the
50+
architecture.
51+
</Callout>
52+
4653
Every deployment serves MCP at `/api/v1/mcp` by default (a core platform
4754
capability — set `OS_MCP_SERVER_ENABLED=false` to opt out), with two
4855
authentication tracks: The in-product entry point is the

content/docs/ai/connect-mcp.mdx

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
---
2+
title: Connect an MCP Client
3+
description: Point Claude Code, Claude Desktop, or any MCP client at your running app — OAuth or API key — and verify the agent can see and operate it.
4+
---
5+
6+
# Connect an MCP Client
7+
8+
Every ObjectStack deployment is already an MCP server. The runtime serves the
9+
[Model Context Protocol](https://modelcontextprotocol.io) at **`/api/v1/mcp`**
10+
— on by default, no plugin to install, no configuration step. Your objects and
11+
exposed actions become typed tools the moment you define them; this page is
12+
about the only thing left to do: **connecting a client and proving it works**.
13+
14+
<Callout type="info">
15+
To turn the surface off, set `OS_MCP_SERVER_ENABLED=false` — the endpoint then
16+
returns 404 and the **Setup → Connect an Agent** page disappears with it. See
17+
[environment variables](/docs/deployment/environment-variables#mcp-server).
18+
</Callout>
19+
20+
## Claude Code (one command)
21+
22+
Interactive clients use OAuth — each deployment is its own OAuth 2.1
23+
authorization server, so there are no admin-minted credentials to pass around.
24+
The first tool call opens a browser login and you connect **as yourself**:
25+
26+
```bash
27+
# local dev server
28+
claude mcp add --transport http my-app http://localhost:3000/api/v1/mcp
29+
30+
# a deployed instance
31+
claude mcp add --transport http my-app https://your-deployment.example.com/api/v1/mcp
32+
```
33+
34+
For headless use (CI, containers) skip OAuth and attach an
35+
[API key](#headless-api-keys) instead:
36+
37+
```bash
38+
claude mcp add --transport http my-app https://your-deployment.example.com/api/v1/mcp \
39+
--header "x-api-key: osk_..."
40+
```
41+
42+
## Claude Desktop and claude.ai
43+
44+
**Settings → Connectors → Add custom connector**, then paste the MCP URL
45+
(`https://your-deployment.example.com/api/v1/mcp`). The first use walks through
46+
the same browser login.
47+
48+
## Any MCP client (`.mcp.json`)
49+
50+
Clients that read an `mcpServers` map connect the same way. With an API key:
51+
52+
```json
53+
{
54+
"mcpServers": {
55+
"objectstack": {
56+
"type": "http",
57+
"url": "https://your-deployment.example.com/api/v1/mcp",
58+
"headers": { "x-api-key": "osk_..." }
59+
}
60+
}
61+
}
62+
```
63+
64+
## Headless: API keys
65+
66+
Mint a key from **Setup → Connect an Agent** in the Console (which also shows
67+
copy-paste-ready connect snippets per client), or over REST:
68+
69+
```bash
70+
curl -b cookies.txt -X POST https://your-deployment.example.com/api/v1/keys
71+
# → { "key": "osk_..." } — shown once; store it in your secret manager
72+
```
73+
74+
Send it on every request in any of three equivalent forms:
75+
76+
| Header | Example |
77+
|:---|:---|
78+
| `x-api-key` | `x-api-key: osk_...` |
79+
| `Authorization: ApiKey` | `Authorization: ApiKey osk_...` |
80+
| `Authorization: Bearer` | `Authorization: Bearer osk_...` (recognized by the `osk_` prefix) |
81+
82+
<Callout type="warn">
83+
OAuth requires TLS — plain-HTTP deployments (except `localhost`) fall back to
84+
**API-key-only**: the browser-login track is disabled rather than allowed to
85+
run insecurely.
86+
</Callout>
87+
88+
## What the agent gets
89+
90+
Ten data and action tools, generated from your metadata:
91+
92+
| Tool | What it does |
93+
|:---|:---|
94+
| `list_objects` / `describe_object` | Discover which objects exist and their fields |
95+
| `query_records` / `get_record` | Read data (list queries are capped at 50 rows per page by default) |
96+
| `aggregate_records` | Grouped aggregation (registered when the active driver supports it) |
97+
| `create_record` / `update_record` / `delete_record` | Write data |
98+
| `list_actions` / `run_action` | Discover and invoke your business actions by name |
99+
100+
Two exposure rules to know:
101+
102+
- **Objects are exposed automatically** — except `sys_*` system objects, which
103+
are blocked fail-closed.
104+
- **Actions require the author's opt-in**: `ai: { exposed: true }` plus an
105+
`ai.description` of at least 40 characters, and the action must be callable
106+
without a UI (`script` with a body or registered handler, or `flow`).
107+
See [Actions as Tools](/docs/ai/actions-as-tools) and
108+
[Actions](/docs/ui/actions).
109+
110+
## The security model
111+
112+
- **Every call runs as the caller.** The MCP bridge resolves the same
113+
`ExecutionContext` as a REST request, so RBAC, row-level security, and
114+
field-level security apply to the agent exactly as they do to a person in
115+
the Console. Sparse results or denied writes usually mean governance is
116+
*working*, not that the connection is broken.
117+
- **OAuth scopes narrow the toolset.** Tokens carry `data:read`,
118+
`data:write`, and `actions:execute` scopes — tools outside the granted
119+
scopes are not even registered for that session. API-key and session
120+
callers get the full set, still permission-checked per call.
121+
- **Action bodies run as trusted app code** once invoked (the `ai.exposed`
122+
gate and `requiredPermissions` are checked at *invoke* time). Treat writing
123+
an action as a code-review-worthy act — that's the real security boundary.
124+
- An action can also declare `ai.requiresConfirmation`; destructive-looking
125+
actions (`confirmText`, danger variants) default to requiring it.
126+
127+
## Verify the connection
128+
129+
Ask the agent something only the live schema can answer:
130+
131+
> "What objects does this app have, and what fields does the main one carry?"
132+
133+
You should see `list_objects` and `describe_object` fire. The natural working
134+
pattern for an agent is `list_objects``describe_object``query_records`
135+
`run_action` — if all four work, the connection is fully operational.
136+
137+
Agents work noticeably better with the app's **skill file**: download it from
138+
`GET /api/v1/mcp/skill`, or install the
139+
[official Claude plugin](https://github.com/objectstack-ai/claude-plugin)
140+
(`claude plugin marketplace add objectstack-ai/claude-plugin`) which bundles the
141+
skill and a guided `/objectstack:connect` command.
142+
143+
## Troubleshooting
144+
145+
| Symptom | Cause → fix |
146+
|:---|:---|
147+
| `404` on `/api/v1/mcp` | The surface is disabled — unset `OS_MCP_SERVER_ENABLED` (default is on) |
148+
| `501 Not Implemented` | The MCP plugin isn't part of this build — check your stack's plugins |
149+
| `401` on every call | Anonymous or invalid credentials. Interactive clients: complete the browser login (the `WWW-Authenticate` header advertises the OAuth metadata). Headless: check the `osk_` key and header spelling |
150+
| `403 insufficient_scope` | The OAuth token lacks the scope for that tool family (e.g. writes without `data:write`) — reconnect and grant the scope |
151+
| An action is missing from `list_actions` | `ai.exposed` is not `true`, `ai.description` is shorter than 40 characters, the type isn't headless-callable (`url` / `modal` / `form` never appear), it targets a `sys_*` object, or the caller fails its `requiredPermissions` |
152+
| Reads return few rows / writes denied | Working as designed — the caller's permissions and RLS apply. Verify with the same user in the Console |
153+
154+
## Related
155+
156+
- [Actions as Tools](/docs/ai/actions-as-tools) — the `run_action` bridge and its governance
157+
- [Actions](/docs/ui/actions) — defining the actions you expose
158+
- [Your app as an MCP server](/docs/api#your-app-as-an-mcp-server) — the API-level view
159+
- [AI Agents](/docs/ai/agents) — building agents *inside* your app (the other direction)

content/docs/ai/meta.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"icon": "Bot",
44
"pages": [
55
"index",
6+
"connect-mcp",
67
"agents",
78
"actions-as-tools",
89
"knowledge-rag",

0 commit comments

Comments
 (0)