Skip to main content
Glama

Fizzy MCP Server

npm version License: MIT Node.js Version

A Model Context Protocol (MCP) server for Fizzy — the project management tool by Basecamp.

🚀 Try it live: https://fizzy.fabric.pro/mcp

📖 Fizzy API Documentation: github.com/basecamp/fizzy/blob/main/docs/API.md

This MCP server allows AI assistants like Claude, Cursor, and GitHub Copilot to interact with your Fizzy boards, cards, and projects through natural language.

Table of Contents

Related MCP server: fizzy-mcp

Features

  • Full Fizzy API Coverage: 53 tools covering Boards, Cards, Card Actions, Pins, Comments, Reactions, Steps, Columns, Tags, Users, and Notifications

  • Multiple Transport Protocols: Stdio (CLI/IDE), HTTP (Streamable), and SSE (deprecated)

  • Multi-User Support: HTTP and SSE transports support multiple users with per-user authentication

  • Flexible Deployment: Run locally (Node.js) or deploy globally (Cloudflare Workers)

  • IDE Integration: Works with Cursor, VS Code, Claude Desktop, and other MCP-compatible tools

  • Robust Error Handling: Structured error classes with detailed error messages

  • Automatic Retries: Exponential backoff retry logic for transient failures (5xx errors, timeouts, network issues)

  • Request Timeout: 30-second default timeout to prevent hanging requests

  • ETag Caching: Automatic HTTP caching using ETags to reduce bandwidth and improve response times (as per Fizzy API caching spec)

  • Fully Tested: Comprehensive test suite with 450+ test cases

Transport Support

The Fizzy MCP server supports multiple transport protocols depending on your deployment environment:

Transport Comparison

Transport

Protocol Version

Node.js

Cloudflare

Use Case

Authentication

stdio

N/A

✅ Yes

❌ No

CLI/IDE integrations (Cursor, VS Code, Claude Desktop)

Single-user via FIZZY_ACCESS_TOKEN env var

HTTP (Streamable)

2025-03-26

✅ Yes

✅ Yes

Production deployments, multi-user applications

Multi-user via Authorization: Bearer <token> header

SSE

2024-11-05

✅ Yes

❌ No

⚠️ Deprecated - backwards compatibility only

Multi-user via Authorization: Bearer <token> header

Deployment-Specific Support

Node.js Deployment

Supports all three transports:

  • stdio: For single-user CLI/IDE integrations (recommended for local development)

  • HTTP (Streamable): For multi-user web applications and production deployments (recommended)

  • SSE: Deprecated, maintained for backwards compatibility only

Cloudflare Workers Deployment

Supports HTTP transport only:

  • HTTP (Streamable): The only supported transport for Cloudflare Workers

  • Why no stdio? Cloudflare Workers cannot spawn processes

  • Why no SSE? SSE transport is deprecated and not supported on Cloudflare

Recommendations

  • For IDE integrations (Cursor, VS Code, Claude Desktop): Use stdio transport

  • For production deployments: Use HTTP (Streamable) transport

  • For multi-user applications: Use HTTP (Streamable) transport

  • For testing with MCP Inspector: Use HTTP (Streamable) transport

  • Avoid SSE: The SSE transport is deprecated and will be removed in a future version

Authentication Models

stdio Transport (Single-User)

  • Requires FIZZY_ACCESS_TOKEN environment variable

  • One user per server instance

  • Ideal for personal CLI/IDE use

HTTP/SSE Transports (Multi-User)

  • Each user provides their own Fizzy Personal Access Token via Authorization: Bearer <token> header

  • Multiple users can connect simultaneously

  • Each session is isolated with its own FizzyClient instance

  • Sessions timeout after 30 minutes of inactivity

  • Optional server-level authentication via MCP_AUTH_TOKEN environment variable (clients send it in the X-MCP-Auth-Token header)

Prerequisites

  • Node.js 22 or higher

  • A Fizzy account with API access


Quick Start

Get up and running in 3 steps:

  1. Get your Fizzy access token from app.fizzy.do → Profile → API → Personal access tokens

  2. Run with npx (no installation needed):

    FIZZY_ACCESS_TOKEN="your-token-here" npx fizzy-mcp
  3. Configure your IDE (e.g., Cursor):

    • Open Cursor Settings → Features → MCP Servers

    • Click "Edit in mcp.json" and add:

    {
      "mcpServers": {
        "fizzy": {
          "command": "npx",
          "args": ["-y", "fizzy-mcp"],
          "env": {
            "FIZZY_ACCESS_TOKEN": "your-token-here"
          }
        }
      }
    }
    • Restart Cursor

That's it! You can now ask your AI assistant to interact with Fizzy.

💡 Note: This Quick Start uses stdio transport for single-user IDE integration. For production deployments or multi-user applications, see the HTTP Transport section.

For detailed installation options and configuration, see the sections below.


Installation

npm install -g fizzy-mcp

The fizzy-mcp command will be available globally.

Option 2: Use with npx (no installation required)

npx fizzy-mcp --help

Option 3: Install from source

# Clone the repository
git clone https://github.com/Fabric-Pro/fizzy-mcp.git
cd fizzy-mcp

# Install dependencies
npm install

# Build the project
npm run build

# Link globally (makes `fizzy-mcp` command available)
npm link

To verify the installation:

fizzy-mcp --help

Getting Your Fizzy Access Token

  1. Log in to your Fizzy account

  2. Go to your Profile (click your avatar)

  3. Navigate to the API section

  4. Click on Personal access tokens

  5. Click Generate new access token

  6. Give it a description and select permissions:

    • Read: For read-only access

    • Read + Write: For full access (recommended)

  7. Copy and save your token securely

⚠️ Important: Keep your access token secret! Anyone with your token can access your Fizzy account.


Configuration

For Cursor IDE

💡 Note: The root mcp.json in this repository is a manifest for the Cursor Plugin marketplace. For manual setup in your local ~/.cursor/mcp.json, substitute your actual token as shown below (do not copy the literal ${FIZZY_ACCESS_TOKEN}).

