Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@
"version": "1.2.0",
"description": "Read-only access to Jira issues, epics, sprints, boards, and Confluence pages from Atlassian Cloud."
},
{
"name": "bitwarden-atlassian-tools",
"source": "./plugins/bitwarden-atlassian-tools",
"version": "1.0.0",
"description": "Read-only Jira access via custom MCP server: issue retrieval, JQL search, comments, and project discovery"
},
{
"name": "bitwarden-security-engineer",
"source": "./plugins/bitwarden-security-engineer",
Expand Down
10 changes: 10 additions & 0 deletions .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@
"words": [
"AKIA",
"ASVS",
"adf",
"anthropics",
"appsec",
"appsettings",
"atlassian",
"Bitwarden",
"blocklist",
"boardId",
"checkmarx",
"codeBlock",
"CODEOWNERS",
"Confluence",
"CQL",
Expand All @@ -25,12 +28,17 @@
"exploitability",
"frontmatter",
"grype",
"hardBreak",
"hotspot",
"hotspots",
"IDOR",
"issueIdOrKey",
"Jira",
"JQL",
"lockfiles",
"maxResults",
"mcp",
"nextPageToken",
"NVARCHAR",
"OAEP",
"owasp",
Expand All @@ -40,7 +48,9 @@
"semver",
"sonarcloud",
"sonarqube",
"sprintId",
"ssword",
"startAt",
"startswith",
"stride",
"structurizr",
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ A curated collection of plugins for AI-assisted development at Bitwarden. Enable
| Plugin | Version | Description |
| ------------------------------------------------------------------- | ------- | -------------------------------------------------------------------------------------------------- |
| [atlassian-reader](plugins/atlassian-reader/) | 1.2.0 | Read-only access to Jira issues, epics, sprints, boards, and Confluence pages from Atlassian Cloud |
| [bitwarden-atlassian-tools](plugins/bitwarden-atlassian-tools/) | 1.0.0 | Read-only Jira access via custom MCP server: issues, JQL search, comments, projects |
| [bitwarden-code-review](plugins/bitwarden-code-review/) | 1.8.0 | Autonomous code review agent following Bitwarden engineering standards with GitHub integration |
| [bitwarden-init](plugins/bitwarden-init/) | 1.1.0 | Initialize and enhance CLAUDE.md files with Bitwarden's standardized template format |
| [bitwarden-security-engineer](plugins/bitwarden-security-engineer/) | 0.2.0 | Application security engineering: vulnerability triage, threat modeling, and secure code analysis |
Expand Down
14 changes: 14 additions & 0 deletions plugins/bitwarden-atlassian-tools/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "bitwarden-atlassian-tools",
"version": "1.0.0",
"description": "Read-only Jira access via custom MCP server: issue retrieval, JQL search, comments, and project discovery",
"author": {
"name": "Bitwarden"
},
"keywords": [
"atlassian",
"jira",
"mcp",
"read-only"
]
}
14 changes: 14 additions & 0 deletions plugins/bitwarden-atlassian-tools/.mcp.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"mcpServers": {
"bitwarden-atlassian": {
"type": "stdio",
"command": "node",
"args": ["${CLAUDE_PLUGIN_ROOT}/mcp/bitwarden-atlassian-mcp-server/build/index.js"],
"env": {
"ATLASSIAN_JIRA_URL": "${ATLASSIAN_JIRA_URL}",
"ATLASSIAN_EMAIL": "${ATLASSIAN_EMAIL}",
"ATLASSIAN_JIRA_READ_ONLY_TOKEN": "${ATLASSIAN_JIRA_READ_ONLY_TOKEN}"
}
}
}
}
21 changes: 21 additions & 0 deletions plugins/bitwarden-atlassian-tools/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Changelog

All notable changes to the Bitwarden Atlassian Tools plugin will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.0.0] - 2026-02-23

### Added

- Custom MCP server with 4 read-only Jira tools
- `get_issue`, `search_issues`, `get_issue_comments`, `list_projects`
- Jira client layer with Basic Auth using `ATLASSIAN_*` environment variables
- Optimized ADF-to-plaintext transformation for reduced token consumption
- Unit test suite using vitest covering validation, auth, ADF extraction, and formatting

### Fixed

- Add domain-specific terms to `.cspell.json` for spell-check compatibility
- Extract shared `extractPlainText` ADF utility to eliminate duplication
41 changes: 41 additions & 0 deletions plugins/bitwarden-atlassian-tools/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Bitwarden Atlassian Tools

## Overview

