npm package: @informatiktirol/anthrop.ops_mcp
Description: MCP server for Redmine
Author: informatik_tirol
Latest version: 2.0.16

# Redmine MCP Server

Forked from https://github.com/milldea-mitsuya/redmine-mcp-server

Model Context Protocol (MCP) server for Redmine that provides comprehensive access to the Redmine REST API.

[![npm version](https://img.shields.io/npm/v/@informatiktirol/anthrop.ops_mcp)](https://www.npmjs.com/package/@informatiktirol/anthrop.ops_mcp)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

## Table of Contents

- [Overview](#overview)
- [What's New in v2.0.0](#whats-new-in-v200)
- [Installation](#installation)
- [Quick Start](#quick-start)
- [Available Tools](#available-tools)
- [Features](#features)
- [Prerequisites](#prerequisites)
- [Configuration](#configuration)
- [Use Cases](#use-cases)
- [Documentation](#documentation)
- [Plugin Requirements](#plugin-requirements)
- [Development](#development)
- [Changelog](#changelog)

## Overview

This project is an MCP server that comprehensively covers Redmine's [REST API](https://www.redmine.org/projects/redmine/wiki/rest_api). It allows you to operate Redmine from MCP clients (such as Claude Desktop).

## What's New in v2.x

### Core Improvements
- **Unified Tools**: 9 consolidated tools (50% reduction from 18) for faster LLM response
- **`assigned_to_id: "me"`**: Assign issues to yourself using the "me" alias
- **Auto User ID Detection**: Current user automatically detected from API key
- **Graceful Degradation**: Optional plugins work when available, fail silently when not

### MCP Chat Integration
- **Bidirectional Communication**: Send notifications to users, read their messages
- **Action URLs**: Clickable links to issues, project kanban, or global kanban
- **Auto Notifications**: Issue create/update and time entries notify users automatically
- **Batch Support**: Suppress individual notifications with `suppress_chat: "1"`, send summary at end

### Unified Tool Design
| Tool | Operations |
|------|------------|
| **issues** | LIST, GET, CREATE, UPDATE + optional todos |
| **timeEntries** | LIST or CREATE |
| **relations** | LIST or CREATE |
| **todos** | LIST, CREATE, TOGGLE, BULK UPDATE/DELETE |
| **mcpChat** | NOTIFY, GET_MESSAGES, MARK_PROCESSED |
| **search** | Global search |

### Configuration Options
- **Read-Only Mode**: Safe data reference mode (`REDMINE_MCP_READ_ONLY=true`)
- **Feature Flags**: Disable specific tool groups via environment variables
- **Email Suppression**: Silent issue updates with `suppress_mail: "1"`

## Installation

Install directly via npm - no configuration required:

```bash
npm install @informatiktirol/anthrop.ops_mcp
```

Or use directly with `npx` (recommended for MCP clients).

## Quick Start

Add the MCP server to your client:

**For Claude Code:**
```bash
claude mcp add redmine \
  -e REDMINE_URL=https://your-redmine.example.com \
  -e REDMINE_API_KEY=your-api-key-here \
  -- npx -y @informatiktirol/anthrop.ops_mcp
```

**For Claude Desktop** - add to `claude_desktop_config.json`:
```json
{
  "mcpServers": {
    "redmine": {
      "command": "npx",
      "args": ["-y", "@informatiktirol/anthrop.ops_mcp"],
      "env": {
        "REDMINE_URL": "https://your-redmine.example.com",
        "REDMINE_API_KEY": "your-api-key-here"
      }
    }
  }
}
```

See [Configuration](#configuration) below for all options including read-only mode and feature flags.

## Available Tools

This MCP server provides **12 consolidated tools** optimized for LLM usage:

### Core Tools (Always Active)

| Tool | Description |
|------|-------------|
| **issues** | Unified: LIST (filters), GET (id), CREATE (issue data), UPDATE (id + issue). Auto chat notification on create/update (use `suppress_chat:'1'` for batch ops). Supports optional `todos` array (graceful degradation) |
| **search** | Global search across Redmine |

### Optional Tools (Configurable via Environment Variables)

| Tool | Description | Disable with |
|------|-------------|--------------|
| **timeEntries** | List OR create time entries (`action: "list"` or `"create"`) | `REDMINE_MCP_DISABLE_TIME_ENTRIES=true` |
| **relations** | List OR create issue relations (`action: "list"` or `"create"`) | `REDMINE_MCP_DISABLE_RELATIONS=true` |
| **todos** | List, create, toggle, bulk update/delete todos (requires redmine_todos plugin) | `REDMINE_MCP_DISABLE_TODOS=true` |
| **mcpChat** | Bidirectional chat: notify user with action links, read messages, mark processed (requires redmine_mcp_chat plugin) | `REDMINE_MCP_DISABLE_CHAT=true` |

### Attachment Tools

| Tool | Description |
|------|-------------|
| **downloadAttachmentAsBase64Content** | Download attachment from Redmine. Returns MCP `image` content for images (PNG, JPEG, GIF, WebP) so LLMs can see them directly. Non-image files returned as Base64 text. |
| **downloadThumbnailAsBase64Content** | Download smaller thumbnail preview of an attachment as MCP `image` content. Good for quick visual overview without loading full-size images. |
| **uploadAttachmentFromFile** | Upload a local file to Redmine by file path. Server reads the file directly -- no Base64 encoding needed. Returns upload token. |

### Tool Usage Examples

```typescript
// List my active issues
issues({ queryParams: { assigned_to_id: ["me"], status_id: ["open"] } })

// Show single issue with watchers
issues({ pathParams: { id: 18390 }, queryParams: { include: ["watchers", "relations"] } })

// Create issue with todos (graceful degradation if plugin unavailable)
issues({
  queryParams: {
    issue: { project_id: 267, subject: "New feature" },
    todos: [
      { subject: "Design" },
      { subject: "Implementation" },
      { subject: "Testing" }
    ]
  }
})

// Assign issue to current user (using "me" alias)
issues({
  queryParams: {
    issue: { project_id: 267, subject: "My task", assigned_to_id: "me" }
  }
})

// Batch update: suppress individual notifications, send summary at end
issues({ pathParams: { id: 123 }, queryParams: { issue: { status_id: 2 }, suppress_chat: "1" } })
issues({ pathParams: { id: 124 }, queryParams: { issue: { status_id: 2 }, suppress_chat: "1" } })
issues({ pathParams: { id: 125 }, queryParams: { issue: { status_id: 2 }, suppress_chat: "1" } })
// Then send summary notification
mcpChat({ queryParams: {
  action: "notify", user_id: 5, type: "info",
  message: "3 tickets updated",
  action_type: "project_kanban", project_identifier: "myproject"
} })

// Create time entry
timeEntries({ pathParams: { action: "create" }, queryParams: { time_entry: { issue_id: 123, hours: 2.5, comments: "Dev work" } } })

// Create relation
relations({ pathParams: { issueId: 123, action: "create" }, queryParams: { relation: { issue_to_id: 456, relation_type: "blocks" } } })

// Todos: list, create, toggle
todos({ pathParams: { issueId: 123 }, queryParams: {} })  // list
todos({ pathParams: { issueId: 123 }, queryParams: { todo: { subject: "New item" } } })  // create single
todos({ pathParams: { issueId: 123 }, queryParams: { todoId: 789, is_done: true } })  // toggle

// MCP Chat - basic notification
mcpChat({ queryParams: { action: "notify", user_id: 5, message: "Task completed!", type: "success" } })

// MCP Chat - with action link to issue
mcpChat({ queryParams: {
  action: "notify", user_id: 5, type: "success",
  message: "Ticket #19188 created",
  action_type: "issue", issue_id: 19188
} })

// MCP Chat - with action link to project kanban
mcpChat({ queryParams: {
  action: "notify", user_id: 5, type: "info",
  message: "5 tickets updated (@landeck)",
  action_type: "project_kanban", project_identifier: "landeck"
} })

// MCP Chat - with action link to global kanban
mcpChat({ queryParams: {
  action: "notify", user_id: 5, type: "info",
  message: "8 tickets updated (3 projects)",
  action_type: "global_kanban"
} })

mcpChat({ queryParams: { action: "getMessages", user_id: 5 } })
mcpChat({ queryParams: { action: "markProcessed", message_id: 123 } })

// Download attachment image (LLM sees it directly)
downloadAttachmentAsBase64Content({ pathParams: { attachmentId: 7734, filename: "screenshot.png" } })

// Download thumbnail (smaller preview)
downloadThumbnailAsBase64Content({ pathParams: { attachmentId: 7734 } })

// Upload file and attach to issue
const token = uploadAttachmentFromFile({ pathParams: { filePath: "/path/to/diagram.png" } })
issues({ pathParams: { id: 123 }, queryParams: { issue: { uploads: [{ token, filename: "diagram.png" }] } } })
```



## Features

- 📋 **Consolidated Tools**: 12 unified tools for optimal LLM performance
- 🖼️ **Image-Aware Attachments**: Download images as MCP `image` content - LLMs see attachments directly
- 🔒 **Read-Only Mode**: Optional safe data reference mode (`REDMINE_MCP_READ_ONLY=true`)
- ⚙️ **Feature Flags**: Granular control over enabled features via environment variables
- ✅ **Todo Support**: Full integration with redmine_todos plugin (anthrop.todos)
- 💬 **MCP Chat**: Bidirectional communication with Redmine chat widget (requires redmine_mcp_chat plugin)
- 🔗 **Issue Relations**: Create and manage dependencies between issues
- ⏱️ **Time Tracking**: Log and manage time entries on issues
- 🔍 **Advanced Search**: Global search across Redmine instances
- 🔕 **Email Suppression**: Optional email notification control for issue operations (requires redmine_silencer plugin)
- 🛡️ **Type Safety**: Full TypeScript support with Zod schema validation
- 🔧 **Auto-Generated**: API client generated from OpenAPI specification

## Prerequisites

### Getting Redmine API Key

1. Log in to Redmine with administrator privileges
2. Go to "Administration" → "Settings" → "API" tab
3. Check "Enable REST web service"
4. Generate "API access key" in personal settings

For details, refer to [Redmine REST API documentation](https://www.redmine.org/projects/redmine/wiki/rest_api#Authentication).

## Configuration

### Environment Variables

#### Required Variables

- **REDMINE_URL** (Required): Base URL of the Redmine instance
  - Example: `https://redmine.example.com`
- **REDMINE_API_KEY** (Required): API key generated in Redmine
  - Set the API key obtained in prerequisites

#### Optional Variables

- **REDMINE_MCP_READ_ONLY** (Optional): Enable read-only mode
  - `true`: Read-only mode (disables all data modification operations)
  - `false` or unset: Allow all operations (default)

#### Feature Flags (Optional)

All features are **enabled by default**. Set these to `true` to disable specific tool groups:

- **REDMINE_MCP_DISABLE_TODOS**: Disable todo tools (requires redmine_todos plugin)
- **REDMINE_MCP_DISABLE_RELATIONS**: Disable issue relations tools
- **REDMINE_MCP_DISABLE_TIME_ENTRIES**: Disable time entry tools
- **REDMINE_MCP_DISABLE_CHAT**: Disable MCP chat tools (requires redmine_mcp_chat plugin)
- **REDMINE_MCP_CHAT_USER_ID**: Default user ID for automatic chat notifications on issue create/update

**Use Case**: Reduce tool count for specific workflows or when plugins are not available.

### MCP Client Configuration

Add the following as MCP configuration for your AI agent:

```json
{
  "mcpServers": {
    "redmine": {
      "command": "npx",
      "args": ["-y", "@informatiktirol/anthrop.ops_mcp"],
      "env": {
        "REDMINE_URL": "https://redmine.example.com",
        "REDMINE_API_KEY": "your-api-key-here",
        "REDMINE_MCP_READ_ONLY": "true"
      }
    }
  }
}
```

Below are specific configuration methods for several MCP clients:

#### Claude Desktop

Add the following to `claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "redmine": {
      "command": "npx",
      "args": ["-y", "@informatiktirol/anthrop.ops_mcp"],
      "env": {
        "REDMINE_URL": "https://redmine.example.com",
        "REDMINE_API_KEY": "your-api-key-here",
        "REDMINE_MCP_READ_ONLY": "true"
      }
    }
  }
}
```

#### Claude Code

In Claude Code, you can add MCP servers using the following commands:

**Basic Installation (All Features Enabled):**
```bash
# Local configuration (current project only)
claude mcp add redmine \
  -e REDMINE_URL=https://redmine.example.com \
  -e REDMINE_API_KEY=your-api-key-here \
  -- npx -y @informatiktirol/anthrop.ops_mcp

# Project configuration (committed to git)
claude mcp add -s project redmine \
  -e REDMINE_URL=https://redmine.example.com \
  -e REDMINE_API_KEY=your-api-key-here \
  -- npx -y @informatiktirol/anthrop.ops_mcp

# User configuration (global - all projects)
claude mcp add -s user redmine \
  -e REDMINE_URL=https://redmine.example.com \
  -e REDMINE_API_KEY=your-api-key-here \
  -- npx -y @informatiktirol/anthrop.ops_mcp
```

**Read-Only Mode (Safe for Production):**
```bash
claude mcp add -s user redmine \
  -e REDMINE_URL=https://redmine.example.com \
  -e REDMINE_API_KEY=your-api-key-here \
  -e REDMINE_MCP_READ_ONLY=true \
  -- npx -y @informatiktirol/anthrop.ops_mcp
```

**Custom Feature Configuration:**
```bash
# Minimal setup - Core features only (no plugins)
claude mcp add -s user redmine \
  -e REDMINE_URL=https://redmine.example.com \
  -e REDMINE_API_KEY=your-api-key-here \
  -e REDMINE_MCP_DISABLE_TODOS=true \
  -e REDMINE_MCP_DISABLE_RELATIONS=true \
  -e REDMINE_MCP_DISABLE_TIME_ENTRIES=true \
  -- npx -y @informatiktirol/anthrop.ops_mcp

# Todos only (with redmine_todos plugin)
claude mcp add -s user redmine \
  -e REDMINE_URL=https://redmine.example.com \
  -e REDMINE_API_KEY=your-api-key-here \
  -e REDMINE_MCP_DISABLE_RELATIONS=true \
  -e REDMINE_MCP_DISABLE_TIME_ENTRIES=true \
  -- npx -y @informatiktirol/anthrop.ops_mcp

# Time tracking focus
claude mcp add -s user redmine \
  -e REDMINE_URL=https://redmine.example.com \
  -e REDMINE_API_KEY=your-api-key-here \
  -e REDMINE_MCP_DISABLE_TODOS=true \
  -e REDMINE_MCP_DISABLE_RELATIONS=true \
  -- npx -y @informatiktirol/anthrop.ops_mcp
```

**Available Feature Flags:**
- `REDMINE_MCP_DISABLE_TODOS=true` - Disable todo tools (requires `redmine_todos` plugin)
- `REDMINE_MCP_DISABLE_RELATIONS=true` - Disable issue relations tools
- `REDMINE_MCP_DISABLE_TIME_ENTRIES=true` - Disable time entry tools

See [doc/configuration.md](doc/configuration.md) for complete configuration options.

#### Visual Studio Code

Project configuration (`.vscode/mcp.json`):

```json
{
  "servers": {
    "redmine": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@informatiktirol/anthrop.ops_mcp"],
      "env": {
        "REDMINE_URL": "https://redmine.example.com",
        "REDMINE_API_KEY": "your-api-key-here",
        "REDMINE_MCP_READ_ONLY": "true"
      }
    }
  }
}
```

User configuration (`settings.json`):

```json
{
  "mcp": {
    "servers": {
      "redmine": {
        "type": "stdio",
        "command": "npx",
        "args": ["-y", "@informatiktirol/anthrop.ops_mcp"],
        "env": {
          "REDMINE_URL": "https://redmine.example.com",
          "REDMINE_API_KEY": "your-api-key-here",
          "REDMINE_MCP_READ_ONLY": "true"
        }
      }
    }
  }
}
```

## Use Cases

### Task Management with Todos
```
1. Create issue for feature development
2. Add todo items for implementation steps
3. Toggle todos as work progresses
4. Track done ratio automatically
```

### Issue Dependency Tracking
```
1. Create multiple related issues
2. Link with relations tool (blocks, precedes, etc.)
3. Manage dependencies and workflow
4. Track duplicate issues
```

### Time Tracking Integration
```
1. Create/update issues via MCP
2. Log time entries with timeEntries tool
3. Track hours per issue/project
4. Generate time reports
```

### Automated Workflows
```
1. AI assistant creates issues from conversations
2. Links related issues based on context
3. Logs time as work is discussed
4. Toggles todos as tasks complete
```

## Documentation

- **[doc/configuration.md](doc/configuration.md)** - Complete configuration guide with environment variables
- **[doc/features.md](doc/features.md)** - Comprehensive feature overview and API reference
- **[DEVELOPMENT.md](DEVELOPMENT.md)** - Development and contribution guide

## Plugin Requirements

### Todos Feature

To use todo tools, install the **redmine_todos** plugin on your Redmine instance:

- Plugin: Custom `redmine_todos` plugin (fork of anthrop.todos)
- Provides task breakdown within issues with completion tracking
- Fully integrated with MCP server
- Auto-disabled if `REDMINE_MCP_DISABLE_TODOS=true`

### MCP Chat Feature

To use the `mcpChat` tool for bidirectional communication, install the **redmine_mcp_chat** plugin:

- Plugin: Custom `redmine_mcp_chat` plugin (anthrop.agent_chat)
- Enables agent-to-user notifications in Redmine UI
- User can send messages back to the agent
- Chat widget appears in Redmine header
- Auto-disabled if `REDMINE_MCP_DISABLE_CHAT=true`
- **Graceful degradation**: If plugin not installed, tool returns informative error

**Actions:**
- `notify` - Send notification to user (info, success, warning)
- `getMessages` - Read pending user messages
- `markProcessed` - Mark message as handled

**Action URLs (Clickable Links in Notifications):**

Notifications can include clickable action buttons that navigate users directly to relevant pages:

| action_type | Required params | Generated URL |
|-------------|-----------------|---------------|
| `issue` | `issue_id` | `/issues/{issue_id}` |
| `project_kanban` | `project_identifier` | `/projects/{identifier}/kanban_boards` |
| `global_kanban` | - | `/kanban_boards` |

Optional: `action_label` for custom button text (auto-generated if omitted).

**Auto Chat Notifications:**

Issue CREATE and UPDATE operations automatically send chat notifications with action links. Use `suppress_chat: "1"` for batch operations, then send a summary notification via `mcpChat`.

Requires `REDMINE_MCP_CHAT_USER_ID` environment variable to specify the target user.

### Email Notification Control (Optional)

To suppress email notifications when updating issues, install the **redmine_silencer** plugin:

- Plugin: https://github.com/paginagmbh/redmine_silencer
- Allows silent issue updates without sending notification emails
- Useful for bulk operations or automated workflows
- **Only works with `updateIssue`** - issue creation always sends notifications

**Usage Example:**

```typescript
// Update issue silently (no emails sent to watchers)
updateIssue({
  suppress_mail: "1",
  issue: {
    status_id: 2,
    notes: "Silent update - no email notifications"
  }
})

// Bulk update example
updateIssue({
  suppress_mail: "1",
  issue: {
    assigned_to_id: 5,
    priority_id: 3,
    done_ratio: 50
  }
})
```

**Important Notes:**
- ⚠️ **Issue creation (`createIssue`) does NOT support email suppression** - the plugin only hooks into update operations
- If you need to create issues without notifications, don't assign users or add watchers initially
- If the plugin is not installed, the `suppress_mail` parameter is gracefully ignored (no error)

## Development

See [DEVELOPMENT.md](DEVELOPMENT.md) for:
- Building from source
- Code generation from OpenAPI spec
- Adding new features
- Testing and debugging

## Changelog

### v2.0.16 (2026-03-31)

**Improvement:**
- **File path upload**: New `uploadAttachmentFromFile` tool uploads files by local path -- server reads the file directly, no Base64 encoding over MCP transport. Replaces `uploadAttachmentFromBase64Content` which was too slow for files over a few KB.

### v2.0.15 (2026-03-26)

**New Feature:**
- **Attachment Image Support**: LLMs can now see Redmine attachment images directly via MCP `image` content type
  - `downloadAttachmentAsBase64Content` - Full image download (returns MCP image for PNG/JPEG/GIF/WebP, Base64 text for other files)
  - `downloadThumbnailAsBase64Content` - Thumbnail preview as MCP image
- **Workflow**: Fetch issue with `include: ["attachments"]`, then download images for visual context

### v2.0.14 (2026-03-19)

**Bug Fix:**
- **Todo toggle 403 fix**: Todo toggle now uses the bulk update endpoint (`PUT /issues/{id}/todos.json`) instead of the dedicated `toggle_done` route, which returns 403 for API-key authentication. This fixes todo completion toggling for all API-key based clients.

### v2.0.13 (2025-12-03)

**Bug Fix:**
- **`assigned_to_id: "me"` Support**: Issue create/update now accepts `"me"` as alias for current user (in addition to numeric user IDs). This matches Redmine's native API behavior.

### v2.0.12 (2025-12-02)

**Improvements:**
- **Optional subject in notifications**: Issue notification subject is now optional - handles cases where subject isn't available
- **Auto Time Entry Notifications**: Time entry creation now automatically sends MCP Chat notifications

### v2.0.10 (2025-12-01)

**Improvements:**
- **Auto User ID Detection**: Current user ID is now automatically fetched from the API key - no need to manually configure `REDMINE_MCP_CHAT_USER_ID` in most cases

### v2.1.0 (2025-12-01)

**MCP Chat Enhancements:**
- **Action URLs**: Notifications can now include clickable action buttons
  - `action_type: "issue"` + `issue_id` → Link to ticket
  - `action_type: "project_kanban"` + `project_identifier` → Link to project kanban
  - `action_type: "global_kanban"` → Link to global kanban overview
  - Optional `action_label` for custom button text
- **Auto Chat Notifications**: Issue CREATE/UPDATE automatically send chat notifications with action links
  - New `suppress_chat: "1"` parameter to suppress notifications (for batch operations)
  - New `REDMINE_MCP_CHAT_USER_ID` environment variable for target user
- **Batch Operation Pattern**: Suppress individual notifications, send summary at end

### v2.0.0 (2025-11-28)

🎉 **Major optimization release** - Consolidated tools for faster LLM response:

- **BREAKING**: Tool consolidation reduces 18 tools → 9 tools (50% reduction)
- **Unified `issues` Tool**: Combines `getIssues` + `getIssue` into single tool (use `id` param for single issue)
- **Unified `timeEntries` Tool**: List OR create time entries with `action: "list" | "create"`
- **Unified `relations` Tool**: List OR create issue relations with `action: "list" | "create"`
- **Unified `todos` Tool**: Full todo management with redmine_todos plugin (list, create, toggle, bulk operations)
- **New `mcpChat` Tool**: Bidirectional communication with Redmine chat widget (requires redmine_mcp_chat plugin)
  - Send notifications to users
  - Read pending user messages
  - Mark messages as processed
- **Removed Tools**: `getIssue`, `getIssues`, `getTimeEntries`, `createTimeEntry`, `updateTimeEntry`, `getIssueRelations`, `createIssueRelation`, `getVersionsByProject`, `addWatcher`
- **Feature Flags**: `REDMINE_MCP_DISABLE_TODOS`, `REDMINE_MCP_DISABLE_CHAT`

### v1.2.2
- **Email Notification Suppression**: Added `suppress_mail` parameter for `updateIssue` tool (requires redmine_silencer plugin)
- Silent issue updates without sending notification emails to watchers
- Graceful degradation when plugin is not installed
- **Note**: Issue creation (`createIssue`) does not support email suppression due to plugin limitations

### v1.2.1 (2025-10-30)
- **Watcher Support**: Added `addWatcher` tool to add users as watchers to issues
- **Feature Flag**: New `REDMINE_MCP_DISABLE_WATCHERS` environment variable to disable watcher tools

### v1.2.0 (2025-10-29)
- **Feature Flags**: Granular control over enabled features via environment variables
- **Issue Relations**: Create and manage relationships between issues
- **Time Tracking**: Enhanced time entry tools with activity support
- **Versions Support**: Access project versions and milestones

### v1.1.3
- Added time entry creation and updates
- Enhanced TypeScript configuration

### v1.1.1
- Initial fork and package rename
- Core issue and search functionality

## License

MIT License

## Author

Original: [onozaty](https://github.com/onozaty)

Modified: informatik_tirol

## Acknowledgments

- Original project: [milldea-mitsuya/redmine-mcp-server](https://github.com/milldea-mitsuya/redmine-mcp-server)
- OpenAPI specification: [d-yoshi/redmine-openapi](https://github.com/d-yoshi/redmine-openapi)
- Code generation: [Orval](https://orval.dev/) - TypeScript client and schema generator from OpenAPI
- MCP Protocol: [Model Context Protocol](https://modelcontextprotocol.io/)