homeassistant-ai/ha-mcp

Configure and automate Home Assistant with Claude, ChatGPT, and other AI assistants.

Python★ 6,124+31 that day#7 on trending

Analyzed November 10, 2026 at ceb8bed (master) with jscpd v5 in 5.6s.

D48.6/100
Project health800,353 lines of code (L)
Duplication63
5.7% in python, javascript, astro, bash, docker, typescript, powershell
Dead code43
9.2%
Complexity43
61.6%

The score is jscpd's own --health model: markup, data and text left out, tests kept. The numbers below are the trending scan's.

5.52%duplicated code · 19,525 of 353,877 lines
948clones in code
907code files of 2,269 scanned
6.72%duplicated over all files · 3,199 clones

The code number leaves out tests, fixtures, docs, examples, data files, styles, translations and vendored code, and 3 generated files: src/ha_mcp/_vendor/mcp_types/_v2025_11_25/__init__.py, src/ha_mcp/_vendor/mcp_types/_v2026_07_28/__init__.py, src/ha_mcp/settings_ui/settings_js/05_feature_flags.js.

Largest clones in the code

  • 714 lines in 2 placespython4,040 tokens
    1"""ha_auth-mode OAuth indirection in front of Home Assistant core.
    2
    3The proxy-owned authorize and token routes keep client endpoint caches stable
    4while Home Assistant core remains the authorization server. This module also
    5validates cross-origin Client ID Metadata Documents before translating their
    6client identities into the same-origin form accepted by core.
    7
    8MIRROR: this module is the near-verbatim twin of
    9``custom_components/ha_mcp_tools/oauth_ha_auth.py``. Keep behavioural changes
    10on the two sides in step. This pair has exactly TWO intended deltas. The
    

    First 10 of 714 lines.

  • 361 lines in 2 placespython2,058 tokens
    396HEARTBEAT_FILE = Path("/config/.mcp_proxy_dev_heartbeat")
    397_HEARTBEAT_MAX_AGE = 90.0  # three missed 30-second touches
    398# Only the NEGATIVE verdict is cached (#2218 review): a clean shutdown deletes
    399# the heartbeat file but cannot clear a cache in the integration process, so a
    400# cached True would keep the surface serving after the stop. A fresh stat per
    401# request while alive is microseconds in the executor; the cache exists so an
    402# anonymous flood against a STOPPED install does not stat per request.
    403#
    404# The lease MUST stay shorter than start.py's `_probe_oauth_active` delay
    405# (2 s between 3 attempts): that probe drives a DESTRUCTIVE path — it tears
    

    First 10 of 361 lines.

  • 333 lines in 2 placespython2,050 tokens
    269def __init__(self, hass: HomeAssistant) -> None:
    270    """Bind the view to the HA instance; liveness is resolved per request."""
    271    self._hass = hass
    272
    273async def get(self, request: web.Request) -> web.Response:
    274    """Dispatch an authorization request to the currently active mode."""
    275    if not await _addon_alive(self._hass):
    276        return _json_not_found()
    277    data = _domain_data(self._hass)
    278    if data is None:
    

    First 10 of 333 lines.

7 more
Largest clones over all files, tests and data included
By format, code only
FormatFilesLinesClonesDuplicated linesDuplication
python834335,13289218,7625.6%
html122,9333743914.97%
javascript2710,431122582.47%
typescript114144327.73%
css527733412.27%
astro123,917000%
bash5603000%
powershell1170000%
By format, all files
FormatFilesLinesClonesDuplicated linesDuplication
python1,840779,4322,87444,8205.75%
yaml14823,6892046,01925.41%
html122,9333743914.97%
markdown7627,747327,31226.35%
javascript4516,347304232.59%
json5828,39854391.55%
css71,7194422.44%
typescript114144327.73%
docker628636020.98%
bash311,4662120.82%

Trending appearances

DayRankStarsFilesLinesClonesAll filesCodeHealthCommit
Nov 10, 2026#76,124 (+31)2,269888,3273,1996.72%5.52%D 48.6ceb8bed

Want this for your own project? Install jscpd and run jscpd ., or measure it the way the baselines were measured.