aiseg2-mcp 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. aiseg2_mcp-0.1.0/.env.example +15 -0
  2. aiseg2_mcp-0.1.0/.github/workflows/build.yml +53 -0
  3. aiseg2_mcp-0.1.0/.github/workflows/release.yml +150 -0
  4. aiseg2_mcp-0.1.0/.github/workflows/test.yml +19 -0
  5. aiseg2_mcp-0.1.0/.gitignore +8 -0
  6. aiseg2_mcp-0.1.0/.python-version +1 -0
  7. aiseg2_mcp-0.1.0/Dockerfile +41 -0
  8. aiseg2_mcp-0.1.0/LICENSE +21 -0
  9. aiseg2_mcp-0.1.0/PKG-INFO +146 -0
  10. aiseg2_mcp-0.1.0/README.ja.md +126 -0
  11. aiseg2_mcp-0.1.0/README.md +128 -0
  12. aiseg2_mcp-0.1.0/aiseg2_mcp/__init__.py +1 -0
  13. aiseg2_mcp-0.1.0/aiseg2_mcp/__main__.py +6 -0
  14. aiseg2_mcp-0.1.0/aiseg2_mcp/client.py +203 -0
  15. aiseg2_mcp-0.1.0/aiseg2_mcp/config.py +52 -0
  16. aiseg2_mcp-0.1.0/aiseg2_mcp/history.py +312 -0
  17. aiseg2_mcp-0.1.0/aiseg2_mcp/models.py +108 -0
  18. aiseg2_mcp-0.1.0/aiseg2_mcp/parsers.py +518 -0
  19. aiseg2_mcp-0.1.0/aiseg2_mcp/server.py +283 -0
  20. aiseg2_mcp-0.1.0/examples/remote/.env.example +18 -0
  21. aiseg2_mcp-0.1.0/examples/remote/README.ja.md +55 -0
  22. aiseg2_mcp-0.1.0/examples/remote/README.md +56 -0
  23. aiseg2_mcp-0.1.0/examples/remote/docker-compose.yml +65 -0
  24. aiseg2_mcp-0.1.0/k8s/base/aiseg2-mcp.yaml +216 -0
  25. aiseg2_mcp-0.1.0/k8s/base/kustomization.yaml +5 -0
  26. aiseg2_mcp-0.1.0/k8s/overlays/production/.argocd-source-aiseg2-mcp.yaml +3 -0
  27. aiseg2_mcp-0.1.0/k8s/overlays/production/kustomization.yaml +7 -0
  28. aiseg2_mcp-0.1.0/pyproject.toml +56 -0
  29. aiseg2_mcp-0.1.0/server.json +61 -0
  30. aiseg2_mcp-0.1.0/tests/conftest.py +36 -0
  31. aiseg2_mcp-0.1.0/tests/fixtures/electricflow_111.json +1 -0
  32. aiseg2_mcp-0.1.0/tests/fixtures/electricflow_1113_id1.html +183 -0
  33. aiseg2_mcp-0.1.0/tests/fixtures/electricflow_1113_id2.html +183 -0
  34. aiseg2_mcp-0.1.0/tests/fixtures/electricflow_1113_id3.html +183 -0
  35. aiseg2_mcp-0.1.0/tests/fixtures/electricflow_1113_id4.html +131 -0
  36. aiseg2_mcp-0.1.0/tests/fixtures/electricflow_1113_id5.html +131 -0
  37. aiseg2_mcp-0.1.0/tests/fixtures/empty_body_500.html +14 -0
  38. aiseg2_mcp-0.1.0/tests/fixtures/exectop2.html +2063 -0
  39. aiseg2_mcp-0.1.0/tests/fixtures/graph_51111.html +215 -0
  40. aiseg2_mcp-0.1.0/tests/fixtures/graph_52111.html +216 -0
  41. aiseg2_mcp-0.1.0/tests/fixtures/graph_53111.html +267 -0
  42. aiseg2_mcp-0.1.0/tests/fixtures/graph_54111.html +229 -0
  43. aiseg2_mcp-0.1.0/tests/fixtures/installation_734.html +289 -0
  44. aiseg2_mcp-0.1.0/tests/fixtures/sd_zip/30minhistory_rc_20260412.csv +49 -0
  45. aiseg2_mcp-0.1.0/tests/fixtures/sd_zip/co2.conf +0 -0
  46. aiseg2_mcp-0.1.0/tests/fixtures/sd_zip/daycost_rc_202507.csv +32 -0
  47. aiseg2_mcp-0.1.0/tests/fixtures/sd_zip/dayhistory_rc_202507.csv +32 -0
  48. aiseg2_mcp-0.1.0/tests/fixtures/sd_zip/hourhistory_rc_20260412.csv +25 -0
  49. aiseg2_mcp-0.1.0/tests/fixtures/sd_zip/monthcost_rc_2025.csv +13 -0
  50. aiseg2_mcp-0.1.0/tests/fixtures/sd_zip/monthhistory_rc_2025.csv +13 -0
  51. aiseg2_mcp-0.1.0/tests/fixtures/sd_zip/yearcost_total_rc.csv +12 -0
  52. aiseg2_mcp-0.1.0/tests/fixtures/sd_zip/yearhistory_total_rc.csv +12 -0
  53. aiseg2_mcp-0.1.0/tests/test_client.py +200 -0
  54. aiseg2_mcp-0.1.0/tests/test_history.py +263 -0
  55. aiseg2_mcp-0.1.0/tests/test_parsers.py +187 -0
  56. aiseg2_mcp-0.1.0/tests/test_server.py +91 -0
  57. aiseg2_mcp-0.1.0/tests/test_tools.py +72 -0
  58. aiseg2_mcp-0.1.0/uv.lock +823 -0
