Every change Wellknown observed on this MCP server, newest first, with what it was before and what it became. Tool-surface changes carry the definition diff. Nothing here is edited after the fact.
Authorization required, Bearer, issuer https://chartlink.app/api/auth
Authorization required, Bearer, issuer https://chartlink.app/api/auth
Authorization not required → required, Bearer, issuer https://chartlink.app/api/auth
Removed "create_edit_link" and "signup" (10 tools before, 8 now)
Mint a no-login tweak link — hand it to your human — Returns a URL opening the visual tweak panel for ONE chart (text, colors, spacing, label nudges) with no login. PUBLISH FIRST: the editor saves and republishes a published chart, it cannot publish a draft. Scope: view, tweak, and republish that chart only — never delete, never spend credits, nothing else in the workspace. OFFER THIS whenever the human's request is aesthetic fine-tuning: handing over the wheel beats a nudge-by-nudge back-and-forth. The secret is shown once; links don't expire and can be revoked with revoke_edit_link.
Get an API key — no account, one call — Creates a workspace and returns its API key (shown ONCE — keep it). Works on a keyless connection; every other tool needs the key. Then put the key where your client keeps it (plugin api_key setting, the Authorization header, or CHARTLINK_API_KEY for the npx bridge) and reconnect.
Changed the definition of "publish_asset"
⟨10 unchanged words⟩ },"premium":{"description":"Spend onepaidcredit to publish as premium (2400px, SVG,itsyourownbrandingfooter, no badge, SVG) in this call","type":"boolean" ⟨4 unchanged words⟩
Changed the definition of "check_template_data", "create_from_template" and "update_asset"
⟨145 unchanged words⟩ matching columns","items":{"items":{"anyOf":[{"type":["string"},{"type":"number"},{"type":"boolean"},{"type":"null"}]},"type":"array"},"type": ⟨29 unchanged words⟩
Changed the definition of "check_template_data", "create_from_template" and "get_template"
⟨174 unchanged words⟩ "},"template":{"description":"Template id, slug, orslugpage address (sweden/municipalities)","type":"string"}},"required": ⟨4 unchanged words⟩
⟨11 unchanged words⟩ settings (get_template shows the schema): themelight|darklight|dark|editorial, dataType gradient|buckets|categories and surroundings true|false
Changed the definition of "create_from_template" and "get_template"
⟨14 unchanged words⟩ the schema): theme light|dark, dataType gradient|buckets|categories and surroundings true|false for maps, title/description/source/brand {text, fontFamily, fontSize, ⟨72 unchanged words⟩
⟨7 unchanged words⟩ with `contract`: its looks (theme × dataType × surroundings), the knobs JSON Schema, the columns ⟨40 unchanged words⟩
Added "check_template_data", "create_from_template" and "get_template"; removed "clear_data_source", "create_asset", "create_brand" and 17 more; changed the definition of "list_templates" (27 tools before, 10 now)
{"$schema":"http://json-schema.org/draft-07/schema#","properties":{"limit":{"description":"At most this many, best first (default 20)","maximum":200,"minimum":1,"type":"integer"},"q":{"description":"What is needed, in the person's words","type":"string"},"tags":{"description":"Comma-separated tags every result must carry, e.g. map,united-states","type":"string"},"type":{ ⟨12 unchanged words⟩
Dry run: would this data and these knobs work with the template? Creates nothing — Matches every region value against the template's geography and reports unmatched values with the closest real codes, how many regions would stay grey, and the scale the map would use. No key needed. Use it when unsure of the codes; then create_from_template with the same data and knobs.
Changed the definition of "list_geographies"
countries, us-states, us-states-pr (with Puerto Rico), us-counties, us-districts (congressional districts), us-metros (metro areas), us-zip3, us-zips-<st> (one state's ZIP codes), ⟨48 unchanged words⟩
Changed the definition of "list_geographies", "list_templates" and "replace_asset_data"
countries, us-states, us-states-pr (with Puerto Rico), us-counties, us-zip3, us-zips-<st> (one state's ZIP codes), and every country's states/provinces as <alpha-2>-regions (de-regions, ⟨41 unchanged words⟩
Charts offeredTemplatesasbytemplatesneed — search, then start a
Certificate recorded, valid to 2026-12-07
Authorization not required
Changed the definition of "clear_data_source", "create_asset", "create_brand" and 15 more
{"destructiveHint":true,"openWorldHint":false,"readOnlyHint":false}
{"destructiveHint":false,"openWorldHint":false,"readOnlyHint":false}
Changed the definition of "create_brand" and "update_brand"
⟨55 unchanged words⟩ title, description, source, notes, legend,brandingbadge, chart, palette, colors, shape, chrome) minus the words (no text/url) and the type-specific chartoptions.options — chart carries the style half of every element (xAxis.ticks.labels.font, yAxis.gridlines, seriesLabels.font…). Resolution: ENGINE_DEFAULTS <- brand <- the chart's ⟨58 unchanged words⟩
⟨41 unchanged words⟩ title, description, source, notes, legend,
Unknown → Live
First tool surface recorded: 27 tools (server version 0.1.0)
npm:chartlink-mcp (package_npm) — from mcp_registry, with the record
https://chartlink.app/mcp (mcp_streamable_http) — from mcp_registry, with the record
Showing the latest 19 events. The API returns up to 500 and filters by kind: ?kind=tool_surface_changed
⟨164 unchanged words⟩ matching columns","items":{"items":{"anyOf":[{"type":["string"},{"type":"number"},{"type":"boolean"},{"type":"null"}]},"type":"array"},"type": ⟨65 unchanged words⟩
{"$schema":"http://json-schema.org/draft-07/schema#","properties":{"brand":{"anyOf":[{"type":["string"},{"type":"null"}]},"config":{"additionalProperties":{}," ⟨190 unchanged words⟩ matching columns","items":{"items":{"anyOf":[{"type":["string"},{"type":"number"},{"type":"boolean"},{"type":"null"}]},"type":"array"},"type": ⟨63 unchanged words⟩
⟨218 unchanged words⟩ template":{"description":"Template id or slug,from list_templates, or the page address (sweden/municipalities, us/texas/counties, london/wards) when you know the place","type":"string"}},"required": ⟨4 unchanged words⟩
⟨48 unchanged words⟩ call whose shape you copy. Takes an id, the page slug, or the pageslugaddress(map-us-counties).as on chartlink.app/maps — sweden/municipalities, us/texas/counties, london/wards — so you can skip list_templates when you know the place.
⟨4 unchanged words⟩ id":{"description":"Template id (ast_…), slug, orslugpage address (place/level)","type":"string"}},"required": ⟨3 unchanged words⟩
Create a chart from a template with your data and a few knobs — returns an inline preview — The template's design, your data, your words. `knobs` are the template's settings (get_template shows the schema): theme light|dark, dataType gradient|buckets|categories for maps, title/description/source/brand {text, fontFamily, fontSize, color}, backgroundColor, and the scale knob for the dataType (range, breaks or classes, categoryColors/categoryOrder). data = {columns: [{id, type}], rows: [[…]]}: use the template's column ids, or exactly two columns (region first, value second) for a map. publish: true makes the URLs live in the same call. A success means it validated AND rendered — look …
One template's contract: knobs, columns, region codes, an example call — Read this before create_from_template. Returns the template with `contract`: its looks (theme × dataType), the knobs JSON Schema, the columns with their roles, the region-code convention with three real codes and a lookup URL, what each dataType expects of the value column, and a complete example call whose shape you copy. Takes an id or the page slug (map-us-counties).
Detach a chart's data source — Stops scheduled fetches; the chart keeps its current data.
Create a draft asset — returns an inline preview image — Creates a draft. The response includes a low-res PNG preview INLINE — look at it, then iterate with update_asset. Nothing is public until publish_asset, or until you pass publish: true here (one call instead of two, once the chart is final). A success means the config validated AND rendered. Style comes from the defaults and your brand, if any — only set config fields the story needs. data = {columns: [{id,type,...}], rows: [[...], ...]} (row-major, matching column order). LIMITS: keep each call under ~100 KB of rows (asset cap 2 MB) — for larger datasets create with a few rows and attach set…
Create a brand (reusable style token set) — A brand styles every asset that references it — and the workspace default brand styles everything created without an explicit brand. Create one, then render any asset with brand: "<slug>" to see it applied. Style only: brands can never inject data or text content.
Payment link for a credit pack — hand it to your human — Returns a URL that opens straight into Paddle checkout: no login, no account. It can only add credits to THIS workspace, so it is safe to share. Credits arrive seconds after payment (get_billing).
Soft-delete an asset — Embeds go dark. Restorable via the REST API (POST /api/assets/{id}/restore).
Duplicate an asset into a new draft — New id, new embed URLs. Useful for rebranding a chart for another audience.
Refresh a chart from its data source right now — Runs one fetch on top of the schedule. Returns {ok, rows, published, error}.
Get one asset (draft state) — Full asset envelope. includePreview=true also returns an inline PNG of the current draft.
This workspace's credit balance and asset cap — Hosting is free (unlimited badged charts, live updates included). One credit makes one chart premium forever: 2400px, SVG, your own branding, no badge. Updates are never metered.
Get the config schema + worked examples for a type — Returns the JSON Schema for the type's config, the data schema, two worked examples (minimal + rich), and `defaults` — the complete config in force when nothing is set (every font, padding, color), which a brand and then the chart's own config merge over. Read this before your first create_asset of a given type; read a baseline value from defaults instead of guessing it.
List available asset types — Chart/table types you can create, with links to per-type schemas.
List assets — Filterable list; rows elide config/data. Use get_asset for full bodies.
List brands — Style-only token sets applied under your config. Pass a slug as `brand` on create_asset.
Which boundaries a map can draw, and how its regions are named — countries, us-states, us-states-pr (with Puerto Rico), us-counties, us-districts (congressional districts), us-metros (metro areas), us-zip3, us-zips-<st> (one state's ZIP codes), and every country's states/provinces as <alpha-2>-regions (de-regions, ru-regions…). Pass id to get one geography's full region list — codes (ISO 3166-2 like DE-BY), names and aliases — and read it BEFORE naming regions in your data: unknown regions fail loudly. Set chart.geography to the id; chart.bounds crops.
Replace data rows — published assets auto-republish (live embeds update) — THE core flow for refreshing numbers. publish defaults to auto: a published asset republishes immediately (every embed/PNG updates); a draft stays draft. Set publish=false to stage instead. LIMITS: an asset holds up to 2 MB of data, but keep each tool call under ~100 KB of rows — for larger datasets chunk with mode: "append" (publish: "false" on every chunk but the last), or skip inline entirely with set_data_source (the server fetches a URL, up to the full 2 MB).
Revoke an edit link — The URL stops working immediately. List links (prefixes + tokenIds) via GET /assets/{id}/edit-links.
Make a chart self-updating: attach a source URL, fetched on schedule — The chart refetches this URL (CSV or JSON) hourly/daily/weekly, replaces its rows, and republishes itself if published — refreshes are free, updates are never metered. Columns stay as defined on the asset: CSV headers / JSON object keys match column ids or labels case-insensitively, with spaces, underscores and hyphens interchangeable (births_per_woman matches a column labeled 'Births per woman'). Fetches once immediately and returns that outcome — check fetch.ok and fix fetch.error before moving on. get_asset shows dataSource + dataSourceState when a source is attached. Clear with clear_data…
Take an asset offline — Embeds and PNGs return 410 until republished.
Update a brand (tokens deep-merge) — Deep-merges tokens (objects merge, arrays replace, null clears). Drafts restyle immediately; published assets pick the change up on their next publish. Requires expectedVersion from list_brands.
Upgrade a trial-hosted chart to premium (spends 1 paid credit) — Same URLs, instantly rebranded: badge removed, 2400px PNG and SVG unlocked, custom branding applies. Idempotent for already-premium charts.
PublishedTemplateschartsaretheirnamedownersbyofferedtheasNEEDstartingtheypointsanswer (need, asks, tags), each with urls.png (showa fewit to your human),the chart's typeandtitle, and`columns`: the column ids your data must supply. Pass q with what the person asked for — "map of brazil's states", "ranked bars with flags", "change between two years" — and the list comes back ranked; take the first. Then create_asset with template: <id> and your data ⟨12 unchanged words⟩ works as a template too, not only these.The human-facing version is the gallery link in the result.
{"$schema":"http://json-schema.org/draft-07/schema#","properties":{"q":{"description":"What is needed, in the person's words","type":"string"},"type":{"description":"Only this asset type ⟨7 unchanged words⟩
{"$schema":"http://json-schema.org/draft-07/schema#","properties":{"config":{"additionalProperties":{},"description":"The full settings to store with the data — send it when the new columns differ from what the current config's encoding names, so both are checked together","propertyNames":{"type":"string"},"type":"object"},"data":{"additionalProperties":false,"description":"Typed ⟨217 unchanged words⟩
{"destructiveHint":false,"openWorldHint":false,"readOnlyHint":false}
{"destructiveHint":false,"openWorldHint":false,"readOnlyHint":false}
{"destructiveHint":false,"openWorldHint":false,"readOnlyHint":false}
{"destructiveHint":true,"openWorldHint":false,"readOnlyHint":false}
{"destructiveHint":false,"openWorldHint":false,"readOnlyHint":false}
{"destructiveHint":true,"openWorldHint":false,"readOnlyHint":false}
{"destructiveHint":true,"openWorldHint":false,"readOnlyHint":false}
{"destructiveHint":true,"openWorldHint":false,"readOnlyHint":false}
{"destructiveHint":true,"openWorldHint":false,"readOnlyHint":false}
{"destructiveHint":true,"openWorldHint":false,"readOnlyHint":false}
{"destructiveHint":false,"openWorldHint":false,"readOnlyHint":false}
{"destructiveHint":false,"openWorldHint":false,"readOnlyHint":false}
{"destructiveHint":true,"openWorldHint":false,"readOnlyHint":false}
{"destructiveHint":true,"openWorldHint":false,"readOnlyHint":false}
{"destructiveHint":true,"openWorldHint":false,"readOnlyHint":false}
{"destructiveHint":true,"openWorldHint":false,"readOnlyHint":false}