Skip to content

Commit 611247f

Browse files
baozhoutaoclaude
andcommitted
docs(ai): connect-mcp — record what a first real connection actually hits
Walked the page against a live app (Claude Code 2.1 + `@objectstack/mcp` 17.2) and wrote down the four places a first attempt stalls that the page did not cover: - OAuth track: after `claude mcp add`, `claude mcp list` reports "Failed to connect" until `/mcp` → Authenticate is done in a NEW session — the health probe is answered 401, not a broken setup. A running session never picks the server up. - API-key track: where the key is minted (Setup → Connect an Agent, page route, button at the bottom, shown once with a ready `x-api-key:` line), that a keyed registration shows "Connected" with no login, and that `claude mcp add` is local-scope by default (`-s user` for everywhere). - Verify: an anonymous curl that must return 401, and a keyed curl walk through initialize → tools/list → query_records, with the two gotchas that cost a retry — the argument is `objectName`, and its value is the API name from `list_objects` (`crm_opportunity`, not `opportunity`). - Troubleshooting: four rows for the above symptoms. Docs-only; publishes nothing. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
1 parent 460134a commit 611247f

1 file changed

Lines changed: 70 additions & 5 deletions

File tree

content/docs/ai/connect-mcp.mdx

Lines changed: 70 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,31 @@ claude mcp add --transport http my-app http://localhost:3000/api/v1/mcp
2929
claude mcp add --transport http my-app https://your-deployment.example.com/api/v1/mcp
3030
```
3131

32-
For headless use (CI, containers) skip OAuth and attach an
33-
[API key](#headless-api-keys) instead:
32+
Then **open a new Claude Code session** and run `/mcp` — pick the server and
33+
choose *Authenticate* to complete the browser login. Two things to expect on
34+
this track:
35+
36+
- Until that login has happened, `claude mcp list` / `claude mcp get my-app`
37+
report the server as **✘ Failed to connect**. That is the health probe being
38+
answered with a 401, not a broken setup — the status flips once the session
39+
is authenticated.
40+
- A Claude Code session that was already running when you ran `claude mcp add`
41+
does not pick the server up; start a fresh one.
42+
43+
For headless use (CI, containers), or whenever you would rather not go through
44+
the browser login, skip OAuth and attach an [API key](#headless-api-keys)
45+
instead — with a key the server reports **✔ Connected** immediately, no login
46+
step:
3447

3548
```bash
3649
claude mcp add --transport http my-app https://your-deployment.example.com/api/v1/mcp \
3750
--header "x-api-key: osk_..."
3851
```
3952

53+
`claude mcp add` registers the server at **local** scope by default — visible
54+
only from the directory you ran it in. Add `-s user` to make it available from
55+
every project.
56+
4057
## Claude Desktop and claude.ai
4158

4259
**Settings → Connectors → Add custom connector**, then paste the MCP URL
@@ -61,8 +78,16 @@ Clients that read an `mcpServers` map connect the same way. With an API key:
6178

6279
## Headless: API keys
6380

64-
Mint a key from **Setup → Connect an Agent** in the Console (which also shows
65-
copy-paste-ready connect snippets per client), or over REST:
81+
Mint a key from **Setup → Connect an Agent** in the Console: the page lives at
82+
`/_console/apps/com.objectstack.setup/page/connect_agent` (a link in the Setup
83+
sidebar takes you there), and the **Create key** button sits at the bottom
84+
under *API keys*. The new key is shown **once**, together with a ready-to-paste
85+
`x-api-key: osk_...` header line — copy it before you dismiss the panel. The
86+
same page carries copy-paste connect snippets for Claude Code, Claude Desktop,
87+
Cursor, VS Code, and Codex, and a download link for the app's `SKILL.md`.
88+
Existing keys are listed (prefix only) and revoked under **Setup → API keys**.
89+
90+
Or mint one over REST:
6691

6792
```bash
6893
curl -b cookies.txt -X POST https://your-deployment.example.com/api/v1/keys
@@ -217,7 +242,43 @@ drive this MCP server. Same word, different layer.
217242

