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.
- aiseg2_mcp-0.1.0/.env.example +15 -0
- aiseg2_mcp-0.1.0/.github/workflows/build.yml +53 -0
- aiseg2_mcp-0.1.0/.github/workflows/release.yml +150 -0
- aiseg2_mcp-0.1.0/.github/workflows/test.yml +19 -0
- aiseg2_mcp-0.1.0/.gitignore +8 -0
- aiseg2_mcp-0.1.0/.python-version +1 -0
- aiseg2_mcp-0.1.0/Dockerfile +41 -0
- aiseg2_mcp-0.1.0/LICENSE +21 -0
- aiseg2_mcp-0.1.0/PKG-INFO +146 -0
- aiseg2_mcp-0.1.0/README.ja.md +126 -0
- aiseg2_mcp-0.1.0/README.md +128 -0
- aiseg2_mcp-0.1.0/aiseg2_mcp/__init__.py +1 -0
- aiseg2_mcp-0.1.0/aiseg2_mcp/__main__.py +6 -0
- aiseg2_mcp-0.1.0/aiseg2_mcp/client.py +203 -0
- aiseg2_mcp-0.1.0/aiseg2_mcp/config.py +52 -0
- aiseg2_mcp-0.1.0/aiseg2_mcp/history.py +312 -0
- aiseg2_mcp-0.1.0/aiseg2_mcp/models.py +108 -0
- aiseg2_mcp-0.1.0/aiseg2_mcp/parsers.py +518 -0
- aiseg2_mcp-0.1.0/aiseg2_mcp/server.py +283 -0
- aiseg2_mcp-0.1.0/examples/remote/.env.example +18 -0
- aiseg2_mcp-0.1.0/examples/remote/README.ja.md +55 -0
- aiseg2_mcp-0.1.0/examples/remote/README.md +56 -0
- aiseg2_mcp-0.1.0/examples/remote/docker-compose.yml +65 -0
- aiseg2_mcp-0.1.0/k8s/base/aiseg2-mcp.yaml +216 -0
- aiseg2_mcp-0.1.0/k8s/base/kustomization.yaml +5 -0
- aiseg2_mcp-0.1.0/k8s/overlays/production/.argocd-source-aiseg2-mcp.yaml +3 -0
- aiseg2_mcp-0.1.0/k8s/overlays/production/kustomization.yaml +7 -0
- aiseg2_mcp-0.1.0/pyproject.toml +56 -0
- aiseg2_mcp-0.1.0/server.json +61 -0
- aiseg2_mcp-0.1.0/tests/conftest.py +36 -0
- aiseg2_mcp-0.1.0/tests/fixtures/electricflow_111.json +1 -0
- aiseg2_mcp-0.1.0/tests/fixtures/electricflow_1113_id1.html +183 -0
- aiseg2_mcp-0.1.0/tests/fixtures/electricflow_1113_id2.html +183 -0
- aiseg2_mcp-0.1.0/tests/fixtures/electricflow_1113_id3.html +183 -0
- aiseg2_mcp-0.1.0/tests/fixtures/electricflow_1113_id4.html +131 -0
- aiseg2_mcp-0.1.0/tests/fixtures/electricflow_1113_id5.html +131 -0
- aiseg2_mcp-0.1.0/tests/fixtures/empty_body_500.html +14 -0
- aiseg2_mcp-0.1.0/tests/fixtures/exectop2.html +2063 -0
- aiseg2_mcp-0.1.0/tests/fixtures/graph_51111.html +215 -0
- aiseg2_mcp-0.1.0/tests/fixtures/graph_52111.html +216 -0
- aiseg2_mcp-0.1.0/tests/fixtures/graph_53111.html +267 -0
- aiseg2_mcp-0.1.0/tests/fixtures/graph_54111.html +229 -0
- aiseg2_mcp-0.1.0/tests/fixtures/installation_734.html +289 -0
- aiseg2_mcp-0.1.0/tests/fixtures/sd_zip/30minhistory_rc_20260412.csv +49 -0
- aiseg2_mcp-0.1.0/tests/fixtures/sd_zip/co2.conf +0 -0
- aiseg2_mcp-0.1.0/tests/fixtures/sd_zip/daycost_rc_202507.csv +32 -0
- aiseg2_mcp-0.1.0/tests/fixtures/sd_zip/dayhistory_rc_202507.csv +32 -0
- aiseg2_mcp-0.1.0/tests/fixtures/sd_zip/hourhistory_rc_20260412.csv +25 -0
- aiseg2_mcp-0.1.0/tests/fixtures/sd_zip/monthcost_rc_2025.csv +13 -0
- aiseg2_mcp-0.1.0/tests/fixtures/sd_zip/monthhistory_rc_2025.csv +13 -0
- aiseg2_mcp-0.1.0/tests/fixtures/sd_zip/yearcost_total_rc.csv +12 -0
- aiseg2_mcp-0.1.0/tests/fixtures/sd_zip/yearhistory_total_rc.csv +12 -0
- aiseg2_mcp-0.1.0/tests/test_client.py +200 -0
- aiseg2_mcp-0.1.0/tests/test_history.py +263 -0
- aiseg2_mcp-0.1.0/tests/test_parsers.py +187 -0
- aiseg2_mcp-0.1.0/tests/test_server.py +91 -0
- aiseg2_mcp-0.1.0/tests/test_tools.py +72 -0
- 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 @@
|
|
|
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"]
|
aiseg2_mcp-0.1.0/LICENSE
ADDED
|
@@ -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)
|