v1.0.0
What's New in v1.0.0
Added
- New MCP Tool:
list_project_members- List members and groups of a Redmine project- Returns user/group info along with assigned roles
- Supports both numeric project IDs and string identifiers
- New MCP Tools: Time Tracking - Full time entry management
list_time_entries- List time entries with filtering by project, issue, user, and date rangecreate_time_entry- Log time against projects or issues with activity and date supportupdate_time_entry- Modify existing time entries (hours, comments, activity, date)list_time_entry_activities- Discover available activity types (Development, Design, etc.) for time entry creation- All tools support pagination and use
_get_redmine_client()for OAuth compatibility
- 50 new unit tests for project members and time tracking tools (
test_project_members.py,test_time_entries.py) - 26 new integration tests covering all 21 MCP tools with zero skips — includes project members (4), time entries (7), custom fields (3), search issues (3), summarize project (3), global search (4), and cleanup (2)
- OAuth2 per-user authentication mode (
REDMINE_AUTH_MODE=oauth)- New
oauth_middleware.py: Starlette middleware that validatesAuthorization: Bearer <token>headers against Redmine's/users/current.jsonbefore forwarding MCP requests - Per-request token isolation via
contextvars.ContextVar— safe under async concurrent load GET /.well-known/oauth-protected-resourceendpoint (RFC 8707) — points MCP clients to the authorization serverGET /.well-known/oauth-authorization-serverendpoint (RFC 8414) — advertises Redmine's Doorkeeper OAuth endpoints (/oauth/authorize,/oauth/token,/oauth/revoke) since Redmine does not serve this document itselfPOST /revokeendpoint (RFC 7009) — proxies token revocation to Redmine's/oauth/revoke, enabling proper disconnect flow from MCP clients- PKCE (
S256) and bothclient_secret_post/client_secret_basictoken endpoint auth methods advertised - Requires Redmine 6.1+ (Doorkeeper OAuth2 support)
- New
REDMINE_AUTH_MODEenvironment variable — selectslegacy(default) oroauthmode; legacy mode is unchanged so existing deployments require no changesREDMINE_MCP_BASE_URLenvironment variable — public base URL of this server, used in OAuth discovery documents (only required in oauth mode)_get_redmine_client()factory function inredmine_handler.py— creates a per-request Redmine client using OAuth token → API key → username/password priority; replaces the module-level shared client- 33 new unit tests for OAuth middleware, discovery endpoints, token revocation, and auth selection logic (
tests/test_oauth_middleware.py) - Prompt Injection Protection - User-controlled content from Redmine is now wrapped in unique boundary tags to prevent prompt injection attacks against LLM consumers
- New
wrap_insecure_content()function wraps non-empty strings in<insecure-content-{boundary}>tags with a random 16-character hex boundary per call - Applied to 6 helper functions:
_issue_to_dict(description),_issue_to_dict_selective(description),_journals_to_list(notes),_resource_to_dict(excerpt),_wiki_page_to_dict(text),_version_to_dict(description) - 22 new tests in
test_prompt_injection.py
- New
- Read-Only Mode - Block all write operations via
REDMINE_MCP_READ_ONLY=trueenvironment variable- Guards 5 write tools:
create_redmine_issue,update_redmine_issue,create_redmine_wiki_page,update_redmine_wiki_page,delete_redmine_wiki_page - Read tools (
get_redmine_issue,list_redmine_projects,list_redmine_issues, etc.) remain fully functional - Local operations (
cleanup_attachment_files) are not restricted - 15 new tests in
test_read_only_mode.py - Updated
.env.exampleand.env.dockerwithREDMINE_MCP_READ_ONLYvariable
- Guards 5 write tools:
- Journal Pagination on
get_redmine_issue- Newjournal_limitandjournal_offsetparameters for paginating through issue journals- When
journal_limitis set, response includesjournal_paginationmetadata (total,offset,limit,count,has_more) - Default behavior unchanged (returns all journals without pagination metadata)
- 9 new tests covering limit, offset, combined pagination, edge cases, and backward compatibility
- When
- Include Flags on
get_redmine_issue- Three new boolean parameters for fetching additional issue datainclude_watchers(default:false) - Returns watcher list withidandnameinclude_relations(default:false) - Returns issue relations withid,issue_id,issue_to_id,relation_typeinclude_children(default:false) - Returns child issues withid,subject,tracker- All flags default to
falsefor backward compatibility - Include parameters are passed to the Redmine API for server-side inclusion
- 11 new tests covering all flags, combinations, missing attributes, and structure validation
Breaking
- Removed
list_my_redmine_issues- Deprecated since v0.11.0. Uselist_redmine_issues(assigned_to_id='me')instead.- All references in docstrings updated to point to
list_redmine_issues()
- All references in docstrings updated to point to
Fixed
- Custom routes (well-known endpoints) not served at runtime —
mcp.run()created a fresh internal app discarding route registrations; switched touvicorn.run(app, ...)so the decorated app instance is always what serves requests REDMINE_URLKeyError at import time —oauth_middleware.pynow usesos.environ.get()instead ofos.environ[], so the server starts cleanly even ifREDMINE_URLis not set before import- Legacy client recreated on every tool call —
_get_redmine_client()now caches a singleton_legacy_clientin legacy mode instead of building a newRedmine()instance per request - OAuth routes exposed in legacy mode — well-known endpoints and
/revokeare now only registered whenREDMINE_AUTH_MODE=oauth
Changed
main()now runs viauvicorn.run(app, ...)directly instead ofmcp.run(transport="streamable-http")to ensure custom route registrations are preserved
Improved
- Code Quality - Added
.flake8config for Black compatibility (E203 ignore)
Acknowledgements
Thanks to @mihajlovicjj for contributing:
- OAuth2 per-user authentication,
/revokeendpoint, discovery endpoints, and 33 new tests (#71) - Project members and time tracking tools with 50 new tests (#72)
Installation
pip install redmine-mcp-server==1.0.0