@@ -0,0 +1,15 @@
1
+ # Local development env for aiseg2-mcp. Copy to .env and fill in. Never commit a real password.
2
+
3
+ # AiSEG2 controller base URL (http only — the device has no HTTPS).
4
+ AISEG_URL=http://192.168.0.216
5
+ # HTTP Digest password for the AiSEG2 web UI.
6
+ AISEG_PASSWORD=
7
+ # Optional overrides (defaults shown):
8
+ # AISEG_USER=aiseg
9
+ # AISEG_TRANSPORT=stdio # or streamable-http
10
+ # AISEG_HOST=0.0.0.0 # streamable-http bind host
11
+ # AISEG_PORT=8000 # streamable-http bind port
12
+ # AISEG_DISABLE_DNS_REBINDING_PROTECTION=false # true ONLY behind a trusted auth proxy
13
+ # AISEG_CACHE_DIR= # SD-card history cache dir (default: <tempdir>/aiseg2-mcp-cache)
14
+ # AISEG_CACHE_TTL=3600 # seconds to reuse a cached history export before re-downloading
15
+ # LOG_LEVEL=info
@@ -0,0 +1,53 @@
1
+ name: Build and Push
2
+
3
+ # Builds the MCP server image and pushes it to the Zot registry (fumo homelab delivery). ArgoCD
4
+ # Image Updater then detects the new 7-hex SHA tag and writes it back to the k8s overlay. This is
5
+ # independent of test.yml / release.yml (PyPI + GHCR public distribution). Excludes k8s/** on
6
+ # purpose: Image Updater writes the new tag into k8s/overlays/production/.argocd-source-*.yaml, so
7
+ # triggering on it would loop forever (writeback -> build -> new tag -> writeback -> ...).
8
+
9
+ on:
10
+ push:
11
+ branches: [main]
12
+ paths:
13
+ - 'aiseg2_mcp/**'
14
+ - 'pyproject.toml'
15
+ - 'uv.lock'
16
+ - 'Dockerfile'
17
+ - '.github/workflows/build.yml'
18
+ workflow_dispatch: {}
19
+
20
+ jobs:
21
+ build:
22
+ # GitHub-hosted arm64 native runner (no QEMU); the k3s cluster is all arm64.
23
+ runs-on: ubuntu-24.04-arm
24
+ steps:
25
+ - name: Checkout
26
+ uses: actions/checkout@v4
27
+
28
+ - name: Set up Docker Buildx
29
+ uses: docker/setup-buildx-action@v3
30
+
31
+ - name: Get image tag
32
+ id: tag
33
+ run: echo "tag=$(echo $GITHUB_SHA | cut -c1-7)" >> "$GITHUB_OUTPUT"
34
+
35
+ - name: Login to Zot registry
36
+ uses: docker/login-action@v3
37
+ with:
38
+ registry: registry.fumo.jp
39
+ username: ${{ secrets.ZOT_USERNAME }}
40
+ password: ${{ secrets.ZOT_PASSWORD }}
41
+
42
+ - name: Build and Push Docker image
43
+ uses: docker/build-push-action@v6
44
+ with:
45
+ context: .
46
+ file: Dockerfile
47
+ platforms: linux/arm64
48
+ push: true
49
+ tags: registry.fumo.jp/aiseg2-mcp:${{ steps.tag.outputs.tag }}
50
+ # type=gha lives in the same datacenter as the hosted runner; caches the slow uv sync
51
+ # dependency layer (the ephemeral runner throws away the Dockerfile --mount cache).
52
+ cache-from: type=gha,scope=aiseg2-mcp-deps
53
+ cache-to: type=gha,scope=aiseg2-mcp-deps,mode=max
@@ -0,0 +1,150 @@
1
+ name: Release
2
+
3
+ # Tag-driven release: publishes the PyPI package, the multi-arch GHCR image, and the MCP registry
4
+ # entry. Triggered by pushing a semver tag (e.g. v0.1.0).
5
+ #
6
+ # Prerequisite (one-time, human): configure PyPI Trusted Publishing for this workflow/environment
7
+ # so publish-pypi needs no API token. Until that is set up, do not push a release tag.
8
+ on:
9
+ push:
10
+ tags:
11
+ - 'v*.*.*'
12
+
13
+ env:
14
+ IMAGE: ghcr.io/chanyou0311/aiseg2-mcp
15
+
16
+ jobs:
17
+ test:
18
+ runs-on: ubuntu-24.04
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+ with:
22
+ fetch-depth: 0
23
+ fetch-tags: true
24
+ - uses: astral-sh/setup-uv@v5
25
+ - run: uv sync --locked
26
+ - run: uv run pytest -q
27
+
28
+ publish-pypi:
29
+ needs: test
30
+ runs-on: ubuntu-24.04
31
+ environment: pypi
32
+ permissions:
33
+ id-token: write # Trusted Publishing (OIDC); no API token needed
34
+ steps:
35
+ - uses: actions/checkout@v4
36
+ with:
37
+ fetch-depth: 0
38
+ fetch-tags: true # hatch-vcs derives the version from the tag
39
+ - uses: astral-sh/setup-uv@v5
40
+ - name: Build sdist + wheel
41
+ run: uv build
42
+ - name: Publish to PyPI
43
+ uses: pypa/gh-action-pypi-publish@release/v1
44
+
45
+ publish-ghcr:
46
+ needs: test
47
+ runs-on: ${{ matrix.runner }}
48
+ permissions:
49
+ contents: read
50
+ packages: write
51
+ strategy:
52
+ fail-fast: false
53
+ matrix:
54
+ include:
55
+ - runner: ubuntu-24.04
56
+ platform: linux/amd64
57
+ arch: amd64
58
+ - runner: ubuntu-24.04-arm
59
+ platform: linux/arm64
60
+ arch: arm64
61
+ steps:
62
+ - uses: actions/checkout@v4
63
+ - uses: docker/setup-buildx-action@v3
64
+ - name: Login to GHCR
65
+ uses: docker/login-action@v3
66
+ with:
67
+ registry: ghcr.io
68
+ username: ${{ github.actor }}
69
+ password: ${{ secrets.GITHUB_TOKEN }}
70
+ - name: Build and push by digest
71
+ id: build
72
+ uses: docker/build-push-action@v6
73
+ with:
74
+ context: .
75
+ platforms: ${{ matrix.platform }}
76
+ outputs: type=image,name=${{ env.IMAGE }},push-by-digest=true,name-canonical=true,push=true
77
+ - name: Export digest
78
+ run: |
79
+ mkdir -p /tmp/digests
80
+ digest="${{ steps.build.outputs.digest }}"
81
+ touch "/tmp/digests/${digest#sha256:}"
82
+ - name: Upload digest
83
+ uses: actions/upload-artifact@v4
84
+ with:
85
+ name: digests-${{ matrix.arch }}
86
+ path: /tmp/digests/*
87
+ if-no-files-found: error
88
+ retention-days: 1
89
+
90
+ merge-ghcr:
91
+ needs: publish-ghcr
92
+ runs-on: ubuntu-24.04
93
+ permissions:
94
+ contents: read
95
+ packages: write
96
+ steps:
97
+ - name: Download digests
98
+ uses: actions/download-artifact@v4
99
+ with:
100
+ path: /tmp/digests
101
+ pattern: digests-*
102
+ merge-multiple: true
103
+ - uses: docker/setup-buildx-action@v3
104
+ - name: Docker metadata (tags)
105
+ id: meta
106
+ uses: docker/metadata-action@v5
107
+ with:
108
+ images: ${{ env.IMAGE }}
109
+ tags: |
110
+ type=semver,pattern={{version}}
111
+ type=semver,pattern={{major}}.{{minor}}
112
+ type=raw,value=latest
113
+ - name: Login to GHCR
114
+ uses: docker/login-action@v3
115
+ with:
116
+ registry: ghcr.io
117
+ username: ${{ github.actor }}
118
+ password: ${{ secrets.GITHUB_TOKEN }}
119
+ - name: Create manifest list and push
120
+ working-directory: /tmp/digests
121
+ run: |
122
+ docker buildx imagetools create \
123
+ $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
124
+ $(printf '${{ env.IMAGE }}@sha256:%s ' *)
125
+ - name: Inspect
126
+ run: docker buildx imagetools inspect ${{ env.IMAGE }}:${{ steps.meta.outputs.version }}
127
+
128
+ publish-mcp-registry:
129
+ needs: [publish-pypi, merge-ghcr]
130
+ runs-on: ubuntu-24.04
131
+ permissions:
132
+ id-token: write # GitHub OIDC login to the MCP registry
133
+ contents: read
134
+ steps:
135
+ - uses: actions/checkout@v4
136
+ - name: Stamp version into server.json
137
+ run: |
138
+ VERSION="${GITHUB_REF_NAME#v}"
139
+ jq --arg v "$VERSION" '.version = $v | .packages |= map(.version = $v)' server.json > server.json.tmp
140
+ mv server.json.tmp server.json
141
+ - name: Install mcp-publisher
142
+ run: |
143
+ TAG=$(curl -sSL https://api.github.com/repos/modelcontextprotocol/registry/releases/latest | jq -r .tag_name)
144
+ VER="${TAG#v}"
145
+ curl -sSL "https://github.com/modelcontextprotocol/registry/releases/download/${TAG}/mcp-publisher_${VER}_linux_amd64.tar.gz" \
146
+ | tar xz mcp-publisher
147
+ - name: Login (GitHub OIDC)
148
+ run: ./mcp-publisher login github-oidc
149
+ - name: Publish to MCP registry
150
+ run: ./mcp-publisher publish
@@ -0,0 +1,19 @@
1
+ name: Test
2
+
3
+ # Runs the test suite (parser regressions + read-only tool-surface guards) on every push and PR.
4
+ on:
5
+ pull_request:
6
+ push:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-24.04
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+ - name: Set up uv
15
+ uses: astral-sh/setup-uv@v5
16
+ - name: Sync deps (locked)
17
+ run: uv sync --locked
18
+ - name: Run tests
19
+ run: uv run pytest -q
@@ -0,0 +1,8 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ .venv/
4
+ .env
5
+ .pytest_cache/
6
+ *.egg-info/
7
+ dist/
8
+ build/
@@ -0,0 +1 @@
1
+ 3.12
@@ -0,0 +1,41 @@
1
+ # Container image for the AiSEG2 MCP server. Two-stage uv build; the dependency layer caches until
2
+ # pyproject.toml / uv.lock change. Built from the repo root (context: .).
3
+ #
4
+ # The image defaults to the streamable-http transport because a container is normally run as a
5
+ # long-lived network service (behind an authenticating proxy). stdio users should instead run the
6
+ # published PyPI package with `uvx aiseg2-mcp`.
7
+ #
8
+ # Note: .git is not in the build context, so hatch-vcs falls back to version 0.0.0 inside the image
9
+ # (the real version is carried by the image tag). Pass SETUPTOOLS_SCM_PRETEND_VERSION at build time
10
+ # to override if an accurate __version__ is needed in the container.
11
+
12
+ # --- build stage -----------------------------------------------------------------------------
13
+ FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim AS build
14
+ WORKDIR /app
15
+ ENV UV_COMPILE_BYTECODE=1 \
16
+ UV_LINK_MODE=copy
17
+
18
+ # Dependency layer: manifests only, so it caches until deps change.
19
+ COPY pyproject.toml uv.lock ./
20
+ RUN --mount=type=cache,target=/root/.cache/uv \
21
+ uv sync --locked --no-dev --no-install-project
22
+
23
+ # Source layer: copy the package and install it into the venv.
24
+ COPY aiseg2_mcp/ aiseg2_mcp/
25
+ COPY README.md ./
26
+ RUN --mount=type=cache,target=/root/.cache/uv \
27
+ uv sync --locked --no-dev --no-editable
28
+
29
+ # --- runtime stage ---------------------------------------------------------------------------
30
+ FROM python:3.12-slim-bookworm
31
+ LABEL io.modelcontextprotocol.server.name="io.github.chanyou0311/aiseg2-mcp"
32
+ WORKDIR /app
33
+ COPY --from=build /app/.venv /app/.venv
34
+ ENV PATH="/app/.venv/bin:$PATH" \
35
+ AISEG_TRANSPORT=streamable-http
36
+ # Run unprivileged. USER must be NUMERIC: Kubernetes runAsNonRoot cannot verify a non-root user
37
+ # from a name and refuses to start the container, so reference the UID.
38
+ RUN useradd -u 10001 -m app
39
+ USER 10001
40
+ EXPOSE 8000
41
+ CMD ["python", "-m", "aiseg2_mcp"]
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 chanyou0311
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,146 @@
1
+ Metadata-Version: 2.4
2
+ Name: aiseg2-mcp
3
+ Version: 0.1.0
4
+ Summary: Unofficial read-only MCP server for the Panasonic AiSEG2 HEMS controller.
5
+ Project-URL: Homepage, https://github.com/chanyou0311/aiseg2-mcp
6
+ Project-URL: Repository, https://github.com/chanyou0311/aiseg2-mcp
7
+ Author: chanyou0311
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Keywords: aiseg2,hems,home-energy,mcp,panasonic
11
+ Requires-Python: >=3.12
12
+ Requires-Dist: httpx>=0.27
13
+ Requires-Dist: lxml>=5
14
+ Requires-Dist: mcp<2,>=1.28
15
+ Requires-Dist: pydantic-settings>=2
16
+ Requires-Dist: pydantic>=2
17
+ Description-Content-Type: text/markdown
18
+
19
+ <!-- mcp-name: io.github.chanyou0311/aiseg2-mcp -->
20
+
21
+ # aiseg2-mcp
22
+
23
+ 日本語版は [README.ja.md](./README.ja.md) をご覧ください。
24
+
25
+ An **unofficial, read-only** [Model Context Protocol](https://modelcontextprotocol.io) server for
26
+ the **Panasonic AiSEG2** home energy management (HEMS) controller. It lets an MCP client (e.g.
27
+ Claude) read your home's live power flow, per-circuit consumption, circuit names, and daily energy
28
+ totals from the AiSEG2's local web interface.
29
+
30
+ This project is not affiliated with or endorsed by Panasonic. "AiSEG" is a Panasonic trademark.
31
+
32
+ ## Verified environment
33
+
34
+ Developed and tested against:
35
+
36
+ - AiSEG2 model **MKN713** series
37
+ - Firmware **Ver.2.97I-01**
38
+
39
+ The AiSEG2 web interface is undocumented and changes between firmware revisions. **On a different
40
+ model or firmware the pages this server scrapes may differ and some tools may not work.** If you hit
41
+ a parse error, please open an issue with your model / firmware version.
42
+
43
+ ## Tools
44
+
45
+ All tools are **read-only** (annotated `readOnlyHint`, non-destructive). The server only issues
46
+ GETs and the display-only refresh POSTs the web UI itself uses; it never touches settings or any
47
+ `/action/` endpoint.
48
+
49
+ | Tool | Returns |
50
+ |---|---|
51
+ | `get_power_flow` | Instantaneous generation/consumption (kW), buy/sell state, battery status, generation sources, top consuming circuits |
52
+ | `get_circuit_breakdown` | Every measured circuit's instantaneous draw (W), ranked highest first, with the total |
53
+ | `list_circuits` | Registered circuit ids and names (the authoritative naming source) |
54
+ | `get_daily_totals` | Today's cumulative generation / consumption / grid-buy / grid-sell (kWh) |
55
+ | `get_history` | Long-term energy history from the SD-card export (Wh), long-form points. Args: `granularity` (`30min`/`hour`/`day`/`month`/`year`), `start`/`end` (per granularity: `YYYY-MM-DD`, `YYYY-MM`, or `YYYY`), optional `metrics`/`circuits` filters, `limit`/`offset` paging |
56
+ | `get_cost_history` | Long-term energy-cost history from the SD-card export (JPY). Args: `granularity` (`day`/`month`/`year`), `start`/`end`, `limit`/`offset` |
57
+
58
+ > **The two history tools require an SD card inserted in the AiSEG2** — they read the device's SD-card CSV export. The export is downloaded once and cached (see `AISEG_CACHE_DIR` / `AISEG_CACHE_TTL`), so the first call is slow and later calls are fast.
59
+
60
+ ## Install & run
61
+
62
+ Three ways to run it, depending on your setup.
63
+
64
+ ### 1. uvx (PyPI — once published)
65
+
66
+ The simplest option for a local (stdio) MCP client. Requires [uv](https://docs.astral.sh/uv/).
67
+
68
+ ```bash
69
+ AISEG_URL=http://192.168.0.216 AISEG_PASSWORD=... uvx aiseg2-mcp
70
+ ```
71
+
72
+ Add it to Claude Code:
73
+
74
+ ```bash
75
+ claude mcp add aiseg2 \
76
+ --env AISEG_URL=http://192.168.0.216 \
77
+ --env AISEG_PASSWORD=your-digest-password \
78
+ -- uvx aiseg2-mcp
79
+ ```
80
+
81
+ ### 2. docker run (GHCR)
82
+
83
+ The container defaults to the `streamable-http` transport (long-lived network service). Only expose
84
+ it behind an authenticating proxy — see [Security](#security).
85
+
86
+ ```bash
87
+ docker run --rm -p 8000:8000 \
88
+ -e AISEG_URL=http://192.168.0.216 \
89
+ -e AISEG_PASSWORD=your-digest-password \
90
+ ghcr.io/chanyou0311/aiseg2-mcp:latest
91
+ ```
92
+
93
+ ### 3. From source
94
+
95
+ Requires Python 3.12+ and uv.
96
+
97
+ ```bash
98
+ uv sync
99
+ AISEG_URL=http://192.168.0.216 AISEG_PASSWORD=... uv run aiseg2-mcp
100
+ ```
101
+
102
+ ### Remote (authenticated claude.ai Custom Connector)
103
+
104
+ To reach the server from claude.ai while your AiSEG2 stays on your LAN, see
105
+ [`examples/remote/`](./examples/remote/) — a Docker Compose stack (MCP + GitHub-OAuth proxy +
106
+ Cloudflare Tunnel).
107
+
108
+ ## Configuration (environment variables)
109
+
110
+ | Variable | Required | Default | Description |
111
+ |---|---|---|---|
112
+ | `AISEG_URL` | yes | — | AiSEG2 base URL, e.g. `http://192.168.0.216` (http only) |
113
+ | `AISEG_PASSWORD` | yes | — | HTTP Digest password for the AiSEG2 web UI |
114
+ | `AISEG_USER` | no | `aiseg` | HTTP Digest user |
115
+ | `AISEG_TRANSPORT` | no | `stdio` | `stdio` or `streamable-http` |
116
+ | `AISEG_HOST` | no | `0.0.0.0` | Bind host (streamable-http only) |
117
+ | `AISEG_PORT` | no | `8000` | Bind port (streamable-http only) |
118
+ | `AISEG_DISABLE_DNS_REBINDING_PROTECTION` | no | `false` | Disable the SDK Host allowlist — **only** behind a trusted auth proxy |
119
+ | `AISEG_CACHE_DIR` | no | `<tempdir>/aiseg2-mcp-cache` | Where the SD-card history export is cached |
120
+ | `AISEG_CACHE_TTL` | no | `3600` | Seconds to reuse a cached history export before re-downloading |
121
+ | `LOG_LEVEL` | no | `info` | Log level |
122
+
123
+ ## Security
124
+
125
+ - **LAN-only by design.** The AiSEG2 speaks plain HTTP with Digest auth; keep it and this server on
126
+ a trusted local network. The password is read from the environment and is never logged.
127
+ - **Read-only.** There is no tool that changes a device setting. The tool surface is enforced by
128
+ tests (registered-tool allowlist, tool-name guard, a source scan for `/action/`, and read-only
129
+ annotation checks).
130
+ - **Do not expose the `streamable-http` transport to untrusted networks without authentication.**
131
+ This server carries no auth of its own; if you run it as a network service, put an authenticating
132
+ reverse proxy in front of it. `AISEG_DISABLE_DNS_REBINDING_PROTECTION=true` is only appropriate in
133
+ that proxied setup.
134
+
135
+ ## Acknowledgements
136
+
137
+ The AiSEG2 web interface is undocumented; this project builds on the reverse-engineering knowledge
138
+ shared by prior work:
139
+
140
+ - [shimosyan/aiseg2-influxdb-forwarder](https://github.com/shimosyan/aiseg2-influxdb-forwarder) — the circuit-paging "repeat the last page" terminator and the electric-flow fields.
141
+ - [hiroaki0923/aiseg2-bridge](https://github.com/hiroaki0923/aiseg2-bridge) — endpoint and page structure.
142
+ - [Bugfire/aiseg_download](https://github.com/Bugfire/aiseg_download) — Digest auth and data-endpoint conventions.
143
+
144
+ ## License
145
+
146
+ [MIT](./LICENSE)
@@ -0,0 +1,126 @@
1
+ # aiseg2-mcp
2
+
3
+ English version: [README.md](./README.md)
4
+
5
+ Panasonic **AiSEG2**(HEMS コントローラー)を対象とした、**非公式・読み取り専用**の
6
+ [Model Context Protocol](https://modelcontextprotocol.io) サーバーです。MCP クライアント
7
+ (Claude など)から、AiSEG2 のローカル Web インターフェース経由で、自宅のリアルタイムな電力フロー・
8
+ 回路別消費電力・回路名・日次エネルギー総量を読み取れます。
9
+
10
+ 本プロジェクトは Panasonic とは無関係であり、Panasonic による承認・提携はありません。
11
+ 「AiSEG」は Panasonic の商標です。
12
+
13
+ ## 検証済み環境
14
+
15
+ 以下の環境で開発・動作確認しています。
16
+
17
+ - AiSEG2 機種: **MKN713** 系
18
+ - ファームウェア: **Ver.2.97I-01**
19
+
20
+ AiSEG2 の Web インターフェースは非公開で、ファームウェアの版により変化します。
21
+ **機種やファームウェアが異なると、本サーバーがスクレイプするページの構造が変わり、一部のツールが
22
+ 動作しない可能性があります。** パースエラーが出た場合は、機種・ファームウェア版を添えて issue を
23
+ 立ててください。
24
+
25
+ ## ツール一覧
26
+
27
+ すべて**読み取り専用**(`readOnlyHint`・非破壊のアノテーション付き)です。本サーバーは GET と、
28
+ Web UI 自身が画面更新に使う表示用 POST のみを発行し、設定変更や `/action/` 系エンドポイントには
29
+ 一切触れません。
30
+
31
+ | ツール | 返す内容 |
32
+ |---|---|
33
+ | `get_power_flow` | 瞬時の発電/消費(kW)、売買電の状態、蓄電池状態、発電内訳、消費上位回路 |
34
+ | `get_circuit_breakdown` | 計測回路ごとの瞬時消費電力(W)を降順で全件・合計付き |
35
+ | `list_circuits` | 登録された回路の id と名称(名称の正本) |
36
+ | `get_daily_totals` | 当日の発電/消費/買電/売電の積算(kWh) |
37
+ | `get_history` | SD カードエクスポートからの長期履歴(Wh)をロング形式で。引数: `granularity`(`30min`/`hour`/`day`/`month`/`year`)、`start`/`end`(粒度に応じ `YYYY-MM-DD` / `YYYY-MM` / `YYYY`)、任意の `metrics`/`circuits` フィルタ、`limit`/`offset` ページング |
38
+ | `get_cost_history` | SD カードエクスポートからの長期コスト履歴(円)。引数: `granularity`(`day`/`month`/`year`)、`start`/`end`、`limit`/`offset` |
39
+
40
+ > **履歴系 2 ツールは AiSEG2 に SD カードが挿入されている場合のみ動作する** — デバイスの SD カード CSV エクスポートを読む。エクスポートは 1 回だけダウンロードしてキャッシュする(`AISEG_CACHE_DIR` / `AISEG_CACHE_TTL` 参照)。初回呼び出しは遅く、以降は高速。
41
+
42
+ ## インストール・起動
43
+
44
+ 環境に応じて 3 通りの起動方法があります。
45
+
46
+ ### 1. uvx(PyPI 公開後)
47
+
48
+ ローカル(stdio)MCP クライアント向けの最も簡単な方法。[uv](https://docs.astral.sh/uv/) が必要です。
49
+
50
+ ```bash
51
+ AISEG_URL=http://192.168.0.216 AISEG_PASSWORD=... uvx aiseg2-mcp
52
+ ```
53
+
54
+ Claude Code に追加:
55
+
56
+ ```bash
57
+ claude mcp add aiseg2 \
58
+ --env AISEG_URL=http://192.168.0.216 \
59
+ --env AISEG_PASSWORD=your-digest-password \
60
+ -- uvx aiseg2-mcp
61
+ ```
62
+
63
+ ### 2. docker run(GHCR)
64
+
65
+ コンテナは既定で `streamable-http` トランスポート(常駐ネットワークサービス)になります。
66
+ 必ず認証付きプロキシの背後で公開してください([セキュリティ](#セキュリティ)参照)。
67
+
68
+ ```bash
69
+ docker run --rm -p 8000:8000 \
70
+ -e AISEG_URL=http://192.168.0.216 \
71
+ -e AISEG_PASSWORD=your-digest-password \
72
+ ghcr.io/chanyou0311/aiseg2-mcp:latest
73
+ ```
74
+
75
+ ### 3. ソースから
76
+
77
+ Python 3.12 以上と uv が必要です。
78
+
79
+ ```bash
80
+ uv sync
81
+ AISEG_URL=http://192.168.0.216 AISEG_PASSWORD=... uv run aiseg2-mcp
82
+ ```
83
+
84
+ ### リモート(認証付き claude.ai Custom Connector)
85
+
86
+ AiSEG2 を LAN 内に置いたまま claude.ai から接続するには、[`examples/remote/`](./examples/remote/)
87
+ を参照してください(MCP + GitHub OAuth プロキシ + Cloudflare Tunnel の Docker Compose 構成)。
88
+
89
+ ## 設定(環境変数)
90
+
91
+ | 変数 | 必須 | 既定値 | 説明 |
92
+ |---|---|---|---|
93
+ | `AISEG_URL` | はい | — | AiSEG2 のベース URL 例: `http://192.168.0.216`(http のみ) |
94
+ | `AISEG_PASSWORD` | はい | — | AiSEG2 Web UI の HTTP Digest パスワード |
95
+ | `AISEG_USER` | いいえ | `aiseg` | HTTP Digest ユーザー |
96
+ | `AISEG_TRANSPORT` | いいえ | `stdio` | `stdio` または `streamable-http` |
97
+ | `AISEG_HOST` | いいえ | `0.0.0.0` | バインドホスト(streamable-http のみ) |
98
+ | `AISEG_PORT` | いいえ | `8000` | バインドポート(streamable-http のみ) |
99
+ | `AISEG_DISABLE_DNS_REBINDING_PROTECTION` | いいえ | `false` | SDK の Host 許可リストを無効化。**信頼できる認証プロキシ配下でのみ** |
100
+ | `AISEG_CACHE_DIR` | いいえ | `<tempdir>/aiseg2-mcp-cache` | SD カード履歴エクスポートのキャッシュ先 |
101
+ | `AISEG_CACHE_TTL` | いいえ | `3600` | キャッシュした履歴エクスポートを再ダウンロードするまでの秒数 |
102
+ | `LOG_LEVEL` | いいえ | `info` | ログレベル |
103
+
104
+ ## セキュリティ
105
+
106
+ - **LAN 内利用が前提。** AiSEG2 は平文 HTTP + Digest 認証です。AiSEG2 と本サーバーは信頼できる
107
+ ローカルネットワーク内に置いてください。パスワードは環境変数から読み込み、ログには出力しません。
108
+ - **読み取り専用。** 設定を変更するツールは存在しません。ツール表面はテストで強制しています
109
+ (登録ツールの許可リスト、ツール名ガード、`/action/` のソース走査、読み取り専用アノテーション検査)。
110
+ - **`streamable-http` トランスポートを認証なしで信頼できないネットワークに公開しないでください。**
111
+ 本サーバー自身は認証を持ちません。ネットワークサービスとして動かす場合は、前段に認証付きリバース
112
+ プロキシを置いてください。`AISEG_DISABLE_DNS_REBINDING_PROTECTION=true` はそのプロキシ構成でのみ
113
+ 適切です。
114
+
115
+ ## 謝辞
116
+
117
+ AiSEG2 の Web インターフェースは非公開であり、本プロジェクトは先行するリバースエンジニアリングの
118
+ 知見に基づいています。
119
+
120
+ - [shimosyan/aiseg2-influxdb-forwarder](https://github.com/shimosyan/aiseg2-influxdb-forwarder) — 回路ページングの「前頁と同一で終端」判定、電力フローのフィールド。
121
+ - [hiroaki0923/aiseg2-bridge](https://github.com/hiroaki0923/aiseg2-bridge) — エンドポイントとページ構造。
122
+ - [Bugfire/aiseg_download](https://github.com/Bugfire/aiseg_download) — Digest 認証と data エンドポイントの流儀。
123
+
124
+ ## ライセンス
125
+
126
+ [MIT](./LICENSE)