Back to search
D
53.9 /100

io.github.jztan/redmine-mcp-server

Author jztan
Scanned 47d ago

Production-ready MCP server for Redmine with security, pagination, and enterprise features

Versions

2.0.0scored
first seen May 19, 2026

Trust breakdown

PermissionsTool SafetyAuthAnnotationsCode QualityStabilitySpecVuln HistoryAuthorTransparencyCommunity

Tools 69

get_redmine_issue
annotations: none low

issue_id int
list_time_entries
annotations: none low

needs_int
annotations: none low

x int
needs_int_or_sentinel
annotations: none low

status_id string
union_return
annotations: none low

status_id string
create_redmine_issue
annotations: none low

Probe registered while read-only mode is active.

project_id int
some_probe_tool
annotations: none low

Probe registered with an explicit annotations=None.

update_redmine_issue
annotations: none low

fields string uploads string issue_id int
list_redmine_issues
annotations: none low

project_id str
manage_document
annotations: none low

action str project_id str
get_current_user
annotations: none low

not_in_map_tool
annotations: none low

get_checklist
annotations: none low

Retrieve all checklist items for a Redmine issue. Requires the RedmineUP Checklists plugin and ``REDMINE_CHECKLISTS_ENABLED=true``. Args: issue_id: The ID of the issue whose checklist to retrieve. Returns: A dictionary with an ``items`` list of checklist item dicts, each containing ``id``, ``subject``, ``is_done``, ``position``, ``created_at``, and ``updated_at``. Also includes ``total_count``. Returns an error dict if the plugin is disabled or on failure.

issue_id int
update_checklist_item
annotations: none low

Update a checklist item's text, done state, or position. Requires the RedmineUP Checklists plugin and ``REDMINE_CHECKLISTS_ENABLED=true``. This is a write operation and is blocked when ``REDMINE_MCP_READ_ONLY=true``. Args: checklist_item_id: The ID of the checklist item to update. subject: New text for the checklist item (optional). is_done: New done state (optional). position: New position/order (optional). Returns: A success dict with the updated fields, or an error dict on failure.

is_done string subject string position string checklist_item_id int
create_checklist_item
annotations: none low

Create a new checklist item (or section header) on a Redmine issue. Requires the RedmineUP Checklists plugin and ``REDMINE_CHECKLISTS_ENABLED=true``. This is a write operation and is blocked when ``REDMINE_MCP_READ_ONLY=true``. Set ``is_section=True`` to create a bold section header with no checkbox. Args: issue_id: The ID of the issue to add the item to. subject: The checklist item text (required, non-blank). is_section: Whether this item is a section header (default False). is_done: Initial done state (default False). position: Optional 1-based ordering position. Returns: A success dict with the created ``checklist_item_id`` and echoed fields, or an error dict on failure.

is_done bool subject str issue_id int position string is_section bool
manage_contact
annotations: none low

RedmineUP CRM (Contacts) plugin tool. Combined CRUD-by-action. Actions: ``list``, ``get``, ``create``, ``update``, ``delete``, ``assign_to_project``, ``remove_from_project``. Requires ``REDMINE_CRM_ENABLED=true`` and the RedmineUP CRM plugin. One flat signature serves every action, so most parameters apply to some actions and are ignored by the rest. ``search``, ``tags`` and ``assigned_to_id`` narrow a ``list`` on every CRM build. The contact attributes narrow one only on the plugin's Pro build, which registers them as query filters; the Light build registers ``tags`` and nothing else, and Redmine drops an unregistered filter parameter silently, answering with the unfiltered collection. They are therefore refused unless ``REDMINE_CRM_EDITION=pro`` says the Pro build is installed -- an explicit error rather than a quietly wrong list. Which parameter belongs to which action: Args: action: Which operation to run. One of ``list``, ``get``, ``create``, ``update``, ``delete``, ``assign_to_project``, ``remove_from_project``. contact_id: The contact to act on. Required by every action except ``list`` and ``create``. project_id: On ``list``, restrict to contacts in this project. On ``create``, the project to file the new contact under (required). On ``assign_to_project`` / ``remove_from_project``, the project to attach or detach. search: ``list`` only. Free-text search over name, company and email. Note that Redmine applies it to the page it returns without narrowing the reported total, so paging through a search is unreliable for more than one page. tags: ``list`` only. Comma-separated tag filter. assigned_to_id: ``list`` only. Filter by the assigned user's ID. author_id: ``list`` only. Filter by the ID of the user who created the contact. Needs ``REDMINE_CRM_EDITION=pro``. limit: ``list`` only. Contacts per call, capped at 100 by Redmine. offset: ``list`` only. Contacts to skip, for paging past the first 100. include_pagination_info: ``list`` only. Return ``{"contacts": [...], "pagination": {...}}`` rather than a bare list (default: False), with the keys ``list_redmine_issues`` returns. ``total`` is ``null`` whenever Redmine reported no total that measures the collection being paged -- read it as "not reported", never as a number, and note that passing ``search`` is one such case. ``has_next`` is always a boolean, never ``null``, so it is safe to loop on. include: ``get`` only. Comma-separated related data to request. first_name: Required on ``create``. Filters a ``list`` where ``REDMINE_CRM_EDITION=pro``. last_name: ``create`` attribute. Filters a ``list`` where ``REDMINE_CRM_EDITION=pro``. middle_name: ``create`` attribute. Filters a ``list`` where ``REDMINE_CRM_EDITION=pro``. company: ``create`` attribute. Filters a ``list`` where ``REDMINE_CRM_EDITION=pro``. job_title: ``create`` attribute. Filters a ``list`` where ``REDMINE_CRM_EDITION=pro``. email: ``create`` attribute. Filters a ``list`` where ``REDMINE_CRM_EDITION=pro``. phone: ``create`` attribute. Filters a ``list`` where ``REDMINE_CRM_EDITION=pro``. is_company: ``create`` only -- ``true`` files the record as a company rather than a person. This is **not** a list filter: the plugin's own ``is_company`` filter returns the same wrong set for every value, so filter the ``is_company`` key on the returned contacts instead. visibility: ``create`` only. ``0`` project, ``1`` public, ``2`` private. fields: ``create`` and ``update`` only. Contact attributes to write. filters: ``list`` only. Additional Redmine query parameters, for filters this signature does not name -- most usefully ``{"cf_42": "value"}`` to filter on a contact custom field. What a build registers as a filter is the build's own business, so this cannot promise any key works: confirm a narrow filter actually narrowed. A contact custom field needs its "Used as a filter" setting on, and on the Light edition no contact custom field is ever a registered filter. Accepted keys are the filters ``ContactQuery`` registers, plus ``cf_<id>``, ``author.cf_<id>`` and ``assigned_to.cf_<id>``; any other key is refused, with an error naming what it objected to. Keys this signature already names are rejected too -- pass them as the named parameter so they are validated -- as are ``fields``, ``f`` and ``query_id``, which Redmine reads as the query's own definition and which discard every filter built from the rest of the request. Each value is one scalar -- a string, number, date or datetime, never a list, a dict, ``None`` or a ``bool`` (write a yes/no filter as ``"1"``). Returns: ``list`` a list of contact dicts -- or, with ``include_pagination_info=True``, a dict of ``contacts`` and ``pagination`` -- ``get`` / ``create`` one contact dict, the remaining actions a status dict, and ``{"error": ...}`` on failure.

tags string email string limit string phone string action string fields string offset string search string company string filters string include string author_id string job_title string last_name string contact_id string first_name string is_company bool project_id string visibility int middle_name string assigned_to_id string include_pagination_info bool
list_contact_tags
annotations: none low

List the tags in use on RedmineUP CRM contacts. Use it to discover valid names for the ``tags`` filter of ``manage_contact(action="list")`` and for ``tag_list`` on create/update. Requires ``REDMINE_CRM_ENABLED=true``. Returns: A list of ``{id, name, color}`` ordered by name, or ``{"error": ...}``.

get_redmine_attachment
annotations: none low

Download a Redmine attachment and return a usable reference to it. Downloads the attachment to local disk and returns either an HTTP URL (when the server has a publicly reachable hostname configured) or an absolute local file path (in stdio mode). The caller does not need to know which mode is active. **HTTP mode** (any explicit ``PUBLIC_HOST``, or a non-loopback ``SERVER_HOST``): Returns a dict with ``uri``, ``uri_type: "http"``, filename, content_type, size, expires_at, and attachment_id. An explicit ``PUBLIC_HOST=localhost`` also selects this mode so Docker port-forwarded deployments produce a URL the host can reach. **stdio mode** (neither variable set, or only ``SERVER_HOST`` set to a loopback bind address): Returns a dict with ``file_path`` (absolute), ``uri_type: "file"``, filename, content_type, size, expires_at, and attachment_id. The path can be passed directly to Claude Code's ``Read`` tool or pdf-mcp. Downloads are capped at ``ATTACHMENT_MAX_DOWNLOAD_BYTES`` (default 200 MB). Files are cleaned up automatically by the background cleanup manager. Args: attachment_id: The ID of the attachment to retrieve. Returns: Dict with uri or file_path reference on success, or a dict with an ``"error"`` key on failure.

attachment_id int
list_files
annotations: none low

List all files uploaded to a Redmine project. Returns file metadata (id, filename, size, content type, description, download URL, author, optional version/release) for every file uploaded under Project > Files. Note: This lists files from Redmine's core "Files" module (enabled per project via Settings > Modules > Files). It does NOT list issue attachments (use ``get_redmine_issue`` with ``include_attachments=True`` for those) and does NOT list DMSF documents (pending separate tools). Args: project_id: Project identifier (numeric ID or string identifier). Returns: A list of file metadata dictionaries. On failure, a dict with an ``"error"`` key. Example: >>> await list_files("web") [ { "id": 42, "filename": "spec.pdf", "filesize": 125678, "content_type": "application/pdf", "description": "Design spec v2", "content_url": "https://example.com/attachments/download/42/spec.pdf", "author": {"id": 5, "name": "Alice"}, "version": {"id": 3, "name": "Release 1.0"}, "created_on": "2026-04-10T10:30:00" } ]

project_id string
create_upload_ticket
annotations: none low

Reserve a slot for a file on the caller's own machine, and say where to send it. Use this whenever the file to attach lives on the caller's side. It is the only route that does not put the file's bytes through the conversation: there is no way to pipe a file into a tool argument, so a ``content_base64`` payload is written out character by character by the model, and a payload of a few thousand characters does not reliably survive that (#305). Three steps: 1. Call this. It answers with ``upload_url``, ``ticket`` and ``expires_at``. 2. Send the file to ``upload_url`` in one HTTP request, with the ticket in the ``X-Upload-Ticket`` header and the file as the body:: curl -sS -H "X-Upload-Ticket: TICKET" --data-binary @file.png URL The response carries ``upload_id``, ``size`` and ``sha256``. Multipart is deliberately not accepted: the whole body would be buffered before its size could be checked. 3. Name that ``upload_id`` as the content source: in ``uploads`` on ``create_redmine_issue`` / ``update_redmine_issue`` / ``manage_redmine_wiki_page``, or on ``upload_file``. The ticket is good for one upload, for a few minutes (``REDMINE_MCP_UPLOAD_TICKET_MINUTES``, default 15), up to ``max_bytes``. It authorises nothing else. The staged file is swept on the same expiry as a downloaded attachment, so a failed attach can be retried without sending the file again. Returns: ``{upload_url, upload_id, ticket, filename, expires_at, max_bytes}``, or ``{"error": ...}`` when this server has no address a caller could POST to -- a stdio-style deployment with neither ``PUBLIC_HOST`` nor a routable ``SERVER_HOST``. There, a file the server can already read is reachable through ``file_path`` instead. Args: filename: Name the attachment should get. Optional here and overridable later, but passing it now keeps the staged file recognisable. content_type: Optional MIME type recorded with the staged file.

filename string content_type string
upload_file
annotations: none low

