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
2 changes: 1 addition & 1 deletion .github/workflows/publish-ghidra.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:
java-version: "21"
distribution: "microsoft"
- name: Install Ghidra 🐉
uses: antoniovazquezblanco/[email protected].13
uses: antoniovazquezblanco/[email protected].14
with:
version: ${{ matrix.ghidra-version }}
- name: Compile ReVa 👩‍💻✨
Expand Down
16 changes: 8 additions & 8 deletions .github/workflows/test-ghidra.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ jobs:
distribution: "microsoft"

- name: Install Ghidra 🐉
uses: antoniovazquezblanco/[email protected].13
uses: antoniovazquezblanco/[email protected].14
with:
version: ${{ matrix.ghidra-version }}

Expand All @@ -46,7 +46,7 @@ jobs:


- name: Setup Gradle 🔧
uses: gradle/actions/setup-gradle@v4
uses: gradle/actions/setup-gradle@v5
with:
gradle-version: "8.14"

Expand Down Expand Up @@ -96,7 +96,7 @@ jobs:
distribution: "microsoft"

- name: Install Ghidra 🐉
uses: antoniovazquezblanco/[email protected].13
uses: antoniovazquezblanco/[email protected].14
with:
version: "latest"

Expand All @@ -107,7 +107,7 @@ jobs:
echo "DISPLAY=:99" >> $GITHUB_ENV

- name: Setup Gradle 🔧
uses: gradle/actions/setup-gradle@v4
uses: gradle/actions/setup-gradle@v5
with:
gradle-version: "8.14"
dependency-graph: generate-and-submit
Expand Down Expand Up @@ -137,27 +137,27 @@ jobs:
distribution: "microsoft"

- name: Initialize CodeQL
uses: github/codeql-action/init@v3
uses: github/codeql-action/init@v4
with:
languages: java
# Use security-extended queries for more thorough analysis
queries: security-extended,security-and-quality

- name: Install Ghidra 🐉
uses: antoniovazquezblanco/[email protected].13
uses: antoniovazquezblanco/[email protected].14
with:
version: "latest"


- name: Setup Gradle for CodeQL 🔧
uses: gradle/actions/setup-gradle@v4
uses: gradle/actions/setup-gradle@v5
with:
gradle-version: "8.14"

