LABSCO SUMMARY
Keeping the token out of the container is the design decision worth copying.
Because the token arrives per request, the running container holds no credentials, and the same instance can serve different users and different OpenProject servers without a redeploy. Version compatibility was handled deliberately rather than generated: the author dropped a generated OpenAPI client because it broke on minor spec differences, and mapped values directly instead, which is why a spread of OpenProject releases works. Pick your transport before you deploy — switching later means restarting with a different protocol setting.
What it is
A Java proxy in front of the OpenProject API, packaged as a Docker container. It lets a model list projects, read work packages and write them back, which is what turns 'add acceptance criteria to every epic in this project' into something a model can carry out rather than describe.
What you get
- Project and work-package access over the OpenProject API — list projects, pull work packages for a project, analyse them, and write changes back
- Bulk editorial work on a whole project, such as translating every epic or adding INVEST criteria, Gherkin acceptance criteria and a definition of done
- Generating new work packages from a description, so a set of epics can be created from a paragraph about the product
- Authentication per request: your OpenProject API token is sent as a bearer header from the client and is not kept in the container
- Multi-server operation — start the container with
OPENPROJECT_ALLOW_HEADER_BASE_URLand the target instance travels in anX-OpenProject-Base-Urlheader, so one container serves several OpenProject servers - Compatibility tested against OpenProject 14, 15, 16.6 and 17.5
Requirements
Docker, and an OpenProject instance the container can reach — OPENPROJECT_URL is set when the container starts and the service listens on port 8080. The client connects over SSE at /sse with the API token as an Authorization: Bearer header. Spring binds one transport at a time, so a server started for SSE exposes GET /sse and POST /mcp/message, while the streamable mode exposes a single /mcp endpoint instead — the two cannot run together.
Setup effort
One command plus a key — docker run -d -p 0.0.0.0:8080:8080 -e OPENPROJECT_URL=https://${yourOpenProjectUrl} --tmpfs /tmp docker.io/tmskln/spring-openproject-mcp-server:latest, then supply credentials
USE CASES
01
Turning a rough brief into a filled-out backlog
Generate epics for a new application and write them into the project as real work packages.
02
Bringing existing tickets up to standard
Add acceptance criteria, a definition of done and risks across every epic in a project in one pass.
03
Reading a project before a planning session
Pull the work packages and get an analysis of where the project actually stands.
04
Serving several OpenProject instances from one container
Enable the header override and let each client name the server it wants to reach.
BEFORE YOU INSTALL
What to know first
Requires
- Docker
- An OpenProject instance and its URL (tested against OpenProject 14, 15, 16.6 and 17.5)
- An OpenProject API token, sent by your client in an Authorization: Bearer header
Where it runs
The documented client runs the server on your machine.
INSTALLATION
Connect your client
Server setup
Launch the Docker container: docker run -d -p 0.0.0.0:8080:8080 -e OPENPROJECT_URL=https://${<YOUR_OPEN_PROJECT_URL>} --tmpfs /tmp docker.io/tmskln/spring-openproject-mcp-server:latest
Run LM Studio and choose an appropriate model for your project domain.
Configure LM Studio's mcp.json below "mcpServers":{...} with the url http://127.0.0.1:8080/sse and the Authorization: Bearer <YOUR_OPEN_PROJECT_API_TOKEN> header
Check that "mcp/openproject-mcp" appears on the right side below Integrations, then start prompting.
MCP Clients
LM Studio
LM STUDIO · JSON
{
"mcpServers": {
"openproject-mcp": {
"url": "http://127.0.0.1:8080/sse",
"headers": {
"Authorization": "Bearer <YOUR_OPEN_PROJECT_API_TOKEN>"
}
}
}
}