<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Postbye Team</title>
    <description>The latest articles on DEV Community by Postbye Team (@postbye).</description>
    <link>https://dev.to/postbye</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4221383%2Ff75c5619-7a00-46b3-82fa-fec3a008fed4.png</url>
      <title>DEV Community: Postbye Team</title>
      <link>https://dev.to/postbye</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/postbye"/>
    <language>en</language>
    <item>
      <title>Subscription Cancellation MCP Server: 4 Read-Only Tools for Claude, Cursor and VS Code</title>
      <dc:creator>Postbye Team</dc:creator>
      <pubDate>Mon, 02 Nov 2026 02:34:37 +0000</pubDate>
      <link>https://dev.to/postbye/subscription-cancellation-mcp-server-4-read-only-tools-for-claude-cursor-and-vs-code-2jj1</link>
      <guid>https://dev.to/postbye/subscription-cancellation-mcp-server-4-read-only-tools-for-claude-cursor-and-vs-code-2jj1</guid>
      <description>&lt;p&gt;We built a public MCP server that lets an AI assistant answer one narrow question properly: how do I cancel this subscription? It exposes four read-only tools over a single endpoint, needs no API key, and stores nothing. This post covers what it does, how to add it to Claude, Cursor or VS Code, what a real call returns, and the design choices we made. The source is open: &lt;a href="https://github.com/postbye-team/postbye-mcp" rel="noopener noreferrer"&gt;postbye-team/postbye-mcp&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does
&lt;/h2&gt;

&lt;p&gt;Ask an assistant "how do I cancel Planet Fitness?" and a general model may guess, or send you to a help page that may have moved. Our server gives the assistant structured answers from our cancellation guides instead: how the company takes cancellations, the notice period, the traps to check first, billing-partner notes, sources, the date the facts were verified, and the mailing address on file.&lt;/p&gt;

&lt;p&gt;Every answer is built from the same data as the matching company page on postbye.com, so the assistant and the website cannot disagree. The site publishes 8,692 cancellation guides in 30 categories, 1,038 of them verified by hand against each company's own pages.&lt;/p&gt;

&lt;h2&gt;
  
  
  The four tools
&lt;/h2&gt;

&lt;p&gt;All four are marked read-only and closed-world in their annotations (&lt;code&gt;readOnlyHint: true&lt;/code&gt;, &lt;code&gt;destructiveHint: false&lt;/code&gt;, &lt;code&gt;idempotentHint: true&lt;/code&gt;, &lt;code&gt;openWorldHint: false&lt;/code&gt;).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;search_companies&lt;/code&gt;: finds a company by name and returns its slug, category, how it takes cancellations and the guide URL. Inputs are &lt;code&gt;query&lt;/code&gt; and an optional &lt;code&gt;limit&lt;/code&gt; from 1 to 10.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;get_cancellation_guide&lt;/code&gt;: the full guide for one company, from a slug. Merged duplicate slugs resolve to the current company.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;get_cancellation_letter&lt;/code&gt;: a plain-text cancellation letter built from the same template as our free letter tool, plus where to send it. Inputs are &lt;code&gt;slug&lt;/code&gt;, optional &lt;code&gt;customer_name&lt;/code&gt; and optional &lt;code&gt;account_number&lt;/code&gt;. Anything you do not supply stays as a &lt;code&gt;[bracketed]&lt;/code&gt; placeholder.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;list_categories&lt;/code&gt;: the guide categories (streaming, gyms, phone and internet, insurance and more) with the number of guides in each and the hub URL.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The intended flow is simple: &lt;code&gt;search_companies&lt;/code&gt; turns a name into a slug, then &lt;code&gt;get_cancellation_guide&lt;/code&gt; or &lt;code&gt;get_cancellation_letter&lt;/code&gt; takes that slug.&lt;/p&gt;

&lt;h2&gt;
  
  
  The endpoint
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://postbye.com/mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It speaks MCP Streamable HTTP with JSON responses and no sessions. It only accepts POST; a GET returns a short description with HTTP 405. Cross-origin calls from web clients are allowed. Our server card advertises these protocol versions: 2026-07-28, 2025-11-25, 2025-06-18, 2025-03-26 and 2024-11-05. Authentication is &lt;code&gt;none&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add it to your client
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Claude
&lt;/h3&gt;

&lt;p&gt;On claude.ai, Claude Desktop or the mobile app, open Settings, then Connectors, and choose Add custom connector. Enter &lt;code&gt;Postbye&lt;/code&gt; as the name and &lt;code&gt;https://postbye.com/mcp&lt;/code&gt; as the URL, then save. Leave the sign-in fields empty.&lt;/p&gt;

&lt;p&gt;For Claude Code, run this once:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;claude mcp add --transport http postbye https://postbye.com/mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Cursor
&lt;/h3&gt;

&lt;p&gt;Add this to &lt;code&gt;.cursor/mcp.json&lt;/code&gt; in your project, or to &lt;code&gt;~/.cursor/mcp.json&lt;/code&gt; for every project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"postbye"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://postbye.com/mcp"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  VS Code
&lt;/h3&gt;