- name: Build Extension for CodeQL Analysis 🔨
run: gradle buildExtension

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
uses: github/codeql-action/analyze@v4
with:
category: "/language:java"
13 changes: 7 additions & 6 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,8 @@ sourceSets {

configurations {
integrationTestImplementation.extendsFrom testImplementation
// Force Jackson 2.17.0 to be compatible with MCP SDK v0.11.1

// Force Jackson 2.19.2 to be compatible with MCP SDK v0.14.0
all {
resolutionStrategy {
force 'com.fasterxml.jackson.core:jackson-core:2.19.2'
Expand Down Expand Up @@ -108,16 +108,17 @@ repositories {
dependencies {
// Any external dependencies added here will automatically be copied to the lib/ directory when
// this extension is built.
implementation platform("io.modelcontextprotocol.sdk:mcp-bom:0.12.1")
implementation platform("io.modelcontextprotocol.sdk:mcp-bom:0.14.0")
implementation "io.modelcontextprotocol.sdk:mcp"
implementation "io.modelcontextprotocol.sdk:mcp-json-jackson2"
implementation "jakarta.servlet:jakarta.servlet-api:6.1.0"
// Add Jetty for embedded servlet support
implementation "org.eclipse.jetty:jetty-server:11.0.26"
implementation "org.eclipse.jetty:jetty-servlet:11.0.26"
// Force Jackson 2.17.0 to be compatible with MCP SDK v0.11.1

// Force Jackson 2.19.2 to be compatible with MCP SDK v0.14.0
implementation "com.fasterxml.jackson.core:jackson-core:2.19.2"
implementation "com.fasterxml.jackson.core:jackson-databind:2.19.2"
implementation "com.fasterxml.jackson.core:jackson-databind:2.19.2"
implementation "com.fasterxml.jackson.core:jackson-annotations:2.19.2"

// Testing dependencies
Expand Down
13 changes: 3 additions & 10 deletions src/main/java/reva/server/McpServerManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@
import java.util.EnumSet;
import jakarta.servlet.DispatcherType;

import com.fasterxml.jackson.databind.ObjectMapper;

import generic.concurrent.GThreadPool;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.listing.Program;
Expand All @@ -40,7 +38,6 @@
import io.modelcontextprotocol.server.McpServer;
import io.modelcontextprotocol.server.McpSyncServer;
import io.modelcontextprotocol.server.transport.HttpServletStreamableServerTransportProvider;
import io.modelcontextprotocol.spec.McpError;
import io.modelcontextprotocol.spec.McpSchema;
import reva.plugin.ConfigManager;
import reva.plugin.ConfigChangeListener;
Expand Down Expand Up @@ -69,7 +66,6 @@
* the same server instance and coordinates program lifecycle events across tools.
*/
public class McpServerManager implements RevaMcpService, ConfigChangeListener {
private static final ObjectMapper JSON = new ObjectMapper();
private static final String MCP_MSG_ENDPOINT = "/mcp/message";
private static final String MCP_SERVER_NAME = "ReVa";
private static final String MCP_SERVER_VERSION = "1.0.0";
Expand Down Expand Up @@ -163,12 +159,9 @@ private void initializeToolProviders() {
toolProviders.add(new BookmarkToolProvider(server));

// Register all tools with the server
// Note: As of MCP SDK v0.14.0, tool registration is idempotent and replaces duplicates
for (ToolProvider provider : toolProviders) {
try {
provider.registerTools();
} catch (McpError e) {
Msg.error(this, "Failed to register tools for provider: " + provider.getClass().getSimpleName(), e);
}
provider.registerTools();
}
}

Expand Down Expand Up @@ -403,8 +396,8 @@ private void recreateTransportProvider() {
String baseUrl = "http://" + serverHost + ":" + serverPort;

// Create new transport provider with updated configuration
// Note: As of MCP SDK v0.14.0, the builder uses McpJsonMapper.getDefault() automatically
currentTransportProvider = HttpServletStreamableServerTransportProvider.builder()
.objectMapper(JSON)
.mcpEndpoint(MCP_MSG_ENDPOINT)
.keepAliveInterval(java.time.Duration.ofSeconds(30))
.build();
Expand Down
4 changes: 1 addition & 3 deletions src/main/java/reva/tools/AbstractToolProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
import reva.plugin.RevaProgramManager;
import reva.util.ProgramLookupUtil;
import io.modelcontextprotocol.server.McpSyncServer;
import io.modelcontextprotocol.spec.McpError;
import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.spec.McpSchema.Content;
import io.modelcontextprotocol.spec.McpSchema.TextContent;
Expand Down Expand Up @@ -134,9 +133,8 @@ protected McpSchema.CallToolResult createMultiJsonResult(List<Object> dataList)
* Register a tool with the MCP server
* @param tool The tool to register
* @param handler The handler function for the tool
* @throws McpError if there's an error registering the tool
*/
protected void registerTool(Tool tool, java.util.function.BiFunction<io.modelcontextprotocol.server.McpSyncServerExchange, CallToolRequest, McpSchema.CallToolResult> handler) throws McpError {
protected void registerTool(Tool tool, java.util.function.BiFunction<io.modelcontextprotocol.server.McpSyncServerExchange, CallToolRequest, McpSchema.CallToolResult> handler) {
// Wrap the handler with safe execution
java.util.function.BiFunction<io.modelcontextprotocol.server.McpSyncServerExchange, CallToolRequest, McpSchema.CallToolResult> safeHandler =
(exchange, request) -> {
Expand Down
4 changes: 1 addition & 3 deletions src/main/java/reva/tools/ToolProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
package reva.tools;

import ghidra.program.model.listing.Program;
import io.modelcontextprotocol.spec.McpError;

/**
* Interface for MCP tool providers.
Expand All @@ -26,9 +25,8 @@
public interface ToolProvider {
/**
* Register all tools with the MCP server
* @throws McpError if there's an error registering the tools
*/
void registerTools() throws McpError;
void registerTools();

/**
* Notify the provider that a program has been opened
Expand Down
18 changes: 6 additions & 12 deletions src/main/java/reva/tools/bookmarks/BookmarkToolProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
import ghidra.program.model.listing.BookmarkManager;
import ghidra.program.model.listing.Program;
import io.modelcontextprotocol.server.McpSyncServer;
import io.modelcontextprotocol.spec.McpError;
import io.modelcontextprotocol.spec.McpSchema;
import reva.tools.AbstractToolProvider;
import reva.util.SchemaUtil;
Expand All @@ -48,7 +47,7 @@ public BookmarkToolProvider(McpSyncServer server) {
}

@Override
public void registerTools() throws McpError {
public void registerTools() {
registerSetBookmarkTool();
registerGetBookmarksTool();
registerRemoveBookmarkTool();
Expand All @@ -58,9 +57,8 @@ public void registerTools() throws McpError {

/**
* Register a tool to set or update a bookmark at an address
* @throws McpError if there's an error registering the tool
*/
private void registerSetBookmarkTool() throws McpError {
private void registerSetBookmarkTool() {
Map<String, Object> properties = new HashMap<>();
properties.put("programPath", SchemaUtil.stringProperty("Path to the program in the Ghidra Project"));
properties.put("addressOrSymbol", SchemaUtil.stringProperty("Address or symbol name where to set the bookmark"));
Expand Down Expand Up @@ -122,9 +120,8 @@ private void registerSetBookmarkTool() throws McpError {

/**
* Register a tool to get bookmarks at an address or range
* @throws McpError if there's an error registering the tool
*/
private void registerGetBookmarksTool() throws McpError {
private void registerGetBookmarksTool() {
Map<String, Object> properties = new HashMap<>();
properties.put("programPath", SchemaUtil.stringProperty("Path to the program in the Ghidra Project"));
properties.put("addressOrSymbol", SchemaUtil.stringProperty("Address or symbol name to get bookmarks from (optional if using addressRange)"));
Expand Down Expand Up @@ -222,9 +219,8 @@ private void registerGetBookmarksTool() throws McpError {

/**
* Register a tool to remove a bookmark
* @throws McpError if there's an error registering the tool
*/
private void registerRemoveBookmarkTool() throws McpError {
private void registerRemoveBookmarkTool() {
Map<String, Object> properties = new HashMap<>();
properties.put("programPath", SchemaUtil.stringProperty("Path to the program in the Ghidra Project"));
properties.put("addressOrSymbol", SchemaUtil.stringProperty("Address or symbol name of the bookmark"));
Expand Down Expand Up @@ -281,9 +277,8 @@ private void registerRemoveBookmarkTool() throws McpError {

/**
* Register a tool to search bookmarks
* @throws McpError if there's an error registering the tool
*/
private void registerSearchBookmarksTool() throws McpError {
private void registerSearchBookmarksTool() {
Map<String, Object> properties = new HashMap<>();
properties.put("programPath", SchemaUtil.stringProperty("Path to the program in the Ghidra Project"));
properties.put("searchText", SchemaUtil.stringProperty("Text to search for in bookmark comments (optional)"));
Expand Down Expand Up @@ -387,9 +382,8 @@ private void registerSearchBookmarksTool() throws McpError {

/**
* Register a tool to list bookmark categories for a type
* @throws McpError if there's an error registering the tool
*/
private void registerListBookmarkCategoriesTool() throws McpError {
private void registerListBookmarkCategoriesTool() {
Map<String, Object> properties = new HashMap<>();
properties.put("programPath", SchemaUtil.stringProperty("Path to the program in the Ghidra Project"));
properties.put("type", SchemaUtil.stringProperty("Bookmark type to get categories for"));
Expand Down
15 changes: 5 additions & 10 deletions src/main/java/reva/tools/comments/CommentToolProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
import ghidra.program.model.listing.Listing;
import ghidra.program.model.listing.CodeUnitIterator;
import io.modelcontextprotocol.server.McpSyncServer;
import io.modelcontextprotocol.spec.McpError;
import io.modelcontextprotocol.spec.McpSchema;
import reva.tools.AbstractToolProvider;
import reva.util.AddressUtil;
Expand Down Expand Up @@ -59,7 +58,7 @@ public CommentToolProvider(McpSyncServer server) {
}

@Override
public void registerTools() throws McpError {
public void registerTools() {
registerSetCommentTool();
registerGetCommentsTool();
registerRemoveCommentTool();
Expand All @@ -68,9 +67,8 @@ public void registerTools() throws McpError {

/**
* Register a tool to set or update a comment at an address
* @throws McpError if there's an error registering the tool
*/
private void registerSetCommentTool() throws McpError {
private void registerSetCommentTool() {
Map<String, Object> properties = new HashMap<>();
properties.put("programPath", SchemaUtil.stringProperty("Path to the program in the Ghidra Project"));
properties.put("addressOrSymbol", SchemaUtil.stringProperty("Address or symbol name where to set the comment"));
Expand Down Expand Up @@ -127,9 +125,8 @@ private void registerSetCommentTool() throws McpError {

/**
* Register a tool to get comments at an address or range
* @throws McpError if there's an error registering the tool
*/
private void registerGetCommentsTool() throws McpError {
private void registerGetCommentsTool() {
Map<String, Object> properties = new HashMap<>();
properties.put("programPath", SchemaUtil.stringProperty("Path to the program in the Ghidra Project"));
properties.put("addressOrSymbol", SchemaUtil.stringProperty("Address or symbol name to get comments from (optional if using addressRange)"));
Expand Down Expand Up @@ -231,9 +228,8 @@ private void registerGetCommentsTool() throws McpError {

/**
* Register a tool to remove a comment at an address
* @throws McpError if there's an error registering the tool
*/
private void registerRemoveCommentTool() throws McpError {
private void registerRemoveCommentTool() {
Map<String, Object> properties = new HashMap<>();
properties.put("programPath", SchemaUtil.stringProperty("Path to the program in the Ghidra Project"));
properties.put("addressOrSymbol", SchemaUtil.stringProperty("Address or symbol name where to remove the comment"));
Expand Down Expand Up @@ -287,9 +283,8 @@ private void registerRemoveCommentTool() throws McpError {

/**
* Register a tool to search for comments containing text
* @throws McpError if there's an error registering the tool
*/
private void registerSearchCommentsTool() throws McpError {
private void registerSearchCommentsTool() {
Map<String, Object> properties = new HashMap<>();
properties.put("programPath", SchemaUtil.stringProperty("Path to the program in the Ghidra Project"));
properties.put("searchText", SchemaUtil.stringProperty("Text to search for in comments"));
Expand Down
12 changes: 4 additions & 8 deletions src/main/java/reva/tools/data/DataToolProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.model.symbol.Symbol;
import ghidra.program.model.symbol.SymbolTable;
import io.modelcontextprotocol.spec.McpError;
import io.modelcontextprotocol.server.McpSyncServer;
import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.spec.McpSchema.CallToolResult;
Expand All @@ -54,17 +53,16 @@ public DataToolProvider(McpSyncServer server) {
}

@Override
public void registerTools() throws McpError {
public void registerTools() {
registerGetDataTool();
registerApplyDataTypeTool();
registerCreateLabelTool();
}

/**
* Register a unified tool to get data by address or symbol name
* @throws McpError if there's an error registering the tool
*/
private void registerGetDataTool() throws McpError {
private void registerGetDataTool() {
// Define schema for the tool
Map<String, Object> properties = new HashMap<>();
properties.put("programPath", Map.of(
Expand Down Expand Up @@ -98,9 +96,8 @@ private void registerGetDataTool() throws McpError {

/**
* Register a tool to apply a data type to an address or symbol
* @throws McpError if there's an error registering the tool
*/
private void registerApplyDataTypeTool() throws McpError {
private void registerApplyDataTypeTool() {
// Define schema for the tool
Map<String, Object> properties = new HashMap<>();
properties.put("programPath", Map.of(
Expand Down Expand Up @@ -201,9 +198,8 @@ private void registerApplyDataTypeTool() throws McpError {

/**
* Register a tool to create a label at a specific address in a program
* @throws McpError if there's an error registering the tool
*/
private void registerCreateLabelTool() throws McpError {
private void registerCreateLabelTool() {
// Define schema for the tool
Map<String, Object> properties = new HashMap<>();
properties.put("programPath", Map.of(
Expand Down
Loading
Loading