Upload a file to a Redmine project's Files section. This is the project's document store, not an attachment on something. To attach a file to an issue, pass ``uploads`` to ``create_redmine_issue`` or ``update_redmine_issue``; to a wiki page, to ``manage_redmine_wiki_page``. All three take the same content sources as this tool. **Content sources — provide exactly ONE of:** - ``upload_id``: a file already staged with ``create_upload_ticket``. **The way to send a file that lives on the caller's own machine.** The caller POSTs the bytes to the ticket's ``upload_url`` in one HTTP request, so they travel from disk to this server directly and are never written into a tool argument. - ``source_url``: an HTTP(S) URL the server will download from. Preferred whenever the file is already reachable at one — chaining from another MCP tool that returns a download URL, a file on the public web — since it spares the caller the bytes entirely. - ``content_base64``: raw file bytes encoded as base64. For content the caller **generated** and that is small: a short CSV, an SVG, a note. Not for a file on disk. There is no way to pipe a file into a tool argument, so this payload is written out character by character by the model, and a long one does not reliably survive that (#305). Pass ``sha256`` with it. - ``file_path``: a path read on **this server's own** filesystem, inside ``ATTACHMENTS_DIR`` or a directory listed in ``REDMINE_MCP_UPLOAD_FILE_ROOTS``. It reaches the caller's own files only where the server runs on the caller's machine; against a server on a different host a caller-side path cannot be read, whatever the roots are set to. **Integrity:** ``sha256`` and ``size_bytes`` are optional on any source and are checked after the content is resolved, before anything is sent to Redmine. They matter most for ``content_base64``: 64 characters of checksum survive being copied in a way a multi-kilobyte payload does not, so a mangled upload fails loudly instead of attaching a corrupt file. Take them from the same shell invocation that encoded the file. Under the hood this performs Redmine's standard two-step upload: ``POST /uploads.json`` to get a token, then ``POST /projects/{id}/files.json`` to attach it to the project. Args: project_id: Project identifier (numeric ID or string identifier). filename: Name the file should have in Redmine (e.g., ``spec.pdf``). Required when using ``content_base64``. Optional with ``source_url`` — if omitted, inferred from the URL path. Always prefer passing an explicit filename. upload_id: A file staged with ``create_upload_ticket``. Mutually exclusive with the other three sources. content_base64: File content encoded as a base64 string. Mutually exclusive with the other three sources. source_url: HTTP(S) URL to download the file from. Mutually exclusive with the other three sources. file_path: Path to a file on this server, inside ``ATTACHMENTS_DIR`` or a directory listed in ``REDMINE_MCP_UPLOAD_FILE_ROOTS``. Mutually exclusive with the other three sources. sha256: Optional hex digest of the file. Verified after the content is resolved; a mismatch refuses the upload. size_bytes: Optional byte count of the file, verified the same way. description: Optional human-readable description. version_id: Optional version/release ID to attach the file to (use ``list_redmine_versions`` to discover valid IDs). Returns: Dictionary containing the uploaded file's metadata. On failure, a dict with an ``"error"`` key is returned. Size limit: Uploads are capped at 50 MiB. For larger files, upload via the Redmine web UI. Examples: >>> # From a URL (chained from another MCP tool) >>> await upload_file( ... project_id="web", ... source_url="http://localhost:3012/attachments/abc-123", ... filename="report.pdf", ... description="Q2 report", ... ) >>> # From a file on the caller's own machine >>> ticket = await create_upload_ticket(filename="report.pdf") >>> # the caller then sends the bytes itself, in one request: >>> # curl -H "X-Upload-Ticket: TICKET" --data-binary @report.pdf URL >>> await upload_file(project_id="web", upload_id=ticket["upload_id"]) >>> # From generated content, with its checksum >>> import base64, hashlib >>> body = "id,name".encode("utf-8") >>> await upload_file( ... project_id="web", ... filename="people.csv", ... content_base64=base64.b64encode(body).decode("ascii"), ... sha256=hashlib.sha256(body).hexdigest(), ... )

sha256 string filename string file_path string upload_id string project_id string size_bytes string source_url string version_id string description string content_base64 string
delete_file
annotations: none low

Delete a file from a Redmine project. **Important:** Redmine's ``DELETE /attachments/{id}.json`` endpoint removes ANY attachment by ID, not just project files. If ``file_id`` refers to an issue/wiki attachment (e.g., from ``get_redmine_issue(include_attachments=True)``), that attachment will be deleted from its issue. To avoid accidentally removing issue attachments when you meant to remove a project file, the tool verifies the target attachment is project-scoped (its ``container_type`` is ``Project``) before deleting. Pass ``confirm_delete_any_attachment=True`` to bypass this check when you explicitly want to delete an issue/wiki attachment. Args: file_id: ID of the attachment to delete (the ``id`` field returned by ``list_files`` or attachment-include responses). confirm_delete_any_attachment: When ``True``, skip the project-scope check and delete the attachment regardless of container type. Use only when you intentionally want to remove an issue/wiki/news attachment via this tool. Returns: Dictionary with ``success: true`` on success. On failure, a dict with an ``"error"`` key is returned.

file_id int confirm_delete_any_attachment bool
manage_redmine_wiki_page
annotations: none low

List, get, create, update, delete, or rename a Redmine wiki page. Args: action: One of: ``list``, ``get``, ``create``, ``update``, ``delete``, ``rename``. project_id: Project identifier (required for all actions). wiki_page_title: Wiki page title. Required for all actions except ``list``. version: Specific version to retrieve (``get`` only, optional). include_attachments: Include attachment metadata in ``get`` response. Default ``True``. text: Page content. Required for ``create``. Required for ``update`` unless ``uploads`` is given, in which case the server reuses the page's current text so an attachment-only update does not have to resend the body. comments: Change log comment. Optional for ``create`` and ``update``. parent_title: Title of the page this page sits under, for ``create`` and ``update``. Omit it to leave an existing parent untouched; pass a title to file the page under it; pass ``""`` to move the page back to the wiki root. Must name a page that already exists in the same project. A ``rename`` keeps the current parent on its own, so reparent with ``update`` instead. new_title: New title for the page (required for ``rename``). redirect_existing_links: When ``True`` (default), the rename creates a redirect from ``wiki_page_title`` to ``new_title``. Passed to the API as ``"1"`` / ``"0"``. uploads: Files to attach, for ``create`` and ``update`` only. Requires the ``edit_wiki_pages`` permission on the project. Maximum 10 items, 50 MiB each. Each item needs exactly ONE source key: ``upload_id`` (a file staged with ``create_upload_ticket``), ``source_url`` (an HTTP(S) URL the server fetches), ``content_base64``, or ``file_path`` (a path read on **this server's own** filesystem, inside ``ATTACHMENTS_DIR`` or a directory listed in ``REDMINE_MCP_UPLOAD_FILE_ROOTS``). A file on the caller's own machine goes through ``upload_id``: the caller POSTs it to the ticket's ``upload_url``, so the bytes never pass through the model. ``source_url`` is preferable where the file is already at a URL. ``content_base64`` is for small content the caller generated, and should carry ``sha256``, since a payload of any length is written out by the model itself. Optional per item: ``filename`` (required with ``content_base64``), ``sha256``, ``size_bytes``, ``content_type``, ``description``. Ignored by the other actions. expected_version: The ``version`` the page had when the caller read it, for ``update``. Redmine refuses the write with an edit conflict when the page has moved on since, where it would otherwise overwrite the other edit silently. Optional; pass it whenever the new text was derived from a page read earlier. With ``text_edits`` a page that has moved on is refused before anything is sent. Ignored on an attachment-only ``update`` and by the other actions. text_edits: Change part of a long page in place, for ``update``: a list of ``{"find": ..., "replace": ...}`` applied in order on this server. **Prefer this to ``text`` for a long page**, which would otherwise have to be written out in full into the argument. Each ``find`` must occur exactly once in the page as it stands after the preceding edits; zero matches or several refuse the whole call and change nothing. The write carries the version that was patched, so an edit landing in between is an edit conflict. Mutually exclusive with ``text`` and ``text_upload_id``. text_upload_id: Take the whole page from a file staged with ``create_upload_ticket``, decoded as UTF-8, for ``create`` and ``update``. For a long page that really is all new. Mutually exclusive with ``text`` and ``text_edits``. Returns: ``list``: list of page metadata dicts (no body text). ``get`` / ``create`` / ``update``: wiki page dict, carrying ``parent_title`` when the page has a parent and omitting the key when it sits at the wiki root. A write made with ``text_edits`` or ``text_upload_id`` reports ``text_length`` in place of ``text``, since echoing the page would put it in the conversation after all. ``delete``: ``{"success": True, "title": ..., "message": ...}``. ``rename``: ``{"success": True, ...}`` with the renamed page's metadata to confirm the title change actually applied. On error: ``{"error": "..."}``.

text string action string uploads string version string comments string new_title string project_id string text_edits string parent_title string text_upload_id string wiki_page_title string expected_version string include_attachments bool redirect_existing_links bool
list_redmine_news
annotations: none low

List Redmine news (project announcements), newest first. Without ``project_id`` this spans every project the caller can see. Comments and attachments are not included -- the list endpoint does not serve them; use ``get_redmine_news`` for one item's full context. Args: project_id: Restrict to one project (numeric ID or string identifier). Redmine narrows the collection server-side, and answers 404 for a project that does not exist. limit: Maximum news items to return (default 25, max 100). offset: Items to skip, for paging. Returns: A list of news dictionaries ``{id, project, author, title, summary, description, created_on}``. On failure, a dict with an ``"error"`` key, with ``code: NOT_FOUND`` for an unknown project. Examples: >>> await list_redmine_news(project_id="my-project", limit=5) [{"id": 12, "title": "Release 2.4 is out", ...}, ...]

limit string offset string project_id string
get_redmine_news
annotations: none low

Retrieve one news item, with its comments and attachments. Args: news_id: ID of the news item. include_comments: Include the comment thread (default ``True``). Comments are where a discussion about an announcement lives, so they are on by default -- unlike the issue tools, a news item without them is usually just three fields. include_attachments: Include attachment metadata (default ``True``). Returns: A news dictionary; ``comments`` and ``attachments`` are present only when requested *and* non-empty. On failure, a dict with an ``"error"`` key, with ``code: NOT_FOUND`` for an unknown id.

news_id int include_comments bool include_attachments bool
manage_redmine_news
annotations: none low

Create or update a Redmine news item (project announcement). Needs a Redmine that exposes the news write endpoint -- core Redmine has since 4.1. A server without it answers with an error rather than silently doing nothing. Deleting is a separate tool, ``delete_redmine_news``, so a deployment can offer announcements without offering their destruction. Args: action: One of ``create``, ``update``. project_id: Project to announce in. Required for ``create``; ignored by ``update``, since news cannot move between projects. news_id: Item to change. Required for ``update``. title: Headline. Required for ``create``, optional for ``update`` (cannot be blank). summary: One-line teaser shown in listings. Optional; an empty string clears it on ``update``. description: The body. Required for ``create``, optional for ``update`` (cannot be blank). Returns: The resulting news dictionary. Where Redmine's bodyless response makes the result unverifiable, an envelope with ``confirmed: False`` and a ``code`` of ``CREATE_UNCONFIRMED`` / ``UPDATE_UNCONFIRMED`` instead of a possibly wrong record. On error, ``{"error": "..."}``. Blocked in read-only mode (``REDMINE_MCP_READ_ONLY=true``).

title string action string news_id string summary string project_id string description string
delete_redmine_news
annotations: none low

Hard-delete a news item via ``DELETE /news/{id}.json``. Deletion is **irreversible** and takes the item's comments and attachments with it. Like the other destructive tools here, this one refuses unless ``confirm_delete=True``, and the refusal carries a preview of what would be lost. Needs a Redmine that exposes the news write endpoints, as core Redmine has since 4.1. For the other operations use ``manage_redmine_news`` (create, update), ``get_redmine_news`` or ``list_redmine_news``. Args: news_id: ID of the news item to delete. confirm_delete: When ``False`` (default), the tool refuses and returns the impact preview. Pass ``True`` to actually delete. Returns: On refusal: ``{"error", "code": "CONFIRMATION_REQUIRED", "hint", "impact"}``, where ``impact`` names the title and counts the comments and attachments that would go with it. On success: ``{"success": True, "deleted_news_id": N, "cascade_deleted": {"comments": C, "attachments": A}}``. Blocked in read-only mode (``REDMINE_MCP_READ_ONLY=true``).

news_id string confirm_delete bool
manage_crm_note
annotations: none low

