Skip to main content
Glama

opendesk-mcp

A Model Context Protocol server for openDesk, the sovereign workplace suite that ZenDiS builds for German public administration on behalf of the Federal Ministry of the Interior.

It gives an MCP-capable assistant read-only access to the files, projects, knowledge pages, calendar, contacts, mail and chat of one openDesk instance.

Why this exists

openDesk publishes no MCP server, and there is no unified openDesk API to write one against. openDesk is a curated bundle of separate open-source products behind a shared Keycloak, and the architecture documentation lists one API per component rather than one for the suite.

That leaves every openDesk deployment, roughly 100,000 administrative workstations at the time of writing, without a way to point an assistant at its own content. This server closes that gap by talking to each bundled product directly.

Module

Product

Protocol

Default host

Files

Nextcloud

WebDAV

files.<domain>

Projects

OpenProject

API v3, HAL+JSON

projects.<domain>

Knowledge

XWiki

REST, media=json

wiki.<domain>

Calendar

Open-Xchange

CalDAV

dav.<domain>

Contacts

Open-Xchange

CardDAV

dav.<domain>

Mail

Dovecot

IMAP

none, see below

Chat

Synapse / Matrix

client-server API

matrix.<domain>

The default hosts are openDesk's own deployment defaults, from helmfile/environments/default/global.yaml.gotmpl, where every service gets its own subdomain. Each one is overridable.

Calendar, contacts and mail are Open-Xchange, not Nextcloud. Nextcloud in openDesk serves files. Pointing a calendar tool at the Nextcloud host would read a different calendar, usually an empty one, and look like a data problem rather than a configuration one.

Related MCP server: AuroraDocs MCP Server

Scope and safety

Every tool in this server is read-only. There is no code path that creates, updates or deletes anything in openDesk, that sends a message or an email, and none that writes to disk or contacts a host other than the configured modules.

Each module authenticates as one account and therefore sees exactly what that account sees. openDesk's own permissions remain the access boundary; this server does not widen them.

Modules are independent. If your XWiki allows single sign-on only and rejects the password, the Knowledge tools are simply not registered and everything else keeps working. The server prints which modules it started with on stderr.

Responses are size-capped before they reach the assistant. A response body is read up to a limit and then aborted, long text is truncated with an explicit [truncated] marker, and a file above the read limit returns metadata with a note instead of its contents.

Known limitations of openDesk itself

Two of these modules depend on things that are not this server's to fix. Read this before filing a bug.

Calendar and contacts may fail on your deployment. openDesk issue #155, "openxchange CalDav & CardDav do not work", has been open since February 2025, is assigned upstream to Open-Xchange and sits in the backlog. It reports a broken ingress rewrite plus an unresolved "No session created" authentication failure on /servlet/dav. On an affected deployment these two modules cannot authenticate no matter which credentials you supply. The error message from this server says so rather than leaving you to suspect your password.

Check before configuring them:

curl -u 'username:password' 'https://dav.example.org/servlet/dav/'

Mail needs IMAP to be exposed at all. IMAP is not HTTP, so it cannot travel through the cluster's HTTP ingress that serves every other module. Whether Dovecot is reachable from outside is a decision your operator makes, which is why OPENDESK_MAIL_HOST has no default and must be set by hand.

Requirements

  • Node.js 20 or newer

  • An openDesk instance reachable from the machine running the server

  • Credentials for at least one module

Obtaining the credentials

Files, a Nextcloud app password

  1. Open the Files app in openDesk.

  2. Go to Settings, then Security.

  3. Under "Devices & sessions", enter a name and choose "Create new app password".

  4. Copy the generated password. It is shown once.

Projects, an OpenProject API key

  1. Open the Projects app in openDesk.

  2. Open your avatar menu and choose "My account".

  3. Go to "Access tokens".

  4. Under "API", choose "Generate" and copy the key.

Knowledge, calendar, contacts and mail: the account password

XWiki, the Open-Xchange DAV endpoints and IMAP have no app-password concept of their own, so these modules use the account's credentials. Whether that works depends on how your deployment configured single sign-on. Test each one with curl (see above) before wiring it up.

Chat, a Matrix access token

  1. Open the Chat app (Element) in openDesk.

  2. Go to Settings, then Help & About.

  3. Expand "Advanced" and copy the access token.

A Matrix access token is as powerful as the account. Treat it like a password.

Installation

git clone https://github.com/Nraitschew/opendesk-mcp.git
cd opendesk-mcp
npm install
npm run build

The build writes an executable entry point to dist/index.js.

Configuration

The server is configured through environment variables. Only OPENDESK_DOMAIN and the credentials of the modules you want are required.

Domain

Variable

Required

Meaning

OPENDESK_DOMAIN

yes

The domain of your openDesk instance, for example example.org. A pasted URL and a leading portal. are stripped.

