Skip to main content
Glama

Bug Tracker MCP Server

Summary

An MCP Server that leverages notes written in Markdown to track bugs. The server was written for those developing Cisco Nexus Dashboard applications which use the REST API, but could easily be leveraged for other uses.

My use case is providing Claude Code with a resource through which it can determine the suitability of various Nexus Dashboard endpoints for a given task, and whether an endpoint exhibits any behavioral bugs and, if so, what version(s) exhibit the behavior and what version (if any) fixes the behavior. Notes might also contain workaround(s).

The actual notes are not included in this repository.

Related MCP server: Scopecraft Command

Setup

1. Install Obsidian and login

2. Setup sync with the ND Vault (vault should be in $HOME/Obsidian/ND)

3. Clone this repository and install its dependencies

The server needs Python 3.14 or later and uv. The LaunchDaemon template in step 4 expects this repository at $HOME/repos/mcp/bug-tracker-mcp, with uv installed inside the project's virtual environment at .venv/bin/uv:

mkdir -p $HOME/repos/mcp
cd $HOME/repos/mcp
git clone https://github.com/allenrobel/bug-tracker-mcp.git
cd bug-tracker-mcp
python3.14 -m venv .venv
.venv/bin/pip install uv
.venv/bin/uv sync

uv sync installs the dependencies pinned in uv.lock into .venv. It leaves uv itself in place.

Check that the server starts, then stop it with Ctrl-C:

OBSIDIAN_VAULT_PATH=$HOME/Obsidian/ND .venv/bin/uv run server.py

It should report Uvicorn running on http://0.0.0.0:8001.

If you already have a standalone uv (for example from the uv installer or Homebrew), you can use that instead. Skip the venv and pip commands and run uv sync, which creates .venv and downloads Python 3.14 if it is missing. Then, in step 4, point the plist at your uv as described there.

Do not move or rename the repository directory afterwards. The scripts in .venv/bin and the installed plist both contain its absolute path. If you have to move it, delete .venv, repeat this step, and reinstall the plist.

4. Install the LaunchDaemon

The server runs as a system LaunchDaemon, so it starts at boot without anyone logging in. The UserName key makes it run as your account, not as root. (The vault itself only stays current while Obsidian is running in a login session.)

com.bug-tracker-mcp.plist in this repository is a template. Two placeholders must be replaced before it is installed:

Placeholder

Replace with

YOUR_USERNAME

The account the server runs as (id -un)

YOUR_TMPDIR

That account's temp directory (getconf DARWIN_USER_TEMP_DIR)

The template also assumes the following. Edit the file if your host differs:

  • This repository is at /Users/YOUR_USERNAME/repos/mcp/bug-tracker-mcp (ProgramArguments and WorkingDirectory).

  • uv is at .venv/bin/uv inside this repository, as set up in step 3. If you use a standalone uv instead, use the path printed by command -v uv as the first ProgramArguments entry.

  • The vault is at /Users/YOUR_USERNAME/Obsidian/ND (OBSIDIAN_VAULT_PATH).

  • The account's primary group is staff (GroupName; check with id -gn).

Run the following as the account the server should run as. It fills in the placeholders, installs the result, and starts the server:

cd $HOME/repos/mcp/bug-tracker-mcp
mkdir -p $HOME/Library/Logs/mcp
sed -e "s|YOUR_USERNAME|$(id -un)|g" \
    -e "s|YOUR_TMPDIR|$(getconf DARWIN_USER_TEMP_DIR)|" \
    com.bug-tracker-mcp.plist \
    | sudo tee /Library/LaunchDaemons/com.bug-tracker-mcp.plist > /dev/null
sudo chown root:wheel /Library/LaunchDaemons/com.bug-tracker-mcp.plist
sudo chmod 644 /Library/LaunchDaemons/com.bug-tracker-mcp.plist
plutil -lint /Library/LaunchDaemons/com.bug-tracker-mcp.plist
sudo launchctl bootstrap system /Library/LaunchDaemons/com.bug-tracker-mcp.plist

launchd will not load a LaunchDaemon plist unless it is owned by root and not writable by group or others, hence the chown and chmod.

If you previously installed the server as a LaunchAgent, remove that first. Otherwise both copies compete for port 8001:

launchctl bootout gui/$(id -u)/com.bug-tracker-mcp
rm $HOME/Library/LaunchAgents/com.bug-tracker-mcp.plist

5. Check, restart, and update the server

Check that it is running, and read its log:

launchctl print system/com.bug-tracker-mcp | grep -E '^\s(state|pid|last exit code) '
tail $HOME/Library/Logs/mcp/bug-tracker-mcp.err.log

Restart it:

sudo launchctl kickstart -k system/com.bug-tracker-mcp

Without sudo, stop the process instead. It runs as your account, and KeepAlive makes launchd start it again within a few seconds:

kill $(launchctl print system/com.bug-tracker-mcp | awk '/^\tpid = /{print $3}')

Edits to the vault are picked up without a restart, but changes to server.py are not. After a git pull, restart the server. uv run installs any changed dependencies when it starts, so no separate uv sync is needed.

A restart does not re-read the plist. To change the installed plist, or to uninstall, unload it first (then repeat the install commands if reinstalling):

sudo launchctl bootout system/com.bug-tracker-mcp
sudo rm /Library/LaunchDaemons/com.bug-tracker-mcp.plist

6. Edit Claude Code's config on the client Mac to point to this MCP server

  • edit $HOME/.claude.json

  • Search for the mcpServers block

  • Add the following (where mm1e is the hostname or IP address of the Mac that's hosting the MCP server)

  "mcpServers": {
    "bug-tracker-mcp": {
      "type": "http",
      "url": "http://mm1e:8001/mcp"
    }
  }

7. Restart Claude Code and check the MCP server status using the /mcp slash command

MCP Server Logic Diagram

flowchart TD
    A("Module import and setup") --> B["Read environment, constants, and create FastMCP"]
    B --> C{"Running as main script?"}
    C -->|Yes| D["Start MCP HTTP server"]
    D --> E["Await MCP tool calls"]
    C -->|No| E

    E --> F{"Which tool is called?"}
    F -->|list_bugs, search_bugs, or get_bug_by_id| I[["_all_notes()"]]
    F -->|find_bugs_for_endpoint or find_bugs_for_version| G{"Version parses?"}
    F -->|get_bug| J{"Target file exists and is relevant?"}

    G -->|No| ERR["Raise ValueError or FileNotFoundError"]
    G -->|Yes| I
    J -->|No| ERR
    J -->|Yes| L[["_load_note(path)"]]

    I --> M{"Vault directory exists?"}
    M -->|No| ERR
    M -->|Yes| R[("Vault files and note cache")]
    R --> N{"More markdown files?"}
    N -->|Yes| O{"Relevant markdown file?"}
    N -->|No| W["Drop stale cache entries and return note set"]

    O -->|No| N
    O -->|Yes| L

    L --> P{"Cached note has same mtime?"}
    P -->|Yes| Q["Reuse cached Note"]
    P -->|No| S["Parse frontmatter and build Note"]

    Q --> T{"Called from get_bug?"}
    S --> T
    T -->|Yes| Z["Return full metadata and content"]
    T -->|No| N

    W --> X["Apply tool-specific sorting, scoring, snippets, and filters"]
    X --> Z

Related MCP Connectors

Related MCP Servers