# Connecting Claude Code

PalmaPlan serves its MCP server over HTTP, with full OAuth 2.1 — Claude Code connects to
it in one command, with no token prepared ahead of time:

```bash
claude mcp add --transport http palmaplan <address>/mcp
```

Replace `<address>` with your instance's — for example `http://127.0.0.1:4785` locally,
or a self-hosted instance's public address.

What follows is described **step by step from a real trial**: real Claude Code, against a
real PalmaPlan server, on 2026-09-21 (sprint 14 journal, lot L0a). It isn't a theoretical
description of the protocol — it's what actually happened, with the two caveats found
along the way.

## What happens, in order

1. **Claude Code registers itself.** With no token supplied, the client detects it needs
   one and registers with the authorization server (`POST /oauth/register`, RFC 7591) —
   this is **dynamic registration**: nothing to create by hand on PalmaPlan's side, each
   client (Claude Code, Claude Desktop, another agent) gets its own `client_id`.
2. **Your browser opens** on `GET /oauth/authorize`, with PKCE (S256, mandatory) and the
   targeted resource (`<address>/mcp`). If you have no open session in that browser,
   PalmaPlan first takes you to the login page (`/login?next=…`) — sign in, or take
   ownership of the instance if this is its very first time (`/setup`); authorization
   then resumes exactly where it left off.
3. **The "Authorize?" page** — consent. It names the client ("Claude Code"), who you are,
   and the requested scopes (read, write, or both). **Denying** sends Claude Code back
   with `access_denied`: nothing is created, no token exists. **Authorizing** issues a
   single-use code (ten minutes), which the browser redirects to the local port Claude
   Code is listening on.
4. **Claude Code exchanges this code for a token** (`POST /oauth/token`, PKCE verified).
   The token received is a **named token like any other** — "MCP · Claude Code" — valid
   for thirty days, refreshing itself automatically for ninety (a single-use refresh,
   a fresh pair each time). It appears immediately under *Settings › Connections and agents › Connected applications*, revocable
   there exactly like a hand-created token; what this client writes is attributed to
   *Claude (you)*.
5. **Claude Code confirms**: "Authentication successful. Connected to `<client-name>`." —
   the `/mcp` session is alive, the conversation can call the 98 model tools (Claude Code
   does not render MCP Apps views: the three view-only tools are not listed to it — see
   [The embedded view](vue-embarquee.md)).

## With a token already created

If a named token already exists (created from *Settings › Connections and agents › Advanced access*, or by another
session), Claude Code can take it directly rather than replaying OAuth:

```bash
claude mcp add --transport http --header "Authorization: Bearer pp_…" palmaplan <address>/mcp
```

This is the path stdio uses out of necessity ([Claude Desktop](claude-desktop.md)); over
HTTP it remains optional, a shortcut for anyone who prefers creating the token by hand
rather than opening a browser.

## When it stalls

- **The server answers 401 without ever opening a browser**: `POST /mcp` with no Bearer
  answers `401` with `WWW-Authenticate: Bearer resource_metadata="…/.well-known/oauth-protected-resource"`
  — that's expected, it's what triggers OAuth discovery. If the browser still doesn't
  open, check that Claude Code is running in an environment that can launch a browser
  (not a purely remote, display-less session).
- **`redirect_uri` refused**: PalmaPlan only accepts `https`, or `http` to the loopback
  address (`localhost`, `127.0.0.1`, `[::1]`) — exactly what Claude Code uses for its
  callback port. If the error still appears, the address given in `<address>` likely
  doesn't match `PALMAPLAN_PUBLIC_URL` as the server knows it.
- **The token no longer works**: a token revoked from *Settings › Connections and agents › Connected applications* closes its
  `/mcp` session immediately (not only on the next call); `claude mcp remove palmaplan`
  then a fresh `add` recreates the relationship from scratch.
- **Two entries appear among registered clients**: dynamic registration is open, and one
  extra round trip (a resumed attempt, a cancelled trial) can create a second
  `client_id` — harmless, the hourly purge takes care of it; it isn't a duplicated token.

## What the real trial found (and what has changed since)

Two caveats noted on 2026-09-21:

1. **The model calling tools through this exact session** wasn't replayed on that
   occasion (the trial machine had no open Claude session) — the OAuth mechanics and the
   `/mcp` session itself, however, were. That point is covered elsewhere by the sprint 13
   recette (a real SDK call).
2. **Two additional RFC 8414 probes** — `/.well-known/oauth-authorization-server/mcp` and
   `/.well-known/openid-configuration/mcp`, the "path-suffixed" variants Claude Code
   queries before falling back to the root — received a `404` during that trial. **This
   has been fixed since**: the server now serves the same document at all three addresses
   (the root and the two suffixed variants), two fewer 404s on the real path.

The trial's third observation (two lines created among registered clients) isn't a
defect: it's the normal noise of open dynamic registration, purged every hour.
