Skip to main content
Eptura Knowledge Center

Deploy AI Integration

AI Integration

Overview


The AI integration ships as two independent binaries built from one Go module, communicating over MCP Streamable HTTP:

  • mcp-server - a single-tenant, read-only MCP server. It exposes 69 read-only tools over Archibus/WebCentral data (space, maintenance/work requests, assets, people, move management, leases) and proxies every tool call to WebCentral's typed REST endpoints (/api/v1/mcp/...) using an OAuth2 client-credentials service account. It has no database and calls no LLM.
  • orchestrator - the AI host. It serves POST /api/v1/ai/query and POST /api/v1/ai/chat, which WebCentral's "Ask AI" drawer and work-request AI-summary feature call. It drives an agent loop against a configured LLM provider (Anthropic or Azure OpenAI) and is itself an MCP client of mcp-server - it never talks to WebCentral directly.

Neither service uses a database. Configuration is entirely environment variables; each service authenticates its single caller with one static bearer token.

These two services can run on the same host or two different hosts and the only requirement is that orchestrator can reach mcp-server over HTTP, and that WebCentral can reach orchestrator over HTTP.

clipboard_cc5f0822-53de-4573-b3ee-2c90e4d29a70.png

Contents

Prerequisites


Ensure the following are in place before starting:

  • A target host (or two) running Linux, macOS, or Windows, with network access to the WebCentral instance and outbound access to your chosen LLM provider (Anthropic or Azure OpenAI)
  • An Archibus/WebCentral OAuth2 service account (client ID + client secret) with a token endpoint, scoped for the webcentral-platform-mcp REST module (/api/v1/mcp/...). The token must include the archibus.mcp.read scope.
  • An LLM provider API key, such as Anthropic, or an Azure OpenAI endpoint + deployment
  • Administrative/elevated access on the target host, to install a systemd unit (Linux), a launchd daemon (macOS), or a Windows service via WinSW (Windows)

No Go toolchain, CGO, or external system libraries are required to run the services, and you only need Go/GoReleaser if you intend to build the release archives yourself rather than using a pre-built release.

Obtain and verify the release archives


Each tagged release produces, per binary, one archive per platform plus a single checksum manifest.

OS Arch Archive format
Linux amd64, arm64 .tar.gz (one archive per arch)
macOS universal (amd64 + arm64 in one binary) .tar.gz (single archive covers both Mac architectures)

Windows

amd64 .zip

That is 4 archives per binary (8 total), named like mcp-server_VERSION_OS_ARCH.tar.gz / orchestrator_VERSION_OS_ARCH.tar.gz, plus one checksums.txt covering all of them.

Each archive already bundles the README.md, .env.example, the deployment docs, and the full service-template tree for all 3 Operating Systems (OS) therefore you only need to pick out the template relevant to your platform.

Verify the checksum before installing

Verify every archive against checksums.txt before extracting or running it as this confirms the download completed correctly and wasn't tampered with in transit. Both files must be in the same directory.

Platform  Command

Linux

sha256sum -c checksums.txt --ignore-missing
macOS shasum -a 256 -c checksums.txt --ignore-missing
Windows (PowerShell)

Get-FileHash -Algorithm SHA256 .\ARCHIVE

compared against the matching line in checksums.txt

Windows (cmd)

certutil -hashfile ARCHIVE SHA256

compared against the matching line in checksums.txt

If a hash doesn't match: don't run the binary then re-download both files from the original source and check again.

Environment configuration


Both binaries are configured entirely from environment variables there is no config file and no database. Copy .env.example from the archive as a starting point for each service's env file.

mcp-server

Variable Required  Default Description

LISTEN_ADDR

No

:8085

HTTP listen address

MCP_INBOUND_TOKEN

Yes Static bearer the orchestrator must present on /mcp

ARCHIBUS_BASE_URL

Yes WebCentral base URL

ARCHIBUS_TOKEN_URL

Yes OAuth2 token endpoint

ARCHIBUS_CLIENT_ID

Yes Service-account client ID

ARCHIBUS_CLIENT_SECRET

Yes Service-account client secret

ARCHIBUS_AUDIENCE

No Optional OAuth2 audience parameter

LOG_FILE

