Optional multi-portal mode: a single server can serve many customer portals,
selecting the active one at runtime, instead of running one server (and pasting one
token) per portal. With LM_MULTI_PORTAL=true the server no longer binds to a fixed
portal + token at startup — it loads a credential vault and switches portals on
demand, so the full tool set is registered once rather than per portal. Core LM tools
273 -> 277 (full surface 306). Single-portal behavior is unchanged.
Added
list_portals-- list the portals in the vault (name, host, auth type, writable).
Returns metadata only; never a token.use_portal-- make a portal active for subsequent tool calls (builds and caches a
LogicMonitor client per portal on demand).current_portal-- show the active portal.reload_portals-- re-read the vault so portals added/removed since startup take
effect without a client restart (keeps the active portal if it still exists).- New
portalsgrouping in search_tools and the tool-categories resource (not an
LM_MCP_CATEGORIEStoken; portal tools are exempt from category filtering in
multi-portal mode).
Behavior and safety
- Credentials load from an age-encrypted vault (
LM_VAULT_FILE+LM_AGE_KEY) or a
plaintext JSON file (LM_PORTALS_FILE, testing only) instead of the environment. - Read-only by default per portal: a write requires both
LM_ENABLE_WRITE_OPERATIONS=true
and"writable": trueon that portal's vault record (error codePORTAL_READ_ONLY). - Data tools return a clear "No portal selected" message until
use_portalis called. - Single-portal mode is preserved: without
LM_MULTI_PORTAL, a fixedLM_PORTALis
still required (fail-fast retained), and behavior matches previous releases.
Config
portalis now optional (multi-portal selects at runtime); addedmulti_portal,
vault_file,age_key, andportals_file. Authentication validation is skipped in
multi-portal mode;base_urlguards a missing portal.
Fixed (multi-portal hardening)
- Multi-portal mode is stdio-only: config construction rejects it with the HTTP
transport, whose process-global client would leak the active portal across
concurrent callers (this also removes the unreachable-healthyhealthzstate). - Portal tools are hidden and rejected outside multi-portal mode; a vault in the
environment can no longer repoint a single-portal server or bypass the per-portal
write gate. - Multi-portal config fails fast at startup when no vault source is configured;
vault paths expand~; the encrypted vault takes precedence over
LM_PORTALS_FILEwith a warning when both are set. - age failures surface stderr, a missing age binary gets a clear error, and
decryption has a 30s timeout. - Vault record hostnames are normalized like
LM_PORTAL(scheme stripped,
validated); one invalid record warns instead of breaking the vault. reload_portalsis atomic (a failed reload leaves the old registry, active
portal, and client intact) and closes replaced clients instead of leaking
connection pools; shutdown clears the global client reference.LM_MCP_CATEGORIESno longer filters out the portal tools in multi-portal mode
(the documented Cursor recipe previously made the mode unusable).search_tools,get_reference, andget_workflowwork before a portal is
selected.- Terraform tools return a clear unsupported error in multi-portal mode instead of
running with no credentials. portal_urldeep links use the active portal instead of emitting
https://None/...;ingest_urlguards a missing portal.- The write gate reports "No portal selected" before claiming a portal is
read-only; portal switches are recorded in session history and the write audit
log, and audit lines carry the active portal name. - Deploy scripts and MULTIPORTAL.md:
lm-mcp-add.shcreates the age identity on
first run (the referenced vault setup now exists), the launcher honors
LM_PORTALS_FILEand falls back to the published package when no clone is
present, hardcoded personal paths are gone, and the manual re-encrypt snippet
can no longer truncate the vault via an unset variable.