RedmineUP CRM notes on contacts and deals. Combined CRUD-by-action. Notes are the CRM's activity log ("called them", "sent proposal"). Available when ``REDMINE_CRM_ENABLED`` or ``REDMINE_DEALS_ENABLED`` is set; a note on a deal additionally needs deals enabled and a note on a contact needs CRM enabled. There is no list action: read a parent's notes with ``manage_deal(action="get", include="notes")``. Args: action: ``get``, ``create``, ``update`` or ``delete``. note_id: Required by every action except ``create``. source_type: ``create`` only, required: ``contact`` or ``deal``. source_id: ``create`` only, required: the contact or deal id. project_id: ``create`` only, required: the project the source belongs to (the plugin resolves the note's project from it). content: Required on ``create``; optional on ``update``. subject: Optional short title, ``create`` and ``update``. type_id: Optional note type, ``create`` and ``update``: 0 email, 1 call, 2 meeting. Returns: ``get`` / ``create``: ``{id, source {id, name, type}, subject, content, type_id, note_type, author, created_on, updated_on}``. ``update``: ``{success, note_id, updated_fields}``. ``delete``: ``{success, note_id, message}``. ``{"error": ...}`` on failure. Editing and deleting both require the plugin's ``delete_notes`` permission (or ``delete_own_notes`` for the author).

action string content string note_id string subject string type_id string source_id string project_id string source_type string
manage_product
annotations: none low

RedmineUP Products plugin tool. Combined CRUD-by-action. Actions: ``list``, ``get``, ``create``, ``update``. The plugin exposes no delete endpoint, so there is no ``delete`` action. Requires ``REDMINE_PRODUCTS_ENABLED=true`` and the RedmineUP Products plugin. One flat signature serves every action, so most parameters apply to some actions and are ignored by the rest. The two write actions do not take their payload the same way: ``create`` reads the flat parameters below, while ``update`` reads ``fields`` and ignores every flat one. Args: action: Which operation to run. project_id: On ``list``, restrict to products in this project; omit for every product the caller can see. On ``create``, the project to file the new product under (optional). Name or numeric id. limit: ``list`` only. Products per call, capped at 100 by Redmine; a larger value is clamped, not rejected. product_id: The product to act on. Required by ``get`` and ``update``, ignored by the rest. name: ``create`` only -- the new product's name (required). status_id: ``create`` only. ``1`` (Active, the default) or ``2`` (Inactive); any other value is rejected. To change the status of an existing product, pass ``status_id`` inside ``fields`` on ``update``. description: ``create`` only. Free text. price: ``create`` only. Unit price as a number, e.g. ``49.99``. currency: ``create`` only. Currency code, e.g. ``"USD"``. code: ``create`` only. The product's catalogue code / SKU. category_id: ``create`` only. Product category, as a positive integer id. tag_list: ``create`` only. Comma-separated tag names. custom_fields: ``create`` only. List of ``{"id": N, "value": ...}`` dicts. fields: ``update`` only, and the only way to change a product, so it is required there and must be non-empty. Allowed keys: ``name``, ``description``, ``price``, ``currency``, ``status_id``, ``code``, ``project_id``, ``category_id``, ``tag_list``, ``custom_fields``. Any other key is dropped without an error, so check ``updated_fields`` in the response for what was written. Returns: ``list`` a list of product dicts, ``get`` / ``create`` one product dict, ``update`` ``{"success": true, "product_id", "updated_fields"}``, and ``{"error": ...}`` on failure.

code string name string limit string price string action string fields string currency string tag_list string status_id int product_id string project_id string category_id string description string custom_fields string
manage_deal
annotations: none low

RedmineUP CRM (Deals) plugin tool. Combined CRUD-by-action. Actions: ``list``, ``get``, ``create``, ``update``, ``delete``. Requires ``REDMINE_DEALS_ENABLED=true`` and the RedmineUP CRM plugin. One flat signature serves every action, so most parameters apply to some actions and are ignored by the rest. Which is which: Args: action: Which operation to run. project_id: On ``list``, restrict to deals in this project. On ``create``, the project to file the new deal under (required). search: ``list`` only. Free-text search over the deal name. status_id: **``list`` returns only OPEN deals unless told otherwise.** Accepts ``"o"`` (open), ``"c"`` (won and lost), ``"*"`` (every status), or a numeric status id. On ``create``, the status to open the deal in, as a numeric id. Status and deal category ids come from ``list_deal_statuses``. assigned_to_id: On ``list``, filter by the assigned user's ID. On ``create``, the user to assign the new deal to. limit: ``list`` only. Deals per call, capped at 100 by Redmine. deal_id: The deal to act on. Required by every action except ``list`` and ``create``. include: ``get`` only. Comma-separated: ``"notes"`` (returned under a ``notes`` key) and, when the Products plugin is installed, ``"lines"`` (the deal's product lines). name: ``create`` only -- the new deal's name (required). contact_id: ``create`` only. The contact the deal belongs to. price: ``create`` only. Send an unformatted string such as ``"1500.5"``. currency: ``create`` only. The deal's currency code, e.g. ``"USD"``. due_date: ``create`` only. The deal's due date as ``YYYY-MM-DD``. fields: ``create`` and ``update`` only. Deal attributes to write. On ``update`` it is the only way to change a deal, so it is required and must be non-empty. Returns: ``list`` a list of deal dicts, ``get`` / ``create`` one deal dict, ``update`` / ``delete`` a status dict, and ``{"error": ...}`` on failure.

name string limit string price string action string fields string search string deal_id string include string currency string due_date string status_id string contact_id string project_id string assigned_to_id string
list_deal_statuses
annotations: none low

List RedmineUP CRM deal statuses, and a project's deal categories. Call this before ``manage_deal(action="create")``, which requires a numeric ``status_id`` and accepts an optional ``category_id``. Requires ``REDMINE_DEALS_ENABLED=true`` and the CRM plugin, Pro edition. Args: project_id: Optional project identifier or id. When given, the project's deal categories are returned as well (categories are defined per project). Returns: ``statuses``: list of ``{id, name, position, is_default, status_type (open|won|lost), status_type_id, color}`` ordered by position. The plugin only serves this list to Redmine administrators; for other users ``statuses`` is ``None`` and ``statuses_error`` explains the restriction while the rest of the answer is still returned. ``categories``: list of ``{id, name}``, present only when ``project_id`` was given. ``{"error": ...}`` on failure.

project_id string
manage_deal_category
annotations: none low

List, create, rename, or delete RedmineUP CRM deal categories. Categories are defined per project and referenced by ``category_id`` on deals. Requires ``REDMINE_DEALS_ENABLED=true``; writes need the plugin's ``manage_deals`` permission. Args: action: ``list``, ``create``, ``update`` or ``delete``. project_id: Required for ``list`` and ``create``. category_id: Required for ``update`` and ``delete``. name: Required for ``create`` and ``update``; at most 30 characters and unique within the project. reassign_to_id: ``delete`` only. Category to move the deleted category's deals to. Without it the plugin leaves those deals uncategorised. Returns: ``list`` a list of ``{id, name}``; ``create`` ``{id, name, project_id}``; ``update`` / ``delete`` a status dict; ``{"error": ...}`` on failure.

name string action string project_id string category_id string reassign_to_id string
add_deal_product
annotations: none low

Add a product line to a RedmineUP CRM deal. The plugin recalculates the deal's ``price`` from its lines after each addition. Read the lines back with ``manage_deal(action="get", include="lines")``. Requires ``REDMINE_DEALS_ENABLED=true`` and ``REDMINE_PRODUCTS_ENABLED=true`` (the endpoint only exists when the RedmineUP Products plugin is installed next to CRM). Args: deal_id: The deal to add the line to (required). product_id: Catalogue product to add. Its description and price are used unless overridden. Optional when ``description`` is given, which creates a free-form line. quantity: Positive number (default 1 on the plugin side). price: Unit price, as a string such as ``"100.0"`` or a number. description: Line text; required when no ``product_id``. tax: Tax rate on the line, as a percentage from 0 to 100. discount: Discount on the line, as a percentage from 0 to 100. Returns: ``{"success": true, "deal_id", "line"}`` with the line as sent, or ``{"error": ...}``.

tax string price string deal_id string discount string quantity string product_id string description string
list_redmine_projects
annotations: none low

Lists accessible projects in Redmine. Returns ONLY active projects unless ``filters`` says otherwise. Redmine's ``ProjectQuery`` starts out with a ``status = 1`` filter already set, so a call that passes no ``status`` answers with active projects alone while looking like the whole list. Pass ``filters={"status": "1|5"}`` to get closed projects alongside active ones. ``status`` takes only the ``=`` and ``!`` operators, so ``"*"`` is not a way to ask for every status -- it would be read as a literal value and match nothing. ``filters`` narrows the collection server-side. A filter Redmine cannot read is not an error there -- it answers 200 with the collection unnarrowed -- so check the result against what was asked for. With ``include_custom_fields`` this is the only tool that returns project custom field *values*, which are a different set from the issue custom fields ``list_project_issue_custom_fields`` covers. No tool exposes custom field *definitions* -- ``field_format``, ``is_required``, ``possible_values`` -- for either set: Redmine serves those to administrators only. Args: include_custom_fields: Add ``custom_fields`` to each project. Costs no extra request; opt-in only to keep the default response small. limit: Maximum number of projects to return, up to 1000. Omitted by default, which returns every visible project -- what this tool has always done, and the cheapest way to do it. A supplied limit is paged in full however few projects exist, so ``limit=1000`` on a seven-project instance costs ten requests to return seven rows: ask for a number you want, not a large one meaning "all". offset: Projects to skip before collecting results. With no ``limit`` a late offset costs what reading from zero costs -- paging runs ``total_count`` rows *from* ``offset`` rather than up to it -- so pair a large ``offset`` with a ``limit``. include_pagination_info: Return ``{"projects": [...], "pagination": {...}}`` rather than a bare list (default: False), with the keys ``list_redmine_issues`` returns. ``total`` is Redmine's own count for the filtered collection and costs no extra request -- except where a deployment suppresses API metadata (``nometa``), which truncates the list at one page and reports a ``total`` that agrees with it. filters: Redmine query filters, for what this signature does not name -- most usefully ``{"cf_42": "value"}`` for a project custom field. Accepted keys are ``status``, ``id``, ``name``, ``description``, ``parent_id``, ``is_public``, ``created_on`` and ``updated_on``, plus ``cf_<id>`` and its chained spellings; any other key is refused, with an error naming what it objected to. Each value is one scalar -- a string, number, date or datetime, never a list, a dict, ``None`` or a ``bool`` (write a yes/no filter as ``"1"``). An operator rides inside the value as a prefix, as in ``{"created_on": ">=2024-01-01"}`` or ``{"name": "~api"}``, and alternatives join with ``|``, as in ``{"status": "1|5"}``; an operator the filter's type does not accept is read as a literal value rather than erroring. A ``cf_<id>`` must be a *project* custom field, visible to the caller, with "Used as a filter" on. Returns: A list of dictionaries, each representing a project -- or, with ``include_pagination_info``, a dict of ``projects`` and ``pagination``. Each project carries ``id``, ``name``, ``identifier``, ``description``, ``homepage``, ``parent``, ``status``, ``is_public``, ``inherit_members``, ``created_on`` and ``updated_on``, which is what Redmine's project index renders. ``status`` is Redmine's integer code -- ``1`` active, ``5`` closed. ``parent`` is ``{id, name}``, or ``null``: Redmine renders it only when the parent exists *and* is visible to the caller, so ``null`` means top-level **or** a parent this caller cannot see, and the two cannot be told apart. A key the payload did not carry is ``null`` rather than a substituted default. With ``include_custom_fields``, each project also carries ``custom_fields``, a list of ``{id, name, value}`` entries -- empty if the project has none. On failure, a dict with an ``error`` key.

limit string offset string filters string include_custom_fields bool include_pagination_info bool
list_project_issue_custom_fields
annotations: none low

