diff --git a/ee/changelogs/unreleased/jira-dvcs-merge-requests.yml b/ee/changelogs/unreleased/jira-dvcs-merge-requests.yml
new file mode 100644
index 0000000000000000000000000000000000000000..a403b49d2114b54495a33d1dcbd1e1429192cd11
--- /dev/null
+++ b/ee/changelogs/unreleased/jira-dvcs-merge-requests.yml
@@ -0,0 +1,5 @@
+---
+title: Fix merge requests being added to Jira Development Panel
+merge_request: 10342
+author:
+type: fixed
diff --git a/ee/lib/api/github/entities.rb b/ee/lib/api/github/entities.rb
index 58966273cea6240b28c2060a091f7ed3cca8fe51..58ccc0265fc2532a1ac8137da513981c0ec3c622 100644
--- a/ee/lib/api/github/entities.rb
+++ b/ee/lib/api/github/entities.rb
@@ -170,6 +170,38 @@ class PullRequest < Grape::Entity
           expose :target_project, as: :repo, using: Repository
         end
       end
+
+      class PullRequestPayload < Grape::Entity
+        expose :action do |merge_request|
+          case merge_request.state
+          when 'merged', 'closed'
+            'closed'
+          else
+            'opened'
+          end
+        end
+
+        expose :id
+        expose :pull_request, using: PullRequest do |merge_request|
+          merge_request
+        end
+      end
+
+      class PullRequestEvent < Grape::Entity
+        expose :id do |merge_request|
+          updated_at = merge_request.updated_at.to_i
+          "#{merge_request.id}-#{updated_at}"
+        end
+        expose :type do |_merge_request|
+          'PullRequestEvent'
+        end
+        expose :updated_at, as: :created_at
+        expose :payload, using: PullRequestPayload do |merge_request|
+          # The merge request data is used by PullRequestPayload and PullRequest, so we just provide it
+          # here. Otherwise Grape::Entity would try to access a field "payload" on Merge Request.
+          merge_request
+        end
+      end
     end
   end
 end
diff --git a/ee/lib/api/v3/github.rb b/ee/lib/api/v3/github.rb
index 3975c96ae5944d49ce323cd437fbd41bb1319e9f..a69aae7b3b934c525360489ee6beebcaeaa03b72 100644
--- a/ee/lib/api/v3/github.rb
+++ b/ee/lib/api/v3/github.rb
@@ -131,6 +131,10 @@ def licensed_project?(project)
           present find_merge_requests, with: ::API::Github::Entities::PullRequest
         end
 
+        get '/-/jira/events' do
+          present []
+        end
+
         params do
           use :project_full_path
         end
@@ -142,6 +146,15 @@ def licensed_project?(project)
           present paginate(merge_requests), with: ::API::Github::Entities::PullRequest
         end
 
+        params do
+          use :project_full_path
+        end
+        get ':namespace/:project/pulls/:id', requirements: PROJECT_ENDPOINT_REQUIREMENTS do
+          mr = find_merge_request_with_access(params[:id])
+
+          present mr, with: ::API::Github::Entities::PullRequest
+        end
+
         # In Github, each Merge Request is automatically also an issue.
         # Therefore we return its comments here.
         # It'll present _just_ the comments counting with a link to GitLab on
@@ -166,10 +179,12 @@ def licensed_project?(project)
 
         # Self-hosted Jira (tested on 7.11.1) requests this endpoint right
         # after fetching branches.
-        # We need to respond with a 200 request to avoid breaking the
-        # integration flow (fetching merge requests).
         get ':namespace/:project/events' do
-          present []
+          user_project = find_project_with_access(params)
+
+          merge_requests = MergeRequestsFinder.new(current_user, authorized_only: true, project_id: user_project.id).execute
+
+          present paginate(merge_requests), with: ::API::Github::Entities::PullRequestEvent
         end
 
         params do
diff --git a/ee/spec/fixtures/api/schemas/entities/github/pull_request.json b/ee/spec/fixtures/api/schemas/entities/github/pull_request.json
new file mode 100644
index 0000000000000000000000000000000000000000..dfcddd2eeccca066de8e07fe786f1510bc77cee9
--- /dev/null
+++ b/ee/spec/fixtures/api/schemas/entities/github/pull_request.json
@@ -0,0 +1,142 @@
+{
+  "type": "object",
+  "properties": {
+    "title": {
+      "type": "string"
+    },
+    "created_at": {
+      "type": "string"
+    },
+    "body": {
+      "type": [
+        "string",
+        "null"
+      ]
+    },
+    "id": {
+      "type": "integer"
+    },
+    "number": {
+      "type": "integer"
+    },
+    "state": {
+      "type": "string"
+    },
+    "html_url": {
+      "type": "string"
+    },
+    "merged": {
+      "type": "boolean"
+    },
+    "merged_at": {
+      "type": [
+        "date",
+        "null"
+      ]
+    },
+    "closed_at": {
+      "type": [
+        "date",
+        "null"
+      ]
+    },
+    "updated_at": {
+      "type": "date"
+    },
+    "assignee": {
+      "type": "object",
+      "required": [
+        "id",
+        "login",
+        "url"
+      ],
+      "properties": {
+        "id": {
+          "type": "integer"
+        },
+        "login": {
+          "type": "string"
+        },
+        "url": {
+          "type": "string"
+        }
+      },
+      "additionalProperties": false
+    },
+    "author": {
+      "type": "object",
+      "required": [
+        "id",
+        "login",
+        "url"
+      ],
+      "properties": {
+        "id": {
+          "type": "integer"
+        },
+        "login": {
+          "type": "string"
+        },
+        "url": {
+          "type": "string"
+        }
+      },
+      "additionalProperties": false
+    },
+    "head": {
+      "type": "object",
+      "required": [
+        "label",
+        "ref",
+        "repo"
+      ],
+      "properties": {
+        "label": {
+          "type": "string"
+        },
+        "ref": {
+          "type": "string"
+        },
+        "repo": {
+          "oneOf": [
+            {
+              "type": "null"
+            },
+            {
+              "$ref": "repository.json"
+            }
+          ]
+        }
+      },
+      "additionalProperties": false
+    },
+    "base": {
+      "type": "object",
+      "required": [
+        "label",
+        "ref",
+        "repo"
+      ],
+      "properties": {
+        "label": {
+          "type": "string"
+        },
+        "ref": {
+          "type": "string"
+        },
+        "repo": {
+          "oneOf": [
+            {
+              "type": "null"
+            },
+            {
+              "$ref": "repository.json"
+            }
+          ]
+        }
+      },
+      "additionalProperties": false
+    },
+    "additionalProperties": false
+  }
+}
\ No newline at end of file
diff --git a/ee/spec/requests/api/v3/github_spec.rb b/ee/spec/requests/api/v3/github_spec.rb
index 1fc0f0560447a261eff042677b6cee7bda5fa5f7..403c2748c8ae750ef25369eb21523b23dca71c74 100644
--- a/ee/spec/requests/api/v3/github_spec.rb
+++ b/ee/spec/requests/api/v3/github_spec.rb
@@ -39,15 +39,6 @@
   end
 
   shared_examples_for 'Jira-specific mimicked GitHub endpoints' do
-    describe 'GET /repos/.../events' do
-      it 'returns an empty array' do
-        jira_get v3_api("/repos/#{path}/events", user)
-
-        expect(response).to have_gitlab_http_status(200)
-        expect(json_response).to eq([])
-      end
-    end
-
     describe 'GET /.../issues/:id/comments' do
       context 'when user has access to the merge request' do
         let(:merge_request) do
@@ -116,12 +107,70 @@
     it_behaves_like 'Jira-specific mimicked GitHub endpoints' do
       let(:path) { '-/jira' }
     end
+
+    it 'returns an empty Array for events' do
+      jira_get v3_api("/repos/-/jira/events", user)
+
+      expect(response).to have_gitlab_http_status(200)
+      expect(json_response).to eq([])
+    end
   end
 
   context 'new :namespace/:project jira endpoints' do
     it_behaves_like 'Jira-specific mimicked GitHub endpoints' do
       let(:path) { "#{project.namespace.path}/#{project.path}" }
     end
+
+    describe 'GET events' do
+      let(:group) { create(:group) }
+      let(:project) { create(:project, :empty_repo, group: group) }
+      let(:events_path) { "/repos/#{group.path}/#{project.path}/events" }
+
+      before do
+        stub_licensed_features(jira_dev_panel_integration: true)
+      end
+
+      context 'if there are no merge requests' do
+        it 'returns an empty array' do
+          jira_get v3_api(events_path, user)
+
+          expect(response).to have_gitlab_http_status(200)
+          expect(json_response).to eq([])
+        end
+      end
+
+      context 'if there is a merge request' do
+        let!(:merge_request) { create(:merge_request, source_project: project, target_project: project, author: user) }
+
+        it 'returns an event' do
+          jira_get v3_api(events_path, user)
+
+          expect(response).to have_gitlab_http_status(200)
+          expect(json_response).to be_an(Array)
+          expect(json_response.size).to eq(1)
+        end
+      end
+
+      context 'if there are more merge requests' do
+        let!(:merge_request) { create(:merge_request, id: 10000, source_project: project, target_project: project, author: user) }
+        let!(:merge_request2) { create(:merge_request, id: 10001, source_project: project, source_branch: generate(:branch), target_project: project, author: user) }
+
+        it 'returns the expected amount of events' do
+          jira_get v3_api(events_path, user)
+
+          expect(response).to have_gitlab_http_status(200)
+          expect(json_response).to be_an(Array)
+          expect(json_response.size).to eq(2)
+        end
+
+        it 'ensures each event has a unique id' do
+          jira_get v3_api(events_path, user)
+
+          ids = json_response.map { |event| event['id'] }.uniq
+          expect(ids.size).to eq(2)
+        end
+      end
+    end
   end
 
   describe 'repo pulls' do
@@ -158,6 +207,17 @@
         expect(response).to match_response_schema('entities/github/pull_requests', dir: 'ee')
       end
     end
+
+    describe 'GET /repos/:namespace/:project/pulls/:id' do
+      it 'returns the requested merge request in github format' do
+        stub_licensed_features(jira_dev_panel_integration: true)
+
+        jira_get v3_api("/repos/#{project.namespace.path}/#{project.path}/pulls/#{merge_request.id}", user)
+
+        expect(response).to have_gitlab_http_status(200)
+        expect(response).to match_response_schema('entities/github/pull_request', dir: 'ee')
+      end
+    end
   end
 
   describe 'GET /users/:namespace/repos' do