218243
## Verify the connection
219244

220-
Ask the agent something only the live schema can answer:
245+
Before involving a client, prove the server itself is answering — the anonymous
246+
probe below must return `401`, which is the surface saying "present, needs a
247+
credential" (a `WWW-Authenticate` header naming the OAuth resource metadata
248+
means the browser-login track is live too). Anything else is a server-side
249+
issue; see [Troubleshooting](#troubleshooting).
250+
251+
```bash
252+
curl -s -o /dev/null -w "%{http_code}\n" -X POST http://localhost:3000/api/v1/mcp \
253+
-H 'content-type: application/json' -d '{}'
254+
# → 401
255+
```
256+
257+
With an API key you can drive the whole protocol from the shell — a handshake,
258+
the tool list, and one real read:
259+
260+
```bash
261+
MCP=http://localhost:3000/api/v1/mcp
262+
KEY=osk_...
263+
call() { curl -s -X POST "$MCP" -H "x-api-key: $KEY" \
264+
-H 'content-type: application/json' -H 'accept: application/json, text/event-stream' -d "$1"; }
265+
266+
call '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"probe","version":"0"}}}'
267+
# → {"result":{"serverInfo":{"name":"objectstack",...},"capabilities":{"tools":{...},"prompts":{}}},...}
268+
269+
call '{"jsonrpc":"2.0","id":2,"method":"tools/list"}' | grep -o '"name":"[a-z_]*"'
270+
# → the eleven tools, list_objects … run_action
271+
272+
call '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"query_records","arguments":{"objectName":"crm_opportunity","limit":3}}}'
273+
# → {"result":{"content":[{"type":"text","text":"{ \"object\": \"crm_opportunity\", \"records\": [ ... ], \"total\": 23, \"hasMore\": true }"}]}}
274+
```
275+
276+
Two details that trip up a first attempt: the object argument is
277+
**`objectName`**, and its value is the object's API name as returned by
278+
`list_objects` (`crm_opportunity`, not `opportunity`) — a wrong name comes back
279+
as `Object 'opportunity' not found`.
280+
281+
Then, in the client, ask the agent something only the live schema can answer:
221282

222283
> "What objects does this app have, and what fields does the main one carry?"
223284
@@ -235,6 +296,10 @@ skill and a guided `/objectstack:connect` command.
235296

236297
| Symptom | Cause → fix |
237298
|:---|:---|
299+
| `claude mcp list` says **✘ Failed to connect** right after `claude mcp add` (OAuth track, no `--header`) | Expected until you authenticate — open a new session, run `/mcp`, pick the server, *Authenticate*. Or attach an API key, which connects without a login step |
300+
| **✘ Failed to connect** / `ConnectionRefused` on a server that used to work | The app is not running. Start it — the client reconnects on its own, no need to re-register |
301+
| The server is missing from `/mcp` in a running session | Sessions read MCP config at start — open a new one. If it is still missing, you registered at **local** scope from another directory; re-add with `-s user` |
302+
| `Object 'x' not found` on `query_records` / `get_record` | Wrong object name — pass the API name from `list_objects` in **`objectName`** (`crm_opportunity`, not `opportunity`) |
238303
| `404` on `/api/v1/mcp` | The HTTP surface is disabled — unset `OS_MCP_SERVER_ENABLED` (default is on) |
239304
| `501 Not Implemented` | The MCP plugin isn't part of this build — check your stack's plugins |
240305
| `mcp` missing from `GET /api/v1/discovery` and no Connect-an-Agent card, but `OS_MCP_SERVER_ENABLED` is on | The same cause as the `501` above, seen from the other side: the surface is *enabled* but not *serveable*, so discovery declines to advertise a route that would 501 rather than over-promising it (`declared === enforced`). Load the MCP plugin — `os serve` / `os dev` do it for you; a host that embeds `@objectstack/rest` directly must add `@objectstack/mcp` itself |

0 commit comments

Comments
 (0)