Distributing via Protégé’s “Check for plugins”
Protégé can discover and install this plugin from File ▸ Check for plugins — no manual jar
copying. That menu reads a plugin registry (a .repository URL list) and, for each listed
update descriptor (update.properties), offers the plugin when its id
(= Bundle-SymbolicName, here io.github.hakjuoh.protege-mcp) is either not yet installed, or installed at a
lower version. Both files are published from this GitHub repo, so you can install straight from
the official registry with nothing to fill in:
protege-mcp.repository— the registry list, served from themainbranch athttps://raw.githubusercontent.com/hakjuoh/protege-mcp/main/protege-mcp.repository. Because Protégé’s “Plugin registry” is a single URL, this file lists our descriptor and nests Protégé’s default registry, so pointing Protégé here shows protege-mcp alongside the full official catalog (Cellfie, ELK, OntoGraf, OWLViz, …) — you don’t lose the standard plugins.update.properties— the update descriptor it points at (id/name/version/download/readme/author), served fromhttps://raw.githubusercontent.com/hakjuoh/protege-mcp/main/update.properties. ItsdownloadURL is the jar attached to the matching GitHub Release. The descriptor is authoritative and may intentionally lag the source version while the next release is being prepared; it is advanced only after the named asset exists.
This registry path only describes how the built bundle reaches Protégé. The live server, Ontology Assistant, and headless CLI are separate runtime surfaces described in
DESIGN.md. The sameBundle-SymbolicName/ version rules used here are covered under Packaging and dependency isolation.
Install from the official registry (no setup)
-
Point Protégé at the registry. Settings ▸ Plugins ▸ “Plugin registry” → paste
https://raw.githubusercontent.com/hakjuoh/protege-mcp/main/protege-mcp.repository(The field defaults to the official Protégé registry; “Reset to default registry location” restores it.)
- Discover it. File ▸ Check for plugins → “Protege MCP Server” appears in the list (together with the official plugins, since this registry nests Protégé’s default one).
- Install it. Select it and confirm. Protégé downloads the jar named in
update.properties(download=…/releases/download/v<version>/protege-mcp-<version>.jar) straight from the GitHub Release and drops it into your plugins directory. - Restart Protégé on a Java 17+ JVM (see Requirements). On reload you get the MCP Server view and the Settings ▸ MCP tab.
How the discovery chain is wired (all on GitHub). The registry URL you paste serves
protege-mcp.repository; its single line points Protégé at the rawupdate.propertiesonmain; that descriptor’sdownloadpoints at theprotege-mcp-<version>.jarasset on the matching GitHub Release. Registry list → update descriptor → release asset — three hops, all hosted by this repo, nothing to host yourself.
If Check for plugins shows an empty list, the registry or
downloadURL was unreachable: an unresolvable URL is logged atinfolevel and silently skipped, not shown as an error. Confirm the registry URL above resolves (open it in a browser) and that the current Release asset named byupdate.propertiesexists.
Use your own fork
If you fork the project and want to serve the plugin from your account instead:
- Publish the jar. Build (
mvn clean package) and uploadplugin/target/protege-mcp-<v>.jarsomewhere downloadable — e.g. attach it to a GitHub Release on your fork. - Repoint the URLs. In
update.properties, setdownload=(andreadme=) to your fork’s URLs; inprotege-mcp.repository, change the raw URL so it resolves to your fork’supdate.properties. Commit and push both so their raw URLs are reachable, e.g.https://raw.githubusercontent.com/<you>/protege-mcp/main/protege-mcp.repository. Pointreadme=at a raw, self-contained simple HTML file (like the official plugins’readme.html— heredocs/readme.html), e.g.raw.githubusercontent.com/<you>/protege-mcp/main/docs/readme.html. Protégé ignores the serverContent-Type(raw GitHub servestext/plain) and instead sniffs the body for<html>, rendering it as HTML in a SwingJEditorPane(HTML 3.2) when found, else as plain text — so a raw.htmlfile renders formatted. Never use agithub.com/…/blob/…page: that returns the GitHub web-app HTML, which renders as garbage and whose fetch freezes the dialog.license=is opened in the external browser, so a/blob/URL is fine there. - Point Protégé at your registry (step 1 above) and run Check for plugins.
Quick local test (no hosting)
Serve the repo over loopback HTTP and point a temporary jar URL at your build output:
# from the repo root, after `mvn clean package`:
python3 -m http.server 8000 # serves ./protege-mcp.repository, ./update.properties, ./plugin/target/...
Temporarily set download=http://127.0.0.1:8000/plugin/target/protege-mcp-<v>.jar in update.properties,
then set the Plugin-registry preference to http://127.0.0.1:8000/protege-mcp.repository and run
Check for plugins.
The registry URL you put in Settings must be http(s) — Check for plugins does an
HttpURLConnectionHEAD on it first, so afile://registry root fails there with an uncaughtClassCastException(the action only catchesIOException, so it errors out rather than showing the normal “could not connect” dialog). Thedownload=URL inside the descriptor may befile://.
Version rules (so it actually shows up)
version is compared as an OSGi version. OSGi orders an empty qualifier before a non-empty
one, so 0.1.0 < 0.1.0.SNAPSHOT. Consequences:
- Installing into a Protégé that doesn’t have the plugin yet → it appears regardless of
version. - Updating over an already-installed build →
versionmust be strictly greater than the installed bundle version. Over a0.1.0.SNAPSHOTdev build, use e.g.0.1.1, not0.1.0; to ship an update over the released0.1.0, bumpupdate.propertiesversionand the bundle version together (e.g.0.1.1) and attach the new jar to a matching Release.
Or get it into the official list
To appear in everyone’s Protégé (the default registry), open a PR adding your update.properties
URL to update-info/5.0.0/plugins.repository in
protegeproject/autoupdate — same descriptor format
as above.