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
Requires
- php: >=8.2
- ext-ctype: *
- ext-sodium: *
- doctrine/dbal: ^3
- doctrine/doctrine-bundle: ^2.18
- doctrine/doctrine-migrations-bundle: ^3.7
- doctrine/orm: ^3.6
- kbsali/redmine-api: ^2.8
- knplabs/knp-paginator-bundle: ^6.10
- laminas/laminas-httphandlerrunner: ^2.13
- league/oauth2-google: ^4.1
- mcp/sdk: ^0.1.0
- nyholm/psr7: ^1.8.2
- nyholm/psr7-server: ^1.1
- sentry/sentry-symfony: ^5.8
- symfony/asset: 7.4.*
- symfony/asset-mapper: 7.4.*
- symfony/clock: 7.4.*
- symfony/console: 7.4.*
- symfony/dotenv: 7.4.*
- symfony/expression-language: 7.4.*
- symfony/flex: ^2.10
- symfony/form: 7.4.*
- symfony/framework-bundle: 7.4.*
- symfony/http-client: 7.4.*
- symfony/monolog-bundle: ^3.11.1
- symfony/psr-http-message-bridge: 7.4.*
- symfony/runtime: 7.4.*
- symfony/security-bundle: 7.4.*
- symfony/serializer: 7.4.*
- symfony/translation: 7.4.*
- symfony/twig-bundle: 7.4.*
- symfony/ux-live-component: ^2.31
- symfony/validator: 7.4.*
- symfony/yaml: 7.4.*
Requires (Dev)
- doctrine/doctrine-fixtures-bundle: ^4.3
- friendsofphp/php-cs-fixer: ^3.92.3
- phpstan/phpstan: ^2.1.33
- phpunit/phpunit: ^10.5.60
- symfony/browser-kit: 7.4.*
- symfony/css-selector: 7.4.*
- symfony/web-profiler-bundle: 7.4.*
Conflicts
README
MCP server connecting AI assistants (Claude, Cursor) to Redmine.
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/Redmine/ # 12 tools
│ │ └── Resource/ # MCP Resources
│ ├── Domain/
│ │ ├── Model/ # Issue, Project, TimeEntry, etc.
│ │ └── Port/ # Hexagonal interfaces
│ └── Infrastructure/
│ ├── Adapter/ # AdapterFactory, AdapterHolder
│ └── Provider/Redmine/
│
├── 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 |
|---|---|
list_projects |
List projects |
list_issues |
Assigned issues |
get_issue_details |
Details + comments + attachments |
update_issue |
Update status/assignee/% |
get_attachment |
Download attachment |
list_time_entries |
Time entries |
log_time |
Log time |
update_time_entry |
Update time entry |
delete_time_entry |
Delete time entry |
add_comment |
Add comment |
update_comment |
Update comment |
delete_comment |
Delete comment |
MCP Resources
| 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: Redmine URL, 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 userROLE_ORG_ADMIN: org adminROLE_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
- MCP Client →
/oauth/authorize - → Google Sign-In
- → Redmine API key
- →
/oauth/token→ access_token + refresh_token - MCP Client →
/mcpwith Bearer token
Configuration
# .env.local DATABASE_URL="sqlite:///%kernel.project_dir%/var/db/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
# 1. Copy and configure env cp .env.example .env.local # Fill in GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, ENCRYPTION_KEY, etc. # 2. Start with Docker (port 8090) make dev
- Admin panel: http://127.0.0.1:8090/admin
- MCP endpoint: http://127.0.0.1:8090/mcp
Important: use the same host as the OAuth redirect URI configured in Google Cloud Console (e.g. 127.0.0.1), otherwise session cookies won't persist across the OAuth callback.
Testing with Claude Code
Add to ~/.claude/mcp_settings.json:
{
"mcpServers": {
"redmine-local": {
"type": "http",
"url": "http://127.0.0.1:8090/mcp"
}
}
}
On first tool call, Claude Code will open the OAuth flow to authenticate.
Database (SQLite)
# List tables docker exec mcp-project-management php bin/console doctrine:query:sql "SELECT name FROM sqlite_master WHERE type='table'" # List users docker exec mcp-project-management php bin/console doctrine:query:sql "SELECT id, email, roles FROM app_user" # List organizations docker exec mcp-project-management php bin/console doctrine:query:sql "SELECT * FROM organization" # Active MCP sessions docker exec mcp-project-management php bin/console doctrine:query:sql "SELECT * FROM mcp_session"
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 interface (RedmineTool).
Encryption
Provider credentials encrypted with libsodium (EncryptionService).