&lt;p&gt;Add this to &lt;code&gt;.vscode/mcp.json&lt;/code&gt; in your workspace (GitHub Copilot agent mode reads it):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"servers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"postbye"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://postbye.com/mcp"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the different top-level key and the explicit &lt;code&gt;"type": "http"&lt;/code&gt;: Cursor uses &lt;code&gt;mcpServers&lt;/code&gt;, VS Code uses &lt;code&gt;servers&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  A real call
&lt;/h2&gt;

&lt;p&gt;You can test it with nothing but curl. First, initialize:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://postbye.com/mcp &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Accept: application/json, text/event-stream'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"demo","version":"0.1"}}}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The response (trimmed):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"jsonrpc"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"2.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"result"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"protocolVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"2025-06-18"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"capabilities"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"tools"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"listChanged"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;}},&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"serverInfo"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"postbye"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Postbye"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"1.2.0"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"instructions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Read-only reference for cancelling subscriptions and memberships by mail. ..."&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then &lt;code&gt;tools/list&lt;/code&gt; returns the four tool names: &lt;code&gt;search_companies&lt;/code&gt;, &lt;code&gt;get_cancellation_guide&lt;/code&gt;, &lt;code&gt;get_cancellation_letter&lt;/code&gt;, &lt;code&gt;list_categories&lt;/code&gt;. Now the useful call, with &lt;code&gt;"method":"tools/call"&lt;/code&gt; and these params:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"get_cancellation_guide"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"arguments"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"slug"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"planet-fitness"&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The text content of the response (trimmed):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;How to cancel Planet Fitness (Gyms &amp;amp; fitness)
Slug: planet-fitness. Accepts cancellations: Mail (written notice to your home club),
in person at your home club, or online (sign in to the member portal on planetfitness.com).

Notice period: Cancel at least 7 days before the next billing date; same 7 days before
the annual fee date

Traps to check before cancelling:
- $58 buyout fee if the membership has a minimum term and ends early
- Annual fee bills separately and needs its own 7-day notice
- Some policies and procedures may vary by location ...

Where the cancellation letter goes: to your home club, not head office. ...
Address on file (not for cancellations):
- Head office (not for cancellations): Planet Fitness, 4 Liberty Ln W, Hampton, NH 03842.

Sources:
- https://www.planetfitness.com/about-planet-fitness/customer-service

Verified October 28, 2026.
Full guide: https://postbye.com/cancel/planet-fitness
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One response carries the channel, the notice rule, the traps, the address on file, a source and a verification date.&lt;/p&gt;

&lt;h2&gt;
  
  
  Design choices
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Read-only.&lt;/strong&gt; The tools only look things up. Nothing is changed, bought or sent through the server. That makes it safe to connect to any assistant without a permissions conversation, and the annotations say so in a form clients can read.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stateless.&lt;/strong&gt; No sessions, no accounts, nothing you type is stored. A client can call it at any time without a handshake it has to remember.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No API key.&lt;/strong&gt; There is no account, key or token to set up. Cancellation information is the kind of reference data an assistant should be able to fetch the moment a user asks, and a sign-up step would defeat that.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sources and verification dates in every guide.&lt;/strong&gt; An assistant that tells someone to cancel by a certain date needs to say where that rule came from and how fresh it is. Each guide response carries its sources and a "Verified" date, so the model can pass that on instead of presenting a rule as timeless. The category listing also separates total guides from guides verified by hand.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One answer for the site and the assistant.&lt;/strong&gt; The server reads the same data as the company page, so there is no second copy to drift.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Discovery files.&lt;/strong&gt; We publish a server card, a &lt;code&gt;/.well-known/mcp.json&lt;/code&gt; with the endpoint, transport and four tools, and an official MCP Registry entry named &lt;code&gt;com.postbye/postbye&lt;/code&gt; (version 1.2.0), so clients that look for servers on their own can find it. The repo's &lt;code&gt;server.json&lt;/code&gt; is the file published to the registry.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does not do
&lt;/h2&gt;

&lt;p&gt;It does not mail anything or take payment, and it cannot see your account. If a guide says a company takes written notice, the letter tool gives you plain text to fill in and send yourself. Our site offers a separate mailed-letter service for people who want one, but that is not part of the MCP server.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it and tell us what breaks
&lt;/h2&gt;

&lt;p&gt;The repository is MIT licensed. The README holds the same setup notes as this post, and issues are welcome: a wrong address, a missing company or a guide that has gone stale is exactly what we want to hear about. The full documentation lives on our &lt;a href="https://postbye.com/mcp-server" rel="noopener noreferrer"&gt;MCP server page&lt;/a&gt;, and the service itself is at &lt;a href="https://postbye.com" rel="noopener noreferrer"&gt;postbye.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Postbye Team&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>ai</category>
      <category>opensource</category>
      <category>api</category>
    </item>
  </channel>
</rss>
