# MantisBT MCP Server [![npm version](https://img.shields.io/npm/v/@dpesch/mantisbt-mcp-server)](https://www.npmjs.com/package/@dpesch/mantisbt-mcp-server) [![license](https://img.shields.io/npm/l/@dpesch/mantisbt-mcp-server)](LICENSE) [![MCP compatible](https://img.shields.io/badge/MCP-compatible-green.svg?style=flat-square)](https://modelcontextprotocol.io/) [![MCP Badge](https://lobehub.com/badge/mcp/dpesch-mantisbt-mcp-server)](https://lobehub.com/mcp/dpesch-mantisbt-mcp-server) [![MantisBT MCP Server](https://glama.ai/mcp/servers/dpesch/mantisbt-mcp-server/badges/card.svg)](https://glama.ai/mcp/servers/dpesch/mantisbt-mcp-server) **English** · [Deutsch](README.de.md) A [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server that integrates the [MantisBT REST API](https://documenter.getpostman.com/view/29959/mantis-bug-tracker-rest-api) into Claude Code and other MCP-capable clients. Read, create, and update issues directly from your editor. ## Requirements - Node.js ≥ 22 - MantisBT installation with REST API enabled (version 2.23+) - MantisBT API token (create under *My Account → API Tokens*) ## Installation **Via npx (recommended):** Add to `~/.claude/claude_desktop_config.json` (Claude Desktop) or your local `claude_desktop_config.json` (Claude Code): ```json { "mcpServers": { "mantisbt": { "command": "npx", "args": ["-y", "@dpesch/mantisbt-mcp-server"], "env": { "MANTIS_BASE_URL": "https://your-mantis.example.com/api/rest", "MANTIS_API_KEY": "your-api-token" } } } } ``` **Local build:** ```bash git clone https://codeberg.org/dpesch/mantisbt-mcp-server cd mantisbt-mcp-server npm run init npm run build ``` ```json { "mcpServers": { "mantisbt": { "command": "node", "args": ["/path/to/mantisbt-mcp-server/dist/index.js"], "env": { "MANTIS_BASE_URL": "https://your-mantis.example.com/api/rest", "MANTIS_API_KEY": "your-api-token" } } } } ``` ## Configuration ### Environment variables | Variable | Required | Default | Description | |---|---|---|---| | `MANTIS_BASE_URL` | ✅ | – | Base URL of your MantisBT installation. Both `https://your-mantis.example.com` and `https://your-mantis.example.com/api/rest` are accepted — the `/api/rest` suffix is normalized automatically. | | `MANTIS_API_KEY` | ✅ | – | API token for authentication | | `MANTIS_USE_INDEX_PHP` | – | auto | Set to `true` when URL rewriting is unavailable — REST requests then use `/api/rest/index.php/` instead of `/api/rest/`. Detected automatically when `MANTIS_BASE_URL` ends with `/api/rest/index.php`; an explicit value always wins. See the [cookbook](docs/cookbook.md#connect-to-an-installation-without-url-rewriting). | | `MANTIS_CACHE_DIR` | – | `~/.cache/mantisbt-mcp` | Directory for the metadata cache | | `MANTIS_CACHE_TTL` | – | `3600` | Cache lifetime in seconds | | `TRANSPORT` | – | `stdio` | Transport mode: `stdio` or `http` | | `PORT` | – | `3000` | Port for HTTP mode | | `MCP_HTTP_HOST` | – | `127.0.0.1` | Bind address for HTTP mode. **Changed from `0.0.0.0` to `127.0.0.1`** — the server now listens on localhost only by default. Set to `0.0.0.0` for Docker or remote access. | | `MCP_HTTP_TOKEN` | ✅ (HTTP mode) | – | Bearer token for the `/mcp` endpoint (`Authorization: Bearer `). **Required when `TRANSPORT=http`** — the server refuses to start in HTTP mode without it, so tools are never exposed unauthenticated. Ignored in stdio mode. The `/health` endpoint is always public. | | `MANTIS_SEARCH_ENABLED` | – | `false` | Set to `true` to enable semantic search | | `MANTIS_SEARCH_BACKEND` | – | `vectra` | Vector store backend: `vectra` (pure JS) or `sqlite-vec` (requires manual install) | | `MANTIS_SEARCH_DIR` | – | `{MANTIS_CACHE_DIR}/search` | Directory for the search index | | `MANTIS_SEARCH_MODEL` | – | `Xenova/paraphrase-multilingual-MiniLM-L12-v2` | Embedding model name (downloaded once on first use, ~80 MB) | | `MANTIS_SEARCH_THREADS` | – | `1` | Number of ONNX intra-op threads for the embedding model. Default is 1 to prevent CPU saturation on multi-core machines and WSL. Increase only if index rebuild speed matters and the host is dedicated to this workload. | | `MANTIS_UPLOAD_DIR` | – | – | Restrict `upload_file`'s `file_path` to files within this directory (path traversal via `../` is blocked). In **stdio mode** `file_path` is unrestricted unless this is set. In **HTTP mode** `file_path` reads from the server's filesystem, so it is **disabled unless this variable is set** — HTTP clients should upload via the `content` (Base64) parameter instead. | ## Available tools ### Issues | Tool | Description | |---|---| | `get_issue` | Retrieve an issue by its numeric ID; optional `select` for field projection to reduce response size | | `get_issues` | Retrieve multiple issues by ID in one call (1–50 IDs); missing or inaccessible IDs return `null` at their position instead of failing the call | | `list_issues` | Filter issues by project, status, author, and more; optional `select` for field projection and `status` for client-side status filtering — canonical English status names (e.g. `"new"`, `"resolved"`) are matched by ID, making the filter language-independent on localized installations | | `create_issue` | Create a new issue; `severity` and `priority` must be canonical English names (e.g. `minor`, `major`, `normal`, `high`) — call `get_issue_enums` to see all valid values and their localized labels; optional `handler` parameter accepts a username as alternative to `handler_id` (resolved against project members); optional `custom_fields` to set custom field values | | `update_issue` | Update an existing issue; enum fields (`status`, `priority`, `severity`, `resolution`, `reproducibility`) accept canonical English names, localized names, or numeric IDs — the server resolves names to IDs automatically; supports `custom_fields` and an optional `note` parameter that appends a note in the same call (e.g. the reason for a status change) | | `delete_issue` | Delete an issue | ### Notes | Tool | Description | |---|---| | `list_notes` | List all notes of an issue | | `add_note` | Add a note to an issue | | `delete_note` | Delete a note | ### Attachments | Tool | Description | |---|---| | `list_issue_files` | List attachments of an issue | | `upload_file` | Upload a file to an issue — preferred: local `file_path` (server reads and encodes automatically); fallback: Base64-encoded `content` + `filename` (use only when `file_path` is not available) | ### Relationships | Tool | Description | |---|---| | `add_relationship` | Create a relationship between two issues; optional `type_name` parameter accepts a string name (e.g. `"related_to"`, `"duplicate_of"`) as alternative to numeric `type_id` | | `remove_relationship` | Remove a relationship from an issue (use the `id` from the relationship object, not the type) | ### Monitors | Tool | Description | |---|---| | `add_monitor` | Add a user as a monitor of an issue | | `remove_monitor` | Remove a user as a monitor of an issue | ### Tags | Tool | Description | |---|---| | `list_tags` | List all available tags; falls back to the metadata cache when `GET /tags` returns 404 (run `sync_metadata` first to populate) | | `attach_tags` | Attach tags to an issue | | `detach_tag` | Remove a tag from an issue | ### Projects | Tool | Description | |---|---| | `list_projects` | List all accessible projects; returns normalized project data (consistent with `sync_metadata` cache) | | `get_project_versions` | Get versions of a project; optional `obsolete` and `inherit` booleans to include obsolete or parent-inherited versions; each version includes a `timestamp` field (version date); see `create_version`, `update_version`, `release_version`, `delete_version` to modify versions | | `create_version` | Create a new version in a project; returns the created version object (id, name, description, released, obsolete, timestamp); requires `manage_project_threshold` (default: manager) | | `update_version` | Update an existing version; only the fields you pass are changed (at least one required); renaming rewrites version/target_version/fixed_in_version on all referencing issues; requires `manage_project_threshold` (default: manager) | | `release_version` | Mark a version as released and set its date (default: now); optionally create a follow-up version in the same step via `next_version`; requires `manage_project_threshold` (default: manager) | | `delete_version` | Permanently delete a version — irreversible, MantisBT clears version/target_version/fixed_in_version on all referencing issues; prefer `update_version` with `obsolete=true` as the non-destructive alternative; requires `manage_project_threshold` (default: manager) | | `get_project_categories` | Get categories of a project | | `get_project_users` | Get users of a project | | `find_project_member` | Search project members by name, real name, or email (case-insensitive substring match); optional `query` and `limit` (default 10, max 100); cache-first | ### Semantic search *(optional)* Instead of exact keyword matching, semantic search understands the *meaning* behind a query. Ask in plain language — the search engine finds conceptually related issues even when the wording doesn't match: - *"login fails after password reset"* — finds issues about authentication edge cases - *"performance problems on the checkout page"* — surfaces related reports regardless of the exact terminology used - *"duplicate entries in the invoice list"* — catches issues described as "shown twice", "double records", etc. The embedding model (~80 MB) runs entirely **offline** — no OpenAI key, no external API. It is downloaded once on first start and cached locally. Issues are indexed incrementally on every server start (only new and updated issues are re-indexed). Activate with `MANTIS_SEARCH_ENABLED=true`. | Tool | Description | |---|---| | `search_issues` | Natural language search over all indexed issues — returns top-N results with cosine similarity score; optional `select` (comma-separated field names) enriches each result with the requested issue fields; optional `highlight` (boolean, default `false`) adds a `highlights` field per result with keyword-matched excerpts from `summary` and `description` (matched terms shown in `**bold**`) | | `rebuild_search_index` | Build or update the search index; `full: true` clears and rebuilds from scratch | | `get_search_index_status` | Return the current fill level of the search index: how many issues are indexed vs. total, and the timestamp of the last sync | #### Which backend to choose? | | `vectra` *(default)* | `sqlite-vec` | |---|---|---| | Dependencies | None (pure JS) | Requires native build tools | | Install | Included | `npm install sqlite-vec better-sqlite3` | | Best for | Up to ~10,000 issues | 10,000+ issues | | Performance | Fast enough for most setups | Faster for large corpora | Start with `vectra`. Switch to `sqlite-vec` if indexing or query times become noticeably slow. ```bash npm install sqlite-vec better-sqlite3 # then set MANTIS_SEARCH_BACKEND=sqlite-vec ``` ### Metadata & system | Tool | Description | |---|---| | `get_issue_fields` | Return all field names valid for the `select` parameter of `list_issues` | | `get_metadata` | Retrieve a compact metadata summary: project/tag counts and per-project user/version/category counts; use `get_metadata_full` for complete arrays | | `get_metadata_full` | Return the full raw metadata cache as minified JSON (all projects with complete fields, users/versions/categories per project, all tags) | | `sync_metadata` | Refresh the metadata cache | | `list_filters` | List saved filters | | `get_current_user` | Retrieve your own user profile | | `list_languages` | List available languages | | `get_config` | Show server configuration (base URL, cache TTL) | | `get_issue_enums` | Return valid ID/name pairs for all issue enum fields (severity, status, priority, resolution, reproducibility) — use before `create_issue` / `update_issue` to look up correct values; on localized installations each entry may include a `canonical_name` with the standard English API name | | `get_mantis_version` | Get MantisBT version and check for updates | | `get_mcp_version` | Return the version of this mantisbt-mcp-server instance | ## Available resources MCP Resources are URI-addressable, read-only data that clients can fetch directly without calling a tool. They are the third MCP primitive alongside Tools and Prompts. Note that Resource support is less widely implemented in MCP clients than Tools — check your client's documentation. | Resource URI | Description | |---|---| | `mantis://me` | Profile of the authenticated API user (live fetch) | | `mantis://projects` | All accessible MantisBT projects as a compact list (cache-backed, refreshed via `sync_metadata`) | | `mantis://projects/{id}` | Combined project view: project fields + users + versions + categories in one call; cache-first, list-support for enumerating all available project URIs | | `mantis://enums` | Valid values for all issue enum fields: severity, priority, status, resolution, reproducibility (live fetch) | ## Available prompts MCP prompt templates are conversation starters that instruct the LLM to collect structured input and then call the appropriate tool. They are not tools themselves — they initiate a guided workflow. | Prompt | Required args | Optional args | Description | |---|---|---|---| | `create-bug-report` | `project_id`, `category`, `summary`, `description` | `steps_to_reproduce`, `expected`, `actual`, `environment` | Guides through a structured bug report and calls `create_issue` | | `create-feature-request` | `project_id`, `category`, `summary`, `description` | `use_case` | Guides through a feature request and calls `create_issue` | | `summarize-issue` | `issue_id` | – | Fetches an issue via `get_issue` and returns a concise summary | | `project-status` | `project_id` | – | Lists issues via `list_issues` and generates a status report grouped by severity | ## HTTP mode For use as a standalone server (e.g. in remote setups). `MCP_HTTP_TOKEN` is **required** in HTTP mode — the server refuses to start without it: ```bash MCP_HTTP_TOKEN=secret MANTIS_BASE_URL=... MANTIS_API_KEY=... \ TRANSPORT=http PORT=3456 node dist/index.js # With explicit bind address (required for Docker/remote): # MCP_HTTP_TOKEN=secret MANTIS_BASE_URL=... MANTIS_API_KEY=... \ # TRANSPORT=http PORT=3456 MCP_HTTP_HOST=0.0.0.0 node dist/index.js ``` Every `/mcp` request must send `Authorization: Bearer `. Over HTTP, `upload_file`'s `file_path` is disabled unless `MANTIS_UPLOAD_DIR` is set — use the `content` (Base64) parameter instead. Health check: `GET http://localhost:3456/health` (always public, no token required) ## Documentation - [**Cookbook**](docs/cookbook.md) — tool-oriented recipes with copy-paste-ready parameter examples for all registered tools - [**Usage Examples**](docs/examples.md) — natural language prompt examples for everyday use cases (no tool names required) ## Development ```bash npm run init # First-time setup: install deps, git hooks, typecheck npm run build # Compile TypeScript → dist/ npm run typecheck # Type check without output npm run dev # Watch mode for development npm test # Run tests (vitest) npm run test:watch # Run tests in watch mode npm run test:coverage # Coverage report ``` ## License MIT – see [LICENSE](LICENSE) ## Contributing Contributions welcome! Please read [CONTRIBUTING.md](CONTRIBUTING.md). Repository: [codeberg.org/dpesch/mantisbt-mcp-server](https://codeberg.org/dpesch/mantisbt-mcp-server)