LSP4IJ provides a default user-defined language server template, stored in the templates folder.
This section explains how to structure a user-defined template for your language server.
template.json: describes the language server and file types.clientSettings.json: contains the client capabilities and options.initializationOptions.json: custom options passed during initialization.installer.json: defines how to check, install, and configure the server.settings.json: user-defined settings for the server.settings.schema.json: JSON Schema for validatingsettings.json.
If you have created a user-defined language server and want to share it with others, you can contribute it to the official template repository used by LSP4IJ. Follow the steps below to submit your contribution.
- Edit the
template.json
After exporting your language server, a folder will be generated containingtemplate.json.
- Add a unique
idto identify your language server. - Adjust the
programArgssection to support all relevant operating systems. - See the template descriptor section for more details.
- Submit a Pull Request
Add your language server template folder in the/templates/lspdirectory.
- Follow the structure of existing examples like
/templates/lsp/typescript-language-server.
- Write the Documentation
Provide documentation for your language server in the/docs/user-defined-lsfolder.
- Use existing docs as reference, for instance:
/docs/user-defined-ls/typescript-language-server.
- Reference it
Add your language server in theDefault template.
-
template.jsoncontains a uniqueidand correctprogramArgs - Template is placed under
/templates/lsp/<your-language-server-name> - Documentation is placed under
/docs/user-defined-ls/<your-language-server-name>.md - Template is listed in the Default template
- Pull Request includes only relevant files and follows the structure of existing examples
The template descriptor (template.json) is a JSON file used to define:
- the server ID and name
- the command to start the server
- the file type mappings
{
"id": "typescript-language-server",
"name": "TypeScript Language Server",
"programArgs": {
"default": "sh -c \"typescript-language-server --stdio\"",
"windows": "typescript-language-server.cmd --stdio"
},
"fileTypeMappings": [
{
"fileType": {
"name": "JavaScript"
},
"languageId": "javascript"
},
{
"fileType": {
"name": "JavaScript-React",
"patterns": ["*.jsx"]
},
"languageId": "javascriptreact"
},
{
"fileType": {
"name": "TypeScript",
"patterns": ["*.ts"]
},
"languageId": "typescript"
},
{
"fileType": {
"name": "TypeScript-React",
"patterns": ["*.tsx"]
},
"languageId": "typescriptreact"
}
]
}The installer descriptor (installer.json) is a JSON file used to:
checkthe current installation,runthe installation of the LSP/DAP server,- and optionally
configurethe start command once installation is complete.
It is used when:
- a user-defined language server must be installed (at creation time),
- or when the user decides to re-install it.
You can find a sample in the
.
It should follow this structure:
{
"id": "...",
"name": "...",
"check": {
// Declare tasks to check the installation...
},
"run": {
// Declare tasks to run the installation...
}
}check and run define starting tasks, which can trigger other tasks using the onFail or onSuccess keys.
LSP4IJ provides built-in tasks:
- exec to execute a command (e.g.,
npm install typescript-language-server), - download to retrieve a server from a given URL,
- configureServer to set the launch command based on the downloaded files.
To define custom tasks, you can contribute to the extension point com.redhat.devtools.lsp4ij.installerTaskFactory.
Typical task structure:
{
"id": "...",
"name": "...",
// custom keys depending on task type
"onFail": {
// Task to execute on failure
},
"onSuccess": {
// Task to execute on success
}
}Example using npm to install typescript-language-server:
{
"id": "typescript-language-server",
"name": "TypeScript Language Server",
"executeOnStartServer": false,
"properties": {
"workingDir" : "$USER_HOME$/.lsp4ij/typescript-language-server"
},
"check": {
"exec": {
"name": "Trying current command",
"command": "${server.command}",
"timeout": 2000
}
},
"run": {
"exec": {
"name": "Install TypeScript Language Server",
"workingDir": "${workingDir}",
"ignoreStderr": true,
"command": {
"windows": "npm.cmd install typescript-language-server typescript --force",
"default": "npm install typescript-language-server typescript --force"
},
"onSuccess": {
"configureServer": {
"name": "Configure TypeScript Language Server command",
"command": {
"windows": "${workingDir}/node_modules/.bin/typescript-language-server.cmd --stdio",
"default": "${workingDir}/node_modules/.bin/typescript-language-server --stdio"
},
"update": true
}
}
}
}
}Structure of a download task:
{
"download": {
"id": "...",
"name": "...",
"url": "...",
"output": {
"dir": "...",
"file": {
"name": "...",
"executable": true
}
},
"onFail": {},
"onSuccess": {}
}
}Example: downloading a JAR and configuring the start command
{
"id": "sdl-lsp",
"name": "sdl-lsp",
"check": {},
"run": {
"download": {
"name": "Download sdl-lsp",
"url": "https://oss.sonatype.org/.../sdl-lsp-1.0-20250503.111518-23-jar-with-dependencies.jar",
"output": {
"dir": "$USER_HOME$/.lsp4ij/lsp/sdl-lsp"
},
"onSuccess": {
"configureServer": {
"name": "Configure sdl-lsp server command",
"command": "java -jar ${output.dir}/${output.file.name}",
"update": true
}
}
}
}
}
configureServer.commandsupports variable substitution with${output.dir}and${output.file.name}. These values are resolved from theoutputobject of the precedingdownloadtask.
{
"download": {
"url": "<same URL for all OS>"
}
}{
"download": {
"url": {
"windows": "<windows URL>",
"default": "<linux/mac URL>"
}
}
}you can find a sample with clangd installer
{
"download": {
"url": {
"windows": {
"x86_64": "<URL for win x86_64>",
"x86": "<URL for win x86>"
},
"default": "<URL for linux/mac>"
}
}
}If DAP/LSP server can be downloaded from GitHub release like https://github.com/clojure-lsp/clojure-lsp/releases
you can use the github JSON object to download the proper asset:
{
"download": {
"github": {
"owner": "clojure-lsp",
"repository": "clojure-lsp",
"prerelease": false,
"asset": {
"windows": "clojure-lsp-native-windows-amd64.zip",
"unix": {
"amd64": "clojure-lsp-native-linux-amd64.zip",
"arm64": "clojure-lsp-native-linux-aarch64.zip"
},
"mac": {
"aarch64": "clojure-lsp-native-macos-aarch64.zip",
"amd64": "clojure-lsp-native-macos-amd64.zip"
}
}
}
}
}When download will occur, it will request https://api.github.com/repos/${owner}/${repository}/releases URL.
In the previous sample, URL requested will be https://api.github.com/repos/clojure-lsp/clojure-lsp/releases
It will take the first JSON asset which matches GitHub asset.name (by using the download.github.asset rule)
and will return the asset.browser_download_url.
owner(required) the github owner.repository(required) the github repository.prerelease(optional) can be used to select pre-release or not. By default,prereleaseis set to false.asset(required) is used to select the proper file to download. You can use*if asset to download contains some timestamp for instance.
{
"asset": "sdl-lsp-*-jar-with-dependencies.jar"
}If there is an asset per OS and with architecture, you can write:
{
"asset": {
"windows": "clojure-lsp-native-windows-amd64.zip",
"unix": {
"amd64": "clojure-lsp-native-linux-amd64.zip",
"arm64": "clojure-lsp-native-linux-aarch64.zip"
},
"mac": {
"aarch64": "clojure-lsp-native-macos-aarch64.zip",
"amd64": "clojure-lsp-native-macos-amd64.zip"
}
}
}Samples:
If the DAP/LSP server is published on Maven Central, you can use the maven object in your installer JSON to download the corresponding artifact:
{
"download": {
"name": "Download Camel Language Server",
"maven": {
"groupId": "com.github.camel-tooling",
"artifactId": "camel-lsp-server"
}
}
}When the download occurs:
- A request is made to the following Maven Central API endpoint to find the latest artifact:
https://search.maven.org/solrsearch/select?q=g:%22com.github.camel-tooling%22%20AND%20a:%22camel-lsp-server%22&rows=20&wt=json - The first result from the response is used to determine the latest available version.
- The download URL is then computed as:
https://repo1.maven.org/maven2/{groupId with slashes}/{artifactId}/{version}/{artifactId}-{version}.jar
For example, if the groupId is com.github.camel-tooling and the artifactId is camel-lsp-server, the computed download URL might be:
https://repo1.maven.org/maven2/com/github/camel-tooling/camel-lsp-server/1.5.0/camel-lsp-server-1.5.0.jar
Fields:
groupId(required): Maven group ID.artifactId(required): Maven artifact ID.
Sample:
You can customize the output directory and executable name:
{
"output": {
"dir": "$USER_HOME$/.lsp4ij/lsp/rust-analyzer",
"file": {
"name": {
"windows": "rust-analyzer.exe",
"unix": "rust-analyzer-aarch64-unknown-linux-gnu",
"mac": "rust-analyzer-aarch64-apple-darwin"
},
"executable": true
}
}
}dir: base folder where the downloaded file will be saved or extracted. The value is available as${output.dir}for use in other tasks.file.name: name of the executable file (registered as${output.file.name}).
Used to set the server launch command:
{
"configureServer": {
"name": "Configure sdl-lsp server command",
"command": "java -jar ${output.dir}/${output.file.name}",
"update": true
}
}