Skip to main content
Glama
README.md
# jdtls-mcp

> Expose the Eclipse JDT Language Server to LLM agents via the Model Context Protocol (MCP)

## Overview

`jdtls-mcp` is an Eclipse application that extends
[eclipse-jdtls](https://github.com/eclipse-jdtls/eclipse.jdt.ls) with a new
OSGi bundle (`org.eclipse.jdt.ls.mcp`) that exposes Java language intelligence
as [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) tools.

```
┌─────────────────────────────────────────────────────────┐
│  Eclipse / Equinox OSGi container (one JVM process)     │
│                                                          │
│  ┌───────────────────────┐   ┌──────────────────────┐   │
│  │ org.eclipse.jdt.ls.core│   │ org.eclipse.jdt.ls   │   │
│  │ (jdtls: handlers,      │◄──│ .mcp                 │   │
│  │  project manager, JDT) │   │ (McpApplication +    │   │
│  └───────────────────────┘   │  JdtlsMcpTools)       │   │
│                               └──────────┬───────────┘   │
└──────────────────────────────────────────│───────────────┘
                                           │ MCP over stdio
                                 ┌─────────▼─────────┐
                                 │  LLM / MCP client  │
                                 │  (Claude, GPT, …)  │
                                 └────────────────────┘
```

The MCP bundle calls jdtls handler classes **directly in the same JVM** — no
subprocess spawning, no network hop, no second Java process.  LLM agents talk
to the Eclipse application via stdio using the MCP protocol.

## How it works

1. **Target platform** (`org.eclipse.jdt.ls.mcp.target`) references the jdtls
   snapshot p2 repository, Eclipse 2025-12 release train, LSP4J 0.24.0, and
   the MCP Java SDK + langchain4j from Maven Central (wrapped as OSGi bundles
   by Tycho's `missingManifest="generate"` feature).

2. **Plugin bundle** (`org.eclipse.jdt.ls.mcp`) is a standard `eclipse-plugin`
   module built by Tycho.  It declares `Require-Bundle: org.eclipse.jdt.ls.core`
   and calls jdtls handler classes (`HoverHandler`, `NavigateToDefinitionHandler`,
   `ReferencesHandler`, `CompletionHandler`, `DocumentSymbolHandler`,
   `WorkspaceSymbolHandler`) directly.

3. **MCP Application** (`McpApplication`) registers under the extension point
   `org.eclipse.core.runtime.applications` as `org.eclipse.jdt.ls.mcp.app`.
   When selected as the Eclipse application, it initialises the jdtls workspace
   and starts an MCP server on stdio.

4. **Product** (`org.eclipse.jdt.ls.mcp.product`) packages all jdtls bundles
   together with the new MCP bundle into a distributable Eclipse product.

## Related projects

### [sunix/java-lsp-mcp-server](https://github.com/sunix/java-lsp-mcp-server)

A parallel experiment tackling the same goal — exposing jdtls to AI agents via
MCP — but with a fundamentally different architecture.

| Aspect | **jdtls-mcp** (this project) | **java-lsp-mcp-server** |
|---|---|---|
| Architecture | *Embedded* — runs **as** an Eclipse OSGi product | *External controller* — runs jdtls as a managed subprocess |
| MCP transport | **stdio** (NDJSON, one JSON object per line) | **HTTP / SSE** |
| jdtls version | Fixed at build time via the Tycho target platform | Auto-downloaded at runtime (configurable URL or latest) |
| Distribution | Pre-built platform archives (~63 MB each) | Standard Quarkus JAR or GraalVM native binary |
| Workspace | Fixed at server startup (CLI argument) | Changed at runtime via `initializeWorkspace()` tool |
| Java required | Java 21 | Java 25 |
| Framework | Tycho / OSGi | [Quarkus](https://quarkus.io/) + [quarkus-mcp-server](https://docs.quarkiverse.io/quarkus-mcp-server/dev/) |
| LSP tools | hover, document symbols, references, workspace symbols, definition, **diagnostics** | document symbols, completions, diagnostics, format, definition |
| Lifecycle tools | None (transparent to the LLM) | `startJdtls`, `stopJdtls`, `checkJdtls`, `installJdtls`, `initializeWorkspace` |

**When to use which:**

- **jdtls-mcp** — zero operational overhead for the LLM agent; the server is
  ready when the process starts. Good fit for stdio-only MCP clients and
  fixed-workspace setups.
- **java-lsp-mcp-server** — better for HTTP-based MCP clients, multi-workspace
  scenarios, or environments where you want the agent to control the jdtls
  lifecycle directly. The auto-download removes the need to ship a pre-built
  product per platform.

### Improvements this project could borrow

Looking at what `java-lsp-mcp-server` has that this project currently lacks:

| Missing tool | LSP request | What it enables |
|---|---|---|
| `java_completions` | `textDocument/completion` | Let the agent request completions at a position — useful for code generation workflows |
| `java_format` | `textDocument/formatting` + `textDocument/didChange` | Normalise generated code before committing |

Both are available through the jdtls handlers already on the classpath
(`CompletionHandler`, `FormattingHandler`), so
they can be added to `JdtlsMcpTools.java` following the same pattern as the
existing tools.

## Technology stack

| Library | Role |
|---------|------|
| [Tycho](https://github.com/eclipse-tycho/tycho) | OSGi / Eclipse plugin build system |
| [eclipse-jdtls](https://github.com/eclipse-jdtls/eclipse.jdt.ls) | Java compiler, handlers, project manager (via p2) |
| [MCP Java SDK](https://github.com/modelcontextprotocol/java-sdk) (`io.modelcontextprotocol.sdk:mcp-core`) | MCP server protocol + stdio transport |
| [langchain4j-core](https://github.com/langchain4j/langchain4j) | `@Tool` / `@P` annotations |
| [LSP4J 0.24.0](https://github.com/eclipse-lsp4j/lsp4j) | LSP types used by jdtls handlers |

## Available MCP tools

| Tool | Description |
|------|-------------|
| `java_hover` | Get hover information (Javadoc, type info) at a position |
| `java_definition` | Find the definition of a symbol |
| `java_references` | Find all references to a symbol |
| `java_completion` | Get code completion suggestions |
| `java_document_symbols` | List all symbols in a file |
| `java_workspace_symbols` | Search for symbols across the workspace |
| `java_diagnostics` | Get compilation errors and warnings for a file or workspace |
| `java_workspace_status` | Report jdtls workspace readiness — project import progress, build status, index readiness, and classpath/Maven dependency errors. Call before other tools to check the workspace is ready, or to diagnose dependency-resolution failures |

All position-based tools use **0-based** line and character offsets (LSP convention).

## Project structure

```
jdtls-mcp/
├── agent.md                             # LLM agent onboarding guide
├── pom.xml                              # Tycho parent (mirrors eclipse-jdtls)
├── org.eclipse.jdt.ls.mcp.target/      # Target-platform definition
│   ├── pom.xml
│   └── org.eclipse.jdt.ls.mcp.tp.target  # p2 + Maven deps (MCP SDK, langchain4j)
├── org.eclipse.jdt.ls.mcp/             # New OSGi eclipse-plugin bundle
│   ├── META-INF/MANIFEST.MF
│   ├── plugin.xml                      # Registers org.eclipse.jdt.ls.mcp.app
│   ├── build.properties
│   └── src/main/java/org/eclipse/jdt/ls/mcp/
│       ├── McpServerPlugin.java        # BundleActivator
│       ├── McpApplication.java         # Eclipse IApplication — MCP entry point
│       └── JdtlsMcpTools.java          # @Tool methods + MCP tool registration
├── org.eclipse.jdt.ls.mcp.product/    # Eclipse product packaging
│   ├── pom.xml
│   └── jdtls-mcp.product               # All jdtls bundles + org.eclipse.jdt.ls.mcp
└── test-workspace/hello-jdtls/        # Sample Maven project for manual testing
```

---

## Prerequisites

| Tool | Version | Notes |
|------|---------|-------|
| Java | 21+    | Must be on `PATH` |

## Installation

### Option A — Download a release (recommended)

Download the archive for your platform from the
[**Releases page**](https://github.com/sunix/jdtls-mcp/releases/latest),
extract it, and you're ready to go — no build step required.

Release assets are named with their version tag (e.g.
`jdtls-mcp-v1.0.1-linux-x86_64.tar.gz`), so `releases/latest/download/<name>`
only works if you hardcode the current version. Resolve it first instead:

```bash
# Resolve the latest version tag once
VERSION=$(curl -fsSL -o /dev/null -w '%{url_effective}' \
  https://github.com/sunix/jdtls-mcp/releases/latest | sed 's#.*/tag/##')

# Linux x86_64
curl -L "https://github.com/sunix/jdtls-mcp/releases/download/${VERSION}/jdtls-mcp-${VERSION}-linux-x86_64.tar.gz" \
  | tar xz
cd jdtls-mcp

# macOS arm64 (Apple Silicon)
curl -L "https://github.com/sunix/jdtls-mcp/releases/download/${VERSION}/jdtls-mcp-${VERSION}-macos-aarch64.tar.gz" \
  | tar xz
cd jdtls-mcp
```

Other platforms follow the same `jdtls-mcp-${VERSION}-<platform>.<ext>` naming
— see the [Releases page](https://github.com/sunix/jdtls-mcp/releases/latest)
for the full list of assets.

The extracted directory contains `plugins/`, `configuration/`, and `scripts/`.

### Option B — Build from source

Requires **Maven 3.9+** in addition to Java 21.

```bash
git clone https://github.com/sunix/jdtls-mcp.git
cd jdtls-mcp
mvn package -DskipTests
```

The built product lands at:
```
org.eclipse.jdt.ls.mcp.product/target/products/jdtls-mcp.product/
├── linux/gtk/x86_64/
├── linux/gtk/aarch64/
├── macosx/cocoa/x86_64/
├── macosx/cocoa/aarch64/
└── win32/win32/x86_64/
```

## Running

Use the bundled `scripts/start-mcp-server.sh` (included in release archives
and in the repo):

```bash
# Point at your Java workspace
./scripts/start-mcp-server.sh /path/to/your-java-project

# Optional second argument: Eclipse metadata/index directory
./scripts/start-mcp-server.sh /path/to/your-java-project /tmp/jdtls-data
```

The script auto-detects OS and CPU architecture.  The server reads MCP messages
from stdin and writes JSON-RPC responses to stdout.

> [!NOTE]
> Startup takes **~60 s** on the first run while Maven imports the project and
> the JDT type-name index warms up.  Subsequent starts against the same data
> directory are faster.

## GitHub Copilot Coding Agent

Two things are needed: a one-time setup workflow (Java 21) and the MCP server
configuration (download + start on each session).

### Step 1 — Add the setup workflow

Add the following file to your **Java repository** (not this repo).
It runs before every Copilot coding agent session and ensures Java 21 is on PATH.

`.github/workflows/copilot-setup-steps.yml`

```yaml
on:
  workflow_dispatch:

permissions:
  contents: read

jobs:
  copilot-setup-steps:
    runs-on: ubuntu-latest

    steps:
      - name: Set up Java 21
        uses: actions/setup-java@v4
        with:
          distribution: temurin
          java-version: '21'
```

### Step 2 — Add the MCP server configuration

Go to **GitHub Settings → Copilot → Coding agent → MCP configuration** (or your
organisation's equivalent) and paste the following JSON:

```json
{
  "mcpServers": {
    "jdtls": {
      "type": "local",
      "command": "bash",
      "args": [
        "-c",
        "f=$(mktemp /tmp/jdtls-mcp-XXXXXX.sh) && curl -fsSL https://raw.githubusercontent.com/sunix/jdtls-mcp/main/scripts/download-and-start.sh -o \"$f\" && chmod +x \"$f\" && exec \"$f\""
      ],
      "tools": ["*"]
    }
  }
}
```

On each session, `download-and-start.sh` fetches the latest release (or reuses
the cached copy at `~/.cache/jdtls-mcp/<version>/`) and starts the MCP server
against `$GITHUB_WORKSPACE`.  The `mktemp` pattern keeps stdin free for MCP
traffic while `curl` runs.

> [!NOTE]
> Startup takes **~60 s** on the first session while Maven imports the project
> and the JDT type-name index warms up.  Subsequent sessions against the same
> data directory are faster.

---

## Testing with MCP clients

The repository includes a ready-to-use sample Java project at
`test-workspace/hello-jdtls/` — use it as the jdtls workspace when trying
any of the clients below.

```bash
export WORKSPACE="$PWD/test-workspace/hello-jdtls"
```

The examples below assume you have either downloaded a release archive and
extracted it to `~/jdtls-mcp/`, or cloned and built the repo.  Adjust
`JDTLS_MCP_DIR` to wherever `scripts/start-mcp-server.sh` lives:

```bash
# Downloaded release (example)
export JDTLS_MCP_DIR="$HOME/jdtls-mcp"

# Built from source
export JDTLS_MCP_DIR="$PWD"   # repo root
```

---

### GitHub Copilot in VSCode

> **Requires:** VSCode ≥ 1.99 with the GitHub Copilot extension (MCP support is
> enabled by default; no feature flag needed).

1. **Add the MCP server** by creating (or editing) `.vscode/mcp.json` in your
   Java project folder:

   ```bash
   mkdir -p "$WORKSPACE/.vscode"
   cat > "$WORKSPACE/.vscode/mcp.json" << EOF
   {
     "servers": {
       "jdtls": {
         "type": "stdio",
         "command": "$JDTLS_MCP_DIR/scripts/start-mcp-server.sh",
         "args": ["$WORKSPACE"]
       }
     }
   }
   EOF
   ```

2. **Open the project** in VSCode:

   ```bash
   code "$WORKSPACE"
   ```

3. **Start the MCP server** — VSCode will prompt you to start MCP servers
   defined in `.vscode/mcp.json` when you open Copilot Chat.  Click **Start**
   next to `jdtls`.

4. **Open Copilot Chat** (`Ctrl+Alt+I` / `Cmd+Alt+I`) and try these prompts:

   ```
   Use the java_hover tool to show me the Javadoc for the greet() method in
   file:///path/to/test-workspace/hello-jdtls/src/main/java/com/example/Greeter.java at line 34.

   Use java_document_symbols to list all symbols in
   file:///path/to/test-workspace/hello-jdtls/src/main/java/com/example/Greeter.java

   Use java_workspace_symbols to find all classes named Greeter.
   ```

---

### Claude Code

> **Requires:** [Claude Code](https://docs.anthropic.com/en/docs/claude-code)
> CLI installed (`npm install -g @anthropic-ai/claude-code` or follow the
> official install guide).

1. **Register the MCP server** (run once):

   ```bash
   claude mcp add jdtls -- "$JDTLS_MCP_DIR/scripts/start-mcp-server.sh" "$WORKSPACE"
   ```

   Verify it was registered:

   ```bash
   claude mcp list
   ```

2. **Open the project with Claude Code:**

   ```bash
   cd "$WORKSPACE"
   claude
   ```

3. **Try these prompts inside the Claude Code REPL:**

   ```
   Show me the Javadoc for the greet() method in
   src/main/java/com/example/Greeter.java using the jdtls MCP tools.

   Find all references to the `name` field in Greeter.java.

   List all symbols defined in Greeter.java.
   ```

   Claude Code will automatically call the `java_hover`, `java_references`, and
   `java_document_symbols` tools and display the results inline.

4. **Remove the server** when done:

   ```bash
   claude mcp remove jdtls
   ```

---

### GitHub Copilot CLI (`gh copilot`)

> **Requires:** [GitHub CLI](https://cli.github.com/) with the Copilot extension.
> ```bash
> gh extension install github/gh-copilot
> gh auth login          # if not already authenticated
> ```

The GitHub Copilot CLI (`gh copilot suggest` / `gh copilot explain`) uses MCP
servers configured in the GitHub Copilot for CLI settings file.

1. **Find or create the config file:**

   | OS | Path |
   |----|------|
   | Linux / macOS | `~/.config/gh-copilot/config.yaml` (may vary by version) |

   Add the MCP server configuration:

   ```bash
   mkdir -p ~/.config/gh-copilot
   cat >> ~/.config/gh-copilot/config.yaml << EOF
   mcp:
     servers:
       jdtls:
         command: "$JDTLS_MCP_DIR/scripts/start-mcp-server.sh"
         args:
           - "$WORKSPACE"
   EOF
   ```

2. **Ask Copilot CLI a question about the Java project:**

   ```bash
   gh copilot suggest "What public methods does the Greeter class have? Use the jdtls MCP tools to check."
   ```

   Or use `explain` mode:

   ```bash
   gh copilot explain "Use java_workspace_symbols to find all classes in the test-workspace"
   ```

> [!NOTE]
> MCP support in Copilot CLI is evolving. Check
> [`gh copilot --help`](https://cli.github.com/manual/gh_copilot) or the
> [GitHub Copilot CLI changelog](https://docs.github.com/en/copilot/github-copilot-in-the-cli/about-github-copilot-in-the-cli)
> for the latest configuration options.

---

## Contributing

> **TL;DR** — Java 21, Maven 3.9+, then `mvn package -DskipTests`.
> All commits must follow [Conventional Commits](https://www.conventionalcommits.org/).

### Prerequisites

| Tool  | Version | Notes                           |
|-------|---------|---------------------------------|
| Java  | 21+     | Must be on `PATH`               |
| Maven | 3.9+    | Tycho wraps OSGi builds via Maven |

An internet connection is required on first build to resolve the Eclipse p2
target platform and Maven Central dependencies.

### IDE setup

**Eclipse IDE** (recommended for OSGi/plugin development):

1. Install [Eclipse IDE for Eclipse Committers](https://www.eclipse.org/downloads/packages/) (2024-12 or later).
2. Install **Tycho Project Configurators** via *Help → Install New Software* from the Eclipse release update site.
3. Import the project: *File → Import → Maven → Existing Maven Projects*, select the repo root.
4. Eclipse will automatically set up the target platform from `org.eclipse.jdt.ls.mcp.tp.target`.

**VS Code / IntelliJ** also work for editing Java source; just run `mvn package`
from the terminal for builds.

### Build

```bash
mvn package                       # full build (all platforms)
mvn package -DskipTests           # skip test execution for faster iteration
mvn package -pl org.eclipse.jdt.ls.mcp.product -am  # only the plugin + product
```

### Testing your changes locally

Two helper scripts are provided in `scripts/`:

| Script | Purpose |
|--------|---------|
| [`scripts/start-mcp-server.sh`](./scripts/start-mcp-server.sh) | Start the server against any workspace — reads MCP from stdin, writes responses to stdout |
| [`scripts/test-mcp.sh`](./scripts/test-mcp.sh) | Smoke-test all tools against `test-workspace/hello-jdtls` |

**Smoke-test all tools at once:**

```bash
# Run from the repo root after 'mvn package -DskipTests'
./scripts/test-mcp.sh
```

The script starts the server, sends the MCP handshake followed by one call for
every tool, and prints the raw JSON-RPC responses to stdout.  Startup takes
around 60 s on first run while Maven imports the project and the JDT index
warms up.

**Start the server manually against any workspace:**

```bash
# Against the bundled test project
./scripts/start-mcp-server.sh

# Against your own project (workspace dir, optional data/metadata dir)
./scripts/start-mcp-server.sh /path/to/my-java-project /tmp/jdtls-data
```

The server then reads MCP messages from stdin and writes responses to stdout.
See [`agent.md`](./agent.md) for a complete self-testing workflow with example
JSON-RPC messages.

#### Wire-protocol quick test (no MCP client required)

The `StdioServerTransportProvider` from the MCP Java SDK uses
**newline-delimited JSON** (NDJSON) — one JSON object per line — **not**
the `Content-Length` framing used by LSP.  You can therefore drive the server
entirely with shell here-docs or a file of JSON lines, or use the
`scripts/test-mcp.sh` script which handles this automatically.

Write MCP messages — one per line — and pipe them in:

```bash
cat > /tmp/mcp-input.txt << 'EOF'
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}
{"jsonrpc":"2.0","method":"notifications/initialized","params":{}}
{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}
EOF

./scripts/start-mcp-server.sh 2>/dev/null < /tmp/mcp-input.txt
```

> [!TIP]
> The server maps the workspace Maven project on first start; this takes
> roughly 60 s.  Send the messages immediately — the `initialize` reply arrives as
> soon as the transport is ready, and tool responses follow once project import
> and JDT indexing finishes.

#### Example session — annotated server output

Below is a real session against `test-workspace/hello-jdtls/`.

**Input** (`/tmp/mcp-input.txt`) — three NDJSON lines:

```json
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}
{"jsonrpc":"2.0","method":"notifications/initialized","params":{}}
{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}
```

**Response line 1 — `initialize` reply:**

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2024-11-05",
    "capabilities": {
      "logging": {},
      "tools": { "listChanged": true }
    },
    "serverInfo": { "name": "jdtls-mcp", "version": "1.0.0" }
  }
}
```

**Response line 2 — `tools/list` reply** (formatted for readability):

```json
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "tools": [
      {
        "name": "java_hover",
        "description": "Get hover information (Javadoc, type info) for the Java symbol at a given position.",
        "inputSchema": {
          "type": "object",
          "properties": {
            "uri":       { "type": "string",  "description": "Absolute file URI, e.g. file:///path/to/MyClass.java" },
            "line":      { "type": "integer", "description": "0-based line number" },
            "character": { "type": "integer", "description": "0-based character offset" }
          },
          "required": ["uri", "line", "character"]
        }
      },
      {
        "name": "java_definition",
        "description": "Find the definition of the Java symbol (class, method, field) at the given position.",
        "inputSchema": {
          "type": "object",
          "properties": {
            "uri":       { "type": "string",  "description": "Absolute file URI, e.g. file:///path/to/MyClass.java" },
            "line":      { "type": "integer", "description": "0-based line number" },
            "character": { "type": "integer", "description": "0-based character offset" }
          },
          "required": ["uri", "line", "character"]
        }
      },
      {
        "name": "java_references",
        "description": "Find all references to the Java symbol at the given position.",
        "inputSchema": {
          "type": "object",
          "properties": {
            "uri":                { "type": "string",  "description": "Absolute file URI, e.g. file:///path/to/MyClass.java" },
            "line":               { "type": "integer", "description": "0-based line number" },
            "character":          { "type": "integer", "description": "0-based character offset" },
            "includeDeclaration": { "type": "boolean", "description": "Whether to include the declaration itself" }
          },
          "required": ["uri", "line", "character", "includeDeclaration"]
        }
      },
      {
        "name": "java_completion",
        "description": "Get code completion suggestions at the given position in a Java source file.",
        "inputSchema": {
          "type": "object",
          "properties": {
            "uri":       { "type": "string",  "description": "Absolute file URI, e.g. file:///path/to/MyClass.java" },
            "line":      { "type": "integer", "description": "0-based line number" },
            "character": { "type": "integer", "description": "0-based character offset" }
          },
          "required": ["uri", "line", "character"]
        }
      },
      {
        "name": "java_document_symbols",
        "description": "List all symbols (classes, methods, fields) defined in a Java source file.",
        "inputSchema": {
          "type": "object",
          "properties": {
            "uri": { "type": "string", "description": "Absolute file URI, e.g. file:///path/to/MyClass.java" }
          },
          "required": ["uri"]
        }
      },
      {
        "name": "java_workspace_symbols",
        "description": "Search for Java symbols (classes, methods, fields) by name across the workspace.",
        "inputSchema": {
          "type": "object",
          "properties": {
            "query": { "type": "string", "description": "Search query, e.g. a class name or method name prefix" }
          },
          "required": ["query"]
        }
      }
    ]
  }
}
```

#### Example tool calls

**`java_workspace_symbols`** — find all classes named `Greeter`:

```json
{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"java_workspace_symbols","arguments":{"query":"Greeter"}}}
```

**`java_document_symbols`** — list all symbols in a file:

```json
{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"java_document_symbols","arguments":{"uri":"file:///root/github/sunix/jdtls-mcp/test-workspace/hello-jdtls/src/main/java/com/example/Greeter.java"}}}
```

**`java_hover`** — get Javadoc at a specific position:

```json
{"jsonrpc":"2.0","id":5,"method":"tools/call","params":{"name":"java_hover","arguments":{"uri":"file:///root/github/sunix/jdtls-mcp/test-workspace/hello-jdtls/src/main/java/com/example/Greeter.java","line":10,"character":18}}}
```

**`java_definition`** — jump to the definition of a symbol:

```json
{"jsonrpc":"2.0","id":6,"method":"tools/call","params":{"name":"java_definition","arguments":{"uri":"file:///root/github/sunix/jdtls-mcp/test-workspace/hello-jdtls/src/main/java/com/example/Greeter.java","line":10,"character":18}}}
```

**`java_references`** — find all usages of a symbol:

```json
{"jsonrpc":"2.0","id":7,"method":"tools/call","params":{"name":"java_references","arguments":{"uri":"file:///root/github/sunix/jdtls-mcp/test-workspace/hello-jdtls/src/main/java/com/example/Greeter.java","line":5,"character":13,"includeDeclaration":true}}}
```

#### Example chat prompts for LLM agents

These prompts work well with GitHub Copilot, Claude Code, or any MCP-aware
LLM when the `jdtls` server is connected:

```
List all the methods and fields defined in
file:///…/test-workspace/hello-jdtls/src/main/java/com/example/Greeter.java
using the java_document_symbols tool.

Show me the Javadoc for the greet() method in Greeter.java using java_hover.

Find all classes in the workspace that contain the word "Counter" using
java_workspace_symbols.

Find every place in the codebase where the `name` field of Greeter is
referenced, using java_references.

Jump to the definition of the Counter class from the call site in Greeter.java
using java_definition.
```

### Adding a new MCP tool

1. Add a method annotated with `@Tool` / `@P` in `JdtlsMcpTools.java`, delegating
   to the appropriate jdtls handler class (see `org.eclipse.jdt.ls.core.internal.handlers`).
2. Register it in `JdtlsMcpTools.registerTools()` using the existing
   `.toolCall(tool(…), this::mcpXxx)` pattern.
3. Test it against `test-workspace/hello-jdtls/`.
4. Commit with `feat(tools): add java_<toolname> MCP tool`.

### Commit conventions

This project uses **Conventional Commits**:

```
<type>(<optional scope>): <short description>
```

| Type       | When to use                                             |
|------------|---------------------------------------------------------|
| `feat`     | New feature or new MCP tool                             |
| `fix`      | Bug fix                                                 |
| `refactor` | Code change without behaviour change                    |
| `test`     | Adding or updating tests                                |
| `docs`     | Documentation only                                      |
| `build`    | Build config changes (pom.xml, target platform, …)      |
| `chore`    | Maintenance (CI, .gitignore, …)                         |

### Releasing

Releases are fully automated via the **Release** GitHub Actions workflow
(`.github/workflows/release.yml`). You never need to edit version numbers
manually or push a tag yourself.

**What the workflow does automatically:**
1. Runs `tycho-versions:set-version` to update all version strings atomically —
   `pom.xml` files, `MANIFEST.MF` (`Bundle-Version`), and `jdtls-mcp.product`.
2. Commits the version bump and creates the `v<version>` git tag.
3. Builds the product for all 5 platforms with Maven / Tycho.
4. Packages per-platform archives and publishes a GitHub Release with them.
5. Bumps versions to the next `-SNAPSHOT`, commits, and pushes everything
   (tag + both commits) back to `main`.

**To cut a release:**

1. Go to **Actions → Release → Run workflow** on GitHub.
2. Fill in **Release version** (e.g. `1.0.0`).
   Optionally fill in **Next development version** (e.g. `1.0.1-SNAPSHOT`).
   Leave it blank to auto-increment the patch segment.
3. Click **Run workflow** — that's it.

After the workflow completes:
- A GitHub Release tagged `v1.0.0` appears with the 5 platform archives.
- `main` has two new commits: the release version bump and the snapshot bump.

> **Branch protection note:** if `main` has push restrictions, grant the
> `github-actions[bot]` the **bypass** permission, or use a PAT stored as
> `GH_RELEASE_TOKEN` and reference it in the workflow's `token:` field
> instead of `secrets.GITHUB_TOKEN`.

### Key source files

| File | Purpose |
|------|---------|
| `org.eclipse.jdt.ls.mcp/…/McpApplication.java` | Eclipse `IApplication` — initialises jdtls workspace, starts MCP stdio server |
| `org.eclipse.jdt.ls.mcp/…/JdtlsMcpTools.java` | All MCP tool implementations + registration |
| `org.eclipse.jdt.ls.mcp/…/McpServerPlugin.java` | OSGi `BundleActivator` |
| `org.eclipse.jdt.ls.mcp/plugin.xml` | Registers `org.eclipse.jdt.ls.mcp.app` Eclipse application |
| `org.eclipse.jdt.ls.mcp.target/…tp.target` | Target platform: jdtls p2 repo + MCP SDK + langchain4j |
| `org.eclipse.jdt.ls.mcp.product/jdtls-mcp.product` | Lists all OSGi bundles for the packaged product |
| `test-workspace/hello-jdtls/` | Sample Maven project for manual testing |

## Licence

[EPL-2.0](LICENSE)