Skip to main content
20% off 3 months · code LAUNCH20 · until 31 October

Publish a changelog from Claude Desktop

The agent that wrote the change already knows what changed. With the Nordva Launch MCP server connected, it can publish the release note to your hosted changelog at the end of the session, schedule it for later, or check what has already been posted.

Claude Desktop's config file starts local processes, so a remote server with a header is reached through the mcp-remote bridge. Node.js 18 or later must be installed.

Setup

You need a secret key (nv_live_…) from Dashboard → API keys.

01Add the bridge to the config file

claude_desktop_config.json (Settings → Developer → Edit Config)

{
  "mcpServers": {
    "nordva": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "https://mcp.nordva.dev",
        "--header",
        "Authorization:${NORDVA_AUTH}"
      ],
      "env": {
        "NORDVA_AUTH": "Bearer nv_live_..."
      }
    }
  }
}

The header value is passed through an environment variable because some platforms split arguments that contain a space. On macOS the file is in ~/Library/Application Support/Claude/, on Windows in %APPDATA%\Claude\.

02Check the connection

Quit and reopen Claude Desktop. The nordva tools should appear in the tools menu of a new chat. Ask it to run setup_check.

Then ask Claude Desktop

  • Publish a changelog entry for what we just shipped. Category: fix.
  • Draft an entry for the new export feature and schedule it for Monday 09:00 UTC.
  • What did we publish on the changelog this month?
  • Archive the entry about the beta importer, it went out by mistake.

For “Publish a changelog entry for the CSV export fix we just merged.” Claude Desktop calls publish_changelog_entry with:

{
  "title": "CSV export no longer drops rows with commas in the name",
  "body_markdown": "Names containing a comma were split into two columns, which shifted every field after them. Values are now quoted.\n\nAffects exports made since 2 September. Re-export to get a correct file.",
  "category": "fix",
  "version": "v1.8.2"
}

Returned: The entry id, its status (published or scheduled) and the public URL of the entry on the hosted changelog page.

Changelog tools and arguments

publish_changelog_entry

Publish or schedule a changelog entry

titlerequiredstring, max 200User-facing headline.
body_markdownrequiredstring, max 50,000Full description in Markdown.
categoryrequired"feature" | "fix" | "improvement" | "security" | "breaking"Use 'breaking' only when customers must change code/config.
versionoptionalstring, max 64Free-form version string. Not validated as semver.
scheduled_atoptionalstringISO 8601 timestamp. If set, entry is scheduled, not published.
notify_subscribersoptionalbooleanEmail the changelog subscribers when the entry publishes. Only on the developer's explicit say-so.
notify_in_appoptionalbooleanPost one broadcast to every user's in-app bell when the entry publishes. Leave out to use the project's default.
cover_image_urloptionalstring, max 2,048https:// link to an image they host.
cta_labeloptionalstring, max 40
cta_urloptionalstring, max 2,048http(s) URL or a path starting with /. Send with cta_label.
labelsoptionalarrayLabel slugs.
audienceoptional"public" | "signed_in" | "segment"
segmentoptionalobjectWith audience "segment" (Builder).
pinnedoptionalboolean
expires_atoptionalstring
announcementoptionalobjectIndie and up. One entry per project at a time.
notify_chatoptionalbooleanfalse keeps it out of Slack and Discord webhooks.
statusoptionalliteral"draft" saves without publishing.

list_changelog_entries

Read-only

List recent changelog entries

limitoptionalnumber, 1–50
categoryoptional"feature" | "fix" | "improvement" | "security" | "breaking"
statusoptional"draft" | "published" | "scheduled" | "archived"
sinceoptionalstring
labeloptionalstring, max 40A label slug.
qoptionalstring, max 100Words in the title or text.

get_changelog_entry

Read-only

Read one changelog entry

entry_idrequiredstring, max 64

update_changelog_entry

Edit, reschedule or publish an unpublished changelog entry

