diff --git a/TracToGitlabPlugin.php b/TracToGitlabPlugin.php
index 7ed3947e282443475f0a14c8db26277bc7d5b8ee..01466eca3f3a3d2908abb99b4399998496860a96 100644
--- a/TracToGitlabPlugin.php
+++ b/TracToGitlabPlugin.php
@@ -123,6 +123,10 @@ final class TracToGitlabPlugin extends StudIPPlugin implements StandardPlugin, S
             'merge',
             new Navigation(_('Zu portierende Bugfixes'), PluginEngine::getURL($this, [], 'merge'))
         );
+        $navigation->addSubNavigation(
+            'merge-requests',
+            new Navigation(_('Merge Requests'), PluginEngine::getURL($this, [], 'mergerequests'))
+        );
 
         Navigation::addItem('/gitlab-dashboard', $navigation);
     }
diff --git a/controllers/mergerequests.php b/controllers/mergerequests.php
new file mode 100644
index 0000000000000000000000000000000000000000..16ab1825d1189c87d349c93df663142bd020597a
--- /dev/null
+++ b/controllers/mergerequests.php
@@ -0,0 +1,112 @@
+<?php
+final class MergerequestsController extends TracToGitlab\GitlabController
+{
+    public function before_filter(&$action, &$args)
+    {
+        parent::before_filter($action, $args);
+
+        PageLayout::setTitle(_('Merge Requests'));
+        $this->activateNavigation('merge-requests');
+    }
+
+    public function index_action()
+    {
+        $data = $this->readFromCache('merge-requests', true);
+        if ($data === false) {
+            $this->mrs = $this->fetchMergeRequests();
+            $this->writeToCache('merge-requests', $this->issues);
+        } else {
+            $this->mrs = $data['data'];
+
+            Sidebar::get()->addWidget(new TemplateWidget(
+                'Aus dem Cache',
+                $this->get_template_factory()->open(
+                    $this->get_default_template('sidebar')
+                ),
+                ['time' => $data['time']]
+            ));
+        }
+    }
+
+    public function diff_action($mr_iid)
+    {
+//        $versions = $this->gitlab->mergeRequests()->
+    }
+
+    private function fetchMergeRequests(): array
+    {
+        $mrs = $this->gitlabPager->fetchAll(
+            $this->gitlab->mergeRequests(),
+            'all',
+            [
+                $this->gitlabProjectId,
+                [
+                    'sort'  => 'asc',
+                    'scope' => 'all',
+                    'state' => 'opened',
+                ]
+            ]
+        );
+
+        $mrs = array_filter($mrs, function ($mr) {
+            if ($mr['draft'] || $mr['work_in_progress'] || $mr['merge_when_pipeline_succeeds']) {
+                return false;
+            }
+
+            return true;
+
+//            foreach (['worksforme', 'wontfix', 'Duplicate', 'invalid'] as $label) {
+//                if (in_array($label, $issue['labels'])) {
+//                    return false;
+//                }
+//            }
+//
+//            $has_version = array_reduce($issue['labels'], function ($has_version, $label) {
+//                return $has_version || strpos($label, 'Version::') === 0;
+//            }, false);
+//            return $has_version;
+        });
+
+//        var_dump($mrs);die;
+//
+//        $issues = array_map(function ($issue) {
+//            $issue['studip_version'] = $this->extractVersion($issue['labels']);
+//            $issue['mr'] = $this->fetchRelatedMergeRequest($issue['iid']);
+//            return $issue;
+//        }, $issues);
+//
+        usort($mrs, function ($a, $b) {
+            return strcmp($b['updated_at'], $a['updated_at']);
+        });
+
+        return $mrs;
+    }
+
+    private function fetchRelatedMergeRequest(int $issue_id)
+    {
+        $mrs = $this->gitlab->issues()->closedByMergeRequests(
+            $this->gitlabProjectId,
+            $issue_id
+        );
+        foreach ($mrs as $mr) {
+            if ($mr['state'] === 'merged') {
+                return $mr['iid'];
+            }
+        }
+        return null;
+    }
+
+    private function extractVersion(array $labels): string
+    {
+        $version = '';
+        foreach ($labels as $label) {
+            if (strpos($label, 'Version::') === 0) {
+                $v = substr($label, 9);
+                if (!$version || $v < $version) {
+                    $version = $v;
+                }
+            }
+        }
+        return $version;
+    }
+}
diff --git a/views/mergerequests/index.php b/views/mergerequests/index.php
new file mode 100644
index 0000000000000000000000000000000000000000..b845b08769a0fcb1ac26128c666ce757ac893959
--- /dev/null
+++ b/views/mergerequests/index.php
@@ -0,0 +1,59 @@
+<?php
+/**
+ * @var array<int, array> $mrs
+ */
+?>
+<table class="default">
+    <thead>
+        <tr>
+            <th><?= _('Merge Request') ?></th>
+            <th><?= _('Status') ?></th>
+            <th><?= _('Konflikte') ?></th>
+            <th><?= _('Von') ?></th>
+            <th><?= _('Bearbeitung') ?></th>
+            <th><?= _('Review') ?></th>
+            <th><?= _('Erstellt') ?></th>
+            <th><?= _('Letzte Änderung') ?></th>
+        </tr>
+    </thead>
+    <tbody>
+    <? if (!$mrs): ?>
+        <tr>
+            <td colspan="7" style="text-align: center">
+                <?= _('Keine offenen Merge Request vorhanden 🥳🍺') ?>
+            </td>
+        </tr>
+    <? endif; ?>
+    <? foreach ($mrs as $mr): ?>
+        <tr>
+            <td>
+                <a href="<?= htmlReady($mr['web_url']) ?>" target="_blank">
+                    #<?= htmlReady($mr['iid']) ?>:
+                    <?= htmlReady($mr['title']) ?>
+            </td>
+            <td>
+            <? if ($mr['task_completion_status']['count'] === $mr['task_completion_status']['completed_count']): ?>
+                <?= Icon::create('accept', Icon::ROLE_STATUS_GREEN)->asImg(['alt' => 'ok']) ?>
+            <? else: ?>
+                <?= Icon::create('decline', Icon::ROLE_STATUS_RED)->asImg(['alt' => 'nicht ok']) ?>
+            <? endif; ?>
+            <? if ($mr['task_completion_status']['count'] > 0): ?>
+                <?= $mr['task_completion_status']['completed_count'] ?> / <?= $mr['task_completion_status']['count'] ?>
+            <? endif; ?>
+            </td>
+            <td>
+            <? if ($mr['has_conflicts']): ?>
+                <?= Icon::create('exclaim', Icon::ROLE_STATUS_RED)->asImg(['alt' => 'Ja']) ?>
+            <? else: ?>
+                <?= Icon::create('accept', Icon::ROLE_STATUS_GREEN)->asImg(['alt' => 'Nein']) ?>
+            <? endif; ?>
+            </td>
+            <td><?= htmlReady($mr['author']['username']) ?></td>
+            <td><?= $mr['assignee'] ? htmlReady($mr['assignee']['username']) : '&ndash;' ?></td>
+            <td><?= htmlReady(implode(',', array_column($mr['reviewers'], 'username'))) ?: '&ndash;' ?></td>
+            <td><?= strftime('%x %X', strtotime($mr['created_at'])) ?></td>
+            <td><?= strftime('%x %X', strtotime($mr['updated_at'])) ?></td>
+        </tr>
+    <? endforeach; ?>
+    </tbody>
+</table>
diff --git a/views/mergerequests/sidebar.php b/views/mergerequests/sidebar.php
new file mode 100644
index 0000000000000000000000000000000000000000..d8de1a3a16f952649f3a1edc52f86726ff438cb6
--- /dev/null
+++ b/views/mergerequests/sidebar.php
@@ -0,0 +1 @@
+Zeitpunkt: <?= date('d.m.Y H:i:s', $time) ?>