mcp-hs4
MCP server for controlling HomeSeer HS4 with safe, auditable, and guarded write operations.
README
mcp-hs4
Production-oriented MCP server for HomeSeer HS4.
This project provides MCP tools, resources, and prompts so MCP-compatible LLM agents can read and control HS4 safely with auditability, guarded writes, and local-sidecar deployment.
Start Here
- Install and build:
npm install
npm run build
- Configure environment:
cp .env.example .env
# set HS4_BASE_URL and any auth/guard settings needed for your installation
- Run server (production path):
node dist/index.js
- Optional development mode:
npm run dev
- Register in Codex CLI:
codex mcp add hs4 \
--env HS4_BASE_URL=http://127.0.0.1 \
--env HS4_REQUIRE_CONFIRM=true \
--env HS4_SAFE_MODE=read_write \
--env MCP_LOG_LEVEL=info \
-- node /absolute/path/to/mcp-hs4/dist/index.js
- Smoke test:
codex mcp list
codex mcp get hs4 --json
codex exec --skip-git-repo-check -C /absolute/path/to/mcp-hs4 \
"Use only hs4 MCP tools. Run hs4.selftest.run and summarize any warnings."
At a Glance
- Contract namespaces:
hs4.*,hs4.admin.* - Runtime: Node 20+, TypeScript
- Transports:
stdio(default),http(streamable MCP endpoint) - Safety defaults: confirm+intent+reason guardrails, dry-run-first intent tools, audit logging
- Write reliability: post-write verification with fallback logic in
hs4.devices.set
Architecture
MCP Client (Codex / Claude / Cursor / Cline)
-> MCP transport (stdio or HTTP)
mcp-hs4 server
-> HS4 JSON API (/JSON?request=...)
-> HS4 script route (/runscript.html)
HomeSeer HS4
Project Scope
- This repository is strictly the HomeSeer 4 MCP server implementation (
mcp-hs4). - Client-specific adapters, UIs, and app integrations belong in separate repositories.
- Public API contract in this repo is
hs4.*andhs4.admin.*.
Current Status
- Runtime: TypeScript/Node 20+
- MCP SDK:
@modelcontextprotocol/sdk - HS4 integration target: JSON API (
/JSON?request=...) plus script command path (/runscript.html) - Contract version:
1.0.0 - Deployment profiles:
stdiofor local MCP client process spawning (default),streamable-httpfor optional local LAN service mode
Implemented MCP Surface
Namespaces
hs4.*standard read and control operationshs4.admin.*privileged administration operations (disabled by default)
Tools
Registered tools are listed below. For release verification, confirm the runtime contract with hs4://capabilities/matrix.
Core tools:
hs4.health.geths4.help.routehs4.resolve.deviceshs4.resolve.eventshs4.resolve.camerashs4.change.preparehs4.change.commiths4.intent.device_set_by_namehs4.intent.event_run_by_namehs4.intent.scene_activatehs4.selftest.runhs4.devices.lisths4.devices.geths4.devices.controls.geths4.devices.status.geths4.devices.seths4.events.lisths4.events.geths4.events.definition.geths4.events.runhs4.scripts.runhs4.plugins.function.callhs4.plugins.lisths4.cameras.lisths4.cameras.snapshot.geths4.cameras.panhs4.audit.query
Admin tools:
hs4.admin.users.lisths4.admin.users.createhs4.admin.users.updatehs4.admin.users.deletehs4.admin.users.set_rolehs4.admin.plugins.catalog.geths4.admin.plugins.installhs4.admin.plugins.updatehs4.admin.plugins.removehs4.admin.plugins.set_enabledhs4.admin.plugins.restarths4.admin.interfaces.lisths4.admin.interfaces.addhs4.admin.interfaces.updatehs4.admin.interfaces.removehs4.admin.interfaces.restarths4.admin.interfaces.diagnosticshs4.admin.system.backup.starths4.admin.system.restore.starths4.admin.system.service.restarths4.admin.system.shutdownhs4.admin.system.config.geths4.admin.system.config.seths4.admin.cameras.config.lisths4.admin.cameras.config.createhs4.admin.cameras.config.updatehs4.admin.cameras.config.deletehs4.admin.cameras.stream_profile.seths4.admin.cameras.recording.seths4.admin.events.createhs4.admin.events.updatehs4.admin.events.deletehs4.admin.config.device_metadata.seths4.admin.config.categories.lisths4.admin.config.category.upserths4.admin.config.category.delete
Resources
hs4://devices/cataloghs4://devices/catalog/fullhs4://devices/statushs4://devices/status/fullhs4://events/cataloghs4://capabilities/matrixhs4://audit/recenths4://state/summaryhs4://catalog/aliaseshs4://agent/contracths4://admin/usershs4://admin/interfaceshs4://admin/pluginshs4://admin/cameras/confighs4://admin/policy/state(includes admin execution mode and related routing policy state)hs4://admin/audit/diff
Prompts
hs4_safe_controlhs4_scene_operatorhs4_diagnosticshs4_agent_contracths4_admin_change_controlhs4_admin_backup_restorehs4_admin_plugin_lifecycle
Guarded Write Model
Mutating tools are policy-gated by default.
Base guard requirements for all mutating tools:
confirm=truerequired (unless dry-run)intentandreasonrequired (unless dry-run)- Global read-only mode via
HS4_SAFE_MODE=read_only - Optional allowlists for device refs, event ids, script ids, camera ids, plugin functions
- Mutation attempts and outcomes are audit-logged
Admin tool guard model (hs4.admin.*):
- Inputs include
operationTier,domain,maintenanceWindowId,changeTicket, andriskLevel operationTiercurrently defaults tooperator- When
operationTier=admin, policy enforces: HS4_ADMIN_ENABLED=true- Domain-specific admin flag enabled for the selected domain
maintenanceWindowIdpresent (and matching configured allowlist/required id when set)changeTicketpresent whenHS4_ADMIN_REQUIRE_CHANGE_TICKET=true
Admin Execution Modes
Admin tools support three execution routing modes:
adapter(default): use adapter-backed admin execution paths first.direct: use direct HS4 admin execution paths.auto: try direct execution and cache unsupported operations so subsequent calls route straight to adapter.
Execution routing is controlled by:
HS4_ADMIN_EXECUTION_MODEdefault:adapterHS4_ADMIN_DIRECT_FALLBACKdefault:true(allow direct/auto paths to fall back to adapter when direct execution is unsupported)HS4_ADMIN_CAPABILITY_CACHE_TTL_SECdefault:300(cache TTL, in seconds, for unsupported direct-operation capability checks)
Production recommendation:
- Keep
HS4_ADMIN_EXECUTION_MODE=adapter,HS4_ADMIN_DIRECT_FALLBACK=true, andHS4_ADMIN_CAPABILITY_CACHE_TTL_SEC=300unless you have a validated operational reason to forcedirect. hs4://admin/policy/statereports the active admin execution mode and related routing policy state so operators can verify runtime behavior.
Two-phase mutation model (hs4.change.*):
hs4.change.preparevalidates and stages a mutation as a dry-run plan.hs4.change.commitexecutes the prepared token if policy checks still pass.- Prepared tokens are TTL-bound and can be persisted across restarts.
Device write reliability (hs4.devices.set):
- Default mutation mode is
control_value; useset_statusonly when explicitly required. verify=trueby default; writes are followed by targeted fresh-state readback.mode=set_statuswith a value may be auto-switched tocontrol_valuewhen control pairs indicate that path is safer.- If
set_statusdoes not converge, the server attempts a guardedcontrol_valuefallback when feasible. - Non-converged writes return
HS4_ERRORinstead of reporting a false success. - Successful write responses include convergence context (
requestedMode,mode,verification, optionalmodeAutoSwitch, optionalfallback). dryRun=truevalidates policy and schema only; it does not perform live write verification.
Resolver and intent targeting behavior:
hs4.resolve.devicesnow returnsrecommended=trueon the best mutation target and includesrecommendedRef.- For ambiguous parent/master vs endpoint matches, resolver ranking prefers actionable endpoints (for example child refs with control pairs) unless the query explicitly asks for
master,scene,parent, orroot. hs4.intent.device_set_by_nameand device-fallbackhs4.intent.scene_activateincluderesolutionmetadata and can emitwarningswith codePARENT_OR_WRAPPER_TARGETwhen a wrapper/master target is chosen while an endpoint alternative exists.hs4.intent.scene_activatesupports deterministic path control withpreferPath(auto,event,device_fallback).hs4.intent.scene_activatereturnsselectionmetadata (selectedPath,reason,topEventScore,topDeviceScore,eventMinScore) so clients can explain why an event or device fallback path was selected.
Actionable error contract (all tools):
- Every error includes:
code,message,retryable,fixHint,suggestedNextToolCalls. - Tool-specific context remains under
details.
Contract Naming
Tool names in this project follow the hs4.* and hs4.admin.* contract shown above.
Admin payload delta example
Standard script call:
{
"command": "my_script(arg1)",
"confirm": true,
"intent": "recover interface",
"reason": "operator request"
}
Admin mutation call:
{
"command": "my_script(arg1)",
"confirm": true,
"intent": "recover interface",
"reason": "operator request",
"operationTier": "admin",
"domain": "system",
"maintenanceWindowId": "MW-2026-02-23-02",
"changeTicket": "CHG-4821",
"riskLevel": "medium"
}
Detailed Setup and Client Integration
1) Install dependencies
npm install
2) Configure env
cp .env.example .env
# edit values as needed
3) Run in stdio mode (default)
npm run dev
Client Setup
This server is primarily designed to be used as an MCP stdio server (the client spawns node dist/index.js).
HTTP mode is optional and mainly useful when a client only supports streamable HTTP MCP.
Common stdio config pattern
- Command:
node - Args:
<absolute-path>/dist/index.js - Env: set
HS4_*andMCP_*variables (do not put credentials inHS4_BASE_URL)
Example environment values:
{
"HS4_BASE_URL": "http://127.0.0.1",
"HS4_REQUIRE_CONFIRM": "true",
"HS4_SAFE_MODE": "read_write",
"MCP_LOG_LEVEL": "info"
}
Codex CLI (recommended)
Register:
codex mcp add hs4 \
--env HS4_BASE_URL=http://127.0.0.1 \
--env HS4_REQUIRE_CONFIRM=true \
--env HS4_SAFE_MODE=read_write \
--env MCP_LOG_LEVEL=info \
-- node /absolute/path/to/mcp-hs4/dist/index.js
Verify registration:
codex mcp list
codex mcp get hs4 --json
Prompt-level test:
codex exec --skip-git-repo-check -C /absolute/path/to/mcp-hs4 \
"Use only hs4 MCP tools. Run hs4.selftest.run and summarize any warnings."
LLM Prompt Cookbook
Use these prompts as copy/paste starters for Codex or other MCP-capable agents. Device names shown here are examples; replace them with names from your own HS4 installation.
- Deterministic event-first scene activation
Use only hs4 MCP tools.
Objective: activate "movie time".
Workflow:
1) Dry-run `hs4.intent.scene_activate` with:
- objective: "movie time"
- preferPath: "event"
- execute: false
- dryRun: true
- confirm: true
- intent: "Activate movie time scene"
- reason: "Event-first deterministic scene activation"
2) If step 1 returns NOT_FOUND, run a second dry-run with preferPath: "device_fallback".
3) Execute only the successful path (`execute: true`, `dryRun: false`).
4) Report: `path`, `selection.selectedPath`, `selection.reason`, and any `warnings`.
- Deterministic device-fallback scene activation
Use only hs4 MCP tools.
Objective: activate "coffee bar" using direct device fallback.
Workflow:
1) Dry-run `hs4.intent.scene_activate` with:
- objective: "coffee bar"
- preferPath: "device_fallback"
- fallbackDeviceValue: 99
- execute: false
- dryRun: true
- confirm: true
- intent: "Direct device fallback activation"
- reason: "Prefer endpoint control over event path"
2) Execute the same call only if dry-run succeeds.
3) Return `selection` metadata and any `PARENT_OR_WRAPPER_TARGET` warnings.
- Endpoint-first light control (avoid wrapper/master ghost success)
Use only hs4 MCP tools.
Goal: turn on coffee bar and bar overhead to max.
Workflow:
1) Resolve candidates with `hs4.resolve.devices` for "coffee bar" and "bar overhead light", `includeEvidence=true`.
2) Choose each query's `recommendedRef` when available.
3) Write with `hs4.devices.set` using:
- mode: "control_value"
- value: 99
- verify: true
- confirm: true
- intent/reason filled
4) Immediately read back using `hs4.devices.get` (`includeControls=true`) for written refs.
5) Report per-ref: requested mode, applied mode, verification result, status, and value.
- Wrapper/master-safe intent flow
Use only hs4 MCP tools.
Goal: act on "bar overhead light master" safely.
Workflow:
1) Run `hs4.intent.device_set_by_name` dry-run with query "bar overhead light master", mode "control_value", value 99.
2) If warnings include code `PARENT_OR_WRAPPER_TARGET`, re-run dry-run using the warning `suggestedRef` with `hs4.devices.set`.
3) Execute only after the second dry-run confirms endpoint targeting.
4) Return both runs and explain which target was committed and why.
- Physical-state mismatch recovery prompt
Use only hs4 MCP tools.
User says: "HS4 reports on, but the light is physically off."
Workflow:
1) Read current state with `hs4.devices.get` (`includeControls=true`).
2) Apply recovery pulse with `hs4.devices.set` (`mode=control_value`, `value=0`, `verify=true`) then `value=99`, both with confirm/intent/reason.
3) Re-read state after each write.
4) If still mismatched, run `hs4.intent.scene_activate` dry-run with `preferPath=device_fallback`, then execute if clean.
5) Report exact tool outputs and where convergence failed or succeeded.
Claude Desktop
Add an MCP server entry (client UI/paths vary by OS and version; look for an MCP servers config section). Most installations accept a config shaped like:
{
"mcpServers": {
"hs4": {
"command": "node",
"args": ["/absolute/path/to/mcp-hs4/dist/index.js"],
"env": {
"HS4_BASE_URL": "http://127.0.0.1",
"HS4_REQUIRE_CONFIRM": "true",
"HS4_SAFE_MODE": "read_write",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Cursor
Cursor’s MCP UI/config evolves quickly; use the same stdio pattern:
- Add MCP server named
hs4 - Command
node - Args
.../dist/index.js - Env includes
HS4_BASE_URL,HS4_REQUIRE_CONFIRM,HS4_SAFE_MODE
Cline (VS Code)
Cline’s MCP settings also evolve; use the same stdio pattern:
- Add MCP server named
hs4 - Command
node - Args
.../dist/index.js - Env includes
HS4_BASE_URL,HS4_REQUIRE_CONFIRM,HS4_SAFE_MODE
4) Optional: run as HTTP MCP service
MCP_TRANSPORT=http MCP_HTTP_HOST=127.0.0.1 MCP_HTTP_PORT=7422 npm run dev
Health endpoint in HTTP mode:
curl http://127.0.0.1:7422/healthz
When exposing beyond loopback, set an auth token and include Authorization: Bearer <token> on POST /mcp (and /healthz unless disabled):
MCP_TRANSPORT=http \
MCP_HTTP_HOST=0.0.0.0 \
MCP_HTTP_ALLOW_NON_LOOPBACK=true \
MCP_HTTP_AUTH_TOKEN=replace-me \
npm run dev
HTTP Client Compatibility (JSON-only clients)
Some MCP clients send Accept: application/json only on POST /mcp.
MCP_HTTP_ACCEPT_MODE=compat(default) allows these clients.MCP_HTTP_ALLOW_JSON_ONLY=true(default) enables a compatibility fallback that still preserves streamable clients.MCP_HTTP_ACCEPT_MODE=strictenforces explicitapplication/jsonandtext/event-stream.
Compatibility probes:
# JSON-only client probe (should pass in compat mode)
curl -si -X POST http://127.0.0.1:7422/mcp \
-H 'content-type: application/json' \
-H 'accept: application/json' \
--data '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"diag","version":"0"}}}'
# Strict streamable probe
curl -si -X POST http://127.0.0.1:7422/mcp \
-H 'content-type: application/json' \
-H 'accept: application/json, text/event-stream' \
--data '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"diag","version":"0"}}}'
Token-protected probe:
curl -si -X POST http://127.0.0.1:7422/mcp \
-H 'content-type: application/json' \
-H 'accept: application/json' \
-H 'authorization: Bearer replace-me' \
--data '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"diag","version":"0"}}}'
Build and Test
npm run typecheck
npm run build
npm test
Environment Variables
See .env.example for complete list. Important ones:
HS4_BASE_URLdefault:http://127.0.0.1HS4_USER,HS4_PASSHS4_SAFE_MODEone ofread_write,read_onlyHS4_REQUIRE_CONFIRMdefault:trueHS4_MAX_DEVICES_DEFAULT_CAPdefault:250(global default cap for device-heavy reads)HS4_STATUS_CACHE_TTL_MSdefault:1500(0disables status cache)HS4_SCRIPT_PAGE_PATHdefault:/runscript.htmlHS4_EVENTS_DATA_PATHdefault:/usr/local/HomeSeer/Data/HomeSeerData_2.json/events.jsonHS4_EVENT_GROUPS_DATA_PATHdefault:/usr/local/HomeSeer/Data/HomeSeerData_2.json/eventgroups.jsonHS4_ALIAS_LEARNED_ENABLEDdefault:true(enable learned aliases for resolver tools)HS4_ALIAS_CONFIG_PATHoptional path to alias JSON (device:<ref>,event:<id>,camera:<id>keys)HS4_CHANGE_TOKEN_TTL_SECdefault:900HS4_CHANGE_TOKEN_MAX_ENTRIESdefault:2000HS4_CHANGE_TOKEN_PERSIST_PATHoptional JSONL persistence path for prepared tokensHS4_ALLOWED_DEVICE_REFS,HS4_ALLOWED_EVENT_IDS,HS4_ALLOWED_CAMERA_IDSHS4_ALLOWED_SCRIPTS(lower-case ids)HS4_ALLOWED_PLUGIN_FUNCTIONSinplugin:functionformat (lower-case)HS4_ADMIN_ENABLEDdefault:falseHS4_ADMIN_USERS_ENABLEDdefault:falseHS4_ADMIN_PLUGINS_ENABLEDdefault:falseHS4_ADMIN_INTERFACES_ENABLEDdefault:falseHS4_ADMIN_SYSTEM_ENABLEDdefault:falseHS4_ADMIN_CAMERAS_ENABLEDdefault:falseHS4_ADMIN_EVENTS_ENABLEDdefault:falseHS4_ADMIN_CONFIG_ENABLEDdefault:falseHS4_ADMIN_MAINTENANCE_WINDOW_IDoptional strict window idHS4_ADMIN_ALLOWED_MAINTENANCE_WINDOW_IDSoptional allowlistHS4_ADMIN_REQUIRE_CHANGE_TICKETdefault:trueHS4_ADMIN_ROLLBACK_ENABLEDdefault:trueHS4_ADMIN_EXECUTION_MODEone ofadapter,direct,auto(default:adapter)HS4_ADMIN_DIRECT_FALLBACKdefault:true(recommended in production to preserve guarded fallback to adapter when direct is unsupported)HS4_ADMIN_CAPABILITY_CACHE_TTL_SECdefault:300(admin routing capability cache TTL in seconds; keep non-zero in production)HS4_ADMIN_ALLOWED_USER_IDS,HS4_ADMIN_ALLOWED_PLUGIN_IDS,HS4_ADMIN_ALLOWED_INTERFACE_IDS,HS4_ADMIN_ALLOWED_CATEGORY_IDSMCP_TRANSPORTone ofstdio,httpMCP_HTTP_ALLOW_NON_LOOPBACKdefault:false(must betrueto intentionally bind non-loopback HTTP hosts)MCP_HTTP_ACCEPT_MODEone ofcompat,strict(default:compat)MCP_HTTP_ALLOW_JSON_ONLYdefault:true(json-onlyAcceptfallback in compat mode)MCP_HTTP_AUTH_TOKENoptional bearer token for HTTP auth (required for non-loopback whenMCP_HTTP_AUTH_REQUIRED_NON_LOOPBACK=true)MCP_HTTP_AUTH_REQUIRED_NON_LOOPBACKdefault:true(startup fails on non-loopback HTTP bind without token)MCP_HTTP_AUTH_PROTECT_HEALTHZdefault:true(health endpoint also requires bearer token when auth is enabled)MCP_AUDIT_PERSIST_PATH(optional JSONL audit sink)
HS4 Script Execution Note
hs4.scripts.run uses POST /runscript.html with:
action=run_script_commandscriptcommand=<command>
This behavior is based on HS4 UI implementation patterns in /usr/local/HomeSeer/html/runscript.html (path may vary by installation). It is powerful; use strict allowlists in production.
Documentation
- Research:
docs/01_research/ - Architecture:
docs/02_architecture/ - Operations and hardening:
docs/04_operations/ - Admin enhancements backlog:
docs/05_roadmap/admin_full_parity.txt
Project Policies
- Contribution guide:
CONTRIBUTING.md - Security policy:
SECURITY.md
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.