npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@thelabnyc/redmine-mcp

v0.5.0

Published

An MCP (Model Context Protocol) server that allows AI agents like Claude to interact with Redmine project management data.

Readme

@thelabnyc/redmine-mcp

An MCP (Model Context Protocol) server that allows AI agents like Claude to interact with Redmine project management data.

Features

  • Create issues with full field support including fixed versions, categories, and custom fields
  • Fetch issue details by ID, including subject, description, status, priority, and assignee
  • Update issues: change status, assign users, add notes, set custom fields, and more
  • Log time spent on issues with integrated time tracking
  • List issues with general Redmine filters, saved queries, and optional includes
  • List issues assigned to the current user, with filtering and sorting
  • Search Redmine globally across issues, projects, wiki pages, attachments, and other content
  • List projects accessible to the current user
  • List saved queries visible to the current user
  • List project members to find user IDs for assignments
  • Manage attachments: fetch metadata, attach local files, download content, update descriptions, and delete files
  • Manage issue relations: list, fetch, create, and delete Redmine relation records
  • Discover metadata: list available statuses, trackers, priorities, versions, categories, and custom fields
  • Retrieve change history (journals) with every request
  • Optionally include attachments, watchers, relations, and child issues

Installation

npm install @thelabnyc/redmine-mcp

Or clone and build from source:

git clone https://gitlab.com/thelabnyc/redmine-mcp.git
cd redmine-mcp
npm install
npm run build

Configuration

The server requires two environment variables:

| Variable | Description | Example | | ------------------------------ | --------------------------------------------------------------------------------------- | --------------------------- | | REDMINE_URL | Base URL of your Redmine instance | https://mycompany.plan.io | | REDMINE_API_KEY | Your Redmine API key | abc123def456... | | REDMINE_MCP_FILE_ROOT | Directory that attachment upload paths must stay within; OS temp files are also allowed | /Users/me/redmine-files | | REDMINE_MCP_MAX_UPLOAD_BYTES | Maximum local file size allowed for attach-file-to-issue in bytes | 104857600 |

Getting your Redmine API Key

  1. Log into your Redmine instance
  2. Go to My Account (click your name in the top right)
  3. In the right sidebar, find API access key
  4. Click Show to reveal your key, or Reset to generate a new one

Usage with Claude Code

Add the server to your Claude Code configuration:

Project-level configuration

Create or edit .claude/settings.json in your project:

{
    "mcpServers": {
        "redmine": {
            "command": "npx",
            "args": ["@thelabnyc/redmine-mcp"],
            "env": {
                "REDMINE_URL": "https://your-instance.plan.io",
                "REDMINE_API_KEY": "your-api-key-here"
            }
        }
    }
}

User-level configuration

Add to ~/.claude.json to make available across all projects:

{
    "mcpServers": {
        "redmine": {
            "command": "npx",
            "args": ["@thelabnyc/redmine-mcp"],
            "env": {
                "REDMINE_URL": "https://your-instance.plan.io",
                "REDMINE_API_KEY": "your-api-key-here"
            }
        }
    }
}

Using a local build

If you've cloned the repository:

{
    "mcpServers": {
        "redmine": {
            "command": "node",
            "args": ["/path/to/redmine-mcp/dist/cli.js"],
            "env": {
                "REDMINE_URL": "https://your-instance.plan.io",
                "REDMINE_API_KEY": "your-api-key-here"
            }
        }
    }
}

Available Tools

get-issue

Fetch details about a Redmine issue by ID.

Parameters:

| Parameter | Type | Required | Description | | -------------------- | ------- | -------- | ------------------------------------ | | issueId | string | Yes | Issue ID (e.g., #12345 or 12345) | | includeAttachments | boolean | No | Include file attachments | | includeWatchers | boolean | No | Include watchers list | | includeRelations | boolean | No | Include related issues | | includeChildren | boolean | No | Include child issues |

Note: Change history (journals) is always included by default.

Example usage in Claude:

"Look up Redmine issue #12345 and summarize the recent activity"

get-attachment

Fetch metadata for a Redmine attachment by ID.

Parameters:

| Parameter | Type | Required | Description | | -------------- | ------ | -------- | -------------------- | | attachmentId | number | Yes | Attachment record ID |

Example usage in Claude:

"Show me attachment 42"

attach-file-to-issue

Upload a local file to Redmine and attach it to an issue. The local file must be inside REDMINE_MCP_FILE_ROOT or the OS temp directory. Callers must summarize the target issue, file path, filename, description, content type, notes, and private-notes setting in human-readable form and get explicit user confirmation before using this tool.

Parameters:

| Parameter | Type | Required | Description | | -------------- | ------------- | -------- | ---------------------------------------------------------------- | | issueId | string/number | Yes | Issue ID (e.g., #12345 or 12345) | | filePath | string | Yes | Local path to the file to upload | | filename | string | No | Filename to store in Redmine; defaults to basename of filePath | | description | string | No | Attachment description | | contentType | string | No | Attachment content type | | notes | string | No | Optional issue note to add with the upload | | privateNotes | boolean | No | Make the issue note private |

Example usage in Claude:

"Attach /tmp/error.log to issue #12345 as supporting evidence"

download-attachment

Download a Redmine attachment's content_url to a generated OS temp directory. The tool writes the file using the attachment filename from Redmine and returns the saved path.

Parameters:

| Parameter | Type | Required | Description | | -------------- | ------ | -------- | -------------------- | | attachmentId | number | Yes | Attachment record ID |

Example usage in Claude:

"Download attachment 42"

update-attachment

Update a Redmine attachment description. Callers must summarize the attachment ID and new description in human-readable form and get explicit user confirmation before using this tool.

Parameters:

| Parameter | Type | Required | Description | | -------------- | ------ | -------- | -------------------------- | | attachmentId | number | Yes | Attachment record ID | | description | string | Yes | New attachment description |

Example usage in Claude:

"Update attachment 42's description"

delete-attachment

Delete a Redmine attachment by ID. Callers must summarize the attachment ID and delete action in human-readable form and get explicit user confirmation before using this tool.

Parameters:

| Parameter | Type | Required | Description | | -------------- | ------ | -------- | -------------------- | | attachmentId | number | Yes | Attachment record ID |

Example usage in Claude:

"Delete attachment 42"

list-issue-relations

List relation records for a Redmine issue. This exposes Redmine's GET /issues/:issue_id/relations.json endpoint.

Parameters:

| Parameter | Type | Required | Description | | --------- | ------ | -------- | ------------------------------------------- | | issueId | string | Yes | Source issue ID (e.g., #12345 or 12345) |

Example usage in Claude:

"List the related tickets for issue #12345"

get-issue-relation

Fetch one Redmine issue relation record by relation ID.

Parameters:

| Parameter | Type | Required | Description | | ------------ | ------ | -------- | ------------------ | | relationId | number | Yes | Relation record ID |

Example usage in Claude:

"Show me relation 1819"

create-issue-relation

Create a Redmine issue relation. This exposes Redmine's POST /issues/:issue_id/relations.json endpoint. The issueId parameter is the source/from issue, and issueToId is the target/to issue.

Parameters:

| Parameter | Type | Required | Description | | -------------- | ------ | -------- | --------------------------------------------------- | | issueId | string | Yes | Source/from issue ID (e.g., #12345 or 12345) | | issueToId | number | Yes | Target/to related issue ID | | relationType | string | No | Relation type; defaults to relates | | delay | number | No | Delay in days for precedes or follows relations |

Supported relation types are relates, duplicates, duplicated, blocks, blocked, precedes, follows, copied_to, and copied_from.

Example usage in Claude:

"Relate issue #12345 to issue #67890"

delete-issue-relation

Delete a Redmine issue relation record by relation ID. Redmine does not provide an update endpoint for relation records; callers that need to change a relation should delete the old relation and create the desired new relation explicitly.

Parameters:

| Parameter | Type | Required | Description | | ------------ | ------ | -------- | ---------------------------- | | relationId | number | Yes | Relation record ID to delete |

Example usage in Claude:

"Delete relation 1819"

add-issue-watcher

Add a watcher to a Redmine issue. Callers must summarize the target issue and watcher user in human-readable form and get explicit user confirmation before using this tool.

Parameters:

| Parameter | Type | Required | Description | | --------- | ------------- | -------- | ------------------------------------ | | issueId | string/number | Yes | Issue ID (e.g., #12345 or 12345) | | userId | number | Yes | Redmine user ID to add as a watcher |

Example usage in Claude:

"Add user 15 as a watcher on issue #12345"

remove-issue-watcher

Remove a watcher from a Redmine issue. Callers must summarize the target issue and watcher user in human-readable form and get explicit user confirmation before using this tool.

Parameters:

| Parameter | Type | Required | Description | | --------- | ------------- | -------- | -------------------------------------- | | issueId | string/number | Yes | Issue ID (e.g., #12345 or 12345) | | userId | number | Yes | Redmine user ID to remove as a watcher |

Example usage in Claude:

"Remove user 15 from the watcher list for issue #12345"

create-issue

Create a new Redmine issue.

Parameters:

| Parameter | Type | Required | Description | | ---------------- | ------------- | -------- | --------------------------------------------------------- | | projectId | string/number | Yes | Project identifier (string slug or numeric ID) | | subject | string | Yes | Issue subject/title | | description | string | No | Issue description | | statusId | number | No | Status ID to set | | priorityId | number | No | Priority ID to set | | assignedToId | number | No | User ID to assign | | trackerId | number | No | Tracker ID to set | | parentIssueId | number | No | Parent issue ID | | fixedVersionId | number | No | Fixed version ID to set | | categoryId | number | No | Issue category ID to set | | startDate | string | No | Start date (YYYY-MM-DD format) | | dueDate | string | No | Due date (YYYY-MM-DD format) | | doneRatio | number | No | Percent done (0-100) | | estimatedHours | number | No | Estimated hours for the issue | | isPrivate | boolean | No | Whether the issue is private | | watcherUserIds | number[] | No | User IDs to add as issue watchers | | customFields | array | No | Custom field values (see Custom Fields) |

Example usage in Claude:

"Create a bug in project 'my-app' titled 'Login page crashes on submit'"

update-issue

Update a Redmine issue. Can change fields, add notes, and log time spent.

Parameters:

| Parameter | Type | Required | Description | | ---------------- | ------- | -------- | --------------------------------------------------------- | | issueId | string | Yes | Issue ID (e.g., #12345 or 12345) | | subject | string | No | New issue subject/title | | description | string | No | New issue description | | statusId | number | No | Status ID to set | | priorityId | number | No | Priority ID to set | | assignedToId | number | No | User ID to assign (use 0 to unassign) | | trackerId | number | No | Tracker ID to set | | parentIssueId | number | No | Parent issue ID | | fixedVersionId | number | No | Fixed version ID to set | | categoryId | number | No | Issue category ID to set | | startDate | string | No | Start date (YYYY-MM-DD format) | | dueDate | string | No | Due date (YYYY-MM-DD format) | | doneRatio | number | No | Percent done (0-100) | | estimatedHours | number | No | Estimated hours for the issue | | notes | string | No | Comment/note to add to the issue journal | | privateNotes | boolean | No | Make the notes private | | logHours | number | No | Hours to log as a time entry | | logActivityId | number | No | Activity ID for time entry (uses default if omitted) | | logComments | string | No | Comments for the time entry | | logSpentOn | string | No | Date for time entry (YYYY-MM-DD, defaults to today) | | customFields | array | No | Custom field values (see Custom Fields) |

Example usage in Claude:

"Update issue #12345 to status 2 and assign to user 5"

"Add a note to issue #6789 saying 'Fixed the bug' and log 1.5 hours"

list-time-entries

List Redmine time entries with optional filters and pagination.

Parameters:

| Parameter | Type | Required | Description | | ------------ | ------------- | -------- | ---------------------------------- | | issueId | string/number | No | Filter by issue ID | | projectId | string/number | No | Filter by project ID or identifier | | userId | number/string | No | Filter by user ID, or "me" | | spentOn | string | No | Exact spent date (YYYY-MM-DD) | | from | string | No | Start date (YYYY-MM-DD) | | to | string | No | End date (YYYY-MM-DD) | | activityId | number | No | Filter by time entry activity ID | | limit | number | No | Maximum results to return | | offset | number | No | Number of results to skip |

Example usage in Claude:

"List my time entries for project 'my-app' from 2026-06-01 to 2026-06-30"

get-time-entry

Fetch one Redmine time entry by ID.

Parameters:

| Parameter | Type | Required | Description | | ------------- | ------ | -------- | ------------- | | timeEntryId | number | Yes | Time entry ID |

Example usage in Claude:

"Show me time entry 100"

create-time-entry

Create a Redmine time entry for exactly one issue or numeric project ID. Callers must summarize the target issue or project, hours, activity, spent date, comments, and custom fields in human-readable form and get explicit user confirmation before using this tool.

Parameters:

| Parameter | Type | Required | Description | | -------------- | ------------- | -------- | ------------------------------------------------------------- | | issueId | string/number | No | Issue ID; exactly one of issueId or projectId is required | | projectId | string/number | No | Numeric project ID; exactly one target is required | | hours | number | Yes | Hours to log | | activityId | number | No | Time entry activity ID | | spentOn | string | No | Spent date (YYYY-MM-DD) | | comments | string | No | Time entry comments | | customFields | array | No | Custom field values |

Example usage in Claude:

"Log 2.5 hours on issue #12345 for development today"

update-time-entry

Update a Redmine time entry. Redmine returns an empty response to the update request, so this tool fetches and returns the refreshed time entry after the update. Callers must summarize the time entry ID and all planned changes in human-readable form and get explicit user confirmation before using this tool.

Parameters:

| Parameter | Type | Required | Description | | -------------- | ------ | -------- | ----------------------- | | timeEntryId | number | Yes | Time entry ID | | hours | number | No | Hours to set | | activityId | number | No | Time entry activity ID | | spentOn | string | No | Spent date (YYYY-MM-DD) | | comments | string | No | Time entry comments | | customFields | array | No | Custom field values |

Example usage in Claude:

"Update time entry 100 to 3 hours"

delete-time-entry

Delete a Redmine time entry by ID. Callers must summarize the time entry ID and delete action in human-readable form and get explicit user confirmation before using this tool.

Parameters:

| Parameter | Type | Required | Description | | ------------- | ------ | -------- | ------------- | | timeEntryId | number | Yes | Time entry ID |

Example usage in Claude:

"Delete time entry 100"

list-time-entry-activities

List Redmine time entry activities. Use this to discover activity IDs before creating or updating time entries.

Parameters: None.

Example usage in Claude:

"List available time entry activities"

list-my-issues

List issues assigned to the current user, with optional filtering and sorting.

Parameters:

| Parameter | Type | Required | Description | | ----------- | ------------- | -------- | ----------------------------------------------------- | | statusId | number/string | No | Filter by status ID, or "open", "closed", "*" | | projectId | string/number | No | Filter by project | | limit | number | No | Maximum results to return | | offset | number | No | Number of results to skip for pagination | | sort | string | No | Sort order (default: priority:desc,updated_on:desc) |

Example usage in Claude:

"What issues are assigned to me?"

list-issues

List Redmine issues using general issue filters. This calls Redmine GET /issues.json and returns full issue objects plus total_count, offset, and limit metadata. Use list-queries to discover saved query IDs for the queryId parameter.

Parameters:

| Parameter | Type | Required | Description | | -------------------- | ------------- | -------- | --------------------------------------------------- | | issueIds | array | No | Issue IDs; strings may include # prefixes | | projectId | string/number | No | Filter by project ID or identifier | | trackerId | number | No | Filter by tracker ID | | statusId | number/string | No | Filter by status ID, or "open", "closed", "*" | | assignedToId | number/string | No | Filter by assignee user ID, or "me" | | parentId | number | No | Filter by parent issue ID | | createdOn | string | No | Redmine created_on filter expression | | updatedOn | string | No | Redmine updated_on filter expression | | customFields | array | No | Custom field filters, serialized as cf_<id>=value | | queryId | number | No | Saved query ID; use list-queries to discover IDs | | includeAttachments | boolean | No | Include issue attachments | | includeRelations | boolean | No | Include issue relations | | sort | string | No | Sort order, e.g. updated_on:desc | | limit | number | No | Maximum results to return | | offset | number | No | Number of results to skip for pagination |

Example usage in Claude:

"List open bugs in project 'my-app' updated this month"

search-redmine

Search Redmine globally using GET /search.json. Returns results, total_count, offset, and limit.

Parameters:

| Parameter | Type | Required | Description | | ------------- | -------------- | -------- | ---------------------------------------------------------------------------------------------------------- | | query | string | Yes | Search query, sent as Redmine q | | scope | string | No | Optional Redmine search scope | | allWords | boolean | No | true requires all words; false explicitly disables all words | | titlesOnly | boolean | No | true searches titles only; false is omitted | | issues | boolean | No | true narrows scope to issues; false is omitted | | news | boolean | No | true narrows scope to news; false is omitted | | documents | boolean | No | true narrows scope to documents; false is omitted | | changesets | boolean | No | true narrows scope to changesets; false is omitted | | wikiPages | boolean | No | true narrows scope to wiki pages; false is omitted | | messages | boolean | No | true narrows scope to messages; false is omitted | | projects | boolean | No | true narrows scope to projects; false is omitted | | attachments | boolean/"only" | No | true includes attachment content, false disables attachment search, "only" searches attachments only | | openIssues | boolean | No | true restricts issue results to open issues; false is omitted | | limit | number | No | Maximum results to return | | offset | number | No | Number of results to skip for pagination |

Example usage in Claude:

"Search Redmine for cache invalidation across issues and wiki pages"

list-projects

List all projects accessible to the current user.

Parameters:

| Parameter | Type | Required | Description | | --------- | ------ | -------- | ---------------------------------------- | | limit | number | No | Maximum results to return | | offset | number | No | Number of results to skip for pagination |

Example usage in Claude:

"What Redmine projects do I have access to?"

list-queries

List saved Redmine issue queries visible to the current user.

Parameters:

| Parameter | Type | Required | Description | | --------- | ------ | -------- | ---------------------------------------- | | limit | number | No | Maximum results to return | | offset | number | No | Number of results to skip for pagination |

Example usage in Claude:

"What saved Redmine queries can I use?"

list-project-members

List all members of a Redmine project. Use this to find user IDs for assigning issues.

Parameters:

| Parameter | Type | Required | Description | | ----------- | ------ | -------- | ---------------------------------------------------- | | projectId | string | Yes | Project ID or identifier (e.g., my-project or 1) | | limit | number | No | Maximum number of members to return (default 25) | | offset | number | No | Number of members to skip for pagination |

Example usage in Claude:

"Who can I assign issues to in project 'my-project'?"

list-project-versions

List versions for a Redmine project. Use this to discover fixed version IDs before setting fixedVersionId on create-issue or update-issue.

Parameters:

| Parameter | Type | Required | Description | | ----------- | ------------- | -------- | ---------------------------------------------- | | projectId | string/number | Yes | Project identifier (string slug or numeric ID) |

Example usage in Claude:

"What versions are available for project 'my-app'?"

list-project-issue-categories

List issue categories for a Redmine project. Use this to discover category IDs before setting categoryId on create-issue or update-issue.

Parameters:

| Parameter | Type | Required | Description | | ----------- | ------------- | -------- | ---------------------------------------------- | | projectId | string/number | Yes | Project identifier (string slug or numeric ID) |

Example usage in Claude:

"What issue categories are available for project 'my-app'?"

list-issue-statuses

List all available issue statuses. Use this to find valid status IDs when updating issues.

Parameters: None

Example usage in Claude:

"What statuses can I set for issues?"

list-trackers

List all available trackers (e.g., Bug, Feature, Support). Use this to find valid tracker IDs.

Parameters: None

Example usage in Claude:

"What trackers are available?"

list-issue-priorities

List all available issue priorities. Use this to find valid priority IDs.

Parameters: None

Example usage in Claude:

"What priority levels can I set?"

list-project-custom-fields

List the custom fields available for issues in a given project. Use this to discover custom field IDs before setting them on create-issue or update-issue.

Parameters:

| Parameter | Type | Required | Description | | ----------- | ------------- | -------- | ---------------------------------------------- | | projectId | string/number | Yes | Project identifier (string slug or numeric ID) |

Example usage in Claude:

"What custom fields are available for project 'my-app'?"

whoami

Get information about the currently authenticated Redmine user.

Parameters: None

Example usage in Claude:

"Who am I logged in as in Redmine?"

Custom Fields

The customFields parameter on create-issue and update-issue accepts an array of objects:

[
    { "id": 1, "value": "Sprint 5" },
    { "id": 2, "value": ["option1", "option2"] }
]

Use list-project-custom-fields to discover available custom field IDs for a project. Multi-value fields accept an array of strings.

Development

# Install dependencies
npm install

# Run tests
npm test

# Run tests in watch mode
npm run test:watch

# Build
npm run build

# Lint
npm run lint

License

ISC