Every module URL is derived from it, and every one can be overridden.

Files, Nextcloud

Variable

Required

Default

OPENDESK_FILES_USERNAME

for this module

OPENDESK_FILES_APP_PASSWORD

for this module

OPENDESK_FILES_URL

no

https://files.<domain>

Projects, OpenProject

Variable

Required

Default

OPENDESK_PROJECTS_API_KEY

for this module

OPENDESK_PROJECTS_URL

no

https://projects.<domain>

Knowledge, XWiki

Variable

Required

Default

OPENDESK_WIKI_USERNAME

for this module

OPENDESK_WIKI_PASSWORD

for this module

OPENDESK_WIKI_URL

no

https://wiki.<domain>

OPENDESK_WIKI_NAME

no

xwiki, the main wiki. Only relevant on a multi-wiki farm.

Calendar and contacts, Open-Xchange

One credential enables both, because in openDesk they are the same product on the same host.

Variable

Required

Default

OPENDESK_DAV_USERNAME

for these modules

OPENDESK_DAV_PASSWORD

for these modules

OPENDESK_DAV_URL

no

https://dav.<domain>

Mail, IMAP

Variable

Required

Default

OPENDESK_MAIL_HOST

for this module

none, deliberately

OPENDESK_MAIL_USERNAME

for this module

OPENDESK_MAIL_PASSWORD

for this module

OPENDESK_MAIL_PORT

no

993

OPENDESK_MAIL_TLS

no

true, implicit TLS. Set to false for STARTTLS on port 143.

Chat, Matrix

Variable

Required

Default

OPENDESK_CHAT_TOKEN

for this module

OPENDESK_CHAT_URL

no

https://matrix.<domain>, the Synapse homeserver. Not chat.<domain>, which serves the Element web client.

Limits

Variable

Default

Meaning

OPENDESK_TIMEOUT_MS

15000

Per-request timeout in milliseconds.

OPENDESK_MAX_RESPONSE_BYTES

4194304

Hard cap on a single response body.

OPENDESK_MAX_TEXT_CHARS

50000

Cap on text handed to the assistant.

OPENDESK_MAX_DOWNLOAD_BYTES

2097152

Cap on bytes downloaded for one file read.

Half a credential is an error rather than a silently disabled module: setting OPENDESK_FILES_USERNAME without OPENDESK_FILES_APP_PASSWORD makes the server exit with a message naming the missing variable.

Connecting a client

Claude Desktop

Edit the MCP configuration file:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json

  • Windows: %APPDATA%\Claude\claude_desktop_config.json

{
  "mcpServers": {
    "opendesk": {
      "command": "node",
      "args": ["/absolute/path/to/opendesk-mcp/dist/index.js"],
      "env": {
        "OPENDESK_DOMAIN": "example.org",
        "OPENDESK_FILES_USERNAME": "first.last",
        "OPENDESK_FILES_APP_PASSWORD": "your-app-password",
        "OPENDESK_PROJECTS_API_KEY": "your-api-key",
        "OPENDESK_WIKI_USERNAME": "first.last",
        "OPENDESK_WIKI_PASSWORD": "your-password",
        "OPENDESK_DAV_USERNAME": "first.last",
        "OPENDESK_DAV_PASSWORD": "your-password",
        "OPENDESK_MAIL_HOST": "mail.example.org",
        "OPENDESK_MAIL_USERNAME": "first.last",
        "OPENDESK_MAIL_PASSWORD": "your-password",
        "OPENDESK_CHAT_TOKEN": "your-matrix-token"
      }
    }
  }
}

Restart Claude Desktop afterwards. Leave out the variables of any module you do not want.

Claude Code

claude mcp add opendesk \
  --env OPENDESK_DOMAIN=example.org \
  --env OPENDESK_PROJECTS_API_KEY=your-api-key \
  -- node /absolute/path/to/opendesk-mcp/dist/index.js

Any other MCP client

The server speaks MCP over stdio. Start it with node dist/index.js and the environment set; any client that can spawn a stdio server will work.

Tools

Only the tools of the configured modules are registered.

Files

Tool

Purpose

files_search

Search the drive by file and folder name. Matches names, not contents.

files_list

List the immediate contents of one folder.

files_read

Read one file. Text is returned inline; other types return metadata with a note.

Projects

Tool

Purpose

projects_whoami

Identify the OpenProject account, for questions that say "my" or "me".

projects_list

List visible projects, optionally filtered by name.

projects_search_work_packages

Full-text search over work packages, optionally scoped to a project or the current user.

projects_get_work_package

One work package in full, including its description.

projects_get_work_package_comments

The comments on a work package.

Knowledge

Tool

Purpose

wiki_search

Full-text search across page names, titles and content.

wiki_read_page

One page's content, with its version and syntax.

wiki_list_spaces

The spaces of the wiki.

wiki_list_pages

The pages directly inside one space.

Calendar

Tool

Purpose

calendar_list_calendars

The calendars this account can see.

calendar_list_events

Appointments across all calendars in a date range, default the next 30 days.

Contacts

Tool

Purpose

contacts_search

Search address books by name, email, phone, job title or organisation.

Mail

Tool

Purpose

mail_list_mailboxes

The folders of the mailbox, with the paths to search in.

mail_search

Search one mailbox by sender, subject, body text, date or unread state.

mail_read

One message in full, with its body text and attachment list.

Chat

Tool

Purpose

chat_whoami

Identify the Matrix account, to tell own messages from others'.

chat_list_rooms

The rooms this account has joined.

chat_read_room

The most recent messages of one room.

chat_search

Full-text search across the rooms this account can see.

Tool results are JSON. OpenProject's HAL envelopes are flattened, so a work package carries status, assignee and project as plain names.

Notes on the data

Recurring appointments are not expanded. A CalDAV time-range query returns the recurring master object, and this server reports the appointment as it is stored, with a recurring flag, rather than computing occurrences. Expanding recurrence correctly is a calendar engine's worth of edge cases.

Times without a zone stay without one. An iCalendar value qualified with a TZID is returned as a local wall-clock time rather than being converted, since resolving the zone needs the VTIMEZONE component. Treating such a value as UTC would shift half the appointments in the country by an hour.

Mail UIDs are per mailbox. A uid from mail_search is only valid in the mailbox it came from, and it changes when a message moves. Pass the mailbox along with the uid to mail_read.

Wiki page references

XWiki addresses a page as Space.PageName, and a nested space as A.B.PageName. Two details are easy to get wrong, and this server handles both:

  • A literal dot inside a name is escaped as \.. Splitting on every dot would break exactly the pages whose names contain one, such as release notes or dates.

  • A reference may be fully qualified as wiki:Space.Page. The wiki part is a separate REST path segment, not a dot-separated one.

A bare page name with no space is rejected rather than guessed at. Always pass a reference that wiki_search or wiki_list_pages returned.

Errors

A failing tool call returns a result marked as an error whose text starts with a stable machine code and names the module, so a rejected OpenProject key does not read as a broken Nextcloud:

Code

Meaning

unauthorized

The module's credentials were rejected, or the instance requires single sign-on.

forbidden

Authenticated, but not permitted to read that resource.

not_found

No such file, work package, page or message.

rate_limited

The module is rate limiting this client.

unreachable

The module did not answer, or the request timed out.

invalid_reference

A wiki page reference names no space.

invalid_response

The response was not the expected document. Usually a wrong module URL.

too_large

The response exceeded the configured byte limit.

http_error

Any other non-success status, with the status code in the message.

Testing against your instance

npx @modelcontextprotocol/inspector node dist/index.js

The MCP Inspector lists the tools and lets you call them by hand, which is the fastest way to confirm the domain and credentials are right. The server also prints the configured modules to stderr on startup.

Development

npm install
npm run typecheck
npm test
npm run build

The unit tests cover configuration and URL derivation, the WebDAV multistatus parser and search-body escaping, the OpenProject filter grammar, the XWiki reference grammar, the iCalendar and vCard parsers, and the IMAP search criteria. They make no network requests, so they run anywhere.

Limitations

  • Read-only by design.

  • Video conferencing (Jitsi, NeoDateFix), collaborative documents (Collabora), CryptPad, Notes and the Nubus portal are not covered.

  • File contents are read for text files only. Office documents and PDFs return metadata.

  • Attachments are listed but never downloaded, in files, wiki pages and mail alike.

  • Searches page once with the requested limit rather than paging through a large result set.

  • Every tool call opens its own IMAP connection. That costs a connection setup per call, and buys not having to keep a session alive between questions.

If you run only one of the bundled products rather than a whole openDesk instance, the standalone servers are a better fit:

For Nextcloud on its own, the community already has several servers, including cbcoutinho/nextcloud-mcp-server.

Contributing

Issues and pull requests are welcome, particularly:

  • Reports from real openDesk deployments about which modules accept password authentication, and whether CalDAV and CardDAV work on yours.

  • Corrections to the API assumptions documented in the source comments.

License

Apache License 2.0. See LICENSE.

This project is independent. It is not affiliated with or endorsed by ZenDiS GmbH, the German Federal Ministry of the Interior, Nextcloud GmbH, OpenProject GmbH, Open-Xchange, XWiki SAS or Element. "openDesk", "Nextcloud", "OpenProject", "Open-Xchange", "XWiki", "Element" and "Matrix" are trademarks of their respective owners and are used here only to describe what this software connects to.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables MCP-compatible AI assistants to securely access a user's job-search account, letting them search and save jobs, analyze job fit, and retrieve job queue and profile summaries with links back to the web app.
    MIT

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Nraitschew/opendesk-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server