entry_idrequiredstring, max 64
titleoptionalstring, max 200
body_markdownoptionalstring, max 20,000
versionoptionalstring, max 64
categoryoptional"feature" | "improvement" | "fix" | "security" | "breaking"
scheduled_atoptionalstring
notify_subscribersoptionalboolean
notify_in_appoptionalboolean
publish_nowoptionalboolean
cover_image_urloptionalstring, max 2,048https:// link to an image they host.
cta_labeloptionalstring, max 40
cta_urloptionalstring, max 2,048http(s) URL or a path starting with /. Send with cta_label.
labelsoptionalarrayLabel slugs.
audienceoptional"public" | "signed_in" | "segment"
segmentoptionalobjectWith audience "segment" (Builder).
pinnedoptionalboolean
expires_atoptionalstring
announcementoptionalobjectIndie and up. One entry per project at a time.
notify_chatoptionalbooleanfalse keeps it out of Slack and Discord webhooks.

archive_changelog_entry

Confirms first

Remove a changelog entry from public view

entry_idrequiredstringThe id of the changelog entry to archive (e.g. ce_01hwxyz...).

draft_changelog_from_commits

Draft a changelog entry from commits (never publishes)

commitsrequiredarray
titleoptionalstring, max 200
versionoptionalstring, max 64
categoryoptional"feature" | "fix" | "improvement" | "security" | "breaking"
dry_runoptionalboolean

list_changelog_labels

Read-only

List changelog labels

No arguments.

create_changelog_label

Create a changelog label

namerequiredstring, max 40
slugoptionalstring, max 40
colouroptional"gray" | "red" | "orange" | "amber" | "green" | "teal" | "blue" | "indigo" | "purple" | "pink"

update_changelog_label

Rename or recolour a changelog label

label_idrequiredstring, max 64
nameoptionalstring, max 40
slugoptionalstring, max 40
colouroptional"gray" | "red" | "orange" | "amber" | "green" | "teal" | "blue" | "indigo" | "purple" | "pink"

delete_changelog_label

Confirms first

Delete a changelog label

label_idrequiredstring, max 64

get_changelog_settings

Read-only

Read the changelog widget settings

No arguments.

update_changelog_settings

Choose the changelog widget's reactions

reaction_setrequiredarray

get_changelog_entry_stats

Read-only

Numbers for one changelog entry

entry_idrequiredstring, max 64

get_changelog_stats

Read-only

Numbers for the latest changelog entries

limitoptionalnumber, 1–100

get_changelog_after_reading

Read-onlyBuilder

What happened after people read an entry

entry_idrequiredstring, max 64

list_changelog_subscribers

Read-only

List changelog email subscribers

labeloptionalstring, max 40
limitoptionalnumber, 1–100
cursoroptionalstring, max 64

set_changelog_subscriber_labels

Change which labels a subscriber follows

subscriber_idrequiredstring, max 64
labelsrequiredarray

get_changelog_widget_view

Read-only

See the changelog widget as one person sees it

user_idoptionalstring, max 256
qoptionalstring, max 100
labeloptionalstring, max 40
categoryoptional"feature" | "fix" | "improvement" | "security" | "breaking"
limitoptionalnumber, 1–50
cursoroptionalstring, max 200

record_changelog_widget_event

Test the changelog widget: record a view, reaction or click

actionrequired"seen" | "react" | "unreact" | "click"
entry_idrequiredstring, max 64
reactionoptional"like" | "celebrate" | "love" | "laugh" | "fire" | "eyes" | "confused" | "dislike"
user_idoptionalstring, max 256
client_idoptionalstring

Behaviour worth knowing

  • Without scheduled_at the entry is public immediately. With it, the entry stays in scheduled status until a cron that runs every minute publishes it.
  • Archiving is a soft delete: the entry leaves the public page and feed at once but is not destroyed.
  • On the Free plan the eleventh published entry is refused with PLAN_LIMIT_REACHED. The tool description tells the agent to show the upgrade link and stop rather than retry.
  • Published entries are emailed to confirmed subscribers on plans that include subscribers.
  • The Connectors screen in Claude Desktop and claude.ai expects OAuth. The Nordva Launch server authenticates with an API key header instead, which is why the bridge is needed there.