No OS-specific, see section 6 Rotating log file path

LOG_MAX_SIZE_MB

No 100 Rotate once the active log file reaches this size (MB)

LOG_MAX_BACKUPS

No 5 Number of rotated log files to retain

LOG_MAX_AGE_DAYS

No 30 Delete rotated log files older than this

LOG_COMPRESS

No false gzip rotated log files

orchestrator

Variable Required Default Description

LISTEN_ADDR

No :8090 HTTP listen address

ORCH_INBOUND_TOKEN

Yes Static bearer WebCentral must present on the AI endpoints

MCP_SERVER_URL

Yes

Base URL of mcp-server e.g.

http://mcp-server-host:8085

MCP_OUTBOUND_TOKEN

Yes Bearer sent to mcp-server  must equal its MCP_INBOUND_TOKEN

LLM_PROVIDER

Yes anthropic or azure_openai

LLM_API_KEY

Yes Provider API key

LLM_ENDPOINT

Only for Azure Azure OpenAI endpoint (required when LLM_PROVIDER=azure_openai)

LLM_DEPLOYMENT

Only for Azure Azure deployment name (required when LLM_PROVIDER=azure_openai)

LLM_MODEL

No claude-sonnet-4-6 Model name

AGENT_MAX_ITER

No 8 Max agent-loop round-trips

LOG_FILE

No OS-specific, see section 6 Rotating log file path

LOG_MAX_SIZE_MB

No 100 Rotate when the active log file reaches this size (MB)

LOG_MAX_BACKUPS

No 5 Number of rotated log files to retain

LOG_MAX_AGE_DAYS

No 30 Delete rotated log files older than this

LOG_COMPRESS

No false gzip rotated log files

MCP_INBOUND_TOKEN (mcp-server) and MCP_OUTBOUND_TOKEN (orchestrator) must hold the same shared secret. Make sure to set both env files to one generated value. A binary started with required variables missing logs the full list of missing vars and exits non-zero, so a misconfiguration fails fast and visibly rather than starting in a broken state.

Generating token values for MCP_INBOUND_TOKEN / ORCH_INBOUND_TOKEN

MCP_INBOUND_TOKEN and ORCH_INBOUND_TOKEN are not issued by Archibus; they are opaque static bearer secrets the customer generates and assigns themselves, purely to authenticate calls between these two services and from Web Central. Any sufficiently long random string works; there is no token-issuing endpoint or format requirement to satisfy.

Two distinct secrets are needed:

  • One shared value for MCP_INBOUND_TOKEN (mcp-server) and MCP_OUTBOUND_TOKEN (orchestrator) - These two must be set to the exact same string.
  • A separate value for ORCH_INBOUND_TOKEN (orchestrator) - This is also what you set as WebCentral's ai.properties archibus.ai.apiKey (see Web Central Integration below).

Generate each one as a long random string (32 bytes / 256 bits of randomness is a reasonable minimum) using whatever tool is available on your platform:

Platform Command

Linux / macOS

openssl rand -hex 32
Windows (PowerShell) -join ((1..32 | ForEach-Object { "{0:x2}" -f (Get-Random -Maximum 256) }))

Any platform with Python 3

python3 -c "import secrets; print(secrets.token_hex(32))"

Paste the generated value straight into the relevant env file(s) with no surrounding whitespace or quotes. Treat these like any other credential: don't commit them to source control, and restrict read access on whichever env file, systemd EnvironmentFile=, launchd wrapper script, or WinSW service XML holds them to the service account and administrators only.

Install as an unattended background service


Both binaries are plain console executables with no built-in service/daemon code. Each platform's native service manager supervises the process (auto-start on boot, restart on crash). Service unit/plist/XML templates ship inside every release archive under service-templates/.

Linux — system

Templates: service-templates/linux/archibus-mcp-server.service, archibus-orchestrator.service.

  1. Extract the archive, for example. /opt/archibus-mcp-server/
  2. Create the service account referenced by the unit's User= (or edit it to an existing one), for example useradd --system --no-create-home archibus-mcp
  3. Write the env file the unit expects, for example, /etc/archibus-mcp-server/mcp-server.env (plain KEY=value lines, same variable names as .env.example). Repeat for the orchestrator's env file.
  4. Ensure the service account can write the log directory, either create /var/log/mcp-server and chown it to the service account, or set LOG_FILE in the env file to a path it already owns.
  5. Copy the unit files to /etc/systemd/system/, then reload the daemon and enable both units:
