server.json
1 field changed
- version
-
1.4.01.4.1
io.github.chrischall/artsonia-mcp
11 changes recorded. MCP Harbor re-reads this listing from the official registry every six hours and asks the live server what it exposes, and keeps what changed between one look and the next.
https://raw.githubusercontent.com/chrischall/artsonia-mcp/HEAD/AGENTS.md
− # AGENTS.md− This file provides guidance to coding agents when working with code in this repository.− ## TL;DR− MCP server for **Artsonia** (artsonia.com — kids' artwork portfolios). Cookie-session archetype: there is no public API, so the server logs into the parent/fan website with a username + password, harvests the resulting HttpOnly session cookie, and scrapes/POSTs the member pages. 15 tools across students, portfolio/artwork, comments, fans, teacher feedback, awards, account profile, image downloads, and a small set of confirmation-gated writes.− Two transport modes, selected by `ARTSONIA_TRANSPORT`:− 1. **`fetch` (default, direct)** — Node `fetch` against the site. The server owns the session: `AuthManager` runs the username/password login (POST `/members/login.asp`), keeps the cookie jar, and re-logs-in once on expiry.− 2. **`fetchproxy` (optional, browser-session)** — requests ride the user's already-signed-in browser tab via `@fetchproxy/server`. The browser carries the session, so the server-side login is **skipped entirely** (`usesBrowserSession = true`). No `ARTSONIA_USERNAME/PASSWORD` needed in this mode.− ## Auth resolution− `src/auth.ts` owns the username/password login and the cookie session. It delegates the single-flight login + invalidate/re-login + one-replay-on-expiry to the shared `CookieSessionManager` from `@chrischall/mcp-utils/session`, typed over `ArtsoniaResponse` so the custom transport's response flows through `withSession()` untouched.− - **Env vars:** `ARTSONIA_USERNAME` + `ARTSONIA_PASSWORD` (required in direct mode), `ARTSONIA_TRANSPORT` (`fetch` default | `fetchproxy`), `ARTSONIA_WS_PORT` (fetchproxy WebSocket port override; default `37149` — a shared fleet port, do NOT change), `ARTSONIA_INLINE_DOWNLOADS` (`1`/`true`/`yes`/`on` ⇒ inline image downloads; unset/false ⇒ disk — see "Download I/O" below), `ARTSONIA_SESSION_CACHE` (`false` disables the on-disk session cache; default on, direct mode only) and `ARTSONIA_SESSION_FI− - **Deferred config error:** the `client` is a module singleton constructed in `src/client.ts` (NOT `index.ts`), so the server boots and answers the host's install-time `tools/list` probe even with no creds. The missing-creds error is cached as a *permanent* error (`CONFIG_ERROR_MARKER`) and only surfaces on the first tool call — every later `ensure()` rethrows it rather than retrying a login that can never succeed.− - **Login success marker:** `doLogin()` POSTs `Username`/`Password`/`TargetUrl=/members/`/`Action=login` with `redirect: 'manual'` and treats a 301/302 whose `Location` is NOT `login.asp` (plus a non-empty cookie jar) as success. Magic-link-only accounts are unsupported.− - **Expiry heuristic (`looksUnauthenticated`):** Artsonia expires by redirecting/rendering back to the login page (NOT a 401). Detected from the final URL, login-page body markers (`You need to log in` / `Parent (or Fan) Login`), or a manual 3xx `Location` pointing at `login.asp`.− ### The two-mode split (in `src/client.ts`)− - **Browser-session mode** (`transport.usesBrowserSession === true`): the request is sent straight through — no server jar, no `Cookie` header override, no `withSession()`. If the response looks unauthenticated, the client throws a browser-specific hint ("Open www.artsonia.com in the bridged browser tab and sign in").− - **Direct mode:** every authed request goes through `auth.withSession()`, which ensures a live session, runs the request, and on an `isExpired` signal invalidates + single-flight re-logs-in + replays **exactly once**. A still-login-looking final response surfaces as a clean sign-in error.− ## Architecture− ```− src/− index.ts # Entry — runMcp({name,version,banner,tools}); wires the 8 register*Tools modules over the client singleton− client.ts # ArtsoniaClient: fetchHtml() (GET) / write() (POST). Owns the two-mode split + dotenv load + client/AuthManager singleton− auth.ts # AuthManager: username/password login + looksUnauthenticated(); delegates session lifecycle to CookieSessionManager; jar is the shared CookieJar from @chrischall/mcp-utils (absorb()/header(); deletion = Max-Age<=0 or pre-2000 Expires)− transport.ts # ArtsoniaRequest/Response/Transport types, ARTSONIA_ORIGIN, makeTransport() (picks fetch vs fetchproxy by env)− transport-fetch.ts # FetchArtsoniaTransport: default Node fetch; manual redirect on login POST, follow on reads; 30s timeout− transport-fetchproxy.ts # FetchproxyArtsoniaTransport: usesBrowserSession=true; thin adapter over createFetchproxyTransport (@chrischall/mcp-utils/fetchproxy), lazy-imported + memoized one-time start on the shared port− parse.ts # node-html-parser scrapers: parseStudents, parseNotifications, parsePortfolio, parseArtwork, parseFans, parseFeedback, parseAwards, parseProfile + artworkImageUrl()− version.ts # VERSION constant (x-release-please-version marker)− tools/− healthcheck.ts # artsonia_healthcheck− students.ts # artsonia_list_students, artsonia_get_activity− portfolio.ts # artsonia_get_portfolio, artsonia_get_artwork, artsonia_list_comments− fans.ts # artsonia_get_fans− feedback.ts # artsonia_get_feedback, artsonia_mark_feedback_read− account.ts # artsonia_get_awards, artsonia_get_profile− download.ts # artsonia_download_artwork + buildFilename()/buildRelPath() + FETCH_CONCURRENCY + the DownloadIO/DownloadContentBlock interface (imports NO node:fs)− download-io.ts # NodeDownloadIO: disk-backed IO (persistsFiles=true). The ONLY module in the download path that touches node:fs− download-io-inline.ts # InlineDownloadIO: filesystem-free IO (persistsFiles=false) — accumulates image bytes and returns them as base64 MCP image blocks, capped at MAX_INLINE_BYTES (10 MiB); extraContent() DRAINS on read− make-download-io.ts # makeDownloadIO(): env-driven IO selector (ARTSONIA_INLINE_DOWNLOADS) — the sibling of make-transport.ts− embed.ts # embedJpegMetadata(): EXIF (piexif-ts) + hand-rolled IPTC APP13; lazily imported by download.ts− writes.ts # artsonia_post_comment, artsonia_invite_fan, artsonia_set_notifications + parseProfileForm()+ CLAUDE.md
Showing the first 40 of each.
https://raw.githubusercontent.com/chrischall/artsonia-mcp/HEAD/AGENTS.md
− - **Confirmation-gating.** Every write (including `download_artwork`, which writes files) goes through `requireConfirmationWithFallback(ctx, confirmationFromEnv({...}))` from `@chrischall/mcp-utils` and takes an optional `confirmToken` (`confirmTokenParam`) — there is no `confirm` parameter. A client that can be prompted gets an elicitation prompt showing the details. One that cannot (claude.ai, Claude Desktop) gets the token fallback, per `MCP_CONFIRM_MODE` (`ask-user` default / `auto` / `refus+ - **Confirmation-gating.** Every write (including `download_artwork`, which writes files) goes through `requireConfirmationWithFallback(ctx, confirmationFromEnv({...}))` from `@chrischall/mcp-utils` and takes an optional `confirmToken` (`confirmTokenParam`) — there is no `confirm` parameter. A client that can be prompted gets an elicitation prompt showing the details, unless `MCP_CONFIRM_ELICITATION=off`. One that cannot (claude.ai, Claude Desktop) gets the token fallback, per `MCP_CONFIRM_MODE`
We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect