Step by Step Guide to Develop Custom Model Context Protocol (MCP) Connectors for Atlassian Rovo
- Jessica Piikkila

- Jun 9
- 7 min read
Date: June 9, 2026, Version: 1.2
Author: Jessica Piikkila (with help of my Product Marketer, SME , and Publishing Agents)
Target Audience: Enterprise Architects, DevSecOps Engineers, and Atlassian Platform Owners
Executive Summary
Atlassian Rovo introduces next-generation search and conversational agents to the Atlassian ecosystem. However, a common blocker for enterprises is unlocking private, siloed data from internal databases, proprietary CI/CD pipelines, and legacy systems that sit outside the Atlassian cloud.
The Model Context Protocol (MCP), an open-standard JSON-RPC protocol, addresses this challenge by establishing a secure, standard interface for Large Language Models (LLMs) to interact with localized resources, prompts, and tools.
This guide details how to build and deploy a Custom MCP Connector that acts as a secure intermediary between Atlassian Rovo Agents and internal data stores. By implementing this pattern, enterprise teams can give Rovo Agents real-time execution capabilities and deep contextual knowledge while maintaining robust security boundaries, mTLS encryption, and fine-grained access control.
High-Level Architecture & Event Flow
This diagram illustrates how a user request within Atlassian Rovo triggers a schema-compliant tool call, tunnels securely into the private cloud, and executes a query via the Custom MCP Server.
sequenceDiagram autonumber actor Developer as Developer / User participant Rovo as Atlassian Rovo Agent participant Forge as Forge App (Integration Gateway) participant Tunnel as Secure Link / API Gateway (mTLS) participant MCP as Custom MCP Server participant DB as Internal DB / App (e.g., SAP, Jenkins) Developer->>Rovo: Ask: "Is the deployment build #420 passing?" Rovo->>Forge: Match intent & execute tool get_build_status(id: 420) Forge->>Tunnel: Forward payload to registered MCP URL with JWT Tunnel->>MCP: Route JSON-RPC request to MCP endpoint MCP->>DB: Process tool execution (Query Database/API) DB-->>MCP: Return build status (Success/JSON) MCP-->>Tunnel: Return standardized CallToolResult schema Tunnel-->>Forge: Deliver JSON response payload Forge-->>Rovo: Present structured context to the LLM Rovo-->>Developer: "Yes, build #420 successfully deployed to Prod at 10:15 AM."
Architectural Ecosystem Components
Atlassian Rovo Agent: The host LLM engine matching user prompts to system instructions and registered tool manifests.
Forge Tool Wrapper (Integration Gateway): Hosted in the Atlassian secure sandbox, it translates standard Forge tool definitions into MCP JSON-RPC requests of types resources/read or tools/call.
Secure API Gateway / Tunnel: Provides ingress filtering, rate-limiting, and mTLS verification preventing public access to internal systems.
Custom MCP Server: A localized Node.js/TypeScript or Python application exposing local APIs, data warehouses, or legacy storage clusters using the standardized MCP schema.
Prerequisites
Before starting, ensure you have the following access levels and toolkits configured:
Atlassian Organization Administrator access with an active Rovo license flag.
Atlassian Forge CLI installed locally (npm install -g @atlassian/forge). Forge version v10.4.0 or higher is recommended.
Node.js LTS (v20.x or higher) and TypeScript installed.
A secure hosting platform for the MCP server (e.g., AWS Lambda with API Gateway, Cloudflare Workers, or a secure internal Kubernetes group).
An HTTPS endpoint with TLS 1.3 configured.
Implementation Steps
Phase 1: Foundation & Environmental Setup
Step 1: Bootstrap the Custom MCP Server
Create a local TypeScript project to handle incoming MCP JSON-RPC JSON payloads using the official @modelcontextprotocol/sdk.
mkdir mcps-rovo-connector cd mcps-rovo-connector npm init -y npm install @modelcontextprotocol/sdk dotenv express npm install --save-dev typescript @types/node @types/express ts-node npx tsc --init
Create a server configuration entry point inside src/server.ts:
Correction of Forge Bridge Function Usage
The Forge bridge function incorrectly uses process.env to access secrets. Forge functions operate within a sandboxed environment, meaning that you should not rely on process.env for accessing sensitive information. Instead, utilize @forge/api's storage or the Forge environment variables API, which includes resolver context or Forge variables set. Using process.env.INTERNAL_API_KEY will lead to undefined values in production.
Updated Code
Below is the updated code where the transport.handleMessage(req, res) has been changed to transport.handlePostMessage(req, res):
javascript
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
import express from "express";
import dotenv from "dotenv";
dotenv.config();
const app = express();
const PORT = process.env.PORT || 3000;
// Initialize the MCP server container
const mcpServer = new Server({
name: "rovo-internal-connector",
version: "1.0.0"
}, {
capabilities: {
resources: {},
tools: {}
}
});
// Configure simple SSE (Server-Sent Events) transport for web accessibility
let transport: SSEServerTransport;
app.get("/sse", (req, res) => {
transport = new SSEServerTransport("/messages", res);
mcpServer.connect(transport).catch(console.error);
});
app.post("/messages", (req, res) => {
if (transport) {
transport.handlePostMessage(req, res); // Updated method here
} else {
res.status(400).send("No active transport connections found.");
}
});
app.listen(PORT, () => {
console.log(`[MCP Server] Active and running over HTTP/SSE on port ${PORT}`);
});
This modification updates the method used to handle POST messages in the SSE transport, ensuring proper functionality in the Forge environment.
Step 2: Establish Secure Cloud Access and Secret Mapping
If you have root access, define the .env file containing local credentials. Otherwise stick with local dev server 3000 instead of PORT 443. If utilizing AWS Secrets Manager or HashiCorp Vault, populate these dynamically within your production entry point.
PORT=443 (or 3000)
INTERNAL_API_KEY=xoxb-enterprise-secret-token-value ATLASSIAN_WEBHOOK_SECRET=hmac_signature_verification_key_here
Phase 2: Core Configuration & Rovo Integration
Step 1: Implement Resources and Tools in your MCP Server
To allow Rovo to query production data (e.g., build statuses from a local build queue), define internal schemas using standard MCP definitions.
Append the tool registration and handler to src/server.ts:
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
// Step 1a: Define Schema list for Rovo to ingest mcpServer.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: "get_internal_build_status", description: "Fetch build and deployment telemetry from internal CI/CD servers.", inputSchema: { type: "object", properties: { buildId: { type: "string", description: "The unique identifier of the deployment pipeline build." } }, required: ["buildId"] } } ] }; }); // Step 3b: Handle tool execution payloads mcpServer.setRequestHandler(CallToolRequestSchema, async (request) => { if (request.params.name === "get_internal_build_status") { const buildId = request.params.arguments?.buildId as string; // Replace with real local database or CI/CD endpoint call: const mockBuildStatus = { id: buildId, status: "SUCCESS", deployDurationSeconds: 142, environment: "Production-East" }; return { content: [ { type: "text", text: JSON.stringify(mockBuildStatus, null, 2) } ] }; } throw new Error(`Tool request validation error: ${request.params.name} not found.`); });
Step 2: Configure the Forge Gateway Wrapper App
To present this MCP interface seamlessly to Atlassian Rovo, create an Atlassian Forge app that routes Rovo Agent behaviors to your external MCP endpoint.
Run inside an independent directory:
forge create # Select: "UI Kit" with template "blank-template" # Name: "Rovo-MCP-Bridge"
Open and replace the content of manifest.yml to define a Rovo extension point and authorize egress traffic:
modules:
rovo:agent-tool (or it might be rovo:agent or via API:
- key: rovo-mcp-connector name: Internal CI/CD Tools description: Fetches internal systems and metrics through secure MCP pipelines function: invoke-mcp-server inputs: buildId: type: string description: "Internal pipeline build reference string" required: true function: - key: invoke-mcp-server handler: index.runBridge app: id: ari:cloud:ecosystem::app/your-forge-app-uuid-here permissions: external: fetch: backend: - 'https://your-secure-mcp-host.company.internal'
Step 3: Draft the Bridge Function Logic
In your Forge project's src/index.js, write the gateway integration routing logic that intercepts the agent action and returns an standardized MCP-v1 output back to Rovo.
import { fetch } from '@forge/api'; export async function runBridge(request) { const { buildId } = request.payload; const mcpServerUrl = 'https://your-secure-mcp-host.company.internal/messages'; try { // Generate JSON-RPC payload matching MCP standards const jsonRpcPayload = { jsonrpc: "2.0", id: "rovo-request-1", method: "tools/call", params: { name: "get_internal_build_status", arguments: { buildId } } }; const response = await fetch(mcpServerUrl, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${process.env.INTERNAL_API_KEY}` }, body: JSON.stringify(jsonRpcPayload) }); if (!response.ok) { throw new Error(`MCP Response returned bad status level: ${response.status}`); } const output = await response.json(); // Resolve content payload from MCP payload configuration return { success: true, text: output.result.content[0].text }; } catch (error) { console.error("Bridge failure executing custom MCP tools: ", error); return { success: false, error: error.message }; } }
Deploy your Forge application to your cloud instance environment:
forge deploy forge install
Phase 3: Validation & Testing
Step 1: Verify Endpoint Compliance via CLI Client
Validate that the MCP system is correctly responding to standardized JSON-RPC queries. Use curl to trigger safe local test scopes:
curl -X POST https://your-secure-mcp-host.company.internal/messages \ -H "Content-Type: application/json" \ -H "Authorization: Bearer xoxb-enterprise-secret-token-value" \ -d '{ "jsonrpc": "2.0", "id": "health-check", "method": "tools/call", "params": { "name": "get_internal_build_status", "arguments": { "buildId": "PROD-2026-069" } } }'
Expected Standardized JSON Response Payload:
{ "jsonrpc": "2.0", "id": "health-check", "result": { "content": [ { "type": "text", "text": "{\n \"id\": \"PROD-2026-069\",\n \"status\": \"SUCCESS\",\n \"deployDurationSeconds\": 142,\n \"environment\": \"Production-East\"\n}" } ] } }
Step 2: Verify Agent-MCP Communication within Atlassian Rovo
Navigate to your Atlassian Cloud administration site: Jira Cloud > Rovo Agents.
Create or edit an active Rovo Agent (e.g., "Build Ops Assistant").
Assign the new tool: Internal CI/CD Tools within the Tooling permissions tab.
Input testing prompt inside the chat playground surface:
"Find the system status of build ID PROD-2026-069."
Rovo will map the query parameters into tool arguments, call the Forge function, retrieve the data from your local server, and synthesize the result cleanly.
Operational Governance, Security & Best Practices
Security & Token Isolation
Least Privilege Scopes: Make sure your custom MCP server has read-only access where appropriate. Strip destructive database write capabilities unless explicitly audited.
Header Verification: Use standard HMAC authentication or JWT validation inside the connection handlers to assert the request originated from your Forge instance and passes your identity layer.
Network Isolation: Do not expose the backend MCP port directly to the open web. Leverage enterprise integrations like Cloudflare Tunnels, AWS PrivateLink, or mTLS validation proxies to route internal egress traffic.
Performance & Rate Limits
Caching: Set short cache durations (e.g., Redis layer cached for 60 seconds) for intensive SQL outputs. Agent processes can make duplicate context schema queries inside a single chat thread. (Note, Redis will have to be implemented, here is a good resource https://skywork.ai/skypage/en/redis-mcp-server-ai-data/1980811440015872001. )
Timeouts: Forge backend execution tasks must return a result within 25 seconds. Set your local MCP execution timeouts to 15s to exit cleanly, returning an informative timeout error boundary.
What to Avoid
Avoid Generic JSON-RPC Tunnel Injection: Do not configure a physical tool handler script that takes unvalidated raw SQL queries or dynamic shell arguments as variables from Rovo Agents. Always force strict schema bindings on properties like buildId or userId.
Maintenance and Troubleshooting
Common Edge Cases & Quick Fixes
Issue Symptoms — Root Cause — Remediation Plan
"Function timeout" shown in Rovo Agents chat workspace. — Local MCP server took longer than 25 seconds to process internal DB queries or downstream API call. — Configure index rules on internal DB. Implement asynchronous polling or cache expensive endpoints.
"Failed to verify signature" — Webhook HMAC keys mismatched or corrupted during rotation in Forge local environments. — Re-configure environment variables inside Forge console and deploy with forge deploy -e production.
"Unknown Tool: get_internal_build_status" — Forge manifest declaration key name mismatched inside manifest.yml vs the expected payload in src/server.ts. — Check schema strings inside server code initialization handlers. Run the CLI tool validations.
Monitoring and KPIs
To monitor your connector deployment pipeline, verify metrics against the following telemetry dashboard KPIs:
Execution Success Rate: Ensure successful tool calls remain above 99.5%. Track any server-side database connectivity exceptions.
Latency Profile: Maintain average execution latency under 1200ms for seamless interaction response speeds.
AI Tool Usage Density: Run analytics on how frequently the Rovo Agent uses your tools versus fallback searches. Use this data to optimize the model instructions.
That's it, this should be enough to get you off to a good start. Let us know your experience and how this worked for you. We don't have comments enabled yet, until then feel free to email us directly using the huge contact button in the top navigation.
Comments