List the ids and names of the issue custom fields enabled for a project. Against a stock Redmine only ``id`` and ``name`` carry data. ``field_format``, ``is_required``, ``multiple``, ``default_value``, ``possible_values`` and ``trackers`` come back ``null``, meaning "not readable on this token" -- ``null`` is not ``false`` and not an empty list. In particular ``is_required: null`` does not mean a field is optional, so a create or update can still reject on a field listed here. Use the ids with ``extra_fields={"custom_fields": [{"id": N, "value": ...}]}``, or pass the field by name in ``fields``. Args: project_id: Project identifier (ID number or string identifier). tracker_id: Optional tracker ID to filter custom fields by applicability. Usable only when the response describes every field's tracker bindings, which a stock Redmine does not send; it returns an error rather than an unfiltered list when it cannot. Returns: A list of dicts with ``id``, ``name``, ``field_format``, ``is_required``, ``multiple``, ``default_value``, ``possible_values`` and ``trackers``. On failure, a dict with an ``"error"`` key is returned (callers should check ``isinstance(result, dict)`` to distinguish failure from an empty list). Why the six keys are unreadable: this tool reads ``GET /projects/{id}.json?include=issue_custom_fields``, which Redmine renders as exactly ``id`` and ``name`` per field (``app/helpers/projects_helper.rb``; the same two keys in 6.1, 7.0 and trunk). The definitions live on ``GET /custom_fields.json``, which Redmine restricts to administrators (``before_action :require_admin``), so a non-admin token cannot obtain them at all -- and under OAuth even an administrator's token cannot, because ``User#admin?`` additionally requires the token to carry the ``admin`` scope, which this server never requests. Redmine has four open requests to expose this metadata to non-admins (redmine.org #18875, #41318, #42581, #43407), none with a target version. The keys are kept rather than dropped so the response shape is stable and starts carrying data if that ever changes. **``is_required`` caveat (#119):** even where the flag *is* readable it only reflects the custom field *definition*. Required-ness can also be imposed by **workflow rules**, **role-based field permissions**, or **tracker-bound required-field settings**, none of which are reflected in it. A custom field with ``is_required: false`` can still cause ``create_redmine_issue`` / ``update_redmine_issue`` to reject with ``"<field name> cannot be blank"``. No general-purpose API exists for the "effective" required state. Recovery when the create/update call rejects: 1. **Name-keyed shortcut (preferred):** pass the rejected field by name directly, e.g. ``fields={"Department": "Engineering"}``, on either ``create_redmine_issue`` or ``update_redmine_issue``. Both tools resolve the name to a ``custom_fields`` id; ambiguous names raise. 2. **Explicit id form:** pass ``extra_fields={"custom_fields": [{"id": N, "value": "..."}]}`` using the numeric ID from this tool. Works on either path; use when the name lookup is ambiguous or the value type is awkward (multi-value fields, complex serializations). 3. **Autofill:** set ``REDMINE_AUTOFILL_REQUIRED_CUSTOM_FIELDS=true`` to have the server retry once with values from each field's ``default_value`` or the ``REDMINE_REQUIRED_CUSTOM_FIELD_DEFAULTS`` map. Against a stock Redmine only the env map can supply a value, since ``default_value`` is not in the payload. ``create_redmine_issue`` and ``update_redmine_issue`` augment their validation error envelope with ``missing_required_fields`` and a matching ``hint`` when this pattern fires, so a caller hitting the error gets recovery context inline.

project_id string tracker_id string
list_redmine_versions
annotations: none low

List versions (roadmap milestones) for a Redmine project. Args: project_id: The project ID (numeric) or identifier (string). status_filter: Optional filter by version status. Allowed values: open, locked, closed. When None, all versions are returned. Returns: A list of version dictionaries. On failure, a dict with an ``"error"`` key is returned (callers should check ``isinstance(result, dict)`` to distinguish failure from an empty list).

project_id string status_filter string
manage_redmine_version
annotations: none low

Create, update, or delete a Redmine version (milestone/roadmap entry). Args: action: Operation to perform. One of: ``create``, ``update``, ``delete``. project_id: Project ID or string identifier. Required for ``action="create"``. version_id: Numeric version ID. Required for ``action="update"`` and ``action="delete"``. name: Version name. Required for ``action="create"``, optional for ``action="update"``. description: Version description text. status: Version status. Allowed values: ``open``, ``locked``, ``closed``. Defaults to ``open`` on create. due_date: Due date in ``YYYY-MM-DD`` format. sharing: Sharing scope. Allowed values: ``none``, ``descendants``, ``hierarchy``, ``tree``, ``system``. Defaults to ``none`` on create. wiki_page_title: Associated wiki page title. Returns: For ``create``/``update``: full version dictionary. For ``delete``: ``{"success": True, "version_id": ..., "message": "..."}``. On error: ``{"error": "..."}``.

name string action string status string sharing string due_date string project_id string version_id string description string wiki_page_title string
manage_redmine_project
annotations: none low

Create a Redmine project, edit its settings, or close and reopen it. Use this tool to set up a new project, rename one, change its description, homepage, parent, visibility, enabled modules, trackers or custom field values, or to close a finished project and reopen it later. A closed project stays visible and readable but accepts no edits. This tool writes the project record itself. Its contents have their own tools: ``manage_redmine_version`` for versions, ``manage_project_member`` for memberships, ``manage_issue_category`` for issue categories. Archiving is not offered. Redmine gates ``archive`` and ``unarchive`` on administrator rights rather than on a project permission, so no non-admin token can reach them. Deleting is not offered either: it destroys every issue, wiki page and file in the project and in each of its subprojects. Args: action: Operation to perform. One of: ``create``, ``update``, ``close``, ``reopen``. project_id: Project ID or string identifier. Required for ``update``, ``close`` and ``reopen``. name: Project name. Required for ``action="create"``. identifier: URL identifier, e.g. ``lunar-programme``. Required for ``action="create"`` and rejected for ``action="update"``, because Redmine freezes it once the project exists. description: Project description text. homepage: Project homepage URL. is_public: Whether the project is visible to non-members. Needs the ``select_project_publicity`` permission; without it Redmine ignores this field rather than refusing the call. parent_id: Numeric ID of the parent project. Creating a subproject needs ``add_subprojects`` on the parent. inherit_members: Whether the project inherits the parent's members. enabled_module_names: Modules to enable, e.g. ``["issue_tracking", "wiki"]``. Replaces the current set. Needs the ``select_project_modules`` permission; without it Redmine ignores this field rather than refusing the call. tracker_ids: Numeric tracker IDs to enable. Replaces the current set. issue_custom_field_ids: Numeric issue custom field IDs to enable. Replaces the current set. default_assigned_to_id: Numeric user ID used as the default assignee. default_version_id: Numeric version ID used as the default version. default_issue_query_id: Numeric saved-query ID used as the default issue query. Redmine accepts it but does not render it back, so it is absent from this tool's response. custom_fields: Custom field values, as Redmine's own list of ``{"id": ..., "value": ...}`` entries. Returns: The full project dictionary, read back from Redmine after the write, so permission-gated fields show what was actually stored. On error: ``{"error": "..."}``.

name string action string homepage string is_public string parent_id string identifier string project_id string description string tracker_ids string custom_fields string inherit_members string default_version_id string enabled_module_names string default_assigned_to_id string default_issue_query_id string issue_custom_field_ids string
summarize_project_status
annotations: none low

Provide a summary of project status based on issue activity over the specified time period. Args: project_id: The ID of the project to summarize days: Number of days to look back for analysis. Defaults to 30. Returns: A dictionary containing project status summary with issue counts, activity metrics, and trends. On error, returns a dictionary with an "error" key.

days int project_id int
list_project_members
annotations: none low

List members of a Redmine project. Returns all users and groups that are members of the specified project, along with their assigned roles. Args: project_id: Project identifier (ID number or string identifier) Returns: A list of membership dictionaries containing user/group info and roles. On failure, a dict with an ``"error"`` key is returned (callers should check ``isinstance(result, dict)`` to distinguish failure from an empty list). Examples: >>> await list_project_members("my-project") [ { "id": 1, "user": {"id": 5, "name": "John Doe"}, "group": null, "project": {"id": 1, "name": "My Project"}, "roles": [{"id": 3, "name": "Developer"}] }, ... ]

project_id string
list_redmine_roles
annotations: none low

List all roles defined in the Redmine instance. Returns basic role metadata (``id`` and ``name``) for every role configured in Redmine. Use this tool BEFORE calling ``add_project_member`` or ``update_project_member`` to discover the correct ``role_ids`` — role IDs vary between Redmine instances and must not be guessed. Returns: A list of role dictionaries, each with ``id`` and ``name``. On failure, a dict with an ``"error"`` key. Example: >>> await list_redmine_roles() [ {"id": 3, "name": "Manager"}, {"id": 4, "name": "Developer"}, {"id": 5, "name": "Reporter"} ]

get_project_modules
annotations: none low

Retrieve the enabled modules for a Redmine project. Modules control which features are visible/usable in a project (e.g., ``issue_tracking``, ``time_tracking``, ``wiki``, ``repository``). Args: project_id: Project identifier (numeric ID or string identifier). Returns: Dictionary with ``project_id``, ``project_name`` and ``enabled_modules`` (list of module name strings). On failure a dict with an ``"error"`` key is returned. Example: >>> await get_project_modules("my-project") { "project_id": 1, "project_name": "My Project", "enabled_modules": ["issue_tracking", "wiki", "time_tracking"] }

project_id string
manage_project_member
annotations: none low

Add, update, or remove a Redmine project membership. Args: action: Operation to perform. One of: ``add``, ``update``, ``remove``. project_id: Project ID or identifier. Required for ``action="add"``. membership_id: Membership ID. Required for ``action="update"`` and ``action="remove"``. user_id: User ID. Exactly one of ``user_id`` or ``group_id`` required for ``action="add"``. group_id: Group ID. Exactly one of ``user_id`` or ``group_id`` required for ``action="add"``. role_ids: Non-empty list of role IDs. Required for ``action="add"`` and ``action="update"``. Use ``list_redmine_roles`` to discover valid role IDs. Returns: For ``add``/``update``: membership dictionary. For ``remove``: ``{"success": True, "deleted_membership_id": ...}``. On error: ``{"error": "..."}``.

action string user_id string group_id string role_ids string project_id string membership_id string
list_project_trackers
annotations: none low

List the trackers (issue types) enabled for a specific Redmine project. Unlike ``list_redmine_trackers`` (which returns every tracker defined in the instance), this returns only the trackers available on the given project. Use it to discover valid ``tracker_id`` values before creating an issue in that project. Args: project_id: Project identifier (numeric id or string identifier). Returns: A list of tracker dicts with ``id`` and ``name``. On failure, a list containing a single dict with an ``"error"`` key. Examples: >>> await list_project_trackers("my-project") [{"id": 1, "name": "Bug"}, {"id": 2, "name": "Feature"}]

project_id string
list_crm_queries
annotations: none low

List saved RedmineUP CRM queries for contacts or deals. Saved queries are the named filters users build in the CRM's contact and deal lists. Available with ``REDMINE_CRM_ENABLED`` (``contact``) or ``REDMINE_DEALS_ENABLED`` (``deal``). Args: object_type: ``contact`` or ``deal``. limit: Queries per call, 1 to 100 (default 25). offset: Paging offset (default 0). Returns: A list of ``{id, name, is_public, project_id}`` (``project_id`` is ``None`` for global queries), or ``{"error": ...}``.

limit int offset int object_type string
get_mcp_server_info
annotations: none low

Return the MCP server's version, enabled-feature flags, and current user. Use this tool to: - Detect deployment lag: compare ``server_version`` against the release you expect before relying on a recently-shipped fix. - Understand who ``"me"`` resolves to: ``current_user`` shows the identity behind the configured API key. When a shared or robot API key is in use, ``assigned_to_id="me"`` will match **that** account, not the human operator — call this tool first if issue queries assigned to "me" return unexpectedly empty results. - Check which plugin-gated tool families are active. Returns: A dict with: - ``server_version`` (str): the deployed package version (from ``importlib.metadata``). The literal ``"0.0.0+unknown"`` when the package metadata is unavailable (rare; source-tree runs without an editable install). - ``read_only_mode`` (bool): whether ``REDMINE_MCP_READ_ONLY`` is enabled. When ``True``, all write tools refuse with the standard read-only error. - ``auth_mode`` (str): ``"oauth"`` or ``"legacy"``. - ``current_user`` (dict | None): ``{id, login, name}`` for the authenticated Redmine user. ``None`` if the server cannot reach Redmine (check ``/health`` for connectivity status). - ``plugin_flags`` (dict[str, bool]): which plugin-gated tool families are enabled. Always ``agile``, ``checklists``, ``products``, ``crm``, ``deals``, ``dmsf``, ``tags``, in that order, and after them one key per family this deployment added through ``REDMINE_MCP_EXTENSIONS``, named after the family. The seven are reserved, so each always carries its own flag. ``True`` means the family's tools are listed and routable; ``False`` means they are hidden from ``tools/list`` (``agile`` and ``tags`` only add fields to core tools and are never hidden). The response intentionally excludes credentials, internal hostnames, file-system paths, and any other operator-config that a caller doesn't need to know to choose its call shape. Example: >>> await get_mcp_server_info() { "server_version": "1.3.0", "read_only_mode": False, "auth_mode": "legacy", "current_user": {"id": 5, "login": "vitex", "name": "Vítězslav Dvořák"}, "plugin_flags": { "agile": False, "checklists": False, "products": False, "crm": False, "dmsf": True, "tags": False, }, }