Cursor supports two connection methods: stdio (local process) and HTTP (remote server).

  1. Open Cursor Settings (Cmd/Ctrl + ,)

  2. Search for "MCP" or navigate to Features > MCP Servers

  3. Click Edit in mcp.json or manually edit ~/.cursor/mcp.json:

Using npx (recommended):

{
  "mcpServers": {
    "fizzy": {
      "command": "npx",
      "args": ["-y", "fizzy-mcp"],
      "env": {
        "FIZZY_ACCESS_TOKEN": "your-fizzy-access-token-here"
      }
    }
  }
}

If installed globally:

{
  "mcpServers": {
    "fizzy": {
      "command": "fizzy-mcp",
      "env": {
        "FIZZY_ACCESS_TOKEN": "your-fizzy-access-token-here"
      }
    }
  }
}
  1. Restart Cursor for changes to take effect

Option 2: HTTP Transport (Remote Server - For Shared/Production Deployments)

Use this method to connect to a remote Fizzy MCP server (e.g., deployed on Cloudflare Workers or a shared Node.js server).

  1. Open Cursor Settings and edit ~/.cursor/mcp.json:

{
  "mcpServers": {
    "fizzy": {
      "url": "https://fizzy.fabric.pro/mcp",
      "transport": "streamable-http",
      "headers": {
        "Authorization": "Bearer YOUR_FIZZY_PERSONAL_ACCESS_TOKEN"
      }
    }
  }
}

For local HTTP server:

{
  "mcpServers": {
    "fizzy": {
      "url": "http://localhost:3000/mcp",
      "transport": "streamable-http",
      "headers": {
        "Authorization": "Bearer YOUR_FIZZY_PERSONAL_ACCESS_TOKEN"
      }
    }
  }
}
  1. Restart Cursor for changes to take effect

💡 Tip: Use the live server at https://fizzy.fabric.pro/mcp to try Fizzy MCP without running your own server!

For VS Code with GitHub Copilot

Option 1: Stdio Transport (Local Process)

Create or edit .vscode/mcp.json in your workspace (or global settings):

{
  "mcpServers": {
    "fizzy": {
      "command": "npx",
      "args": ["-y", "fizzy-mcp"],
      "env": {
        "FIZZY_ACCESS_TOKEN": "your-fizzy-access-token-here"
      }
    }
  }
}

Option 2: HTTP Transport (Remote Server)

{
  "mcpServers": {
    "fizzy": {
      "url": "https://fizzy.fabric.pro/mcp",
      "transport": "streamable-http",
      "headers": {
        "Authorization": "Bearer YOUR_FIZZY_PERSONAL_ACCESS_TOKEN"
      }
    }
  }
}

For Claude Desktop

Claude Desktop supports stdio transport only.

Edit your Claude Desktop configuration file:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json

  • Windows: %APPDATA%\Claude\claude_desktop_config.json

  • Linux: ~/.config/Claude/claude_desktop_config.json

{
  "mcpServers": {
    "fizzy": {
      "command": "npx",
      "args": ["-y", "fizzy-mcp"],
      "env": {
        "FIZZY_ACCESS_TOKEN": "your-fizzy-access-token-here"
      }
    }
  }
}

For Other MCP-Compatible IDEs

Most MCP-compatible IDEs support HTTP transport. Use this configuration pattern:

{
  "mcpServers": {
    "fizzy": {
      "url": "https://fizzy.fabric.pro/mcp",
      "transport": "streamable-http",
      "headers": {
        "Authorization": "Bearer YOUR_FIZZY_PERSONAL_ACCESS_TOKEN"
      }
    }
  }
}

Replace https://fizzy.fabric.pro/mcp with your own server URL if you're self-hosting.


Running the Server

Stdio Transport (default - for IDE integration)

# Using npx
FIZZY_ACCESS_TOKEN="your-token" npx fizzy-mcp

# If installed globally
FIZZY_ACCESS_TOKEN="your-token" fizzy-mcp

SSE Transport (for web clients)

# Start the server (no FIZZY_ACCESS_TOKEN needed - users provide their own)
npx fizzy-mcp --transport sse --port 3000

# Endpoints:
#   SSE: http://localhost:3000/sse
#   Messages: http://localhost:3000/messages

Connecting clients:

# Each user provides their own Fizzy token via Authorization header
curl -H "Authorization: Bearer YOUR_FIZZY_TOKEN" \
     http://localhost:3000/sse

Streamable HTTP Transport (for production)

# Start the server (no FIZZY_ACCESS_TOKEN needed - users provide their own)
npx fizzy-mcp --transport http --port 3000

# Endpoints:
#   MCP: http://localhost:3000/mcp
#   Health: http://localhost:3000/health

Connecting clients:

# Each user provides their own Fizzy token via Authorization header
curl -X POST \
     -H "Authorization: Bearer YOUR_FIZZY_TOKEN" \
     -H "Content-Type: application/json" \
     -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' \
     http://localhost:3000/mcp

Cloudflare Workers (for edge deployment)

Deploy to Cloudflare Workers for global distribution with near-zero cold starts:

# Install dependencies
npm install

# Login to Cloudflare
npx wrangler login

# Deploy
npm run cf:deploy

Important Notes:

  • Cloudflare Workers only supports HTTP transport (no stdio or SSE)

  • Multi-user authentication: Each user provides their own Fizzy token via Authorization: Bearer <token> header

  • No FIZZY_ACCESS_TOKEN needed: Unlike stdio transport, Cloudflare deployment uses per-user tokens

  • Durable Objects: Sessions are managed using Cloudflare Durable Objects for persistence

See the Cloudflare Deployment Guide for detailed instructions.


Environment Variables

Core Configuration

Variable

Required

Default

Description

FIZZY_ACCESS_TOKEN

stdio only

—

Your Fizzy API access token (required for stdio transport only). HTTP/SSE users provide tokens via Authorization header.

FIZZY_BASE_URL

No

https://app.fizzy.do

Fizzy API base URL

PORT

No

3000

Port for HTTP/SSE transport

MCP_TRANSPORT

No

stdio

Default transport (stdio, sse, http)

LOG_LEVEL