sudo systemctl daemon-reload
sudo systemctl enable --now archibus-mcp-server
sudo systemctl enable --now archibus-orchestrator
  1. systemctl gives boot-start and restart-on-failure (Restart=on-failure in the unit) for free. systemctl status archibus-mcp-server and journalctl -u archibus-mcp-server remain available even though the app also keeps its own file log.

Update: stop the service, replace the binary, start the service.

Uninstall: disable the service, remove the unit file, reload the daemon.

macOS — launchd

Templates:

  • service-templates/macos/ 
  • 2 plists (com.eptura.archibus-mcp-server.plist, com.eptura.archibus-orchestrator.plist)
  • 2 wrapper-script templates

The launchd plists have no equivalent of systemd's EnvironmentFile=, so each plist's ProgramArguments points at a small wrapper script that sources the env file and execs the real binary.

  1. Extract the archive, for example, /opt/archibus-mcp-server/
  2. Copy launch-mcp-server.sh.template to /opt/archibus-mcp-server/launch-mcp-server.sh (and the orchestrator counterpart), and mark both executable.
  3. Write the env files the wrapper scripts source (mcp-server.env, orchestrator.env).
  4. Choose daemon vs. agent: /Library/LaunchDaemons/ (system-wide, runs at boot with no user logged in, requires elevated access) is the right choice for an unattended server; ~/Library/LaunchAgents/ (per-user, no elevated access needed) only runs while that user is logged in.
  5. Copy the plist(s) into the chosen directory, then load both:
sudo launchctl load /Library/LaunchDaemons/com.eptura.archibus-mcp-server.plist
sudo launchctl load /Library/LaunchDaemons/com.eptura.archibus-orchestrator.plist

Note, drop the elevated-access prefix and use the LaunchAgents path for the per-user variant.

Update: unload, replace the binary, load again.

Uninstall: unload, then remove the plist.

Windows — WinSW

Templates:

  • service-templates/windows/mcp-server-service.xml, orchestrator-service.xml

Windows has no built-in systemd/launchd equivalent, so this uses WinSW which is a small, well-established wrapper for running an existing executable as a Windows Service. No in-binary Windows service code is required.

  1. Extract the archive to C:\archibus-mcp-server\
  2. Download WinSW's latest executable and rename it to archibus-mcp-server.exe (WinSW pairs a name.exe with a matching name.xml), placed next to mcp-server.exe. Repeat with archibus-orchestrator.exe next to orchestrator.exe.
  3. Copy mcp-server-service.xml to archibus-mcp-server.xml alongside the renamed WinSW exe (and the orchestrator counterpart), and fill in the env values in the XML.
  4. From an elevated prompt, install and start both services:
archibus-mcp-server.exe install
archibus-mcp-server.exe start
archibus-orchestrator.exe install
archibus-orchestrator.exe start
  1. Both services are now visible in services.msc, with onfailure-triggered restart configured in the XML. The XML deliberately disables WinSW's own log capture and the app writes its own rotating file log (see Logging configuration below); don't double-log.

Update: stop the service, replace the binary, start the service.

Uninstall: stop the service, then uninstall it.

Logging configuration


Both binaries share one logging implementation. They always write a rotating JSON log file, and additionally echo the same lines to stdout whenever the process has an interactive terminal attached. Running a binary by hand shows live output; running it as a service writes only to the file.

OS Default log path (when LOG_FILE is unset)

Linux

/var/log/<binary-name>/<binary-name>.log

macOS

/Library/Logs/<binary-name>/<binary-name>.log

Falls back to ~/Library/Logs/<binary-name>/<binary-name>.log if that directory isn't writable, e.g. an unprivileged run

Windows %ProgramData%\<binary-name>\logs\<binary-name>.log

Where:

<binary-name> is mcp-server or orchestrator and each logs to its own file even when both run on the same host.

Permissions:

