guiziweb/mcp-redmine

Multi-provider MCP server for project management and time tracking

Installs: 4

Dependents: 0

Suggesters: 0

Security: 0

Stars: 2

Watchers: 0

Forks: 0

Type:project

pkg:composer/guiziweb/mcp-redmine

v2.1.2 2026-01-05 07:36 UTC

README

Multi-provider MCP server connecting AI assistants (Claude, Cursor) to Redmine, Jira and Monday.

Stack

  • Symfony 7.4 / PHP 8.2+
  • Doctrine ORM (SQLite)
  • MCP SDK (mcp/sdk)
  • OAuth 2.0 + Google Sign-In

Architecture

src/
├── Mcp/                    # MCP Core
│   ├── Application/
│   │   ├── Tool/           # Tools by provider
│   │   │   ├── Redmine/    # 12 tools
│   │   │   ├── Jira/       # 6 tools
│   │   │   └── Monday/     # 5 tools
│   │   └── Resource/       # MCP Resources
│   ├── Domain/
│   │   ├── Model/          # Issue, Project, TimeEntry, etc.
│   │   └── Port/           # Hexagonal interfaces
│   └── Infrastructure/
│       ├── Adapter/        # AdapterFactory, AdapterHolder
│       └── Provider/       # Redmine/, Jira/, Monday/
│
├── OAuth/                  # OAuth 2.0 Server
│   └── Infrastructure/
│       ├── Controller/     # /oauth/authorize, /oauth/token
│       └── Security/       # TokenService, CodeStore
│
└── Admin/                  # Multi-tenant Admin Panel
    └── Infrastructure/
        ├── Doctrine/Entity/  # User, Organization, McpSession, AccessToken, InviteLink
        ├── Controller/       # Dashboard, Users, Sessions, Invites
        ├── Security/Voter/   # Permissions
        └── Service/          # ToolRegistry

MCP Tools

Tool Description Redmine Jira Monday
list_projects List projects x x x
list_issues Assigned issues x x x
get_issue_details Details + comments + attachments x x x
update_issue Update status/assignee/% x
get_attachment Download attachment x x x
list_time_entries Time entries x x x
log_time Log time x x
update_time_entry Update time entry x
delete_time_entry Delete time entry x
add_comment Add comment x
update_comment Update comment x
delete_comment Delete comment x

MCP Resources (Redmine only)

Resource Description Used by
provider://statuses Issue statuses update_issue, list_issues
provider://projects/{id}/activities Activity types log_time
provider://projects/{id}/members Project members update_issue (assignment)
provider://projects/{id}/wiki Wiki pages list -
provider://projects/{id}/wiki/{title} Wiki page content -

Multi-tenancy

Entities

  • Organization: provider type, config, enabledTools
  • User: email, roles, providerCredentials (encrypted), enabledTools
  • McpSession: MCP session with TTL (1h default)
  • AccessToken: OAuth tokens (hashed)
  • InviteLink: Invite links with expiration

Roles

  • ROLE_USER: standard user
  • ROLE_ORG_ADMIN: org admin
  • ROLE_SUPER_ADMIN: access to all orgs

Tool Permissions

// Org allows tool AND (user empty OR user allows)
$user->hasToolEnabled('log_time')

Admin Panel

Route Description
/admin Dashboard (users, active sessions)
/admin/users User management (approve, roles, tools)
/admin/sessions Active MCP sessions
/admin/invites Invite links
/admin/organization Org config

Auth Flow

  1. MCP Client → /oauth/authorize
  2. → Google Sign-In
  3. → Provider selection + credentials
  4. /oauth/token → access_token + refresh_token
  5. MCP Client → /mcp with Bearer token

Configuration

# .env.local
DATABASE_URL="sqlite:///%kernel.project_dir%/var/data.db"
ENCRYPTION_KEY=base64-sodium-key

# Google OAuth
GOOGLE_CLIENT_ID=xxx.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=xxx

# Access control (at least one)
ALLOWED_EMAIL_DOMAINS=company.com
ALLOWED_EMAILS=user@example.com

Commands

make dev              # Install deps
make test             # PHPUnit
make static-analysis  # PHPStan + CS
make cs-fix           # Fix code style
make deploy           # Docker rebuild

# Create bot token
php bin/console app:create-bot \
  --organization=my-org \
  --email=bot@company.com \
  --api-key=xxx

Local Dev

composer install
cp .env.example .env.local
# Configure .env.local

symfony server:start --port=8080

Technical Notes

Session TTL

MCP sessions expire after 1h of inactivity (DoctrineSessionStore::$ttl = 3600).

Mixed Types

Numeric tool params use mixed + manual cast to workaround Cursor validation bug.

#[Schema(description: 'Project ID')]
mixed $project_id = null,
// ...
$project_id = (int) $project_id;

ToolRegistry

Auto-discovery via marker interfaces (RedmineTool, JiraTool, MondayTool).

Encryption

Provider credentials encrypted with libsodium (EncryptionService).