No

info

Logging level (debug, info, warn, error)

HTTP/SSE Transport Security

When using HTTP or SSE transports, additional security options are available:

Variable

Required

Default

Description

MCP_ALLOWED_ORIGINS

No

*

Allowed CORS origins (comma-separated or * for all)

MCP_AUTH_TOKEN

No

—

Optional shared token for Client Authentication (authenticates MCP clients connecting to this server). Clients send it bare in the X-MCP-Auth-Token header; Authorization: Bearer <token> is still accepted for compatibility but collides with the per-user Fizzy token

MCP_BIND_ALL_INTERFACES

No

false

Set to true to bind to 0.0.0.0 instead of localhost

Origins are matched exactly. The one convenience is loopback: an entry written without a port (http://localhost) matches any port on that same scheme and hostname, while an entry that pins a port (http://localhost:3000) matches only that port — and never a different loopback hostname or scheme.

Multi-User Support:

SSE and HTTP transports support multiple users simultaneously:

  • Each user provides their own Fizzy Personal Access Token via Authorization: Bearer <token> header

  • Each session is isolated with its own FizzyClient instance

  • Users cannot access each other's data

  • Sessions timeout after 30 minutes of inactivity

Security Model:

  • Localhost binding (default): Server binds to 127.0.0.1, preventing remote access

  • CORS origins: Controls which web origins can connect (default: all)

  • User Authentication: Each user provides their own Fizzy token via Authorization header

  • Client Authentication: Optional bearer token to authenticate MCP clients connecting to this server

# Basic usage (binds to localhost, allows all CORS origins)
# Users provide their own tokens via Authorization header
npx fizzy-mcp --transport http --port 3000

# Restrict CORS to specific origins
MCP_ALLOWED_ORIGINS="http://localhost:3000,https://myapp.com" \
npx fizzy-mcp --transport http --port 3000

# Enable Client Authentication (require MCP clients to present a shared token)
# Clients then send it as: X-MCP-Auth-Token: my-secret-token
MCP_AUTH_TOKEN="my-secret-token" \
npx fizzy-mcp --transport http --port 3000

# For Docker/remote access (use with restricted origins and client auth)
MCP_BIND_ALL_INTERFACES=true \
MCP_ALLOWED_ORIGINS="https://myapp.com" \
MCP_AUTH_TOKEN="my-secret-token" \
npx fizzy-mcp --transport http --port 3000

⚠️ Authentication Types:

  • User Authentication (via Authorization header): Required for SSE/HTTP transports. Each user provides their own Fizzy Personal Access Token. On the Cloudflare Worker, Authorization is only ever read as this token; the Node transports also read it as the client token in the compatibility mode described below, which is why that mode should not be used for new deployments.

  • Client Authentication (MCP_AUTH_TOKEN, via the X-MCP-Auth-Token header): Optional. Authenticates MCP clients (like IDE extensions) connecting to this server. Sent as the bare token, with no Bearer prefix, so it never competes with the Fizzy token above:

    {
      "headers": {
        "Authorization": "Bearer YOUR_FIZZY_PERSONAL_ACCESS_TOKEN",
        "X-MCP-Auth-Token": "YOUR_MCP_AUTH_TOKEN"
      }
    }

    For compatibility, the Node HTTP/SSE transports also still accept the client token as Authorization: Bearer <MCP_AUTH_TOKEN> when no X-MCP-Auth-Token header is present. That mode consumes the header the per-user Fizzy token needs, so don't use it for new deployments. The Cloudflare Worker accepts X-MCP-Auth-Token only.

Note: For stdio transport, use FIZZY_ACCESS_TOKEN environment variable (single-user mode for CLI/IDE integrations).


Available Tools (54 total)

Identity & Accounts (2)

Tool

Description

fizzy_get_identity

Get current user's identity and accounts

fizzy_get_accounts

List all accessible accounts

Boards (5)

Tool

Description

fizzy_get_boards

List all boards in an account (complete list; every upstream page is fetched server-side)

fizzy_get_board

Get details of a specific board

fizzy_create_board

Create a new board

fizzy_update_board

Update a board's name

fizzy_delete_board

Delete a board

Cards (6)

Tool

Description

fizzy_get_cards

List cards with optional filters (board, indexed_by, column, assignees, tags, search); search_mode="all" requires every usable search word instead of any; fields="summary" returns a much smaller payload for browsing

fizzy_get_pins

List the current user's pinned cards (not paginated, max 100); prefer fields="summary"

fizzy_get_card

Get card details including description, assignees, tags; include_attachments=true adds structured attachment metadata

fizzy_create_card

Create a new card with title, description, column, assignees, tags, due date

fizzy_update_card

Update any card property

fizzy_delete_card

Delete a card

Card Actions (13)

Tool

Description

fizzy_close_card

Close a card (mark as done)

fizzy_reopen_card

Reopen a closed card

fizzy_move_card_to_not_now

Move a card to "Not Now" triage

fizzy_move_card_to_column

Move a card from triage to a specific column

fizzy_send_card_to_triage

Send a card back to triage (remove from column)

fizzy_toggle_card_tag

Toggle a tag on/off for a card

fizzy_toggle_card_assignment

Toggle a user assignment on/off for a card

fizzy_watch_card

Subscribe to notifications for a card

fizzy_unwatch_card

Unsubscribe from notifications for a card

fizzy_gild_card

Mark a card as golden (team-wide priority); filter with indexed_by="golden"

fizzy_ungild_card

Remove a card's golden status

fizzy_pin_card

Pin a card to the current user's personal quick-access list

fizzy_unpin_card

Unpin a card for the current user

Comments (5)

Tool

Description

fizzy_get_card_comments

List comments on a card (complete thread; every upstream page is fetched server-side); fields="summary" drops the duplicated HTML body and repeated card/creator detail; include_attachments=true adds structured attachment metadata

fizzy_get_comment

Get a specific comment

fizzy_create_comment

Add a comment to a card (supports HTML)

fizzy_update_comment

Update a comment

fizzy_delete_comment

Delete a comment

Reactions (3)

Tool

Description

fizzy_get_reactions

Get all emoji reactions on a comment

fizzy_add_reaction

Add an emoji reaction to a comment

fizzy_remove_reaction

Remove an emoji reaction from a comment

Steps / To-dos (4)

Tool

Description

fizzy_get_step

Get a specific to-do step on a card

fizzy_create_step

Create a new to-do step on a card

fizzy_update_step

Update a step (description or completion status)

fizzy_delete_step

Delete a step from a card

Columns (5)

Tool

Description

fizzy_get_columns

List columns on a board

fizzy_get_column

Get column details

fizzy_create_column

Create a new column with name and color

fizzy_update_column

Update column name/color

fizzy_delete_column

Delete a column

Tags (1)

Tool

Description

fizzy_get_tags

List all tags in an account (complete list; every upstream page is fetched server-side)

Users (4)

Tool

Description

fizzy_get_users

List users in an account (complete roster; every upstream page is fetched server-side)

fizzy_get_user

Get user details

fizzy_update_user

Update user's display name

fizzy_deactivate_user

Deactivate a user

Notifications (4)

Tool

Description

fizzy_get_notifications

List notifications for current user: default returns up to 100 unread plus the latest page of read ones, page=2,3,... walks older read-only history; fields="summary" shrinks the embedded card and creator objects

fizzy_mark_notification_read

Mark notification as read

fizzy_mark_notification_unread

Mark notification as unread

fizzy_mark_all_notifications_read

Mark all notifications as read

Attachments (2)

Tool

Description

fizzy_upload_file

Upload a file and get back HTML that embeds it in rich text

fizzy_get_attachment

Fetch a file already attached to a card or comment; images come back as an image

Attaching a file to a card or comment

fizzy_upload_file uploads the file and returns an attachment_html snippet. It does not attach anything by itself — every rich-text field already accepts HTML, so you include the snippet wherever you want the file to appear:

// 1. Upload. Use file_path locally, or base64_data anywhere.
{ "name": "fizzy_upload_file",
  "arguments": { "account_slug": "123456", "file_path": "/tmp/screenshot.png" } }

// Returns:
// {
//   "attachable_sgid": "eyJfcmFpbHMi...",
//   "filename": "screenshot.png",
//   "content_type": "image/png",
//   "byte_size": 8124,
//   "attachment_html": "<action-text-attachment sgid=\"eyJfcmFpbHMi...\"></action-text-attachment>"
// }

// 2. Reference it in any rich-text field — a comment body here, but a card
//    description works the same way.
{ "name": "fizzy_create_comment",
  "arguments": {
    "account_slug": "123456",
    "card_number": "42",
    "body": "<p>Steps to reproduce:</p><action-text-attachment sgid=\"eyJfcmFpbHMi...\"></action-text-attachment>"
  } }

Use attachment_html verbatim. It carries the blob's attachable_sgid, which is the only token ActionText resolves; a hand-built tag using some other signed id will save without error and then render as a broken-attachment placeholder.

File input: provide exactly one of file_path or base64_data.

Input

stdio

HTTP / SSE

Cloudflare Workers

base64_data (+ filename)

✅

✅

✅

file_path

✅

❌ rejected

❌ rejected

file_path is accepted only on stdio, where the MCP client and the server are the same user, so the server reads nothing that user could not already read. The HTTP and SSE transports serve remote callers — honouring a path there would let a client read the server's disk — and Workers have no filesystem. Uploads are capped at 10 MB on both paths.

Reading an attachment that is already on a card

The API never reports attachments as data. They exist only as <action-text-attachment> markup inside the rich-text HTML — description_html on a card, body.html on a comment — and the plain-text rendering flattens each one to a bare [filename.png] with no URL. Reading one back is therefore two steps.

include_attachments is opt-in and changes nothing when omitted: without it, both tools return exactly the response they always did.

// 1. Ask for the structured metadata alongside the card.
{ "name": "fizzy_get_card",
  "arguments": { "account_slug": "1234567", "card_id": "42", "include_attachments": true } }

// Adds an "attachments" array to the usual card payload:
// [{
//   "filename": "screenshot.png",
//   "content_type": "image/png",
//   "byte_size": 204800,
//   "width": 1600,
//   "height": 900,
//   "signed_id": "eyJfcmFpbHMi...--1111...",
//   "url": "https://app.fizzy.do/1234567/rails/active_storage/blobs/redirect/...",
//   "preview_url": "https://app.fizzy.do/1234567/rails/active_storage/representations/redirect/...",
//   "preview_variation": "eyJfcmFpbHMi...--3333..."
// }]

// 2. Fetch it. Pass preview_variation as `variation` to get the resized
//    preview, which is what a model can usefully look at.
{ "name": "fizzy_get_attachment",
  "arguments": {
    "account_slug": "1234567",
    "signed_id": "eyJfcmFpbHMi...--1111...",
    "filename": "screenshot.png",
    "variation": "eyJfcmFpbHMi...--3333..."
  } }

PNG, JPEG, GIF and WebP come back as an MCP image block the model can see. Anything else — PDFs, archives, SVG, video — comes back as metadata with a note that it is not renderable, and its bytes are never downloaded.

fizzy_get_attachment takes no URL, by design. Fetching a caller-supplied URL with the account's access token attached would be a server-side request forgery carrying a credential, so the tool takes the blob's signed_id and rebuilds the address itself. Inlined images are capped at 3 MB — Base64 inflates by ~4/3 into the response — and an original over that is refused in favour of its preview rather than truncated.

The token is never sent to the storage host. ActiveStorage answers with a redirect to a signed storage URL, and that redirect is followed by hand: the Authorization header is attached only while the URL is still on the configured Fizzy origin, rather than trusting a runtime to strip credentials across origins.


Example Prompts

Once configured, you can ask your AI assistant things like:

  • "Show me all my Fizzy boards"

  • "What cards are on my Engineering board?"

  • "Create a new card called 'Fix login bug' on the Engineering board"

  • "What cards are assigned to me?"

  • "Move the 'Design review' card to the 'Done' column"

  • "Add a comment to the authentication card saying 'Ready for review'"

  • "Attach this screenshot to card 42 as evidence"

  • "Show me the screenshot attached to card 42"

  • "Show me my unread notifications"

  • "List all users in my account"

  • "Create a new column called 'In Review' with blue color on the Engineering board"


Troubleshooting

"FIZZY_ACCESS_TOKEN environment variable is required"

Make sure you've set your access token in the MCP configuration's env section.

"fizzy-mcp: command not found"

  • Use npx fizzy-mcp instead of fizzy-mcp

  • Or install globally: npm install -g fizzy-mcp

Server not appearing in Cursor/VS Code

  1. Restart the IDE after configuration changes

  2. Check the path to the executable is correct

  3. Verify Node.js is installed: node --version

  4. Check Cursor's MCP logs for errors

"Fizzy API error: 404 Not Found"

  • Verify your access token is valid

  • Check that you're using the correct account slug

  • Ensure you have permission to access the resource

Connection issues

Test your token directly:

curl -H "Authorization: Bearer your-token" \
     -H "Accept: application/json" \
     https://app.fizzy.do/my/identity.json

FAQ

How do I get started quickly?

See the Quick Start section above for a 3-step setup guide.

Is my Fizzy access token secure?

Your access token is stored in your local IDE configuration and is never sent anywhere except directly to Fizzy's API. When using HTTP/SSE transports, the token is used server-side only. Always keep your token secret and never commit it to version control.

Can I use this with multiple Fizzy accounts?

Yes! You can configure multiple MCP server instances in your IDE, each with a different access token. Just give them different names in the configuration (e.g., "fizzy-personal", "fizzy-work").

What's the difference between the transport modes?

  • stdio (default): For single-user IDE integration (Cursor, VS Code, Claude Desktop). Communication happens via standard input/output. Requires FIZZY_ACCESS_TOKEN environment variable.

  • http (Streamable HTTP): Recommended for production. Multi-user support with per-user authentication via Authorization headers. Runs an HTTP server with streamable endpoints and health checks. Supported on both Node.js and Cloudflare Workers.

  • sse (Server-Sent Events): ⚠️ Deprecated - maintained for backwards compatibility only. Multi-user support but uses older protocol version (2024-11-05). Only supported on Node.js. Use HTTP transport instead.

Which transport should I use?

  • For IDE integrations (Cursor, VS Code, Claude Desktop): Use stdio

  • For production deployments: Use HTTP (Streamable)

  • For multi-user applications: Use HTTP (Streamable)

  • For testing with MCP Inspector: Use HTTP (Streamable)

  • For Cloudflare Workers deployment: Use HTTP (Streamable) (only option)

How do I test with MCP Inspector?

MCP Inspector is a tool for testing MCP servers. Here's how to use it with Fizzy MCP:

1. Start the HTTP server:

npm run build
npm run start:http
# Server runs on http://localhost:3000

2. Launch MCP Inspector:

npx @modelcontextprotocol/inspector

3. Configure the connection:

  • Transport: Select "HTTP"

  • URL: http://localhost:3000/mcp

  • Headers: Add Authorization: Bearer YOUR_FIZZY_TOKEN

4. Test the connection:

  • Click "Connect"

  • You should see the list of 47 available tools

  • Try calling tools like fizzy_get_identity or fizzy_get_boards

Note: MCP Inspector does not support the deprecated SSE transport. Always use HTTP transport for testing.

Does this work offline?

No, the server requires an internet connection to communicate with Fizzy's API at app.fizzy.do.

How do I update to the latest version?

If using npx, it will automatically use the latest version. If installed globally, run npm update -g fizzy-mcp. If installed from source, run git pull && npm install && npm run build.

Can I create tags via the API?

No, tag creation is not available via the Fizzy API. However, you can use fizzy_toggle_card_tag which will create a tag if it doesn't exist when toggling it on a card.

What happens if I hit rate limits?

The server includes automatic retry logic with exponential backoff for rate limit errors (429 status). It will retry up to 3 times before failing.

How does ETag caching work?

The server automatically caches GET requests using ETags. When you request the same resource again, it sends the ETag to Fizzy's API. If the resource hasn't changed, Fizzy returns a 304 Not Modified response, saving bandwidth and improving speed.

Can I use this in production?

Yes! You have two options:

  1. Self-hosted: Use the HTTP transport mode with proper security settings (MCP_AUTH_TOKEN, MCP_ALLOWED_ORIGINS, and consider MCP_BIND_ALL_INTERFACES for Docker deployments).

  2. Cloudflare Workers: Deploy to the edge for global distribution, automatic scaling, and near-zero cold starts. See the Cloudflare Deployment Guide.

Where can I find the Fizzy API documentation?

Official Fizzy API docs: github.com/basecamp/fizzy/blob/main/docs/API.md


API Reference

This server implements all endpoints from the official Fizzy API Documentation:

Category

Endpoints Covered

Identity

GET /my/identity

Accounts

Embedded in identity

Boards

GET, POST, PUT, DELETE

Cards

GET (list, board, single), POST, PUT, DELETE + filtering

Comments

GET, POST, DELETE

Columns

GET (list, single), POST, PUT, DELETE

Tags

GET (account, board), POST, DELETE

Users

GET (list, single), PUT, DELETE

Notifications

GET, POST reading, DELETE reading, POST bulk_reading


Development

For contributors and developers:

# Clone the repository
git clone https://github.com/Fabric-Pro/fizzy-mcp.git
cd fizzy-mcp

# Install dependencies
npm install

# Run in development mode with hot reload
npm run dev

# Build for production
npm run build

# Run tests
npm test

# Run tests with coverage
npm run test:coverage

# Type checking
npm run typecheck

License

MIT

Contributing

Contributions are welcome! Please:

  1. Fork the repository

  2. Create a feature branch

  3. Add tests for new functionality

  4. Ensure all tests pass: npm test

  5. Submit a pull request

Author

Created by Preetham Reddy

Available Tools

54 tools
fizzy_add_reactionAdd ReactionA

Add an emoji reaction to a comment. Reactions can be emojis (👍, ❤️, 🎉) or short text (max 16 characters). Use this to quickly acknowledge or respond to comments without writing a full reply.

Inputs: content (required), comment_id (required), card_number (required), account_slug (required).

fizzy_close_cardClose CardA

Close a card to mark it as done/completed. Closed cards are archived and removed from active view. Use this when work on a card is finished.

Inputs: card_number (required), account_slug (required).

fizzy_create_boardCreate BoardA

Create a new board in a Fizzy account. Boards are top-level containers for organizing cards. Returns the newly created board with its ID and URL.

Inputs: name (required), account_slug (required).

fizzy_create_cardCreate CardA

Create a new card on a board with optional title, description (HTML supported), status (draft/published), column placement, assignees, tags, and due date. Cards start in triage by default unless a column is specified.

Inputs: title (required), board_id (required), account_slug (required), due_on, +5 more.

fizzy_create_columnCreate ColumnA

Create a new workflow column on a board with specified name and color. Columns define workflow stages and help organize cards through your process. Available colors: blue, gray, tan, yellow, lime, aqua, violet, purple, pink.

Inputs: name (required), board_id (required), account_slug (required), color.

fizzy_create_commentCreate CommentA

Add a new comment to a card. Supports HTML formatting for rich text content including bold, italic, links, code blocks, and lists. Use this to provide feedback or updates on cards.

Inputs: body (required), account_slug (required), card_id, card_number.

fizzy_create_stepCreate StepA

Create a new to-do step (checklist item) on a card. Steps help break down work into manageable tasks. New steps are created as incomplete by default.

Inputs: content (required), card_number (required), account_slug (required).

fizzy_deactivate_userDeactivate UserA
Destructive

Deactivate a user account, revoking their access to the Fizzy account. ⚠️ This is a significant operation that affects user access. Use with caution.

Inputs: user_id (required), account_slug (required).

fizzy_delete_boardDelete BoardA
Destructive

Permanently delete a board and all its contents including cards, columns, and associated data. ⚠️ This is a destructive operation that cannot be undone. Use with caution.

Inputs: board_id (required), account_slug (required).

fizzy_delete_cardDelete CardA
Destructive

Permanently delete a card and all its contents including comments, steps, and attachments. ⚠️ This is a destructive operation that cannot be undone.

Inputs: card_id (required), account_slug (required).

fizzy_delete_columnDelete ColumnA
Destructive

Permanently delete a workflow column from a board. Cards in this column will be moved to triage. ⚠️ This is a destructive operation that cannot be undone.

Inputs: board_id (required), column_id (required), account_slug (required).

fizzy_delete_commentDelete CommentA
Destructive

Permanently delete a comment from a card. ⚠️ This is a destructive operation that cannot be undone. Only the comment author can delete their own comments.

Inputs: comment_id (required), card_number (required), account_slug (required).

fizzy_delete_stepDelete StepA
Destructive

Permanently delete a to-do step from a card. ⚠️ This is a destructive operation that cannot be undone.

Inputs: step_id (required), card_number (required), account_slug (required).

fizzy_get_accountsList AccountsA
Read-only

Get all Fizzy accounts accessible to the current user. Returns account details including slugs, names, and access levels.

Inputs: no named parameters.

fizzy_get_attachmentGet AttachmentA
Read-only

Fetch a file already attached to a card or comment and return it so it can actually be looked at. Images (PNG, JPEG, GIF, WebP) come back as an image the model can see; any other type comes back as metadata with a note that it cannot be rendered, and its bytes are not downloaded. Get the 'signed_id' and 'filename' to pass here from fizzy_get_card or fizzy_get_card_comments called with include_attachments=true — this tool takes no URL, and building the arguments from a URL by hand will not work. Prefer the preview: when the attachment reports a 'preview_variation', pass it as 'variation' to get the resized version, which is a fraction of the bytes and is what a full-resolution screenshot is refused in favour of. Use this whenever a card or comment references a screenshot, mockup, diagram, or error image and the answer depends on what it shows.

Inputs: filename (required), signed_id (required), account_slug (required), variation.

fizzy_get_boardGet Board DetailsA
Read-only

Get detailed information about a specific board including its name, description, URL, and metadata. Use this to understand board structure before querying cards or columns.

Inputs: board_id (required), account_slug (required).

fizzy_get_boardsList BoardsA
Read-only

Get all boards in a Fizzy account. Returns board details including IDs, names, descriptions, and URLs. Use this to discover available boards before working with cards. The result is the complete list: every upstream page is fetched server-side, so there is no page parameter and nothing further to request.

Inputs: account_slug (required).

fizzy_get_cardGet Card DetailsA
Read-only

Get detailed information about a specific card including full description (HTML), assignees, tags, due dates, steps (to-dos), and metadata. Use this to see complete card content before making updates. Attachments — screenshots, images, PDFs, logs — appear in the description only as raw markup, and the plain-text description flattens them to a bare filename with no way to fetch them. Pass include_attachments=true to also get an 'attachments' array with each file's filename, content_type, byte_size, dimensions and signed_id; pass that signed_id and filename to fizzy_get_attachment to actually see an image. Do that whenever a card mentions a screenshot or the answer depends on what a picture shows.

Inputs: card_id (required), account_slug (required), include_attachments.

fizzy_get_card_commentsList Card CommentsA
Read-only

Get all comments on a card in chronological order. Returns comment text (HTML), authors, timestamps, and reaction counts. Use this to review discussion and feedback on a card. The result is the complete thread: every upstream page is fetched server-side, so there is no page parameter and nothing further to request. Use fields='summary' to drop the duplicated HTML body and the repeated per-comment card/creator detail — comment text itself is never truncated in either mode. Attachments posted in a comment appear only as raw markup inside the HTML body, which fields='summary' drops entirely. Pass include_attachments=true to add a per-comment 'attachments' array with each file's filename, content_type, byte_size, dimensions and signed_id — it works in both modes — then pass that signed_id and filename to fizzy_get_attachment to actually see an image.

Inputs: account_slug (required), fields, card_id, card_number, +1 more.

fizzy_get_cardsList CardsA
Read-only

Get a page of cards in an account with optional filtering by board, indexed_by (e.g., 'golden' for priority cards), column, assignees, tags, or search terms. search OR-matches its words by default; set search_mode='all' to require every usable word (stopwords and words under 3 characters are dropped and listed in ignored_search_terms), which is the mode to use when checking whether a card already exists. Use board_id to scope results to a specific board and column_id to scope to a workflow column. Results are PAGINATED with a server-controlled, variable page size, so never compute a page count from the length of one page. Returns an object {cards, page, total_count, has_more, next_page}, where total_count is the total number of cards matching the filters (NOT the length of this page). To enumerate every match, call repeatedly with page = next_page until has_more is false OR cards comes back empty — an out-of-range page returns empty cards but may still report has_more true. A board's cards_count from fizzy_get_boards can exceed a single page of results; that is expected, not a discrepancy. Use fields='summary' when browsing, searching, or scanning many cards — it drops full descriptions/HTML and returns a much smaller payload (often 100x+ smaller). Once you've identified the specific card you need, call fizzy_get_card for its full detail.

Inputs: account_slug (required), page, fields, search, +6 more.

fizzy_get_columnGet Column DetailsA
Read-only

Get detailed information about a specific workflow column including its name, color, position, and card count.

Inputs: board_id (required), column_id (required), account_slug (required).

fizzy_get_columnsList Board ColumnsA
Read-only

Get all workflow columns on a board. Columns represent workflow stages (e.g., To Do, In Progress, Done). Returns column IDs, names, colors, and positions in the workflow.

Inputs: board_id (required), account_slug (required).

fizzy_get_commentGet Comment DetailsA
Read-only

Get detailed information about a specific comment including full HTML content, author, timestamp, and reactions. Use this to read a specific comment in detail.

Inputs: comment_id (required), card_number (required), account_slug (required).

fizzy_get_identityGet User IdentityA
Read-only

Get the current authenticated user's identity and all associated Fizzy accounts. Returns user information including email, name, and list of accounts with their slugs and permissions.

Inputs: no named parameters.

fizzy_get_notificationsList NotificationsA
Read-only

Get notifications for the current user in an account. Returns notification content, read/unread status, timestamps, and related cards or comments. By default (page omitted) returns up to 100 unread notifications followed by the most recent page of already-read ones — this is what you want for 'what needs my attention'. Pages 2 and up contain ONLY older, already-read notifications; no unread notification ever appears there. To walk back through history, call with page=2, then 3, and so on until the array comes back empty. Page size is server-controlled and variable, so never derive counts or remaining history from the length of a page. Use fields='summary' to shrink the embedded card and creator objects down to their key identifying fields — typically several times smaller than the full payload.

Inputs: account_slug (required), page, fields.

fizzy_get_pinsList Pinned CardsA
Read-only

Get the cards the current user has pinned in an account, as a plain array of cards. Pins are per-user and per-account, so this returns only the authenticated user's pins — it is not a view of what anyone else pinned. This listing is NOT paginated: the server returns at most 100 pinned cards, and there is no page or next_page to follow. Strongly prefer fields='summary' here — the response carries full card descriptions and HTML by default, so a large pin list can run to several megabytes; summary returns the same cards far smaller. Call fizzy_get_card for the full detail of a specific pin. Use fizzy_pin_card and fizzy_unpin_card to change what appears in this list.

Inputs: account_slug (required), fields.

fizzy_get_reactionsList Comment ReactionsA
Read-only

Get all emoji reactions on a comment. Returns reaction content (emoji or text), authors, and timestamps. Use this to see how team members respond to comments.

Inputs: comment_id (required), card_number (required), account_slug (required).

fizzy_get_stepGet Step DetailsA
Read-only

Get detailed information about a specific to-do step on a card including description and completion status. Steps are checklist items that break down card work into smaller tasks.

Inputs: step_id (required), card_number (required), account_slug (required).

fizzy_get_tagsList TagsA
Read-only

Get all tags used in an account. Tags are labels for categorizing and organizing cards. Returns tag IDs, titles, and usage counts across cards. The result is the complete list: every upstream page is fetched server-side, so there is no page parameter and nothing further to request.

Inputs: account_slug (required).

fizzy_get_userGet User DetailsA
Read-only

Get detailed information about a specific user including their name, email, role, and permissions.

Inputs: user_id (required), account_slug (required).

fizzy_get_usersList UsersA
Read-only

Get all active users in an account. Returns user IDs, names, emails, and access levels. Use this to discover available users for card assignments. The result is the complete roster: every upstream page is fetched server-side, so there is no page parameter and nothing further to request.

Inputs: account_slug (required).

fizzy_gild_cardGild CardA

Mark a card as golden (priority/important). Golden cards are highlighted and can be filtered using indexed_by='golden' in fizzy_get_cards. Use this to flag high-priority work items.

Inputs: card_number (required), account_slug (required).

fizzy_mark_all_notifications_readMark All Notifications ReadA

Mark all notifications in an account as read at once. Use this to clear your notification inbox after reviewing all updates.

Inputs: account_slug (required).

fizzy_mark_notification_readMark Notification ReadA

Mark a specific notification as read. Use this to acknowledge notifications and clear them from unread status.

Inputs: account_slug (required), notification_id (required).

fizzy_mark_notification_unreadMark Notification UnreadA

Mark a specific notification as unread. Use this to flag notifications for later attention.

Inputs: account_slug (required), notification_id (required).

fizzy_move_card_to_columnMove Card to ColumnB

Move a card from triage to a specific workflow column. Use this to transition cards through your workflow stages.

Inputs: column_id (required), card_number (required), account_slug (required).

fizzy_move_card_to_not_nowMove Card to Not NowA

Move a card to the 'Not Now' triage area, indicating it's not a current priority. This removes the card from workflow columns but keeps it accessible.

Inputs: card_number (required), account_slug (required).

fizzy_pin_cardPin CardA

Pin a card for the current user, keeping it in their personal quick-access list. Pins are per-user and per-account: pinning affects only the authenticated user's list, not what teammates see. Use this to keep track of a card you need to return to. Retrieve the resulting list with fizzy_get_pins. To flag a card as high-priority for the whole team instead, use fizzy_gild_card.

Inputs: card_number (required), account_slug (required).

fizzy_remove_reactionRemove ReactionA

Remove an emoji reaction from a comment. Only the user who added the reaction can remove it.

Inputs: comment_id (required), card_number (required), reaction_id (required), account_slug (required).

fizzy_reopen_cardReopen CardA

Reopen a previously closed card to make it active again. Use this to resume work on completed cards or undo accidental closures.

Inputs: card_number (required), account_slug (required).

fizzy_send_card_to_triageSend Card to TriageA

Send a card back to the triage area by removing it from its current column. Use this to reassess or reprioritize cards that need more planning.

Inputs: card_number (required), account_slug (required).

fizzy_toggle_card_assignmentToggle Card AssignmentA

Assign or unassign a user to/from a card. If the user is already assigned, they will be unassigned. If not assigned, they will be assigned. Use this to manage card ownership and responsibilities.

Inputs: assignee_id (required), card_number (required), account_slug (required).

fizzy_toggle_card_tagToggle Card TagA

Add or remove a tag from a card. If the tag doesn't exist in the account, it will be created automatically. Tags help organize and categorize cards. Leading '#' characters are automatically stripped from tag titles.

Inputs: tag_title (required), card_number (required), account_slug (required).

fizzy_ungild_cardUngild CardA

Remove golden status from a card. The card will no longer appear in golden card filters and will lose its priority highlighting.

Inputs: card_number (required), account_slug (required).

fizzy_unpin_cardUnpin CardA

Unpin a card for the current user, removing it from their personal quick-access list. Only affects the authenticated user's pins; the card itself is unchanged and remains on its board.

Inputs: card_number (required), account_slug (required).

fizzy_unwatch_cardUnwatch CardA

Unsubscribe from notifications for a card. You'll stop receiving updates about card changes. Use this to reduce notification noise for cards you're no longer actively involved with.

Inputs: card_number (required), account_slug (required).

fizzy_update_boardUpdate BoardA

Update an existing board's name or other properties. This operation modifies board metadata but does not affect cards or columns.

Inputs: name (required), board_id (required), account_slug (required).

fizzy_update_cardUpdate CardA

Update an existing card's properties including title, description, status, column placement, assignees, tags, and due date. Partial updates are supported - only provided fields will be changed.

Inputs: card_id (required), account_slug (required), title, due_on, +5 more.

fizzy_update_columnUpdate ColumnA

Update a workflow column's name or color. Use this to refine your workflow stages or improve visual organization. This does not affect cards in the column.

Inputs: board_id (required), column_id (required), account_slug (required), name, +1 more.

fizzy_update_commentUpdate CommentA

Edit an existing comment's content. Supports HTML formatting. Only the comment author can update their own comments.

Inputs: body (required), comment_id (required), card_number (required), account_slug (required).

fizzy_update_stepUpdate StepA

Update a to-do step's description or completion status. Use this to mark steps as complete/incomplete or edit their descriptions.

Inputs: step_id (required), card_number (required), account_slug (required), content, +1 more.

fizzy_update_userUpdate UserA

Update a user's display name or other profile information. Requires appropriate permissions for user management.

Inputs: name (required), user_id (required), account_slug (required).

fizzy_upload_fileUpload FileA

Upload a file (screenshot, image, PDF, log) to Fizzy and get back the HTML needed to embed it. This does not attach the file on its own — it returns an 'attachment_html' snippet that you then include in any rich-text field: pass it in 'body' to fizzy_create_comment or fizzy_update_comment, or in 'description' to fizzy_create_card or fizzy_update_card. Combine it with your own HTML, e.g. body: "Steps to reproduce:" + attachment_html. Provide the file as 'file_path' (a local path — stdio transport only) or as 'base64_data' with 'filename' (works everywhere).

Inputs: account_slug (required), filename, file_path, base64_data, +1 more.

fizzy_watch_cardWatch CardA

Subscribe to notifications for a card. You'll receive notifications when the card is updated, commented on, or when its status changes.

Inputs: card_number (required), account_slug (required).

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.8/5.0

    Scored across 54 tools

    Disambiguation4/5

    Most tools target a distinct resource and action, and the plural/singular get_* pattern makes collection versus detail calls easy to separate. The main ambiguity is between move_card_to_not_now and send_card_to_triage, which both describe returning a card to a triage-like area, and get_reactions overlaps somewhat with reaction data already exposed by get_comment.

    Naming Consistency5/5

    Every tool uses the fizzy_ prefix with clear snake_case verb_noun names. Collection endpoints consistently use plural nouns and singular endpoints use singular nouns, while create/update/delete/close/reopen/toggle follow a predictable pattern.

    Tool Count2/5

    54 tools is a very large surface for an MCP server, even though the domain is broad. Several calls (get_boards/get_board, get_users/get_user, get_columns/get_column) and many card state toggles could reasonably be consolidated, making the set heavier than necessary.

    Completeness4/5

    The server provides full CRUD and lifecycle coverage for boards, cards, comments, steps, columns, and notifications, plus file upload/retrieval and reactions. Minor gaps remain: no direct tag CRUD beyond auto-creation, no reactivate or invite user, and no delete attachment.

    Maintenance

    ActivityActive
    ResponsivenessMostly unanswered

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      D
      maintenance
      Enables AI agents to interact with the Fizzy task management tool through 40 specialized tools for managing boards, cards, and comments. It supports comprehensive task operations including card creation, triaging, and user assignments with built-in retry logic and secure authentication.
      14 npm
      MIT
    • A
      license
      Not graded
      quality
      D
      maintenance
      Open-source MCP server that connects AI assistants to Fizzy (Basecamp's task management) with 70+ tools for boards, cards, workflows, and AI-powered project management.
      14 npm
      3
      MIT
    • A
      license
      A
      quality
      D
      maintenance
      MCP server for Fizzy, Basecamp's open-source Kanban tool. Enables AI assistants to manage boards, cards, tags, columns, and comments via API.
      13
      33 npm
      MIT