Read-only Jira access via a custom MCP server providing issue retrieval, JQL search, comment reading, and project discovery. All operations are read-only — the server never creates, updates, or deletes Jira resources.

## Installation

Configure the following environment variables:

```bash
export ATLASSIAN_JIRA_URL="https://your-domain.atlassian.net"
export ATLASSIAN_EMAIL="your-email@company.com"
export ATLASSIAN_JIRA_READ_ONLY_TOKEN="your-api-token"
```

## MCP Tools

| Tool | Purpose |
|------|---------|
| `get_issue` | Read a Jira issue by key or ID |
| `search_issues` | Search issues using JQL |
| `get_issue_comments` | Get comments for an issue |
| `list_projects` | List accessible Jira projects |

## Usage

The MCP tools are available as `mcp__bitwarden-atlassian__<tool_name>`. Examples:

- Read an issue: `mcp__bitwarden-atlassian__get_issue` with `issueIdOrKey: "PROJ-123"`
- Search with JQL: `mcp__bitwarden-atlassian__search_issues` with `jql: "project = PROJ AND status = Open"`
- List projects: `mcp__bitwarden-atlassian__list_projects`

## Requirements

- Claude Code with MCP support
- Jira API credentials (see Installation)

## License

MIT License - See repository root for details.
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Dependencies
node_modules/
package-lock.json
yarn.lock
pnpm-lock.yaml

# Build output
build/
dist/
*.js
*.js.map
*.d.ts
*.d.ts.map

# Keep source TypeScript files
!src/**/*.ts

# Environment variables and secrets
.env
.env.local
.env.*.local

# IDE and editor files
.vscode/
.idea/
*.swp
*.swo
*~
.DS_Store

# Logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*

# Testing
coverage/
.nyc_output/

# Temporary files
tmp/
temp/
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"name": "@bitwarden/atlassian-tools-mcp",
"version": "1.0.0",
"description": "Read-only Jira MCP server for issue retrieval, JQL search, comments, and project discovery",
"type": "module",
"main": "build/index.js",
"bin": {
"bitwarden-atlassian-mcp": "./build/index.js"
},
"scripts": {
"build": "tsc && chmod +x build/index.js",
"watch": "tsc --watch",
"dev": "tsc && node build/index.js",
"inspector": "npx @modelcontextprotocol/inspector build/index.js",
"test": "vitest run",
"test:watch": "vitest"
},
"keywords": [
"mcp",
"jira",
"model-context-protocol",
"atlassian",
"read-only",
"jql"
],
"author": "Bitwarden",
"license": "MIT",
"dependencies": {
"@modelcontextprotocol/sdk": "1.27.1",
"axios": "1.13.6",
"zod": "3.24.2"
},
"devDependencies": {
"@types/node": "20.19.35",
"typescript": "5.8.3",
"vitest": "3.1.1"
},
"engines": {
"node": ">=18.0.0"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#!/usr/bin/env node

/**
* Jira MCP Server
* Read-only MCP server for Jira integration with Claude Code
*/

import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from '@modelcontextprotocol/sdk/types.js';
import type { ToolDefinition } from './utils/validation.js';

import getIssue from './tools/get-issue.js';
import getIssueComments from './tools/get-issue-comments.js';
import searchIssues from './tools/search-issues.js';
import listProjects from './tools/list-projects.js';

const tools: ToolDefinition[] = [
getIssue,
getIssueComments,
searchIssues,
listProjects,
];

async function main() {
const requiredEnvVars = ['ATLASSIAN_JIRA_URL', 'ATLASSIAN_EMAIL', 'ATLASSIAN_JIRA_READ_ONLY_TOKEN'];
const missingVars = requiredEnvVars.filter(v => !process.env[v]);

if (missingVars.length > 0) {
console.error(`Missing required environment variables: ${missingVars.join(', ')}`);
process.exit(1);
}

const server = new Server(
{ name: 'bitwarden-atlassian-mcp', version: '1.0.0' },
{ capabilities: { tools: {} } },
);

server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: tools.map(t => ({
name: t.name,
description: t.description,
inputSchema: t.inputSchema,
})),
}));

server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
const tool = tools.find(t => t.name === name);

if (!tool) {
throw new Error(`Unknown tool: ${name}`);
}

try {
const result = await tool.handler(args || {});
return { content: [{ type: 'text', text: result }] };
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
console.error(`Tool error (${name}):`, message);
return { content: [{ type: 'text', text: `Error: ${message}` }], isError: true };
}
});

const transport = new StdioServerTransport();
await server.connect(transport);
}

main().catch((error) => {
console.error('Fatal error:', error);
process.exit(1);
});
Loading