manage_time_entry
annotations: none low

Create or update a Redmine time entry. Args: action: One of: ``create``, ``update``. hours: Hours spent. Required for ``create``; optional for ``update`` (must be positive if provided). project_id: Project to log against. Required for ``create`` if ``issue_id`` is not provided. issue_id: Issue to log against. Required for ``create`` if ``project_id`` is not provided. user_id: Log on behalf of this user (``create`` only). Requires ``log_time_for_other_users`` permission. time_entry_id: Entry to update. Required for ``update``. activity_id: Activity ID (optional for both actions). comments: Description. Empty string clears the field on ``update``. spent_on: Date in ``YYYY-MM-DD`` format (optional). Returns: Time entry dictionary, or ``{"error": "..."}``.

hours string action string user_id string comments string issue_id string spent_on string project_id string activity_id string time_entry_id string
list_time_entry_activities
annotations: none low

List available time entry activities from Redmine. Returns activity types that can be used when creating or updating time entries (e.g., Development, Design, Testing). When called without ``project_id``, returns all global activity types. When called with ``project_id``, returns project-specific activities via ``GET /projects/:id.json?include=time_entry_activities`` (Redmine 3.4.0+). Project-specific IDs differ from global ones — always use project-scoped activities when logging time against a specific project to avoid ``"Activity is not included in the list"`` errors. Args: project_id: Optional project identifier (ID number or string identifier). When provided, returns project-specific activities instead of global ones. Returns: Without ``project_id``: a list of activity dicts, each with ``id``, ``name``, ``active``, ``is_default``. With ``project_id``: a dict with ``project_id`` and ``activities`` (same structure). If the project has no custom activities, ``activities`` is empty and a ``note`` field explains the fallback. On failure: a list containing a single dict with an ``"error"`` key. Examples: >>> await list_time_entry_activities() [{"id": 4, "name": "Development", "active": True, "is_default": False}, ...] >>> await list_time_entry_activities(project_id="my-project") { "project_id": "my-project", "activities": [{"id": 9, "name": "Development", ...}] }

project_id string
import_time_entries
annotations: none low

Bulk import multiple time entries in a single call. **Use this tool (NOT ``manage_time_entry(action="create")`` in a loop) whenever the user asks to:** - import a timesheet / weekly timesheet / monthly report - bulk log, batch log, or log multiple entries at once - import several entries, or any list of 2+ time entries - backfill time across many issues or dates - log the same activity for multiple team members at once - log a day's work spanning multiple issues **Prefer this tool over calling ``manage_time_entry(action="create")`` N times** -- it reports partial failures via a ``succeeded``/``failed`` summary and supports ``stop_on_error`` for transactional-style behaviour. Calling ``manage_time_entry(action="create")`` in a loop gives no aggregate feedback and cannot continue past per-entry errors gracefully. Redmine has no native bulk-import endpoint, so this tool creates each entry individually via ``POST /time_entries.json`` under the hood. Per-entry errors are captured and returned alongside successes so a partial import still yields useful feedback. Each entry must be a dict with the standard ``manage_time_entry(action="create")`` fields: ``hours`` (required), plus at least one of ``project_id``/``issue_id``. Optional fields: ``user_id`` (to log on behalf of a teammate), ``activity_id``, ``comments``, ``spent_on``. Args: entries: List of time entry dicts. Capped at 500 entries per call -- split larger imports into multiple invocations. Example: ``[{"hours": 1.5, "issue_id": 123, "comments": "..."}]`` stop_on_error: When ``True``, abort the import on the first error. When ``False`` (default), continue past errors and report all successes/failures at the end. Returns: Dictionary with: - ``total``: total number of entries attempted - ``succeeded``: count of successfully created entries - ``failed``: count of failed entries - ``created``: list of created time entry dicts - ``errors``: list of ``{"index": i, "entry": {...}, "error": "..."}`` for failed entries Example: >>> await import_time_entries([ ... {"hours": 2.0, "issue_id": 123, "comments": "Bug fix"}, ... {"hours": 1.0, "project_id": "web", "activity_id": 9}, ... ]) {"total": 2, "succeeded": 2, "failed": 0, "created": [...], "errors": []}

entries string stop_on_error bool
get_gantt_chart
annotations: none low

Retrieve project timeline (Gantt) data: issues with dates, dependencies, and milestones. Composite tool that aggregates ``GET /issues.json`` (with relations) and ``GET /projects/{id}/versions.json`` into a single structured response suitable for timeline analysis. Returns structured data, not an image. Use cases: "What's the current timeline for project X?", "Which issues are overdue?", "Show me the dependency chain on this project". Uses the core Redmine REST API only — no plugin required. Performance note: Redmine paginates issues at 25 per HTTP call by default, so a request for ``limit=500`` can trigger ~20 underlying API calls. Expect a few seconds of latency on large projects. Args: project_id: Project identifier (ID or string). start_date_after: Optional ``YYYY-MM-DD`` filter (issues whose ``start_date`` is on or after this date). due_date_before: Optional ``YYYY-MM-DD`` filter (issues whose ``due_date`` is on or before this date). include_closed: When ``True``, include closed issues. Default ``False``: only open issues are returned, which keeps response size and pagination cost low on long-lived projects. limit: Maximum number of issues to return (1-500, default 250). Returns: Dict with: ``project_id``, ``issues`` (list with date fields, progress, parent_id, relations), ``versions`` (list of milestones), ``total_count``.

limit string project_id string include_closed bool due_date_before string start_date_after string
list_redmine_trackers
annotations: none low

List all trackers (issue types) defined in the Redmine instance. Trackers classify issues (e.g., Bug, Feature, Support). Use this tool to discover valid ``tracker_id`` values before calling ``create_redmine_issue`` or ``update_redmine_issue``. Returns: A list of tracker dictionaries with ``id``, ``name``, and ``description``. On failure, a dict with an ``"error"`` key. Example: >>> await list_redmine_trackers() [ {"id": 1, "name": "Bug", "description": ""}, {"id": 2, "name": "Feature", "description": ""}, {"id": 3, "name": "Support", "description": ""} ]

list_redmine_issue_statuses
annotations: none low

List all issue statuses defined in the Redmine instance. Use this tool to discover valid ``status_id`` values before calling ``update_redmine_issue``. You can also pass a status name via the ``status_name`` field in ``update_redmine_issue``, which internally resolves the ID. Returns: A list of status dictionaries with ``id``, ``name``, and ``is_closed`` (whether this status counts as "closed"). On failure, a dict with an ``"error"`` key. Example: >>> await list_redmine_issue_statuses() [ {"id": 1, "name": "New", "is_closed": False}, {"id": 2, "name": "In Progress", "is_closed": False}, {"id": 5, "name": "Closed", "is_closed": True} ]

list_redmine_issue_priorities
annotations: none low

List all issue priority levels defined in the Redmine instance. Use this tool to discover valid ``priority_id`` values before calling ``create_redmine_issue`` or ``update_redmine_issue``. Returns: A list of priority dictionaries with ``id``, ``name``, ``active``, and ``is_default``. On failure, a dict with an ``"error"`` key. Example: >>> await list_redmine_issue_priorities() [ {"id": 1, "name": "Low", "active": True, "is_default": False}, {"id": 2, "name": "Normal", "active": True, "is_default": True}, {"id": 3, "name": "High", "active": True, "is_default": False} ]

list_redmine_users
annotations: none low

List Redmine users with optional filtering. Admin permission is required to list all users. Non-admin users may receive a 403. Use this tool to discover valid user IDs (e.g., for assignment, watchers, or time-entry authoring). Args: name: Optional case-insensitive substring to filter by (matches against login, firstname, lastname, and email). group_id: Optional group ID to filter users who belong to a specific group. limit: Maximum users to return (default 25, max 100). offset: Pagination offset. Default 0. Returns: A list of user dictionaries with ``id``, ``login``, ``firstname``, ``lastname``, ``mail`` (if visible), and ``created_on``. On failure, a dict with an ``"error"`` key. Example: >>> await list_redmine_users(name="alice") [{"id": 5, "login": "alice", "firstname": "Alice", ...}]

name string limit string offset string group_id string
list_redmine_queries
annotations: none low

List all saved custom queries visible to the current user. Custom queries are saved issue filters (defined via the Redmine web UI). Once discovered, the ``id`` can be passed to ``list_redmine_issues`` via a ``query_id`` filter to run the query. Note: This tool only READS queries. Redmine's REST API does not support creating, updating, or deleting saved queries. Returns: A list of query dictionaries with ``id``, ``name``, ``is_public``, and ``project_id`` (may be ``None`` for cross-project queries). On failure, a dict with an ``"error"`` key. Example: >>> await list_redmine_queries() [ {"id": 1, "name": "Open bugs", "is_public": True, "project_id": 10}, {"id": 2, "name": "My tasks", "is_public": False, "project_id": None} ]

search_redmine_issues
annotations: none low

Search Redmine issues matching a query string with pagination support. Performs text search across issues using the Redmine Search API (/search.json), then transparently hydrates the matching ids via /issues.json so structured fields (subject, status, priority, project, assigned_to, author, timestamps) are populated in the response. The follow-up fetch is skipped when ``fields`` only requests id and/or description, which /search.json can serve on its own. Supports server-side pagination to prevent MCP token overflow. Args: query: Text to search for in issues. limit: Maximum number of issues to return (default: 25, max: 1000). offset: Number of issues to skip for pagination (default: 0). include_pagination_info: Return structured response with pagination metadata (default: False). fields: List of field names to include in results (default: all). Available: id, subject, description, project, status, priority, tracker, author, assigned_to, created_on, updated_on, custom_fields. Naming ``custom_fields`` hydrates the results through the issues endpoint, which renders the values. There is no ``relations``: this tool never asks for that include, so the key could only ever come back empty. scope: Search scope. Values: "all", "my_project", "subprojects". open_issues: Search only open issues (default: False). options: Additional Redmine Search API parameters as a dict. Returns: List[Dict] (default) or Dict with 'issues' and 'pagination' keys. Issues are limited to prevent token overflow (25,000 token MCP limit). Examples: >>> await search_redmine_issues("bug fix") [{"id": 1, "subject": "Bug in login", ...}, ...] >>> await search_redmine_issues( ... "performance", limit=10, offset=0, include_pagination_info=True ... ) { "issues": [...], "pagination": {"total": None, "limit": 10, "has_next": True, ...} } >>> await search_redmine_issues("urgent", fields=["id", "subject", "status"]) [{"id": 1, "subject": "Critical bug", "status": {...}}, ...] >>> await search_redmine_issues("bug", scope="my_project", open_issues=True) [{"id": 1, "subject": "Open bug in my project", ...}, ...] Note: The Redmine Search API does not provide total_count, so the pagination metadata reports ``total: null`` ("not reported") and ``has_next`` falls back to the full-page inference: true whenever the page came back full, which is only ever optimistic and costs one wasted request at worst. Search API Limitations: The Search API supports text search with scope and open_issues filters only. For advanced filtering by project_id, status_id, priority_id, etc., use list_redmine_issues() instead, which uses the Issues API with full filter support. Performance: - Memory efficient: Uses server-side pagination - Token efficient: Default limit keeps response under 2000 tokens - Further reduce tokens: Use fields parameter for minimal data transfer

