Customers looking to integrate Omnissa products with their AI agent of choice can use the new Omnissa MCP Server or their own custom MCP server. This article will demonstrate both approaches using Claude Desktop for Windows and a free Claude account from Anthropic, an accessible way to evaluate these MCP options in a lab. We'll start by reviewing the integration of the Omnissa MCP Server with the Claude Desktop client, then further extend our Claude-based management capabilities with a custom MCP server for an on-premises Horizon environment. Combined, these options enable customers to connect Claude across the Omnissa stack, extending Claude's agency to Omnissa management and observability. Though this article focuses on Claude, MCP is an open standard, so the strategies covered in this article should be adaptable to other MCP-capable AI clients like Gemini CLI or ChatGPT.
Omnissa MCP Server In Action
When the Omnissa MCP Server is properly configured for use with Claude Desktop you'll see a corresponding connector available within Claude's chat window.
To use the connector you can begin with a natural language query. For example:
Claude responds with query results against the Workspace ONE environment.
Here's an example of a follow-up question:
Most striking about my first experience working with the Omnissa MCP Server was how agentic the whole process was. I didn't have to understand how the Omnissa MCP Server works or what tools it has to offer. I simply asked Claude a question and it went on to determine which tool offered by the Omnissa MCP Server would be best to try. In fact, you can see Claude's agency at work when you expand the activity summary within the chat interface.
Claude chose the Intelligence QueryAI tool on its own, guided by the descriptions each tool advertises to the client. When the first query failed, it recalibrated, issued a second query and returned the answer.
Setting Up Access To Omnissa MCP Server For Claude Desktop
The Omnissa MCP Server has recently become available for a small subset of customers. Once access to Omnissa MCP Server has been granted to your organization within Omnissa Connect there are five major steps to enabling its integration with Claude Desktop. These steps are:
Assigning authentication and access control permissions within Omnissa Connect
Generating an MCP token for user-based authorization
Installing Claude Desktop
Installing Node.js
Adding an MCP server entry for the Omnissa MCP Server within your Claude Desktop config
The first two steps are well documented within the article, Getting Started with Omnissa MCP Server, so I'll let that documentation speak for itself. However, I will call out that when generating the MCP token you define RBAC controls that refine the scope of administrative access. This helps narrow the blast radius when leveraging the Omnissa MCP Server.
The token scope can only narrow your admin account’s existing permissions, never expand them. After defining the administrative scope and life span an MCP token is generated for you. You'll leverage this token, along with an Omnissa MCP Server URL, in the Claude Desktop config. To get Claude Desktop installed download the installer from https://claude.com/download. There you'll find the different versions of Claude Desktop available for various platforms. For this recipe I'm going with the Windows-based client. The install should be straightforward and uneventful.
Next, install Node.js. It provides npx, which Claude Desktop uses to launch mcp-remote, a small bridge that connects Claude Desktop’s locally launched servers to Omnissa’s remote HTTP endpoint. WinGet makes this easy:
winget install OpenJS.NodeJS.LTS
Close the PowerShell terminal, reopen it, then confirm that Node.js is installed by running node -v.
With the prerequisites in place, the last step is getting the Claude Desktop config, claude_desktop_config.json, edited with a JSON-based description for the Omnissa MCP Server. In Claude Desktop navigate to Settings --> Developer --> Edit config to open the folder containing the file.
Assuming no other MCP servers have already been configured, you'll need to add an entry like this to the config:
This tells Claude Desktop to use npx to launch mcp-remote, pointed at the Omnissa MCP Server URL and authenticated with your token. The MCP server URL would go where <mcp server url> is displayed above. The token goes where it displays [mcp-client-token] above. After making the edits close the Claude application and quit Claude from the system tray. Assuming everything goes well, when you launch Claude again and navigate to the Developer panel you’ll see the Omnissa-uem-mcp server as up and running.
For further confirmation, when you go to the chat window within Claude Desktop you should see that Omnissa MCP Server shows up as an available connector.
At this point you can start leveraging the Omnissa MCP Server in your chats within Claude Desktop, firing off natural language queries at will.
As to security concerns over having an access token embedded in a Claude Desktop config, yes, yes, I know. Both the getting started document and beta announcement indicate there'll be future support for OAuth, so that's likely going to be your long-term solution. In the short term you can limit risk with the token scope and by restricting the use of Omnissa MCP Server to lab or UAT environments. Otherwise, for a more secure approach you could attempt a different MCP server configuration, using some kind of custom wrapper that injects the MCP token securely at runtime. Along those lines, in the following guidance on creating your own custom MCP server, Windows Credential Manager is leveraged to avoid embedding credentials in a script or Claude Desktop config.
Vibe Coding Your Own MCP Server For Omnissa Horizon
The Omnissa MCP Server is impressive, but if you need functionality it doesn’t offer, you can build your own MCP server. I wanted to take more actions against an on-premises Horizon environment, so I had Claude create an MCP server in Python that leverages the Horizon Server API for monitoring and management. When prompting the creation of this script, I pointed Claude to the API documentation as well as a few other articles I've written, including No REST For The RESTful: Python And The Horizon Server API. Claude built a set of Python functions for the Horizon Server API, then exposed them as MCP tools using FastMCP from the official MCP Python SDK. The result is a Python-based MCP server that runs locally alongside Claude Desktop over stdio. You can find the script on GitHub.
A word of caution: this is my personal lab project, not an Omnissa-supported product. Review the code before running it, and point it at a lab first.
With this Python script in hand, the next steps to standing up the MCP server are:
Installing Python
Installing the required Python modules
Staging the Python script and required CA certificate if necessary
Storing Horizon credentials in Windows Credential Manager
Adding the server to your Claude Desktop config
To install Python, for convenience, you can lean on WinGet:
After the install completes, close the PowerShell terminal and reopen it. Python should now be available from the command line as well as pip for installing Python modules. To install the required Python modules you can issue these commands:
Next, we have to stage the Python script and any required CA root in the local directory at C:\mcp. Later when we configure the Claude Desktop config we'll point to this directory.
To keep credentials out of scripts and configs, the script uses the Python keyring module to pull credentials stored in Windows Credential Manager. So, before running our script, we need to populate Windows Credential Manager with credentials for the Horizon account (jj in my lab). For your environment, use a dedicated Horizon service account with only the roles you need. Store its password using the horizon_mcp_server.py script and its --set-password option.
The final step is configuring the Claude Desktop config to run this MCP server, a meticulous but short JSON configuration. Like the Omnissa MCP Server, the Horizon MCP server is configured as a JSON object, with properties like Python paths, Horizon server URL and trusted CA cert. Here’s what the configuration for my lab looks like:
After saving claude_desktop_config.json fully quit Claude, including from the system tray. Then launch the Claude Desktop app again. Hopefully, there are no error messages at launch. Under Settings --> Developer you should see something like this:
And now as we chat through Claude Desktop we have access to this new MCP server.
As with the Omnissa MCP Server, what stood out was how agentic the experience felt. I didn’t have to name a tool or an endpoint. I just asked:
Seconds later, the user was issued a message, and a minute after that, their session was disconnected.
Next, I asked: “Tell me the general health status of my Horizon environment and what needs to be fixed first.” Claude started with several calls to the Connection Server:
After doing these several checks, it summarized:
Hazaa! Getting a warning about the soon-to-expire SSL certificate was not something I anticipated in the response, but was a highly relevant thing for Claude to call out.
Troubleshooting
Claude Desktop is just as clear about MCP Servers failing as it is about them working. Should a configured Server fail to start, you get a very clear indication within the Developer window.
When running into challenges with setting up MCP Server my first steps were feeding screenshots and logs back into Claude. For deeper testing, the official MCP Inspector lets you connect to a server outside Claude, list its tools, and call them directly. For example, on this custom Horizon MCP server we could test the logic with:
This fired off a browser connection to the Inspector interface:
You can also point Inspector at the Omnissa MCP Server to confirm your token and URL work independently of Claude.
As you can see, the tools advertised for Omnissa MCP Server using Inspector match the tools description provided at the end of the article, Getting Started With Omnissa MCP Server.
BYOA - Bring Your Own Agency
The Omnissa MCP Server and custom MCP servers are complementary options allowing customers to leverage their AI agent of choice for Omnissa administration. The Omnissa MCP Server covers a lot of ground, particularly across Workspace ONE and Intelligence. Many customers will find that this Omnissa-provided solution meets their requirements. If it falls short in some regard, there's always an option to augment with a custom MCP server. Given how extensive and well documented the REST APIs are across the Omnissa stack and how capable AI coding assistants have become, custom MCP servers are well within reach. Regardless of whether you choose to use the Omnissa MCP Server or your own custom MCP server, you have the opportunity to bring your AI client of choice, and all its agentic goodness, to bear on your Omnissa environment.
In November of 2024 Omnissa introduced Tunnel Container, a container-based deployment option for Workspace ONE Tunnel that customers can easily run on their Linux distribution of choice. While most organizations will have a, "Linux guy," to build out their Linux hosts for production deployments, this article will review enough Linux administration for WS1 admins to get their hands dirty with Tunnel Container in a lab. To that end, I'll detail a deployment of Tunnel Container to AlmaLinux 10.1 from a macOS endpoint. Then, to highlight the solutions versatility, we'll pivot from this AlmaLinux deployment to an Ubuntu server 24.04 based deployment. First, for some helpful context, let's review what changes and what stays the same with this Tunnel Container option for Workspace ONE Tunnel.
What Changes?
Admins can deploy Tunnel Container to their Linux distribution of choice, so long as it's running Docker and is SSH accessible. It's a significant shift away from the Unified Access Gateway Appliance (UAG), the preferred Tunnel deployment mechanism for years now. UAG is a hardened Linux appliance, currently AlmaLinux based, that includes support for all Omnissa edge services. Though it's an incredibly robust and reliable solution, there are some drawbacks. It doesn't offer support for in-place upgrades, with version changes requiring the deployment of new virtual appliances and administrative access to vSphere infrastructure. Further, to maintain supportability, any modifications directly to the appliances system state isstrictly forbidden. So, no additional OS hardening is allowed and there's no support for installing additional agents. At the other end of the spectrum is Tunnel Container, a model where the Tunnel service is decoupled and abstracted away from the underlying OS using Docker, enabling customers to leverage whatever version of Linux is already standardized for their environments.
Unlike Unified Access Gateway, with Tunnel Container deployments we're no longer leveraging PowerShell, ini files and appliance images. Further, there's no dependencies on underlying hypervisors. Instead, we're leveraging the cross platform Tunnel CLI, dux, to deploy Tunnel Container, with dux being essentially a wrapper for Docker and other system calls. Based off configurations defined in a ts_manifiest.yaml file dux connects directly to the target Linux hosts via SSH to remotely stand up and configure the Tunnel gateway service. There's no need for WS1 admins to understand Docker or it's administration, with the dux cli handling this complexity on the admin's behalf.
Though Tunnel Container adoption introduces some interesting changes, as far as the WS1 Tunnel deployment as whole goes, lots of things stay exactly the same.
What Stays The Same?
Once deployed, Tunnel Container provides the same old Tunnel gateway service we've been working with for over a decade. The networking requirements are the same, save for port connectivity requirements required for dux administration. Communication and security between the end user devices and Tunnel service is exactly the same as it has been. Further, as with UAG based instances of Tunnel gateway, the Tunnel Container based service communicates with the UEM tenant through outbound 443 traffic to retrieve basic configuration instructions and status updates regarding trusted endpoints. Finally, as with UAG based deployments, there's Basic or Cascade Mode deployments to choose from.
Basic mode deployment with Tunnel Container
From the perspective of a WS1 admin solely working through the UEM console, there's absolutely no difference between a Tunnel gateway instance delivered through UAG or Tunnel Container. In fact, both a UAG based instance and Tunnel Container based instance of the Tunnel service can work side by side under the same Tunnel Configuration. With proper load balancing you can deploy Tunnel Container based instances of Tunnel to your existing environments then decommission UAG based instances without a downtime, a non-disruptive blue-green migration.
Tunnel Configuration within the WS1 UEM console
While Tunnel Container may seem rather exotic and new to traditional WS1 admins, most of their prior experience with Tunnel is still very relevant and germane. If I was introducing Tunnel Container to a Workspace ONE newbie, I'd say the most challenging thing about Tunnel Container isn't understanding container management, but getting up to speed on the way Workspace ONE Tunnel has functioned for nearly a decade and half now. On the other hand, if you're a grizzled WS1 admin that's worked for Tunnel for years, shoot, Tunnel Container adoption is going to be fairly straight forward and, at the risk of sounding really nerdy, pretty fun and interesting.
A Quick Demo Of The Deployment
Before walking through the nuts and bolts of a Tunnel Container deployment, here's a quick video demonstration of what it looks like.
Next, we'll walk through the setup requirements on AlamaLinux.
Preparing AlmaLinux 10.1 for Tunnel Container
Preparing AlmaLinux with the bare minimum requirements to host Tunnel Container boils down to 4 tasks: basic OS setup, SSH key setup, Docker installation and firewall configuration.
Basic OS Setup
After downloading the 10.1 iso from https://almalinux.org/get-almalinux/, I uploaded it to my vSphere environment. Then I created a new VM with the iso attached through the virtual CD/DVD drive.
Upon powering up there was an option to boot from the ISO and begin the installation.
Eventually, I found my way to the Installation Summary menu where I could go on to define key configuration for the OS setup.
The most involved steps were regarding networking and the configuration of the default ethernet controller. From the Installation Summary menu I clicked on, "Network and Hostname," then highlighted the default ethernet controller and clicked, "Configure." First, I disabled IPv6.
Then I navigated to IPv4 Settings and configured a static IP address along with other network settings.
Navigating back to the Installation Summary screen, I went with the option to enable the root account. Then, to simplify the administration required to support SSH sessions from dux, I enabled the option, "Allow root SSH login with password."
SSH Key Setup
After the OS install was complete, I confirmed I could login through SSH using the root account:
ssh root@10.0.0.190
In anticipation of Tunnel Container deployment requirements, from the macOS I intended to run dux from, I generated a SSH key using the following command:
At this point my SSH sessions started working against the AlmaLinux instance without requiring a password. While this automatic login using a ssh key is lovely in and of itself, it's critical to automation when deploying Tunnel Container through dux.
Docker Installation
The next step was to setup Docker on this Linux distribution. For that, I leaned on guidance from the article, How To Install Docker On Linux (AlamaLinux). Accordingly, I issued the following commands:
With the AlmaLinux instance setup and ready I proceeded to setup of dux on my macOS.
Setting Up dux for Command And Control
Dux is a cross platform command line interface for deploying Tunnel Container. It's currently supported on macOS, Windows or RHEL-based linux distributions like AlmaLinux, Rocky or CentOS. Further, if you have challenges with ssh connectivity you could install dux on the same server you're deploying Tunnel Container too. However, for my lab I leveraged macOS and the brew based install option detailed in the official Tunnel Container documentation. To install HomeBrew (brew) you can follow the instructions detailed on the HomeBrew home page.
A good way to test a successful install is the version command for dux:
dux version
To progress with the deployment the next step was to execute the dux init command to create a sample template, a ts_manifest.yml file that will define the Tunnel Container deployment.
dux init
The template is created within the dux directory created by the dux install. The directory path varies based on dux version and macOS type but is confirmed as part of the dux init execution.
After executing dux init, I navigated to /usr/local/var/opt/omnissa/dux and found the freshly created manifest file.
When executing deployments with dux, the dux utility will parse values from this YAML file and deploy Tunnel Container accordingly. This ts_manifest.yml file is very similar to the ini files traditionally used for UAG deployments.
Red Is The New Black And YAML Is The New INI
UAG appliances can be automatically deployed via PowerShell, an appliance ISO file and an ini configuration file. Tunnel Containers, on the other hand, are deployed through the dux cli, tunnel container image and ts_manifest.yml. In a nutshell, for UAG veterans, YAML is the new ini. Ts_manifest.yml is configured similarly to the UAG ini files, with settings like UEM instance, group ID, and authentication settings for the UEM tenant. However, since it's a container deployment model, there's no need to define configuration settings associated with standing up an appliance, like gateway addresses, DNS servers or subnet masks. For context, here's the ts_manifest.yml for the deployment demonstrated in the video above and detailed in the next section. I've pulled out all the comments to make it easier to understand.
As you can see, the configuration starts with some basic tenant info, in this case the UEM tenant URL and group_id. (As an alternative for using group_id, there's a more advanced option to use the tunnel_config_id for environments that support multiple Tunnel configurations in a single organization group.) Then for credentials to authenticate to the tenant with I'm leveraging the new OAuth option offered through Tunnel Container. This involves generating an OAuth client under Groups And Settings -> Configurations -> OAuth Client Management.
Under the tunnel_server parent key I've provided the name of the Tunnel Container image downloaded from Customer Connect and placed in the, "images," subdirectory of the dux folder at /usr/local/var/opt/omnissa/dux. As far as the ssh_login_credentials go, this section is based on the SSH key generation I performed when standing up AlmaLinux earlier. These credentials are required for dux to reach out to the target Linux instance and setup the container. The actual Linux host to connect to is specified under the host section, where I've provided the ip address of the Alma Linux instance while also defining it's server role as Basic by setting it to 0. Finally, I've enabled the option to run performance tuning script, generated by dux init, by setting the value of perf_tune to 1.
For more information on the configuration of ts_manifest.yml, there's the official documentation on Tunnel Container. Even more relevant are the comments included within ts_manifest.yml when it's first generated with dux init. While I pulled the comments out for this overview, they're very relevant and should be the first place to look for guidance.
Also, a bit of warning: YAML is unforgiving when it comes to indentation and spaces. Most folks I've talked to about this deployment model have been burnt by an extra space or a messed-up indentation. You can check for these types of challenges by using https://www.yamllint.com/. Also, the subheadings are critical. For example, I chased my tail around for a couple hours regarding OAuth configuration because while I had client_id, client_secret, and token_service_url configured properly, I had not uncommented the parent key, "oauth:" that proceeds these settings.
Deploying A Tunnel Instance Through dux
To get Tunnel Container delivered and configured on a Linux endpoint you leverage the dux deploy command. Before pushing the container out you can check that the manifest is correctly configured using the dry run -d option.
dux deploy -d
With a successful dry run, you can skip ahead to the actual deployment with confidence. To rid yourself of pesky yes prompts, you can leverage the -y option.
dux deploy -y
While the deploy command confirms a successful deployment, there's also a dux status option to confirm the current status of the container.
dux status
Also, for additional kicks you can ssh back into the AlmaLinux instance to confirm some changes. Right off the bat, there a couple nifty docker commands.
docker ps
docker images
You can also confirm the expected port is open on the endpoint. In the case of this deployment we're looking for port 8443. We can confirm this with:
ss -tulpn
Knowing for a fact that port 8443 is now open on the Linux host we can run a curl command against that port from the macOS endpoint.
curl -v telnet://10.0.0.190:8443
Next, we can validate network communication between the new Tunnel instance and WS1 UEM by logging into the WS1 UEM console and navigating to the Tunnel Configuration. From Tunnel Configuration page you can click on the option, "Test Connection"
While this, "Test Connection," option validates connectivity between the Tunnel gateway service and the UEM tenant, it doesn't confirm that the Tunnel gateway service will be accessible from endpoint devices attempting to reach out to the Tunnel hostname. So, theoretically, you could have a successful test connection but have a Tunnel hostname and port and that's not even accessible to the outside world. To test the accessibility of the tunnel host url to the outside world, we could rely on good old fashion telnet commands or network troubleshooting tools of choice to validate things like DNS or port connectivity from the outside world. Or there's my favorite option, a tool I built myself at troubleshoot.evengooder.com.
Troubleshoot.evengooder.com will not only confirm port connectivity from the outside world, but it will also report attributes from the ssl cert used on the VPN port Tunnel leverages. This SSL cert is pulled down from the WS1 UEM tenant to the Tunnel instance and has tell-tale attributes like an expected SSL thumbprint, expiration date and, "Acceptable Client Cert CA Name," which typically indicates the WS1 UEM tenant.
Dux is going to be your primary mechanism for monitoring, troubleshooting and lifecycle management. To see the command line options available, you can leverage the built in help function of dux.
Of all the commands, the dux status command is probably the most relevant one to start off with.
dux status -j
For collecting logs from the Tunnel gateway instances remotely, quite a nifty feature, there's the dux logs command.
dux logs
As you can see, it copies the logs directly to the machine your running dux on, a nice little improvement over how log collection is handled on UAG appliances.
Adopting This Process To Ubuntu Server 24.04 LTS
To show off the versatility of this solution I'm going to walk through the adoption of this process for Ubuntu. If we configure Ubuntu similarly to the AlmaLinux instance, there will be no need to change ts_manifest.yml at all. Like the AlmaLinux setup, I'd break down the Ubuntu setup process to 3 tasks: basic OS setup, ssh access and the Docker install.
Basic OS Setup
The version I'm leveraging is Ubuntu 24.04 LTS, downloaded from the Ubuntu website. After uploading the iso image to the vSphere data store I configured a VM to connect to the iso at power up. At boot up I was presented with an option to install Ubuntu Server.
For type of installation, I went with the default of Ubuntu Server.
I skipped the option to upgrade to Ubuntu Pro, then went on to configure the servers name and a user account name. I also went with the defaults for storage configuration. As with the AlmaLinux setup, one of the most involved actions during setup was the network configuration.
Next, I went with the option to Install OpenSSH server so that I would have the ability to ssh into the Ubuntu instance.
SSH Access
After the installation was complete, I logged in under the user account I created during the setup wizard. To keep things consistent with the AlmaLinux deployment, I decided to leverage the root account for dux's remote SSH sessions. To enable the root account, I set the password for root with:
sudo passwd root
Then, to provide the root account with ssh access, I made an edit to /etc/ssh/sshd_config, changing PermitRootLogin to yes.
At this point, I was successfully able to ssh into the Ubuntu instance as root using the ssh key.
Docker Setup
Fortunately, installing Docker on Ubuntu is really easy, especially when using the convenience script option detailed within the Docker documentation titled, Install Docker Engine on Ubuntu. With this option, the install boils down to two command lines:
At this point, I was good to go with a deployment using dux and the exact same ts_manifest.yml I leveraged for the AlmaLinux deployment. From the perspective of my dux host, the deployment looked exactly the same.
I Hate Change But This Model Is Pretty Damn Cool
I'm old, don't like change and, in fact, didn't like change even when I was young. So, leave my things alone and please don't mess with my things, and get off my lawn! When I first heard about Tunnel Container I curmudgeonly shrugged it off, while mumbling something about UAG being good enough. However, after working with Tunnel Container firsthand, I am now a believer. Yeah, there are definitely customers who may continue to stick with the UAG based deployment model for Tunnel. But for folks interested in advanced Tunnel features or the flexibility to use their Linux distribution of choice, there's little reason not to give Tunnel Containers a try.
Additional Resources
Here are some incredibly useful additional resources: