simplepractice-mcp 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +38 -13
- package/dist/auth.js +31 -4
- package/dist/bundle.js +401 -59
- package/dist/client.js +142 -27
- package/dist/config.js +41 -6
- package/dist/index.js +5 -2
- package/dist/tools/auth.js +35 -13
- package/dist/tools/health.js +103 -0
- package/dist/version.js +1 -1
- package/mint.yaml +74 -0
- package/package.json +8 -6
- package/server.json +4 -4
- package/skills/simplepractice/SKILL.md +17 -8
- package/skills/simplepractice-fpx/SKILL.md +13 -5
- package/skills/simplepractice-fpx/references/requests.md +18 -11
|
@@ -21,18 +21,27 @@ The portal has **no password**. SimplePractice emails a one-time link (or a
|
|
|
21
21
|
6-digit PIN), and that is the only way in.
|
|
22
22
|
|
|
23
23
|
1. `simplepractice_session_status` — check first; a session persists between
|
|
24
|
-
runs, so most of the time there is nothing to do.
|
|
25
|
-
|
|
24
|
+
runs, so most of the time there is nothing to do. It also reports which
|
|
25
|
+
practice is in play, and whether that came from a link, the environment, or
|
|
26
|
+
the saved session.
|
|
27
|
+
2. If the user already has the email, skip straight to step 4 — asking for a
|
|
28
|
+
second link when one is in their inbox spends a rate limit for nothing.
|
|
29
|
+
3. `simplepractice_request_sign_in_link` with the user's portal email. It is
|
|
26
30
|
confirm-gated because it sends a real email and the endpoint is rate-limited
|
|
27
31
|
**per address and per IP** — a retry loop locks the user out of the only
|
|
28
|
-
auth path there is. Ask before sending, and never send twice.
|
|
29
|
-
|
|
32
|
+
auth path there is. Ask before sending, and never send twice. If the server
|
|
33
|
+
does not know the practice yet, pass `practice` (the slug, host, or portal
|
|
34
|
+
URL) — otherwise it has no portal to ask.
|
|
35
|
+
4. The user opens the email and gives you the link. Pass it **whole** to
|
|
30
36
|
`simplepractice_verify_sign_in_token` — it takes the token out of the
|
|
31
|
-
fragment
|
|
37
|
+
fragment *and* the practice out of the host, which is why the whole link is
|
|
38
|
+
worth more than the token alone. Tokens are single-use and last 24 hours.
|
|
32
39
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
40
|
+
Nothing has to be configured: the practice comes from the link, and the stored
|
|
41
|
+
session remembers it. `SIMPLEPRACTICE_PRACTICE` only pins the server to one
|
|
42
|
+
practice. Two link shapes name no practice and need one already known — the
|
|
43
|
+
mobile variant on the bare `clientsecure.me` apex, and a bare token pasted
|
|
44
|
+
without its link.
|
|
36
45
|
|
|
37
46
|
There is no refresh token. When a session lapses the tools say to sign in
|
|
38
47
|
again; that means another email.
|
|
@@ -82,13 +82,21 @@ hammering it locks you out of the only auth path there is. Wait it out.
|
|
|
82
82
|
**b. Take the token out of the emailed link.** The link looks like
|
|
83
83
|
|
|
84
84
|
```
|
|
85
|
-
https://<practice>.clientsecure.me/sign-in/token
|
|
85
|
+
https://<practice>.clientsecure.me/sign-in/token#<TOKEN>
|
|
86
86
|
```
|
|
87
87
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
88
|
+
SimplePractice also mails a mobile-app variant on the bare apex,
|
|
89
|
+
`https://clientsecure.me/client-portal-api/sign-in/token#<TOKEN>`. Either
|
|
90
|
+
works — the path is irrelevant, only the fragment matters.
|
|
91
|
+
|
|
92
|
+
The token is the **URL fragment**, after the `#` (about 300 characters).
|
|
93
|
+
Because it is a fragment it is never sent to the server by a browser
|
|
94
|
+
navigation — the app reads it in JS and posts it. So you must copy it
|
|
95
|
+
yourself; following the link with `curl` does nothing.
|
|
96
|
+
|
|
97
|
+
If you are pulling the link out of a raw message rather than clicking it, note
|
|
98
|
+
the mail is **quoted-printable**: the URL is wrapped across lines with trailing
|
|
99
|
+
`=`, and a naive regex will hand you a silently truncated token. Decode first.
|
|
92
100
|
|
|
93
101
|
**c. Trade it for a session cookie.**
|
|
94
102
|
|
|
@@ -60,10 +60,20 @@ sp -X POST "$SP_API/sign-in-tokens" \
|
|
|
60
60
|
|
|
61
61
|
### 1.2 Exchange the token — `POST /sessions/token`
|
|
62
62
|
|
|
63
|
-
The emailed link is
|
|
64
|
-
|
|
65
|
-
the
|
|
66
|
-
|
|
63
|
+
The emailed link is
|
|
64
|
+
**`https://<practice>.clientsecure.me/sign-in/token#<TOKEN>`** — `/sign-in/token`,
|
|
65
|
+
*not* the `sign-in/token/verify` the app's route tree implies. A second variant,
|
|
66
|
+
sent for the mobile app, points at the bare apex under the API namespace:
|
|
67
|
+
`https://clientsecure.me/client-portal-api/sign-in/token#<TOKEN>`. Either works —
|
|
68
|
+
take the fragment, ignore the path.
|
|
69
|
+
|
|
70
|
+
The token is the **fragment** (303–317 characters observed). A browser never
|
|
71
|
+
sends a fragment to the server; the app reads `location.hash` and posts it.
|
|
72
|
+
Fetching the link with `curl` accomplishes nothing — copy the part after `#`.
|
|
73
|
+
|
|
74
|
+
Both emails are quoted-printable, so the URL is **wrapped across lines with
|
|
75
|
+
trailing `=`**. Pulling it out of a raw message with a naive regex silently
|
|
76
|
+
truncates the token — decode the quoted-printable first.
|
|
67
77
|
|
|
68
78
|
```sh
|
|
69
79
|
sp -X POST "$SP_API/sessions/token" \
|
|
@@ -80,13 +90,10 @@ Success sets the `simplepractice-session` cookie (Rails/Devise) and returns
|
|
|
80
90
|
| `expired` | older than 24h — request a new link |
|
|
81
91
|
| `merged` | the account was merged into another; sign in from the new portal |
|
|
82
92
|
|
|
83
|
-
Tokens are single-use
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
> `routes/sign-in/token/verify.js` + `services/sign-in.js`, but reading the
|
|
88
|
-
> emailed token was out of scope for the agent that wrote this. Treat
|
|
89
|
-
> `meta.status` handling as source-derived until you've run it once.
|
|
93
|
+
Tokens are single-use — confirmed by replay, which answers
|
|
94
|
+
`401 {"title":"Authorization has already been used or expired"}`. That is a 401
|
|
95
|
+
on a sign-in endpoint, where you have no session yet; it means *get a new
|
|
96
|
+
link*, not *your session expired*.
|
|
90
97
|
|
|
91
98
|
### 1.3 PIN variant — `POST /sessions/pin`
|
|
92
99
|
|