Skip to content
Open
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
78 changes: 78 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
name: CI

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Build
run: npm run build

- name: Test CLI
run: node cli.js --version

test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'

- name: Install PMD
run: |
wget https://github.com/pmd/pmd/releases/download/pmd_releases%2F7.9.0/pmd-dist-7.9.0-bin.zip
unzip pmd-dist-7.9.0-bin.zip
echo "$PWD/pmd-bin-7.9.0/bin" >> $GITHUB_PATH

- name: Verify PMD installation
run: pmd --version

- name: Install dependencies
run: npm ci

- name: Build
run: npm run build

- name: Run tests
run: npm test

test-without-pmd:
runs-on: ubuntu-latest
name: Test (without PMD)
steps:
- uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Build
run: npm run build

- name: Run tests (graceful degradation)
run: npm test
99 changes: 99 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
name: Publish to npm

on:
push:
tags:
- 'v*' # Trigger on tags like v0.1.0, v1.0.0
workflow_dispatch:
inputs:
version:
description: 'Version to publish (e.g., patch, minor, major, or specific like 0.2.0)'
required: true
default: 'patch'

jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Build
run: npm run build

- name: Test CLI
run: node cli.js --version

- name: Configure Git
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"

- name: Bump version (manual trigger)
if: github.event_name == 'workflow_dispatch'
run: |
npm version ${{ github.event.inputs.version }} --no-git-tag-version
VERSION=$(node -p "require('./package.json').version")
echo "NEW_VERSION=$VERSION" >> $GITHUB_ENV

- name: Get version from tag
if: startsWith(github.ref, 'refs/tags/v')
run: |
VERSION=${GITHUB_REF#refs/tags/v}
echo "NEW_VERSION=$VERSION" >> $GITHUB_ENV
npm version $VERSION --no-git-tag-version --allow-same-version

- name: Publish to npm
run: npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

- name: Commit version bump
if: github.event_name == 'workflow_dispatch'
run: |
git add package.json package-lock.json
git commit -m "chore: Release v${{ env.NEW_VERSION }}" || echo "No changes to commit"
git push

- name: Create GitHub Release
if: github.event_name == 'workflow_dispatch'
uses: softprops/action-gh-release@v1
with:
tag_name: v${{ env.NEW_VERSION }}
name: PMD MCP v${{ env.NEW_VERSION }}
body: |
## @springsoftware/pmd-mcp v${{ env.NEW_VERSION }}

Install with:
```bash
npx @springsoftware/pmd-mcp
```

Or add to your MCP config:
```json
{
"mcpServers": {
"pmd": {
"command": "npx",
"args": ["@springsoftware/pmd-mcp@${{ env.NEW_VERSION }}"]
}
}
}
```
draft: false
prerelease: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
170 changes: 170 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
# PMD MCP Server

A [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server that provides [PMD](https://pmd.github.io/) static code analysis capabilities to AI assistants.

## Features

- **`pmd_check`** - Run PMD static analysis on source files
- **`pmd_cpd`** - Detect copy-paste (duplicated) code
- **`pmd_list_languages`** - List supported programming languages
- **`pmd_list_rulesets`** - List available rulesets for analysis

## Requirements

- **Node.js 18+**
- **PMD** installed locally (via Homebrew, or in PATH)

### Installing PMD

```bash
# macOS (Homebrew)
brew install pmd

# Verify installation
pmd --version
```

## Installation

### For Windsurf / Cursor / VS Code

Add to your MCP configuration (`.mcp.json` or settings):

```json
{
"mcpServers": {
"pmd": {
"command": "npx",
"args": ["@springsoftware/pmd-mcp"]
}
}
}
```

### For Claude Desktop

Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:

```json
{
"mcpServers": {
"pmd": {
"command": "npx",
"args": ["@springsoftware/pmd-mcp"]
}
}
}
```

## Usage Examples

### Run PMD Analysis

```
Use pmd_check to analyze /path/to/my/java/project for code quality issues
```

### Detect Duplicated Code

```
Use pmd_cpd to find duplicated Python code in /path/to/project with minimum 75 tokens
```

### List Available Rulesets

```
What PMD rulesets are available for Java?
```

## Tools Reference

### `pmd_check`

Run PMD static code analysis on source files.

**Parameters:**
- `path` (required) - Path to source file or directory
- `rulesets` - Array of rulesets to apply (default: quickstart)
- `language_version` - Language version (e.g., "java-21")
- `minimum_priority` - Minimum priority to report (1-5)
- `excludes` - File patterns to exclude

**Example:**
```json
{
"path": "/Users/me/project/src",
"rulesets": ["category/java/bestpractices.xml", "category/java/errorprone.xml"],
"minimum_priority": 3
}
```

### `pmd_cpd`

Run copy-paste detection to find duplicated code.

**Parameters:**
- `path` (required) - Path to source file or directory
- `language` (required) - Programming language (python, java, typescript, etc.)
- `minimum_tokens` - Minimum token count for duplication (default: 50)
- `ignore_literals` - Ignore literal values
- `ignore_identifiers` - Ignore identifier names
- `excludes` - File patterns to exclude

**Example:**
```json
{
"path": "/Users/me/project",
"language": "python",
"minimum_tokens": 75,
"ignore_literals": true
}
```

### `pmd_list_languages`

List all supported programming languages.

### `pmd_list_rulesets`

List available rulesets, optionally filtered by language.

**Parameters:**
- `language` - Filter by language (e.g., "java", "apex")

## Supported Languages

### Static Analysis (pmd_check)
- Java, JavaScript (ECMAScript), Apex, Kotlin, Swift
- HTML, XML, XSL, JSP, Velocity
- PL/SQL, Modelica, Scala, Visualforce

### Copy-Paste Detection (pmd_cpd)
- Python, Java, JavaScript, TypeScript, Kotlin, Swift
- Go, Ruby, Rust, Scala, C/C++, C#, PHP
- And many more...

## Development

```bash
# Install dependencies
npm install

# Build
npm run build

# Run in development mode
npm run dev

# Run tests
npm test
```

## License

BSD-4-Clause (same as PMD)

## Links

- [PMD Documentation](https://docs.pmd-code.org/)
- [MCP Specification](https://modelcontextprotocol.io/)
- [PMD GitHub](https://github.com/pmd/pmd)
Loading