RouterOS LSP

RouterOS LSP is a language server that provides syntax highlighting, code completion, diagnostics, and other intelligent language features for RouterOS scripts (.rsc files) in most LSP-capable editors. By querying a live RouterOS device via the REST API, the LSP ensures syntax always matches your RouterOS version.
Supported Features
RouterOS LSP supports:
- Completion — code suggestions and tab completion
- Diagnostics — real-time syntax error reporting
- Semantic Tokens — syntax highlighting that matches RouterOS CLI colors
- Hover Information — help and variable inspection (Work in Progress)
- Document Symbols — navigate variables and commands (Work in Progress)
- References — find usages
- Definition Lookup — jump to definitions
- VSCode Commands — additional actions via Command Palette (VSCode only)
- Walkthrough — guided setup wizard (VSCode only)
The LSP activates automatically for .rsc files or when language is set to routeros. In most editors, you can manually set the file language to routeros to enable LSP features.
✅ RouterOS LSP requires a HTTP/REST connection to a RouterOS device. The LSP obtains all syntax data and command definitions by querying RouterOS's /console/inspect API.
⚠️ Without a RouterOS connection, the LSP cannot function. Credentials can be provided in editor's LSP configuration, see Configuration section.
𝌡 For known issues, changelog, and feature tracking, see CHANGELOG.md.
Installation
Visual Studio Code (VSCode)
Install RouterOS LSP from VSCode Marketplace
By selecting the "Install" button, you will be prompted by your browser to install the extension.
❤️ Also check out TikBook, which integrates with RouterOS LSP and adds a notebook interface for RouterOS scripts. Installing TikBook will automatically install RouterOS LSP, if missing.
Alternative VSCode Installation Methods
Install from within VSCode
- Open VSCode and go to Extensions (or press ⌘ + Shift + X on Mac, Ctrl + Shift + X on Windows/Linux)
- Search for "TIKOCI", and select "RouterOS LSP"
- Click Install
Install via VSIX File
If you prefer not to use the Marketplace, you can install from a VSIX file from [GitHub Releases](https://github.com/tikoci/lsp-routeros-ts/blob/HEAD/https:/github.com/tikoci/> lsp-routeros-ts/releases) and code --install-extension lsp-routeros-ts-*.vsix from Terminal. To remove, code --uninstall-extension tikoci.lsp-routeros-ts
Other Editors and LSP Clients
For editors other than VSCode, download the LSP server binary from GitHub Releases.

🛟 Limited testing has been done with NeoVim. Other LSP manager plugins are not tested. Contributions welcome!
NeoVim Install
Download the NeoVim LSP server for your platform from GitHub Releases and place it in ~/.bin/ (or adjust the path in step 3)
Edit your NeoVim init.lua (typically at ~/.config/nvim/init.lua) and add:
dofile(os.getenv('HOME') .. '/.config/nvim/nvim-routeros-lsp-init.lua')
Download nvim-routeros-lsp-init.lua to ~/.config/nvim/nvim-routeros-lsp-init.lua
Edit nvim-routeros-lsp-init.lua from GitHub Releases and set your RouterOS credentials and connection details at the top of the file. See NeoVim Configuration below for details.
On macOS only, If the downloaded server binary is blocked, remove the quarantine flag:
xattr -d com.apple.quarantine ~/.bin/lsp-routeros-server-darwin-arm64
Open a .rsc file in NeoVim and the LSP should load. You'll see a confirmation message at the bottom of the editor.
To trigger code completion, use Ctrl + Z followed by Ctrl + O (omni-complete) while in INSERT mode.
Configuration
All RouterOS LSP configuration is controlled through the LSP workspace/configuration capability. The following settings are available:
Properties
interface LspSettings {
baseUrl: string; // "http://192.168.88.1" or "https://router.lan"
username: string; // RouterOS user name
password: string; // RouterOS user password
apiTimeout: number; // Seconds to wait for RouterOS (default: 15)
allowClientProvidedCredentials: boolean; // Allow other extensions to override credentials (default: true)
checkCertificates: boolean; // Verify HTTPS certificates (default: false, ignored in VSCode Web)
}
RouterOS Connection Setup
For the LSP to function, the REST API must be enabled in your RouterOS device and accessible from your editor's computer. A valid RouterOS account must be provided to the RouterOS LSP as well (see Configuration section) .
Theoretically, you may not need any setup in RouterOS...as by default, HTTP is enabled on port 80, and reachable from default LAN; and, any RouterOS account (with sufficient rights, like admin with full rights) can be used in RouterOS LSP for login via REST API.
However, it recommended to use HTTPS with valid certificate, and an account with more limited rights to RouterOS configurations. For example, write policy is not required for core LSP operations since only /console/inspect data is read.
Enabling HTTPS with Let's Encrypt certificate
/certificate/enable-ssl-certificate
/ip/service enable www-ssl
🔐 When using HTTPS, your RouterOS's TLS certificate should be trusted by your system (installed in the system keychain/certificate store). Self-signed certificates are not directly supported by the LSP. Although in some editors, you can disable certificate checking, but this often complex and not recommended._
Creating a Limited RouterOS User
It's recommended to create a dedicated RouterOS user with minimal permissions for the LSP, rather than using a full admin account:
/user/group add name=lsp policy=read,api,rest-api
/user add name=lsp password=<strong-password> group=lsp
VS Code Settings
After installing, configure your RouterOS connection:
- Open Settings (press ⌘ + , on Mac or Ctrl + , on Windows/Linux)
- Go to Extensions > RouterOS LSP
- Set the following required fields:
- Base URL: Protocol and host (e.g.,
http://192.168.88.1 or https://my-router.local) — without trailing slash
- Username: RouterOS user with
read, api, and rest-api policy access
- Password: RouterOS user password
- API Timeout: How long (in seconds) to wait for RouterOS responses (default: 15 seconds)

Alternatively, use the Command Palette (⌘ + Shift + P on Mac or Ctrl + Shift + P on Windows/Linux), search for "RouterOS LSP: Show Settings", and select it. In VS Code's settings.json, all setting uses the routeroslsp.* prefix.
NeoVim Configuration
Edit the configuration section at the top of nvim-routeros-lsp-init.lua with your RouterOS connection details:
local settings = {
routeroslsp = {
baseUrl = "http://192.168.88.1", -- Change to your router or https://
username = "lsp", -- Change to your RouterOS user
password = "changeme", -- Change to your RouterOS password
hotlock = true
}
}
Also verify the platform is correct in the local lspexec variable. For example, on macOS with Apple Silicon:
local lspexec = { os.getenv("HOME") .. "/.bin/lsp-routeros-server-darwin-arm64", "--stdio" }
Adjust the filename for your platform: darwin-x64 (Intel Mac), linux-x64, linux-arm64, windows-x64.exe, etc.
Other LSP Clients
Other LSP clients should work if they support the workspace/configuration capability, which is the standard way LSP clients receive configuration. RouterOS connection settings must be provided somehow to the LSP client. Both NeoVim and VSCode support this; most modern LSP-capable editors do as well.
Troubleshooting
VS Code
Syntax Highlighting (Semantic Tokens)
RouterOS LSP uses semantic tokens for syntax highlighting that matches RouterOS CLI colors by default. If colors don't appear or seem incorrect:
- Open the Command Palette and search for "Refresh Semantic Tokens"
- Select RouterOS LSP: Refresh Semantic Tokens (Syntax Colors)
To customize token colors, use the Command Palette and select "Apply Semantic Color Overrides to Settings" to add token color mappings to your settings.json.
Check Output Logs
If the LSP doesn't work:
- Open the Output view: Shift + ⌘ + U (Mac) or Shift + Ctrl + U (Windows/Linux)
- Select "RouterOS LSP" from the dropdown to view detailed logs
- Check that your RouterOS credentials are correct and the device is accessible
- Use the Command Palette and select "RouterOS LSP: Test RouterOS Connection" to verify connectivity
Unicode and Character Encoding
For proper syntax checking and colorization, RouterOS LSP converts non-ASCII characters to underscores when querying RouterOS's /console/inspect API. This keeps character indexes aligned between RouterOS (Windows1252 encoding) and VSCode (UTF-16 internally), despite HTTP using UTF-8.
Important: Non-ASCII characters cannot appear in syntax elements (commands, paths, attributes); they can only appear in comments and strings. The LSP safely replaces them with underscores during syntax analysis without affecting the actual file content. Your script files preserve all encoding and are never modified by the LSP.
If syntax highlighting becomes misaligned with these characters, use "Refresh Semantic Tokens" command. If issues persist, please report them with the problematic script attached.
Visual Studio Code Specific Features

RouterOS LSP provides several commands accessible via the Command Palette (⌘ + Shift + P on Mac or Ctrl + Shift + P on Windows/Linux):
- Test RouterOS Connection — Verifies the LSP can successfully connect to RouterOS with current credentials
- Refresh Semantic Tokens (Syntax Colors) — Forces recalculation of semantic tokens for open documents
- Show Logs (Output) — Opens the Output pane and selects the RouterOS LSP log channel
- Show Settings — Opens RouterOS LSP extension settings
- Apply Semantic Color Overrides to Settings — Adds custom semantic token color mappings to
settings.json for further customization
Implementation and Development
The RouterOS LSP is built with Microsoft's vscode-languageserver-node library and can run on VSCode, NeoVim, or any LSP-capable editor.
Key Design: The LSP communicates with a running RouterOS device via its /console/inspect REST API. This means:
- Syntax definitions always match the connected RouterOS version
- New commands and attributes are available immediately after a RouterOS upgrade
- The LSP requires a live RouterOS device; it cannot work offline
Building from Source
All builds use Bun:
- Clone the repository:
git clone https://github.com/tikoci/lsp-routeros-ts.git
- Install dependencies:
bun install
- Build:
bun run compile
The compiled LSP server is available at ./server/dist/server.js and can be executed with Node.
Packaging Options
VSCode Extension (VSIX):
bun run vsix:package # Creates lsp-routeros-ts-*.vsix
code --install-extension lsp-routeros-ts-*.vsix
Standalone Server (for NeoVim and other editors):
bun run bun:exe # Creates lsp-routeros-server binary for your platform
cp ./lsp-routeros-server ~/.bin/
The standalone server supports these transport options:
--stdio — Standard input/output (used by NeoVim and most LSP clients)
--node-ipc — Node IPC (used by VSCode)
--socket=<port> — TCP socket (experimental)
Developing with VSCode
- Clone and open the repository in VSCode
- Run
bun run watch:node in a terminal to rebuild on changes
- Press F5 to launch the "Extension Development Host"
- Open a
.rsc file and test LSP features
For detailed extension debugging, see the VSCode Extension Debugging Guide.
Project Structure
Source:
client/src/ — VSCode extension client code
server/src/ — LSP server implementation
controller.ts — LSP protocol handler
server.ts — Main LSP entry point
model.ts — RouterOS data model
routeros.ts — RouterOS HTTP API client
Build Outputs:
client/dist/ — Compiled VSCode extension
server/dist/ — Compiled LSP server
lsp-routeros-server* — Standalone binaries (various platforms)
*.vsix — VSCode extension package
Developer Scripts
The LSP uses bun run scripts defined in package.json:
compile — Build all components
watch:node — Rebuild server on file changes
vsix:package — Package VSCode extension
bun:exe — Build standalone server binary
lint — Run ESLint on code
For new LSP features, add handlers to server/src/controller.ts. Refer to the LSP Protocol Specification for complete details.
ID Fields
In many places some "id" field is used, to clarify naming:
lsp-routeros-ts is generally used to refer to the entire project, the -ts refers that the LSP is implemented in TypeScript – as it possible to implement the LSP in other languages
lsp-routeros-server-* refers to just the actual LSP server code or build products
vscode-lsp-routeros refers to the VSCode-specific "language extension" that "binds" the LSP server with VSCode extension ecosystem, but largely "proxies" VSCode requests into the LSP server code.
routeroslsp is used when - is cannot be used for name, like configuration ("settings") and also the "server" package.json to ensure alignment with configuration.
Understanding LSP Protocol
There are a few dozen APIs that make up an LSP Server. The ones implemented by RouterOS LSP are listed at top of page. For a richer experience (i.e. more "help" from LSP in editor), additional protocols could be implemented. This section attempts to catalog from LSP protocol to implementation to "real features".
LSP Specification
The official LSP specification is what really defines possible language features:
- Go to Declaration
- Go to Definition
- Go to Type Definition
- Go to Implementation
- Find References
- Prepare Call Hierarchy
- Call Hierarchy Incoming Calls
- Call Hierarchy Outgoing Calls
- Prepare Type Hierarchy
- Type Hierarchy Super Types
- Type Hierarchy Sub Types
- Document Highlight
- Document Link
- Document Link Resolve
- Hover
- Code Lens
- Code Lens Refresh
- Folding Range
- Selection Range
- Document Symbols
- Semantic Tokens
- Inline Value
- Inline Value Refresh
- Inlay Hint
- Inlay Hint Resolve
- Inlay Hint Refresh
- Moniker
- Completion Proposals
- Completion Item Resolve
- Publish Diagnostics
- Pull Diagnostics
- Signature Help
- Code Action
- Code Action Resolve
- Document Color
- Color Presentation
- Formatting
- Range Formatting
- On type Formatting
- Rename
- Prepare Rename
- Linked Editing Range
The spec is pretty abstract, since LSP servers support a few transports, so
how to implement them depends on the library – but the list above gives the "full menu" of LSP language features.
langserver.org
https://langserver.org tracks supported protocols against LSPs, with an LSP "declaring" their support ("Implemented", "WIP", "Not implemented", "Not applicable"). Classifying RouterOS LSP in this scheme:
- ✅ Implemented - Code completion - could be improved but functional
- 💡 WIP* - Hover - only shows highlight "syntax" codes but does "something"
- 🚫 Not implemented - Jump to def - somewhat possible but need complex multi-step process and still be lossy and error prone
- ❓ WIP - Workspace symbols - semantic tokens supported, unsure if same
- 🚫 Not implemented - Find references - similar to "Jump to def"
- ✅ Implemented - Diagnostics - could be improved, but do flag the first error found
langserver.org also tracks "Additional capabilities" like
- Automatic dependency management -
Not applicable - Language servers that support this feature are able to resolve / install a project's 3rd-party dependencies without the need for a user to manually intervene.
- No arbitrary code execution -
Implemented - Language servers that support this feature don't execute arbitrary code (some language servers do this when running build scripts, analyzing the project, etc.).
- Tree View Protocol -
Not implemented - Language servers that support this feature are able to render tree views. See this link for more information.
- Decoration Protocol -
Not implemented - Language servers that support this feature are able to provide text to be displayed as "non-editable" text in the text editor. See this link for more information.
Microsoft's vscode-languageserver
The RouterOS LSP implementation uses Microsoft's vscode-languageserver Node library, and the documentation describes many of the LSP protocols and using with the library. The following tables is from the VSCode docs on Language Extensions, which gives a sense of the possibilities:
Microsoft Sample LSP Code
See https://github.com/microsoft/vscode-extension-sample, for example "Code Actions"
Implementation "Tips and Tricks"
Some various notes that are not obvious from docs or specific to RouterOS
Position vs Offset
The vscode-languageserver library provides a "position" generally, which is line and char position. But for programmatic use the "index" into an array with code is often more useful, this is called "offset" in the library. The "offset" is more useful with /console/inspect. To handle this, the TextDocument object supports an offsetAt() and positionAt() to enable conversion from the two forms.
/console/inspect request=syntax
Not currently used — but be useful. It's not used since it requires "tricks" to get useful information for completions and other things.
For example, to get useful data, stuff like a space or = may need to be added to input= — even though it does not exist in loaded script/config.
For now, just documenting how /console/inspect with request=syntax works in various cases:
"TEXT" in output could provide a "description" to some LSP data for a "dir"
> /console/inspect request=syntax input="/ip/route add"
Columns: TYPE, SYMBOL, SYMBOL-TYPE, NESTED, NONORM, TEXT
TYPE SYMBOL SYMBOL-TYPE NESTED NONORM TEXT
syntax collection 0 yes
syntax .. explanation 1 no go up to ip
syntax add explanation 1 no Create a new item
syntax check explanation 1 no
syntax comment explanation 1 no Set static route comment
syntax disable explanation 1 no Disable route
syntax edit explanation 1 no
syntax enable explanation 1 no Enable route
syntax export explanation 1 no Print or save an export script that can be used to restore configuration
syntax find explanation 1 no Find items by value
syntax get explanation 1 no Gets value of item's property
syntax print explanation 1 no Print values of item properties
syntax remove explanation 1 no Remove route
syntax reset explanation 1 no
syntax set explanation 1 no Change item properties
syntax unset explanation 1 no
> /console/inspect request=syntax input="/ip/route add "
Columns: TYPE, SYMBOL, SYMBOL-TYPE, NESTED, NONORM, TEXT
TYPE SYMBOL SYMBOL-TYPE N NON TEXT
syntax collection 0 yes
syntax blackhole explanation 1 no
syntax check-gateway explanation 1 no Whether all nexthops of this route are checking reachability of gateway by sending arp requests every 10 seconds
syntax comment explanation 1 no Short description of the item
syntax copy-from explanation 1 no Item number
syntax disabled explanation 1 no Defines whether item is ignored or used
syntax distance explanation 1 no Administrative distance of the route
syntax dst-address explanation 1 no Destination address
syntax gateway explanation 1 no
syntax pref-src explanation 1 no
syntax routing-table explanation 1 no
syntax scope explanation 1 no
syntax suppress-hw-offload explanation 1 no
syntax target-scope explanation 1 no
syntax vrf-interface explanation 1 no
> /console/inspect request=syntax input="/ip/route add check-gateway="
Columns: TYPE, SYMBOL, SYMBOL-TYPE, NESTED, NONORM, TEXT
TYPE SYMBOL SYMBOL-TYPE NESTED NONORM TEXT
syntax CheckGateway definition 0 no
syntax definition 1 no arp | none | ping
The issue here being the TEXT is not always well-formed – why request=completion is used to retrieve value like above.
Like for num types there is an expression that shows the range allowed:
> /console/inspect request=syntax input="/ip/service set port="
Columns: TYPE, SYMBOL, SYMBOL-TYPE, NESTED, NONORM, TEXT
TYPE SYMBOL SYMBOL-TYPE NESTED NONORM TEXT
syntax Port definition 0 no Num
syntax Num definition 1 no 1..65535 (integer number)
Point being the format of TEXT varies a good bit – and requires parsing to make it actionable in LSP - and all without any documentation on /console/inspect.
Disclaimers
Not affiliated, associated, authorized, endorsed by, or in any way officially connected with MikroTik
Any trademarks and/or copyrights remain the property of their respective holders unless specifically noted otherwise.
Use of a term in this document should not be regarded as affecting the validity of any trademark or service mark. Naming of particular products or brands should not be seen as endorsements.
MikroTik is a trademark of Mikrotikls SIA.
Apple and macOS are trademarks of Apple Inc., registered in the U.S. and other countries and regions. UNIX is a registered trademark of The Open Group.
No liability can be accepted. No representation or warranty of any kind, express or implied, regarding the accuracy, adequacy, validity, reliability, availability, or completeness of any information is offered. Use the concepts, code, examples, and other content at your own risk. There may be errors and inaccuracies, that may of course be damaging to your system. Although this is highly unlikely, you should proceed with caution. The author(s) do not accept any responsibility for any damage incurred.