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
142 changes: 142 additions & 0 deletions modules/GephiMcp/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.gephi</groupId>
<artifactId>gephi-plugin-parent</artifactId>
<version>0.11.1</version>
</parent>

<groupId>org.gephi.plugins</groupId>
<artifactId>gephi-mcp</artifactId>
<version>1.2.3</version>
<packaging>nbm</packaging>

<name>Gephi AI (MCP)</name>
<description>HTTP API for remote Gephi control via MCP (Model Context Protocol)</description>
<url>https://github.com/MattArtzAnthro/gephi-ai</url>

<licenses>
<license>
<name>Apache License, Version 2.0</name>
<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
</licenses>

<developers>
<developer>
<name>Matt Artz</name>
<url>https://www.mattartz.me</url>
</developer>
</developers>

<dependencies>
<!-- Gephi APIs (versions managed by gephi-plugin-parent) -->
<dependency>
<groupId>org.gephi</groupId>
<artifactId>graph-api</artifactId>
</dependency>
<dependency>
<groupId>org.gephi</groupId>
<artifactId>project-api</artifactId>
</dependency>
<dependency>
<groupId>org.gephi</groupId>
<artifactId>layout-api</artifactId>
</dependency>
<dependency>
<groupId>org.gephi</groupId>
<artifactId>io-exporter-api</artifactId>
</dependency>
<dependency>
<groupId>org.gephi</groupId>
<artifactId>io-importer-api</artifactId>
</dependency>
<dependency>
<groupId>org.gephi</groupId>
<artifactId>statistics-api</artifactId>
</dependency>
<dependency>
<groupId>org.gephi</groupId>
<artifactId>utils-longtask</artifactId>
</dependency>
<dependency>
<groupId>org.gephi</groupId>
<artifactId>appearance-api</artifactId>
</dependency>
<dependency>
<groupId>org.gephi</groupId>
<artifactId>preview-api</artifactId>
</dependency>
<dependency>
<groupId>org.gephi</groupId>
<artifactId>filters-api</artifactId>
</dependency>
<dependency>
<groupId>org.gephi</groupId>
<artifactId>visualization-api</artifactId>
</dependency>

<!-- NetBeans Platform APIs (versions managed by gephi-plugin-parent) -->
<dependency>
<groupId>org.netbeans.api</groupId>
<artifactId>org-openide-util</artifactId>
</dependency>
<dependency>
<groupId>org.netbeans.api</groupId>
<artifactId>org-openide-util-lookup</artifactId>
</dependency>
<dependency>
<groupId>org.netbeans.api</groupId>
<artifactId>org-openide-modules</artifactId>
</dependency>
<dependency>
<groupId>org.netbeans.api</groupId>
<artifactId>org-openide-nodes</artifactId>
</dependency>

<!-- Bundled libraries -->
<dependency>
<groupId>org.nanohttpd</groupId>
<artifactId>nanohttpd</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
</dependency>

<!-- Test only: unit tests for the pure helpers (no Gephi runtime needed) -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.2</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.netbeans.utilities</groupId>
<artifactId>nbm-maven-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<licenseName>Apache 2.0</licenseName>
<author>Matt Artz</author>
<authorUrl>https://www.mattartz.me</authorUrl>
<sourceCodeUrl>https://github.com/MattArtzAnthro/gephi-ai</sourceCodeUrl>
<homePageUrl>https://github.com/MattArtzAnthro/gephi-ai</homePageUrl>
<publicPackages>
<publicPackage>org.gephi.plugins.mcp.api</publicPackage>
</publicPackages>
</configuration>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package org.gephi.plugins.mcp;

import java.util.logging.Level;
import java.util.logging.Logger;
import org.gephi.plugins.mcp.api.GephiAPIServer;
import org.openide.modules.ModuleInstall;

public class Installer extends ModuleInstall {

private static final Logger LOGGER = Logger.getLogger(Installer.class.getName());
private static final int DEFAULT_PORT = 8080;
private GephiAPIServer server;

@Override
public void restored() {
LOGGER.info("########## Gephi MCP Plugin: restored() called ##########");
System.out.println("########## Gephi MCP Plugin: restored() called ##########");

// Start server in a new thread to not block module loading
Thread serverThread = new Thread(() -> {
try {
Thread.sleep(2000); // Wait for Gephi to fully initialize
startServer();
} catch (Exception e) {
LOGGER.log(Level.SEVERE, "Failed to start MCP server", e);
System.err.println("Failed to start MCP server: " + e.getMessage());
e.printStackTrace();
}
}, "MCP-Server-Starter");
serverThread.setDaemon(true);
serverThread.start();
}

@Override
public void close() {
LOGGER.info("########## Gephi MCP Plugin: close() called ##########");
stopServer();
}

@Override
public boolean closing() {
LOGGER.info("########## Gephi MCP Plugin: closing() called ##########");
stopServer();
return true;
}

private void startServer() {
try {
int port = Integer.getInteger("gephi.mcp.port", DEFAULT_PORT);
LOGGER.info("########## Starting MCP server on port " + port + " ##########");
System.out.println("########## Starting MCP server on port " + port + " ##########");

server = new GephiAPIServer(port);
server.startServer();

LOGGER.info("===========================================");
LOGGER.info(" Gephi MCP Plugin Active");
LOGGER.info(" API: http://127.0.0.1:" + port);
LOGGER.info("===========================================");
System.out.println("===========================================");
System.out.println(" Gephi MCP Plugin Active");
System.out.println(" API: http://127.0.0.1:" + port);
System.out.println("===========================================");
} catch (Exception e) {
LOGGER.log(Level.SEVERE, "Failed to start MCP server", e);
System.err.println("Failed to start MCP server: " + e.getMessage());
e.printStackTrace();
}
}

private void stopServer() {
final GephiAPIServer s = server;
server = null;
if (s == null) return;
// Stop on a daemon watchdog so a slow/stuck socket close can never block
// Gephi's shutdown (which runs on the EDT). Wait at most 3s, then continue
// regardless; the daemon threads can't keep the JVM alive.
Thread stopper = new Thread(() -> {
try {
s.stopServer();
LOGGER.info("########## MCP server stopped ##########");
} catch (Exception e) {
LOGGER.log(Level.WARNING, "Error stopping server", e);
}
}, "MCP-Server-Stopper");
stopper.setDaemon(true);
stopper.start();
try {
stopper.join(3000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
if (stopper.isAlive()) {
LOGGER.warning("MCP server stop exceeded 3s; continuing Gephi shutdown");
}
}
}
Loading