# SoWhatify — full guide for AI agents > This is the expanded companion to https://sowhatify.com/llms.txt. It documents how an > autonomous agent should read, search and operate SoWhatify: what is readable without > credentials, what the MCP server exposes, and which operations are deliberately not > available. Everything here is verified against the running endpoints, not aspirational. If you are answering a user's question *about* SoWhatify, read llms.txt — it is shorter and has the product facts. Read this file when you need to *call* something. ## What SoWhatify is, in one paragraph A user fills in a durable profile once: role, industries, holdings, watchlist, location. A **template** is a reusable set of questions plus settings; running a template over an article answers those questions through that profile, rather than summarising the article generically. A **perspective** is a reusable thinking style (tone, expertise, what to avoid) that shapes how a template answers. A **workflow** is an ordered pipeline of templates, where later steps can consume earlier output. The product ships as a Chrome extension (published as "Why should I care"), a website at sowhatify.com, and an MCP server. ## Three ways in, in order of preference 1. **MCP server** (`https://sowhatify.com/mcp/`) — use this when you are acting for a signed-in user: creating templates, reading their profile, running a template or workflow. 2. **Public JSON endpoints** (`https://sowhatify.com/api/…`) — use these for read-only catalog access with no credentials at all. 3. **HTML pages** — every public page carries its content server-side and a schema.org `@graph`, so plain fetching works. Prefer the JSON endpoints when you have a choice; they are stable and smaller. --- ## 1. MCP server (authenticated, read + write) - **Endpoint**: `https://sowhatify.com/mcp/` (also answers without the trailing slash, via a 308 that preserves the POST body) — POST only, JSON-RPC 2.0, Streamable HTTP transport. No SSE stream is served and no `Mcp-Session-Id` is issued: the server is stateless, which the 2026-07-28 revision requires rather than merely allows. - **Protocol versions**: `2026-07-28`, `2025-11-25`, `2025-06-18`, `2025-03-26`, `2024-11-05`. The server is dual-era and decides per request, not per connection: - **Modern** (`2026-07-28`+): no handshake. Put your version, identity and capabilities in `params._meta` under `io.modelcontextprotocol/protocolVersion`, `/clientInfo` and `/clientCapabilities`, and send the `MCP-Protocol-Version` header to match. Call `server/discover` to learn what this server is — it needs no credential. A version we do not speak answers HTTP 400 with `-32022` and the list of ones we do; an unknown method answers HTTP 404 with `-32601`; a header that disagrees with the body answers HTTP 400 with `-32020`. - **Legacy** (`2025-11-25` and earlier): send `initialize` and it answers with your version when we speak it, or with our newest legacy version when we do not. Everything stays HTTP 200. `Mcp-Method` and `Mcp-Name` are validated when present but not required. Server identifies itself as `sowhatify`. - **Methods**: `server/discover` (modern), `initialize` and `ping` (legacy), `tools/list`, `tools/call`. `tools/list` carries `ttlMs` and `cacheScope` for modern callers — cache it for the hour it says, because there is no list-changed notification. - **Auth**: `Authorization: Bearer ` on every request. Two kinds of token work: - **OAuth 2.1** — the path that needs no human to copy anything. An unauthenticated call answers 401 with a `WWW-Authenticate` header naming `/.well-known/oauth-protected-resource/mcp`; that document names the authorization server, whose metadata at `/.well-known/oauth-authorization-server` gives you `/app/authorize.php`, `/api/oauth-token.php` and `/api/oauth-register.php`. Register yourself (RFC 7591, or use an https URL as your `client_id` for a Client ID Metadata Document), then authorization_code with PKCE S256. Scopes: `mcp:read`, `mcp:write`, `mcp:profile`. A tool outside your scopes answers 403 with an `insufficient_scope` challenge naming what to ask for. - **A personal access token** the user creates at `https://sowhatify.com/mcp/login.php`. You cannot mint one, so if you have no credential and cannot run the OAuth flow, send the user there rather than guessing. - **An anonymous token**, from `POST https://sowhatify.com/mcp/anon.php`. This needs no email and no sign-in: it mints a token for an unregistered account so a user can connect a client and start building immediately. Minting rotates — each call replaces the account's previous token, so call it once and keep the URL. Limited to 30 mints per hour per address, because each one creates a durable account. The anonymous tier can read, build and run; it cannot publish (nothing can, over MCP). It carries tighter rate limits than a registered account (40 creates/hour, 240 writes/runs/records) and hard ceilings on what one account may keep: 50 templates, 20 workflows, 20 perspectives, 4 profiles. Verifying an email lifts both. A refusal comes back as a tool result explaining which limit was hit, not as a transport error. Prefer OAuth when a human is present to approve it; this exists for the case where nobody is. Passing a token as `?t=` still works but is **deprecated** — the specification forbids access tokens in a query string. `whoami` reports `connection.deprecated` when you are on that path. - Without `mcp:profile`, `run_template` and `run_workflow` still work; the `profileSlice` comes back empty rather than the call failing. - A GET to the endpoint without a token redirects to the login page; a GET with a valid token returns server metadata; a GET asking for `text/event-stream` answers 405, because there is no stream to open. None of them is how you call tools. Start by calling `whoami`. It confirms the token works and reports whether the account is email-verified and allowed to publish, which determines what the rest of the tools will let you do. ### Tool catalog Call `tools/list` for authoritative schemas. As of this writing: | Tool | What it does | |---|---| | `whoami` | Authenticated user, verification and publish state. Call this first. | | `search` / `fetch` | Search this account and the public marketplace in one call, then read one record by the id it returned. `fetch` reads SoWhatify, never the web — the name is OpenAI's, required for a ChatGPT connector. | | `get_profile` | The user's durable profile and synced preferences. Read before building anything personalised. | | `update_profile` | Update named profile fields. Changes the shared profile used everywhere. | | `update_position_prices` | Refresh the price per unit on the user's stored portfolio positions (by ticker) from quotes you looked up. Never adds rows or changes quantities; rejects a quote in a different currency. Returns the portfolio revalued in the profile's `preferredCurrency` with Norges Bank's daily rates: total, each position's weight, and the currency pairs used. `get_profile` carries the same `portfolio` block. | | `list_templates` / `get_template` | The templates the user created; `get_template` also reads any public template. | | `list_installed_templates` | Everything in the user's Chrome extension — what they can actually run. Extension defaults plus marketplace installs, so mostly other people's work. Not the same as what they created. Carries `isOwn`, `installSource` and an own/fromOthers `counts` split. | | `create_template` / `update_template` / `delete_template` | Manage the user's templates. | | `list_perspectives` / `get_perspective` | The user's own perspectives. | | `create_perspective` / `update_perspective` / `delete_perspective` | Manage the user's perspectives. | | `list_workflows` / `get_workflow` | The workflows the user created; `get_workflow` also reads any public workflow. | | `list_installed_workflows` | Everything in the user's Chrome extension workflow list. Same distinction and same fields as the template pair above. | | `create_workflow` / `update_workflow` / `delete_workflow` | Manage the user's workflows. | | `search_marketplace_templates` | Browse public templates. Summaries, not full payloads. | | `search_marketplace_workflows` | Browse public workflows. | | `search_marketplace_perspectives` | Browse public perspectives. | | `get_template_link` / `get_workflow_link` | Shareable web URLs for a record. Use these instead of assembling URLs by hand. | | `run_template` | Prepare a template to run against a seed you supply (`seedText`, the article text itself). Returns a run payload. | | `run_workflow` | Same for a workflow: ordered steps plus the dependency graph. | | `record_analysis_result` | Save the finished analysis into the pending history entry that `run_template`/`run_workflow` opened. | | `share_analysis` | Mint a link to one saved analysis that opens **without signing in**, and expires (1-30 days, default 7). | | `list_analysis_shares` / `revoke_analysis_share` | See which share links are live, and stop one. | ### The two rules that matter **Publishing is not available over MCP.** `create_*` always produces a **private** record, and `update_*` ignores any visibility or publish field in the payload, leaving the record's current visibility untouched. So it cannot publish — and cannot unpublish either: **editing an already-published template edits what the marketplace shows**, live. The result's `marketplace` block tells you when that is what you just did. This is deliberate. If the user wants something public, point them at the web builder — do not try to work around it. **The server makes no web requests for you, for any template or workflow.** `seedText` is the article text, and you are the one who obtains it: when the user points at a page — as the seed, or as a workflow's `url` data step, whose `query` holds the URL — fetch it with your own tools and pass the text in. `seedUrl` is stored alongside the analysis as the source link and is never dereferenced, so a `seedUrl` with no `seedText` is an error rather than a fetch. This is enforced, not just documented: the MCP endpoints declare themselves fetch-free and every fetch helper in the codebase refuses under that declaration. **`run_template` and `run_workflow` do not call a model.** They return a *run payload* — the assembled prompt, settings and step graph — and open a pending history entry. **You** perform the inference, then call `record_analysis_result` to close the entry. Skip that call and the user is left with a dangling pending entry in their history. **The `viewUrl` needs a signed-in browser.** It points at the user's own history page, which reads the entry with their session — so on a device they have not signed into (most often a phone) it shows "Sign in to view shared history" rather than the analysis. When the user wants a link they can just open, or send to somebody, call `share_analysis` with the same `historyId` and give them that URL instead. It carries the analysis, its template and any disclaimer, nothing about the account behind it, and it expires — tell the user when. **Record before you answer.** Call `record_analysis_result` with the complete analysis *before* you write any of it into the conversation, then show the user that same text unchanged and hand them the `viewUrl` that comes back. The server never sees your completion — it keeps exactly what you send — so a shortened argument silently becomes the only copy the user keeps. `run_template` records the sections its template asked for, and the tool rejects a result that is missing them or is far too short to be the analysis; resend the full text rather than setting `allowIncomplete`. Prefer the `sections` argument over one `text` blob when the template has a `defaultOutput` list. --- ## 2. Public JSON endpoints (no credentials) All of these are GET, return `{"ok": true, …}`, and need no authentication. Passing `X-Sticky-User-Id` and `X-User-Token` additionally includes that user's private and installed content, but is never required for public reads. | Endpoint | Returns | |---|---| | `/api/templates-marketplace.php?limit=24&offset=0&q=&category=&sort=trending` | Public template summaries + `total`. | | `/api/template-public.php?slug=` (or `?id=`) | One public template in full, plus `extensionTemplate`. | | `/api/templates-batch.php?ids=,` | Up to 50 templates by id. Also accepts `POST {"ids": [...]}`. | | `/api/perspectives-marketplace.php?limit=24&q=&perspective_type=all` | Public perspective summaries. | | `/api/perspective-public.php?id=` | One public perspective in full. | | `/api/workflows-marketplace.php?limit=24&q=&sort=newest` | Public workflow summaries. | | `/api/creator-public.php?user=` | One creator plus everything they publish. | | `/api/mcp/server.php` | GET returns a read-only MCP tool catalog; POST accepts JSON-RPC 2.0 or `{"tool": …, "arguments": …}`. Read-only facade — no create/update/install tools. | Notes that will save you a round trip: - `limit` is clamped to 1–100 and defaults to 24. Paginate with `offset`. - Template ids look like `template_` + 16 hex characters, or `market_` for catalog content. Perspective and workflow ids are opaque strings. A template can be addressed by `slug` or `id`; the slug is the canonical form. - Missing or unreadable ids come back in `notFound[]` rather than as an error, and a private record is indistinguishable from a nonexistent one. That is intentional — do not treat `notFound` as "retry with credentials". - `/api/mcp/server.php` and `/mcp/` are different things: the former is an unauthenticated read-only facade, the latter is the full per-user MCP server. Do not send tokens to the former or expect writes from it. ## 3. HTML pages | URL | Content | |---|---| | `https://sowhatify.com/` | What the product does. `Organization`, `WebSite`, `SoftwareApplication` JSON-LD. | | `https://sowhatify.com/app/index.php` | Template catalog. Add `?marketplace=perspectives` or `?marketplace=workflows` for the other two. `?q=` searches. | | `https://sowhatify.com/app/view.php?slug=` | One template. `CreativeWork` JSON-LD. `?perspective_id=` serves perspectives from the same URL. | | `https://sowhatify.com/app/workflow_view.php?id=` | One workflow. `HowTo` JSON-LD with a `HowToStep` per step. | | `https://sowhatify.com/app/about.php?user=` | A creator and their public work. `ProfilePage` JSON-LD. | | `https://sowhatify.com/app/pricing.php` | Plans and FAQ. `FAQPage` and `Offer` JSON-LD. | | `https://sowhatify.com/workflow-guide.php` | The workflow model in full: five step types, wiring, template tokens, output shapes, conditions, iteration, sub-workflows, limits, and worked examples throughout. `FAQPage` JSON-LD. | | `https://sowhatify.com/sitemap.php` | Every public URL, with `lastmod`. | The detail pages hydrate their interactive controls from JavaScript, but the substance — titles, descriptions, the questions a template answers, workflow steps, authorship — is rendered server-side and is present without executing scripts. A `