The UnderSelf MCP server is a Streamable HTTP endpoint at https://api.underself.io/mcp. It speaks OAuth 2.1 with discovery, dynamic client registration and PKCE, so any compliant MCP client connects the same way Claude does: paste the URL, sign in, approve.
Updated September 24, 2026
https://api.underself.io/mcpLooking for the friendly version? See the guide for Claude, Grok, ChatGPT, Gemini or Meta Muse, or see every supported app.
| Requirement | UnderSelf |
|---|---|
| Transport | Streamable HTTP, stateless, JSON responses. POST /mcp only; GET /mcp answers 405. No SSE stream and no Mcp-Session-Id. |
| Authorization | OAuth 2.1, authorization code grant with PKCE (S256 only). |
| Discovery | Protected resource metadata (RFC 9728) and authorization server metadata (RFC 8414). |
| Client registration | Dynamic client registration (RFC 7591). Token endpoint auth: none, client_secret_post or client_secret_basic. |
| Scopes | dreams:read and dreams:write. Ask for none and you get both. Consent is all or nothing today. |
| Bearer | Authorization: Bearer <access token> header only. |
No dynamic registration?.A client that cannot register itself cannot connect on its own today. Write to info@underself.io with your client's name and redirect URI and we will set it up with you.
POST https://api.underself.io/mcp answers 401 with WWW-Authenticate: Bearer resource_metadata="https://api.underself.io/.well-known/oauth-protected-resource/mcp".GET /.well-known/oauth-protected-resource/mcp names the resource (https://api.underself.io/mcp), the authorization server (https://api.underself.io) and the scopes.GET /.well-known/oauth-authorization-server lists the authorize, token, registration and revocation endpoints, S256, and the supported grants.POST your client metadata, including your redirect URIs, to the registration_endpoint. You get a client_id, and a client_secret if you asked for one.authorization_endpoint in the user's browser with response_type=code, your client_id, redirect_uri, state, code_challenge, code_challenge_method=S256 and resource=https://api.underself.io/mcp.app.underself.io/connect/. They sign in with Google or Apple, see your app's name, the host you send them back to and what you can do, and choose Approve or Cancel. On Approve, the browser returns to your redirect_uri with code, state and iss.POST the code and your code_verifier to the token_endpoint. You get an access token (a JWT with audience https://api.underself.io/mcp, valid 15 minutes) and a refresh token.POST /mcp with the bearer token: initialize, tools/list, tools/call. Refresh before the access token expires.curl -s https://api.underself.io/.well-known/oauth-protected-resource/mcp
curl -s https://api.underself.io/.well-known/oauth-authorization-serveropenid-configuration answers 404.UnderSelf is an OAuth authorization server, not an OpenID provider, so /.well-known/openid-configuration answers 404. That is expected. Use /.well-known/oauth-authorization-server.
| Item | Lifetime and behaviour |
|---|---|
| Access token | 15 minutes. |
| Refresh token | Opaque and rotated on every use: always store the new one. A connection lapses after 30 days without use, and after 90 days at most. Then the user reconnects. |
| Revocation | POST to the revocation_endpoint when the user removes your connector. The user can also disconnect from app.underself.io/account, Connected apps. |
| After a disconnect | Refresh stops at once; the last access token stops working within 15 minutes. |
| Tool | Scope | What it does |
|---|---|---|
record_dream | dreams:write | Saves a dream (20 to 20,000 characters) and, by default, returns its reading. |
analyze_dream | dreams:write | A new reading of a saved dream. |
get_dream | dreams:read | One dream with its text, summary and latest reading. |
list_dreams | dreams:read | Dreams newest first, up to 50 per page, optionally for one night. |
search_dreams | dreams:read | Dreams whose text or summary mention the query (first 100 characters). |
get_patterns | dreams:read | The insights chapter, recording activity and the Inner Map. |
tools/list shows only the tools the token's scopes allow. A connection reaches nothing outside these six: no delete, no billing, no account changes. Full inputs and outputs are in the tools reference.
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "list_dreams",
"arguments": { "limit": 2 }
}
}{
"dreams": [
{
"dream_id": "3f2a9c1e-0000-4000-8000-000000000001",
"date": "2026-09-23",
"summary": "Walking through a familiar house that keeps opening onto new rooms.",
"has_reading": true
},
{
"dream_id": "3f2a9c1e-0000-4000-8000-000000000002",
"date": "2026-09-21",
"summary": "A slow train along a coast at dusk.",
"has_reading": false
}
],
"page": 1,
"total": 14,
"total_pages": 7
}Every result carries the JSON both as structuredContent and as text, for clients that read only text. A failure is a normal tool result with isError: true and one plain sentence your assistant can read aloud.
| Sentence the tool returns | What happened |
|---|---|
| This account has reached its dream limit; upgrade at https://underself.io/plans | The plan's dream limit is reached. Nothing was saved. |
| This account has reached its dream reading limit; upgrade at https://underself.io/plans | The plan's reading limit is reached. From record_dream, the dream is still saved, without a reading, and the note says so. |
| This account has reached its dream message limit; upgrade at https://underself.io/plans | The plan's message limit is reached while saving the dream text. |
| This account cannot use UnderSelf right now | The account is blocked. |
| This connection is not allowed to do that; reconnect UnderSelf and approve the access it needs | The token lacks the scope for this call. |
| No dream with that id was found in this UnderSelf account | Wrong dream_id, or a dream from another account. |
| The connection to UnderSelf has expired; reconnect it and try again | The token is expired or revoked. Refresh, or reconnect. |
| UnderSelf is getting too many requests from this account; wait a minute and retry | The per account rate limit was hit. |
| UnderSelf took too long to answer; try again in a moment | An upstream call timed out. |
| The reading is taking longer than expected and may still finish; call get_dream in a minute before asking again | From analyze_dream: the reading is still running. Check with get_dream before asking again. |
| UnderSelf could not complete that right now; try again later | Something failed on our side. |
| Give a word or phrase to search for | search_dreams got an empty query. |
| UnderSelf could not accept that: (reason) | The request was invalid; the reason follows. |
record_dream with the same text from the same account within 10 minutes returns the earlier dream with duplicate: true, so an agent retry never spends a second dream.record_dream still returns the saved dream_id with a note; call get_dream a minute later, and analyze_dream only if it still has no reading.status: "incomplete" and the dream_id. Call record_dream again with the same text within 10 minutes to finish it on the same dream./mcp.Questions, or a client that will not connect? Write to info@underself.io.