Any account the service runs as (systemd User=, the launchd daemon/agent's owner, or the Windows service account) must be able to create/write that directory. If it cannot set the LOG_FILE explicitly to a path that the account owns, then for an explicit override, there is no silent fallback: an unwritable explicit path fails fast at startup with a clear error, so a misconfigured override is never masked. Note that macOS is the only platform with an automatic fallback, and only for the OS default path, never for an explicit override.

Verify logging is working by tailing the log path where it writes structured JSON lines; a JSON pretty-printer helps readability.

WebCentral integration


WebCentral's "Ask AI" drawer and WR-summary FAB call the orchestrator, proxied through /core/api/v1/ai/

When the orchestrator is running and reachable from the WebCentral host:

  1. In Web Central's ai.properties set the archibus.ai.baseUrl to the orchestrator's URL e.g. http://orchestrator-host:8090.
  2. Set the archibus.ai.apiKey to the orchestrator's ORCH_INBOUND_TOKEN value.

This is an operational configuration change only and no WebCentral code change is required.

Set the ai.properties values

Both properties live in a single file in the WebCentral project: WEB-INF/config/ai.properties. It ships with both keys present but empty:

# Base URL of the AI orchestrator service.
# Example: archibus.ai.baseUrl=http://localhost:8090
archibus.ai.baseUrl=
# Bearer token presented to the orchestrator on each request.
# Example: archibus.ai.apiKey=your-base64-token-here

Where:

Property Required Description

archibus.ai.baseUrl

Yes

Base URL of the running orchestrator instance, for example:

http://orchestrator-host:8090

Must be reachable from the WebCentral application server.

archibus.ai.apiKey

Yes Must equal the orchestrator's own ORCH_INBOUND_TOKEN value exactly (see Generate token values, above) and this is the bearer WebCentral presents on every call to /api/v1/ai/query and /api/v1/ai/chat

Verify the deployment


Each service exposes an unauthenticated liveness probe at /health on its listen port (mcp-server defaults to 8085, orchestrator to 8090); a healthy response is a JSON object with status ok.

Then confirm the 2 services can actually talk to each other and to Web Central by exercising the orchestrator's AI endpoint directly with an authenticated POST to /api/v1/ai/query, sending a simple free-form question in the request body and the ORCH_INBOUND_TOKEN as a bearer credential. A successful response looks like an answer field plus an iterations count.

Finally, confirm the version actually running matches what you deployed where both binaries log their version on startup and tail each service's log file per section 6 to confirm structured JSON lines are being written.

Troubleshooting


Below details common configuration issues.

Note that both binaries fail fast and log clearly on startup misconfiguration rather than starting in a half-working state. The log file (or console, if run interactively) is the first place to look for any of these.

Service won't start

Symptom

Likely cause

Fix

Process exits immediately; log shows a list of missing environment variables

One or more required vars weren't set in the env file the service reads

Check the exact var names logged against the tables in Environment configuration above. 

Cross-check the env file path referenced by the systemd unit / launchd wrapper script / WinSW XML to make sure it matches where you wrote it.

bind: address already in use

Another process (often a leftover manual run) already holds the configured LISTEN_ADDR port Find and stop the other process, or set LISTEN_ADDR to a free port on both this service and whatever calls it (MCP_SERVER_URL / WebCentral's ai.properties)

Fails at startup with a log-directory permission error, even though LOG_FILE was left unset.

The account the service runs as can't create the OS-default log directory (common for a non-root systemd User=, or a Windows service account without %ProgramData% write access)

Set LOG_FILE explicitly to a path that the account already owns (see Logging configuration above). 

macOS is the only OS with an automatic fallback for the default path, and only when LOG_FILE is unset.

Fails at startup with a log-directory permission error, and LOG_FILE was set explicitly.

The explicit path (or a parent directory) isn't writable by the service account and this never falls back silently, by design. Grant the service account write access to that path, or point LOG_FILE at a directory it already owns.

systemd shows the unit as "activating" then repeatedly restarting.

The binary is crashing on every start.

Usually a config error being masked by how fast systemd retries.

To see the actual startup error run:

journalctl -u archibus-mcp-server -n 50 (or run the orchestrator unit)  

Or run the binary by hand with the same env file sourced to see it directly on the console.

401 / authentication errors between the two services

Symptom

Likely cause

Fix

orchestrator logs 401s when calling mcp-server; tool calls in /api/v1/ai/query fail

MCP_OUTBOUND_TOKEN (orchestrator) doesn't match MCP_INBOUND_TOKEN (mcp-server) and these must be the exact same shared secret.

Compare both values byte-for-byte (watch for trailing whitespace/newlines picked up from copy-paste into an env file); restart both services after fixing.

WebCentral's "Ask AI" drawer / WR-summary FAB gets a 401 or doesn't respond.

The bearer WebCentral sends doesn't match the orchestrator's ORCH_INBOUND_TOKEN

Confirm WebCentral's ai.properties archibus.ai.apiKey equals the orchestrator's current ORCH_INBOUND_TOKEN and a value change on either side requires updating the other.

mcp-server can't reach WebCentral

Symptom

Likely cause

Fix

mcp-server logs OAuth2 token-fetch failures on startup or on each tool call.

ARCHIBUS_TOKEN_URL, ARCHIBUS_CLIENT_ID, or ARCHIBUS_CLIENT_SECRET is wrong, or the service account was disabled/rotated on the WebCentral side Re-verify the service account credentials directly against the token endpoint (e.g. with a manual OAuth2 client-credentials request) before assuming the binary's config is at fault.

Tool calls return 403/permission errors even though the OAuth2 token is obtained successfully.

The service account lacks the WebCentral role/permission needed for the webcentral-platform-mcp REST module (/api/v1/mcp/...) Have a WebCentral admin confirm the service account is scoped for that module

Tool calls hang or time out.

ARCHIBUS_BASE_URL points at an unreachable host, or a firewall/proxy between mcp-server and WebCentral is blocking the request.

Confirm network reachability from the mcp-server host to ARCHIBUS_BASE_URL independently (e.g. a simple HTTP request to a known WebCentral endpoint) before looking further into the binary's config.

orchestrator / LLM provider errors

Symptom

Likely cause

Fix

/api/v1/ai/query or /api/v1/ai/chat returns HTTP 502

The configured LLM provider call itself failed.

Invalid/expired LLM_API_KEY

Wrong LLM_ENDPOINT/LLM_DEPLOYMENT for Azure, or the provider is unreachable from this host.

Check the orchestrator's log for the underlying provider error (it's included in the log line even though the HTTP response body is generic); verify the key/endpoint/deployment directly against the provider's own tooling.

Startup fails citing missing Azure-specific configuration.

LLM_PROVIDER=azure_openai was set without also setting LLM_ENDPOINT and LLM_DEPLOYMENT, both are required only in that mode.

Set both, or switch LLM_PROVIDER to anthropic if that's the intended provider.

Answers are generic, ignore Archibus data, or the loop seems to give up early.

Usually not a config problem.

Check AGENT_MAX_ITER isn't set too low for the query's complexity, and confirm mcp-server itself is returning real data (see mcp-server cant' reach WebCentral above)

WebCentral integration issues

Symptom

Likely cause

Fix

"Ask AI" drawer or WR-summary FAB doesn't appear or errors immediately.

archibus.ai.baseUrl in ai.properties is wrong, unreachable from the WebCentral host, or missing the scheme/port.

From the WebCentral host, confirm you can reach <baseUrl>/health on the orchestrator; fix the URL and restart WebCentral's app server (properties changes usually require a restart to take effect).

Feature works intermittently or times out under load.

Network path between WebCentral and the orchestrator (or orchestrator and mcp-server) has latency/instability, or the LLM provider is rate-limiting.

Check each hop's own logs for timeouts; consider colocating the two services with WebCentral to remove a network hop.

General diagnostic steps

  1. Confirm both binaries are running the version you deployed and check the version line each logs on startup.
  2. Check each service's /health endpoint directly (see Verify the deployment above) to isolate whether a failure is in the service itself or in something calling it.
  3. Tail the rotating log file (see Logging configuration above) rather than relying on the service manager's own log capture. The app's own JSON log line provides more details than a generic "service failed" message from systemd/launchd/WinSW.
  4. Change one variable at a time and restart. The token mismatches, wrong URLs, and missing Azure-only variables account for the large majority of configuration issues seen in practice.