limit string query str scope string fields string offset string options string open_issues bool include_pagination_info bool
copy_issue
annotations: none low

Duplicate an existing Redmine issue with optional field overrides. Uses Redmine's native copy mechanism (``copy_from`` parameter) which preserves the original issue's fields while allowing selected overrides. Args: issue_id: ID of the source issue to copy. project_id: Target project for the new issue (ID or identifier). Defaults to the source issue's project when omitted. subject: Optional new subject for the copy. Defaults to the source issue's subject when omitted. link_original: When True (default), creates a ``copied_to``/ ``copied_from`` relation between the original and the copy. copy_subtasks: When True (default), the source issue's subtasks are recursively copied. copy_attachments: When True (default), attachments are copied to the new issue. field_overrides: Optional dict (or JSON object string) of field values to override on the copy (e.g., ``{"assigned_to_id": 5, "description": "..."}``). Returns: Dictionary containing the newly created issue. On failure a dict with an ``"error"`` key is returned.

subject string issue_id int project_id string copy_subtasks bool link_original bool field_overrides string copy_attachments bool
manage_issue_relation
annotations: none low

List, create, or delete a Redmine issue relation. Args: action: One of: ``list``, ``create``, ``delete``. issue_id: Source issue ID. Required for ``list`` and ``create``. issue_to_id: Target issue ID. Required for ``create``. relation_id: Relation ID. Required for ``delete``. relation_type: One of: ``relates``, ``duplicates``, ``duplicated``, ``blocks``, ``blocked``, ``precedes``, ``follows``, ``copied_to``, ``copied_from``. Defaults to ``relates`` for ``create``. delay: Delay in days for ``precedes`` / ``follows`` relations. Returns: ``list``: list of relation dicts. ``create``: relation dict. ``delete``: ``{"success": True, "deleted_relation_id": ...}``. On error: ``{"error": "..."}``.

delay string action string issue_id string issue_to_id string relation_id string relation_type string
list_subtasks
annotations: none low

List subtasks (child issues) of a given Redmine issue. Retrieves all issues whose ``parent_issue_id`` equals the given ``issue_id``. To create a new subtask, use ``create_redmine_issue`` with the ``parent_issue_id`` field set. Args: issue_id: ID of the parent issue. Returns: List of child issue dictionaries. On failure a list containing a single dictionary with an ``"error"`` key is returned.

issue_id int
delete_redmine_issue
annotations: none low

Hard-delete an issue via ``DELETE /issues/{id}.json``. Issue deletion in Redmine is **irreversible** and cascades to the issue's children (subtasks), journals (comments), attachments, time entries, and inbound relations from issues that referenced it. To prevent accidental destruction, this tool refuses unless the caller passes ``confirm_delete=True``; the refusal envelope includes a structured ``impact`` preview (counts of cascaded items) so a caller can decide whether to proceed. If the issue has subtasks, ``confirm_delete=True`` alone is not enough -- the tool also requires ``confirm_delete_with_children=True`` so the cascade-delete of subtasks is opt-in twice. This is the case most likely to surprise a caller. For other lifecycle operations on an issue, use: - ``create_redmine_issue`` to create - ``update_redmine_issue`` to edit fields (including status, priority, custom fields) - ``copy_issue`` to duplicate - ``get_redmine_issue`` to read Args: issue_id: ID of the issue to delete. Must be a positive integer. confirm_delete: When ``False`` (default), the tool refuses and returns an impact preview. Pass ``True`` to actually delete. confirm_delete_with_children: When the issue has subtasks, ``confirm_delete=True`` alone refuses with ``CHILDREN_PRESENT``. Pass this flag too to opt in to cascade-deleting the subtasks. Returns: On refusal: an error envelope with ``code`` (``CONFIRMATION_REQUIRED`` or ``CHILDREN_PRESENT``), ``hint``, and ``impact`` (counts of cascaded items). On success: ``{"success": True, "deleted_issue_id": N, "cascade_deleted": {...counts}}``. On 404: ``{"error", "code": "NOT_FOUND", "upstream_status": 404, "issue_id"}``. Blocked in read-only mode (``REDMINE_MCP_READ_ONLY=true``).

issue_id string confirm_delete bool confirm_delete_with_children bool
manage_issue_watcher
annotations: none low

Add or remove a watcher on a Redmine issue. Requires Redmine 2.3.0+. Args: action: One of: ``add``, ``remove``. issue_id: ID of the issue. user_id: ID of the user to add or remove as a watcher. Returns: ``{"success": True, "issue_id": ..., "user_id": ...}`` on success. On error: ``{"error": "..."}``.

action string user_id int issue_id int
manage_issue_note
annotations: none low

Edit text or toggle privacy of a Redmine journal (issue note). Both actions are writes and are blocked in read-only mode. Args: action: One of: ``edit``, ``set_private``. journal_id: ID of the journal entry (required for both actions). notes: New notes text for ``edit``; may be an empty string to clear the note. Mutually exclusive with ``notes_upload_id``, and one of the two is required. notes_upload_id: Take the new note from a file staged with ``create_upload_ticket``, decoded as UTF-8. **Prefer this for a long note**: the text travels from disk to this server instead of being written out into this argument, which is slow for a long one and drops characters. The response then reports ``notes_length`` and ``notes_sha256`` rather than echoing the note back, since echoing it would put the whole thing in the conversation after all. notes_edits: Change part of a long note in place instead of sending the whole thing: a list of ``{"find": ..., "replace": ...}``, applied in order on this server. Each ``find`` must occur exactly once in the note as it stands after the preceding edits; zero matches or several refuse the whole call and change nothing. Requires ``issue_id``, and is mutually exclusive with ``notes`` and ``notes_upload_id``. notes_expected_sha256: The hex digest the note had when it was read -- echo back the ``notes_sha256`` that ``get_redmine_issue`` and ``get_private_notes`` report on each journal; do not hash the ``notes`` you read, since they are wrapped in boundary tags whose id changes on every call. Checked before any edit is applied, and a mismatch refuses the call instead of overwriting whatever changed in between. issue_id: The issue the journal belongs to. **Required with ``notes_edits`` and ignored otherwise**: patching reads the note first, and Redmine offers no endpoint for a single journal, so it can only be read through its issue. A ``journal_id`` that is not among that issue's visible journals is refused and nothing is written. private_notes: Optionally toggle private flag during ``edit``. is_private: Required for ``set_private`` -- ``True`` to mark private, ``False`` to make public. Returns: ``edit``: ``{"success": True, "journal_id": ..., "notes": ..., "private_notes": ...}``, or with ``notes_upload_id`` or ``notes_edits`` ``{"success": True, "journal_id": ..., "notes_length": ..., "notes_sha256": ..., "private_notes": ...}``. ``set_private``: ``{"success": True, "journal_id": ..., "private_notes": <bool>}``. On error: ``{"error": "..."}``.

notes string action string issue_id string is_private string journal_id int notes_edits string private_notes string notes_upload_id string notes_expected_sha256 string
get_private_notes
annotations: none low

Retrieve only the private notes/journals of a Redmine issue. Fetches the issue's journals and filters for entries where ``private_notes`` is true. The authenticated user must have the "View private notes" permission for non-empty results. Args: issue_id: ID of the issue. include_journal_values: Return the before/after text of any field changes on these journals in full rather than by length. See ``get_redmine_issue`` for why the default is ``False``. Returns: List of private journal dictionaries, each containing ``id``, ``user``, ``notes``, ``created_on``, and ``private_notes: true``. On failure a list with a single ``"error"`` dict is returned.

issue_id int include_journal_values bool
manage_issue_category
annotations: none low

List, create, update, or delete a Redmine issue category. Args: action: One of: ``list``, ``create``, ``update``, ``delete``. project_id: Project ID or identifier. Required for ``list`` and ``create``. category_id: Category ID. Required for ``update`` and ``delete``. name: Category name. Required for ``create``, optional for ``update`` (cannot be blank). assigned_to_id: Default assignee user ID. Optional for ``create`` and ``update``. reassign_to_id: Reassign existing issues to this category ID on ``delete``. Optional. Returns: ``list``: list of category dicts. ``create``/``update``: category dict. ``delete``: ``{"success": True, "deleted_category_id": ..., "reassigned_to_id": ...}``. On error: ``{"error": "..."}``.

name string action string project_id string category_id string assigned_to_id string reassign_to_id string
search_entire_redmine
annotations: none low

Search for issues, wiki pages and news across the Redmine instance. Args: query: Text to search for. Case sensitivity controlled by server DB config. resources: Filter by resource types. Allowed: ['issues', 'wiki_pages', 'news']. Default: None (searches all three) limit: Maximum number of results to return (max 100) offset: Pagination offset for server-side pagination Returns: Dictionary containing search results, counts, and metadata. On error, returns {"error": "message"}. Note: Only 'issues', 'wiki_pages' and 'news' are supported; Redmine searches more resource types than these. Requires Redmine 3.3.0 or higher for search API support.

limit string query str offset string resources string
show_project_dashboard
annotations: none low

Show a live project dashboard (health snapshot) for a project. Use this whenever the user wants an overview, snapshot, health check, or "how is project X doing" view: open vs closed counts, overdue and due-this-week issues, an open-by-priority breakdown, and recent activity. Natural requests include: "how is <project> doing", "show the dashboard for <project>", "project overview / health / status at a glance", or "what needs attention in <project>". Renders an interactive dashboard in clients that support MCP Apps; other clients receive the same structured data. Prefer ``summarize_project_status`` when the user wants a written narrative summary, and ``show_triage_board`` when they want to work issues in a board. Read-only. Args: project_id: The project to display, as a numeric ID or string identifier (e.g. ``1`` or ``"web"``). filters: Optional extra Redmine filter dict, the same shape ``list_redmine_issues`` accepts (e.g. ``{"tracker_id": 1}``).

filters string project_id string
get_project_dashboard_data
annotations: none low

Backend data source for the project dashboard's Refresh button. Returns the same payload as ``show_project_dashboard`` without a UI resource; the dashboard's iframe calls this over ``tools/call``. Pass the same arguments the dashboard was opened with, so a refresh redraws the same view. Read-only. Args: project_id: The project whose dashboard is being refreshed, as a numeric ID or string identifier (e.g. ``1`` or ``"web"``). filters: Optional extra Redmine filter dict, the same shape ``list_redmine_issues`` accepts (e.g. ``{"tracker_id": 1}``).

filters string project_id string
show_triage_board
annotations: none low

Show a project's issues as a live, interactive board (Kanban view). Use this whenever the user wants to see, view, browse, open, or triage a project's issues visually instead of as a text list. Natural requests that should call this tool include: "show me the board", "open the issue board for <project>", "give me a kanban / board view", "let me see project X's issues", "triage <project>", "what's the status breakdown for <project>", or any ask to display, visualize, or get an overview of a project's issues. Renders the issues grouped into columns by status in clients that support interactive MCP Apps; other clients still receive the same structured data. Prefer this over ``list_redmine_issues`` when the goal is to look at or work through a project's issues; use ``list_redmine_issues`` when the user explicitly wants a plain list or is filtering issues to feed another step. Read-only. Args: project_id: The project to display, as a numeric ID or string identifier (e.g. ``1`` or ``"testing-project1"``). filters: Optional extra Redmine filter dict, the same shape ``list_redmine_issues`` accepts (e.g. ``{"assigned_to_id": "me"}`` or ``{"tracker_id": 1}``).

filters string project_id string
get_triage_board_data
annotations: none low

Backend data source for the triage board's Refresh button. Returns the same payload as ``show_triage_board`` without a UI resource; the board's iframe calls this over ``tools/call``. Pass the same arguments the board was opened with, so a refresh redraws the same view. Read-only. Args: project_id: The project whose board is being refreshed, as a numeric ID or string identifier (e.g. ``1`` or ``"testing-project1"``). filters: Optional extra Redmine filter dict, the same shape ``list_redmine_issues`` accepts (e.g. ``{"assigned_to_id": "me"}`` or ``{"tracker_id": 1}``).

filters string project_id string

Permissions 4

network Server uses network capabilities via: httpx, requests, socket, urllib
medium
filesystem Server uses filesystem capabilities via: open(), os, pathlib, tempfile
low
shell Server uses shell capabilities via: subprocess
high
env_vars Server uses env_vars capabilities via: os.environ, os.getenv()
low

Scan Findings 254

low
Tool 'get_redmine_issue' has no annotations annotation_checker · 100%
low
Tool 'list_time_entries' has no annotations annotation_checker · 100%
low
Tool 'needs_int' has no annotations annotation_checker · 100%
low
Tool 'needs_int_or_sentinel' has no annotations annotation_checker · 100%
low
Tool 'union_return' has no annotations annotation_checker · 100%
low
Tool 'create_redmine_issue' has no annotations annotation_checker · 100%
low
Tool 'some_probe_tool' has no annotations annotation_checker · 100%
low
Tool 'update_redmine_issue' has no annotations annotation_checker · 100%
low
Tool 'list_redmine_issues' has no annotations annotation_checker · 100%
low
Tool 'manage_document' has no annotations annotation_checker · 100%
low
Tool 'get_current_user' has no annotations annotation_checker · 100%
low
Tool 'not_in_map_tool' has no annotations annotation_checker · 100%
low
Tool 'get_checklist' has no annotations annotation_checker · 100%
low
Tool 'update_checklist_item' has no annotations annotation_checker · 100%
low
Tool 'create_checklist_item' has no annotations annotation_checker · 100%
low
Tool 'manage_contact' has no annotations annotation_checker · 100%
low
Tool 'list_contact_tags' has no annotations annotation_checker · 100%
low
Tool 'get_redmine_attachment' has no annotations annotation_checker · 100%
low
Tool 'list_files' has no annotations annotation_checker · 100%
low
Tool 'create_upload_ticket' has no annotations annotation_checker · 100%
low
Tool 'upload_file' has no annotations annotation_checker · 100%
low
Tool 'delete_file' has no annotations annotation_checker · 100%
low
Tool 'manage_redmine_wiki_page' has no annotations annotation_checker · 100%
low
Tool 'list_redmine_news' has no annotations annotation_checker · 100%
low
Tool 'get_redmine_news' has no annotations annotation_checker · 100%
low
Tool 'manage_redmine_news' has no annotations annotation_checker · 100%
low
Tool 'delete_redmine_news' has no annotations annotation_checker · 100%
low
Tool 'manage_crm_note' has no annotations annotation_checker · 100%
low
Tool 'manage_product' has no annotations annotation_checker · 100%
low
Tool 'manage_deal' has no annotations annotation_checker · 100%
low
Tool 'list_deal_statuses' has no annotations annotation_checker · 100%
low
Tool 'manage_deal_category' has no annotations annotation_checker · 100%
low
Tool 'add_deal_product' has no annotations annotation_checker · 100%
low
Tool 'list_redmine_projects' has no annotations annotation_checker · 100%
low
Tool 'list_project_issue_custom_fields' has no annotations annotation_checker · 100%
low
Tool 'list_redmine_versions' has no annotations annotation_checker · 100%
low
Tool 'manage_redmine_version' has no annotations annotation_checker · 100%
low
Tool 'manage_redmine_project' has no annotations annotation_checker · 100%
low
Tool 'summarize_project_status' has no annotations annotation_checker · 100%
low
Tool 'list_project_members' has no annotations annotation_checker · 100%
low
Tool 'list_redmine_roles' has no annotations annotation_checker · 100%
low
Tool 'get_project_modules' has no annotations annotation_checker · 100%
low
Tool 'manage_project_member' has no annotations annotation_checker · 100%
low
Tool 'list_project_trackers' has no annotations annotation_checker · 100%
low
Tool 'list_crm_queries' has no annotations annotation_checker · 100%
low
Tool 'get_mcp_server_info' has no annotations annotation_checker · 100%
low
Tool 'manage_time_entry' has no annotations annotation_checker · 100%
low
Tool 'list_time_entry_activities' has no annotations annotation_checker · 100%
low
Tool 'import_time_entries' has no annotations annotation_checker · 100%
low
Tool 'get_gantt_chart' has no annotations annotation_checker · 100%
low
Tool 'list_redmine_trackers' has no annotations annotation_checker · 100%
low
Tool 'list_redmine_issue_statuses' has no annotations annotation_checker · 100%
low
Tool 'list_redmine_issue_priorities' has no annotations annotation_checker · 100%
low
Tool 'list_redmine_users' has no annotations annotation_checker · 100%
low
Tool 'list_redmine_queries' has no annotations annotation_checker · 100%
low
Tool 'search_redmine_issues' has no annotations annotation_checker · 100%
low
Tool 'copy_issue' has no annotations annotation_checker · 100%
low
Tool 'manage_issue_relation' has no annotations annotation_checker · 100%
low
Tool 'list_subtasks' has no annotations annotation_checker · 100%
low
Tool 'delete_redmine_issue' has no annotations annotation_checker · 100%
low
Tool 'manage_issue_watcher' has no annotations annotation_checker · 100%
low
Tool 'manage_issue_note' has no annotations annotation_checker · 100%
low
Tool 'get_private_notes' has no annotations annotation_checker · 100%
low
Tool 'manage_issue_category' has no annotations annotation_checker · 100%
low
Tool 'search_entire_redmine' has no annotations annotation_checker · 100%
low
Tool 'show_project_dashboard' has no annotations annotation_checker · 100%
low
Tool 'get_project_dashboard_data' has no annotations annotation_checker · 100%
low
Tool 'show_triage_board' has no annotations annotation_checker · 100%
low
Tool 'get_triage_board_data' has no annotations annotation_checker · 100%
info
Sandbox failed to start for behavioral verification behavioral_verifier · 100%
medium
Vulnerable dependency: python-dotenv@1.0.0,<2 (GHSA-mf9w-mj56-hr94) dependency_analyzer · 95%
medium
Vulnerable dependency: python-dotenv@1.0.0,<2 (PYSEC-2026-2270) dependency_analyzer · 95%
medium
Vulnerable dependency: httpx@0.27.0,<1 (GHSA-h8pj-cxx2-jfg2) dependency_analyzer · 95%
medium
Vulnerable dependency: httpx@0.27.0,<1 (PYSEC-2022-183) dependency_analyzer · 95%
medium
Vulnerable dependency: fastmcp@4.0.1,<5 (GHSA-5h2m-4q8j-pqpj) dependency_analyzer · 95%
medium
Vulnerable dependency: fastmcp@4.0.1,<5 (GHSA-c2jp-c369-7pvx) dependency_analyzer · 95%
medium
Vulnerable dependency: fastmcp@4.0.1,<5 (GHSA-m8x7-r2rg-vh5g) dependency_analyzer · 95%
medium
Vulnerable dependency: fastmcp@4.0.1,<5 (GHSA-mxxr-jv3v-6pgc) dependency_analyzer · 95%
medium
Vulnerable dependency: fastmcp@4.0.1,<5 (GHSA-rcfx-77hg-w2wv) dependency_analyzer · 95%
medium
Vulnerable dependency: fastmcp@4.0.1,<5 (GHSA-rj5c-58rq-j5g5) dependency_analyzer · 95%
medium
Vulnerable dependency: fastmcp@4.0.1,<5 (GHSA-rww4-4w9c-7733) dependency_analyzer · 95%
medium
Vulnerable dependency: fastmcp@4.0.1,<5 (GHSA-vv7q-7jx5-f767) dependency_analyzer · 95%
medium
Vulnerable dependency: fastmcp@4.0.1,<5 (PYSEC-2026-1364) dependency_analyzer · 95%
medium
Vulnerable dependency: fastmcp@4.0.1,<5 (PYSEC-2026-1365) dependency_analyzer · 95%
medium
Vulnerable dependency: fastmcp@4.0.1,<5 (PYSEC-2026-2474) dependency_analyzer · 95%
medium
Vulnerable dependency: fastmcp@4.0.1,<5 (PYSEC-2026-2475) dependency_analyzer · 95%
medium
Vulnerable dependency: fastmcp@4.0.1,<5 (PYSEC-2026-2476) dependency_analyzer · 95%
medium
Vulnerable dependency: fastmcp@4.0.1,<5 (PYSEC-2026-338) dependency_analyzer · 95%
medium
Vulnerable dependency: requests@2.31.0,<3 (GHSA-652x-xj99-gmcc) dependency_analyzer · 95%
medium
Vulnerable dependency: requests@2.31.0,<3 (GHSA-9hjg-9r4m-mvj7) dependency_analyzer · 95%
medium
Vulnerable dependency: requests@2.31.0,<3 (GHSA-9wx4-h78v-vm56) dependency_analyzer · 95%
medium
Vulnerable dependency: requests@2.31.0,<3 (GHSA-cfj3-7x9c-4p3h) dependency_analyzer · 95%
medium
Vulnerable dependency: requests@2.31.0,<3 (GHSA-gc5v-m9x4-r6x2) dependency_analyzer · 95%
medium
Vulnerable dependency: requests@2.31.0,<3 (GHSA-x84v-xcm2-53pg) dependency_analyzer · 95%
medium
Vulnerable dependency: requests@2.31.0,<3 (PYSEC-2014-13) dependency_analyzer · 95%
medium
Vulnerable dependency: requests@2.31.0,<3 (PYSEC-2014-14) dependency_analyzer · 95%
medium
Vulnerable dependency: requests@2.31.0,<3 (PYSEC-2018-28) dependency_analyzer · 95%
medium
Vulnerable dependency: requests@2.31.0,<3 (PYSEC-2026-1872) dependency_analyzer · 95%
medium
Vulnerable dependency: requests@2.31.0,<3 (PYSEC-2026-1873) dependency_analyzer · 95%
medium
Vulnerable dependency: requests@2.31.0,<3 (PYSEC-2026-2275) dependency_analyzer · 95%
medium
Vulnerable dependency: starlette@1.3.1,<2 (GHSA-2c2j-9gv5-cj73) dependency_analyzer · 95%
medium
Vulnerable dependency: starlette@1.3.1,<2 (GHSA-74m5-2c7w-9w3x) dependency_analyzer · 95%
medium
Vulnerable dependency: starlette@1.3.1,<2 (GHSA-86qp-5c8j-p5mr) dependency_analyzer · 95%
medium
Vulnerable dependency: starlette@1.3.1,<2 (GHSA-f96h-pmfr-66vw) dependency_analyzer · 95%
medium
Vulnerable dependency: starlette@1.3.1,<2 (GHSA-jp82-jpqv-5vv3) dependency_analyzer · 95%
medium
Vulnerable dependency: starlette@1.3.1,<2 (GHSA-wqp7-x3pw-xc5r) dependency_analyzer · 95%
medium
Vulnerable dependency: starlette@1.3.1,<2 (GHSA-x746-7m8f-x49c) dependency_analyzer · 95%
medium
Vulnerable dependency: starlette@1.3.1,<2 (PYSEC-2023-48) dependency_analyzer · 95%
medium
Vulnerable dependency: starlette@1.3.1,<2 (PYSEC-2026-161) dependency_analyzer · 95%
medium
Vulnerable dependency: starlette@1.3.1,<2 (PYSEC-2026-1941) dependency_analyzer · 95%
medium
Vulnerable dependency: starlette@1.3.1,<2 (PYSEC-2026-1943) dependency_analyzer · 95%
medium
Vulnerable dependency: starlette@1.3.1,<2 (PYSEC-2026-2280) dependency_analyzer · 95%
medium
Vulnerable dependency: starlette@1.3.1,<2 (PYSEC-2026-2281) dependency_analyzer · 95%
medium
Vulnerable dependency: starlette@1.3.1,<2 (PYSEC-2026-248) dependency_analyzer · 95%
medium
Vulnerable dependency: uvicorn@0.24.0,<1 (GHSA-33c7-2mpw-hg34) dependency_analyzer · 95%
medium
Vulnerable dependency: uvicorn@0.24.0,<1 (GHSA-f97h-2pfx-f59f) dependency_analyzer · 95%
medium
Vulnerable dependency: uvicorn@0.24.0,<1 (PYSEC-2020-150) dependency_analyzer · 95%
medium
Vulnerable dependency: uvicorn@0.24.0,<1 (PYSEC-2020-151) dependency_analyzer · 95%
medium
Vulnerable dependency: python-multipart@0.0.30,<1 (GHSA-2jv5-9r88-3w3p) dependency_analyzer · 95%
medium
Vulnerable dependency: python-multipart@0.0.30,<1 (GHSA-59g5-xgcq-4qw3) dependency_analyzer · 95%
medium
Vulnerable dependency: python-multipart@0.0.30,<1 (GHSA-5rvq-cxj2-64vf) dependency_analyzer · 95%
medium
Vulnerable dependency: python-multipart@0.0.30,<1 (GHSA-6jv3-5f52-599m) dependency_analyzer · 95%
medium
Vulnerable dependency: python-multipart@0.0.30,<1 (GHSA-mj87-hwqh-73pj) dependency_analyzer · 95%
medium
Vulnerable dependency: python-multipart@0.0.30,<1 (GHSA-pp6c-gr5w-3c5g) dependency_analyzer · 95%
medium
Vulnerable dependency: python-multipart@0.0.30,<1 (GHSA-v9pg-7xvm-68hf) dependency_analyzer · 95%
medium
Vulnerable dependency: python-multipart@0.0.30,<1 (GHSA-vffw-93wf-4j4q) dependency_analyzer · 95%
medium
Vulnerable dependency: python-multipart@0.0.30,<1 (GHSA-wp53-j4wj-2cfg) dependency_analyzer · 95%
medium
Vulnerable dependency: python-multipart@0.0.30,<1 (PYSEC-2026-1850) dependency_analyzer · 95%
medium
Vulnerable dependency: python-multipart@0.0.30,<1 (PYSEC-2026-1851) dependency_analyzer · 95%
medium
Vulnerable dependency: python-multipart@0.0.30,<1 (PYSEC-2026-1852) dependency_analyzer · 95%
medium
Vulnerable dependency: python-multipart@0.0.30,<1 (PYSEC-2026-3036) dependency_analyzer · 95%
medium
Vulnerable dependency: python-multipart@0.0.30,<1 (PYSEC-2026-3037) dependency_analyzer · 95%
medium
Vulnerable dependency: python-multipart@0.0.30,<1 (PYSEC-2026-3038) dependency_analyzer · 95%
medium
Vulnerable dependency: python-multipart@0.0.30,<1 (PYSEC-2026-3039) dependency_analyzer · 95%
medium
Vulnerable dependency: python-multipart@0.0.30,<1 (PYSEC-2026-3040) dependency_analyzer · 95%
medium
Vulnerable dependency: python-multipart@0.0.30,<1 (PYSEC-2026-3041) dependency_analyzer · 95%
medium
Vulnerable dependency: urllib3@2.7.0,<3 (GHSA-34jh-p97f-mpxf) dependency_analyzer · 95%
medium
Vulnerable dependency: urllib3@2.7.0,<3 (GHSA-g4mx-q9vg-27p4) dependency_analyzer · 95%
medium
Vulnerable dependency: urllib3@2.7.0,<3 (GHSA-gwvm-45gx-3cf8) dependency_analyzer · 95%
medium
Vulnerable dependency: urllib3@2.7.0,<3 (GHSA-mh33-7rrq-662w) dependency_analyzer · 95%
medium
Vulnerable dependency: urllib3@2.7.0,<3 (GHSA-pq67-6m6q-mj2v) dependency_analyzer · 95%
medium
Vulnerable dependency: urllib3@2.7.0,<3 (GHSA-r64q-w8jr-g9qp) dependency_analyzer · 95%
medium
Vulnerable dependency: urllib3@2.7.0,<3 (GHSA-v845-jxx5-vc9f) dependency_analyzer · 95%
medium
Vulnerable dependency: urllib3@2.7.0,<3 (GHSA-wqvq-5m8c-6g24) dependency_analyzer · 95%
medium
Vulnerable dependency: urllib3@2.7.0,<3 (GHSA-www2-v7xj-xrc6) dependency_analyzer · 95%
medium
Vulnerable dependency: urllib3@2.7.0,<3 (PYSEC-2018-32) dependency_analyzer · 95%
medium
Vulnerable dependency: urllib3@2.7.0,<3 (PYSEC-2019-132) dependency_analyzer · 95%
medium
Vulnerable dependency: urllib3@2.7.0,<3 (PYSEC-2019-133) dependency_analyzer · 95%
medium
Vulnerable dependency: urllib3@2.7.0,<3 (PYSEC-2020-148) dependency_analyzer · 95%
medium
Vulnerable dependency: urllib3@2.7.0,<3 (PYSEC-2023-192) dependency_analyzer · 95%
medium
Vulnerable dependency: urllib3@2.7.0,<3 (PYSEC-2023-207) dependency_analyzer · 95%
medium
Vulnerable dependency: urllib3@2.7.0,<3 (PYSEC-2023-212) dependency_analyzer · 95%
medium
Vulnerable dependency: urllib3@2.7.0,<3 (PYSEC-2026-1995) dependency_analyzer · 95%
medium
Vulnerable dependency: urllib3@2.7.0,<3 (PYSEC-2026-1999) dependency_analyzer · 95%
medium
Vulnerable dependency: cryptography@48.0.1,<51 (GHSA-3ww4-gg4f-jr7f) dependency_analyzer · 95%
medium
Vulnerable dependency: cryptography@48.0.1,<51 (GHSA-9v9h-cgj8-h64p) dependency_analyzer · 95%
medium
Vulnerable dependency: cryptography@48.0.1,<51 (GHSA-hggm-jpg3-v476) dependency_analyzer · 95%
medium
Vulnerable dependency: cryptography@48.0.1,<51 (GHSA-m959-cc7f-wv43) dependency_analyzer · 95%
medium
Vulnerable dependency: cryptography@48.0.1,<51 (GHSA-q3cj-2r34-2cwc) dependency_analyzer · 95%
medium
Vulnerable dependency: cryptography@48.0.1,<51 (GHSA-r6ph-v2qm-q3c2) dependency_analyzer · 95%
medium
Vulnerable dependency: cryptography@48.0.1,<51 (PYSEC-2017-8) dependency_analyzer · 95%
medium
Vulnerable dependency: cryptography@48.0.1,<51 (PYSEC-2021-62) dependency_analyzer · 95%
medium
Vulnerable dependency: cryptography@48.0.1,<51 (PYSEC-2026-1283) dependency_analyzer · 95%
medium
Vulnerable dependency: cryptography@48.0.1,<51 (PYSEC-2026-1285) dependency_analyzer · 95%
medium
Vulnerable dependency: cryptography@48.0.1,<51 (PYSEC-2026-2141) dependency_analyzer · 95%
medium
Vulnerable dependency: cryptography@48.0.1,<51 (PYSEC-2026-35) dependency_analyzer · 95%
medium
Vulnerable dependency: cryptography@48.0.1,<51 (PYSEC-2026-3553) dependency_analyzer · 95%
medium
Vulnerable dependency: cryptography@48.0.1,<51 (PYSEC-2026-3554) dependency_analyzer · 95%
medium
Vulnerable dependency: joserfc@1.6.7,<2 (GHSA-gg9x-qcx2-xmrh) dependency_analyzer · 95%
medium
Vulnerable dependency: joserfc@1.6.7,<2 (GHSA-w5r5-m38g-f9f9) dependency_analyzer · 95%
medium
Vulnerable dependency: joserfc@1.6.7,<2 (PYSEC-2026-2528) dependency_analyzer · 95%
medium
Vulnerable dependency: joserfc@1.6.7,<2 (PYSEC-2026-2529) dependency_analyzer · 95%
info
pyproject.toml metadata manifest_parser · 100%
info
Tool: get_redmine_issue manifest_parser · 90%
info
Tool: list_time_entries manifest_parser · 90%
info
Tool: needs_int manifest_parser · 90%
info
Tool: needs_int_or_sentinel manifest_parser · 90%
info
Tool: union_return manifest_parser · 90%
info
Tool: create_redmine_issue manifest_parser · 90%
info
Tool: some_probe_tool manifest_parser · 90%
info
Tool: update_redmine_issue manifest_parser · 90%
info
Tool: list_redmine_issues manifest_parser · 90%
info
Tool: manage_document manifest_parser · 90%
info
Tool: get_current_user manifest_parser · 90%
info
Tool: not_in_map_tool manifest_parser · 90%
info
Tool: get_checklist manifest_parser · 90%
info
Tool: update_checklist_item manifest_parser · 90%
info
Tool: create_checklist_item manifest_parser · 90%
info
Tool: manage_contact manifest_parser · 90%
info
Tool: list_contact_tags manifest_parser · 90%
info
Tool: get_redmine_attachment manifest_parser · 90%
info
Tool: list_files manifest_parser · 90%
info
Tool: create_upload_ticket manifest_parser · 90%
info
Tool: upload_file manifest_parser · 90%
info
Tool: delete_file manifest_parser · 90%
info
Tool: manage_redmine_wiki_page manifest_parser · 90%
info
Tool: list_redmine_news manifest_parser · 90%
info
Tool: get_redmine_news manifest_parser · 90%
info
Tool: manage_redmine_news manifest_parser · 90%
info
Tool: delete_redmine_news manifest_parser · 90%
info
Tool: manage_crm_note manifest_parser · 90%
info
Tool: manage_product manifest_parser · 90%
info
Tool: manage_deal manifest_parser · 90%
info
Tool: list_deal_statuses manifest_parser · 90%
info
Tool: manage_deal_category manifest_parser · 90%
info
Tool: add_deal_product manifest_parser · 90%
info
Tool: list_redmine_projects manifest_parser · 90%
info
Tool: list_project_issue_custom_fields manifest_parser · 90%
info
Tool: list_redmine_versions manifest_parser · 90%
info
Tool: manage_redmine_version manifest_parser · 90%
info
Tool: manage_redmine_project manifest_parser · 90%
info
Tool: summarize_project_status manifest_parser · 90%
info
Tool: list_project_members manifest_parser · 90%
info
Tool: list_redmine_roles manifest_parser · 90%
info
Tool: get_project_modules manifest_parser · 90%
info
Tool: manage_project_member manifest_parser · 90%
info
Tool: list_project_trackers manifest_parser · 90%
info
Tool: list_crm_queries manifest_parser · 90%
info
Tool: get_mcp_server_info manifest_parser · 90%
info
Tool: manage_time_entry manifest_parser · 90%
info
Tool: list_time_entry_activities manifest_parser · 90%
info
Tool: import_time_entries manifest_parser · 90%
info
Tool: get_gantt_chart manifest_parser · 90%
info
Tool: list_redmine_trackers manifest_parser · 90%
info
Tool: list_redmine_issue_statuses manifest_parser · 90%
info
Tool: list_redmine_issue_priorities manifest_parser · 90%
info
Tool: list_redmine_users manifest_parser · 90%
info
Tool: list_redmine_queries manifest_parser · 90%
info
Tool: search_redmine_issues manifest_parser · 90%
info
Tool: copy_issue manifest_parser · 90%
info
Tool: manage_issue_relation manifest_parser · 90%
info
Tool: list_subtasks manifest_parser · 90%
info
Tool: delete_redmine_issue manifest_parser · 90%
info
Tool: manage_issue_watcher manifest_parser · 90%
info
Tool: manage_issue_note manifest_parser · 90%
info
Tool: get_private_notes manifest_parser · 90%
info
Tool: manage_issue_category manifest_parser · 90%
info
Tool: search_entire_redmine manifest_parser · 90%
info
Tool: show_project_dashboard manifest_parser · 90%
info
Tool: get_project_dashboard_data manifest_parser · 90%
info
Tool: show_triage_board manifest_parser · 90%
info
Tool: get_triage_board_data manifest_parser · 90%
info
Transport: streamable-http manifest_parser · 80%
info
Required env vars (56) manifest_parser · 80%
high
High-risk OAuth scope: admin oauth_scope_analyzer · 80%
info
Sandbox failed to start for output poisoning scan output_poisoning · 100%
medium
Permission: network access detected permission_analyzer · 90%
low
Permission: filesystem access detected permission_analyzer · 80%
high
Permission: shell access detected permission_analyzer · 95%
low
Permission: env_vars access detected permission_analyzer · 90%
critical
Tool poisoning in 'list_deal_statuses': Cross-tool sequencing directive poisoning · 85%
critical
Tool poisoning in 'list_time_entry_activities': Directive language: 'always' poisoning · 85%
info
No dependency files found for SBOM generation sbom_generator · 100%
medium
No build provenance detected (SLSA L0) slsa_assessor · 90%