Sign inSign up

msget/msget-app

By msget

•Updated 12 days ago

Image
0

1.1K

msget/msget-app repository overview

⁠MSGET

MSGET gives OpenClaw-compatible apps, MCP tools, and Hermes Agent access to Apple messaging through a service you host. Use the browser dashboard for account setup, Apple activation, and interface settings.

Messages pass between your deployment and Apple, not through MSGET's hosted services. Those services handle account access and activation.

Website⁠ · Image tags⁠ · Broker image⁠ · Dashboard image⁠

MSGET is available only as these container images.

Using an agent to set this up? See Setup guide for agents⁠.

⁠Quick start

You need:

  • Docker Engine 28.0 or later with Docker Compose 2.35 or later and Linux containers, or Podman with podman compose (see the Podman note below). The core mounts the dashboard image, which needs image mounts.
  • An MSGET account with activation access.
  • Your Apple Account and its verification method.
  • Internet access to Apple and MSGET's hosted services.

This example runs on your computer. On a server, use the same file and see Remote access⁠.

⁠1. Configure

MSGET runs two containers. The core, msget/msget-app, stores your data and talks to Apple. The broker, msget/msget-broker, stores nothing. It makes a fixed set of calls to MSGET's account and relay services for the core over the Unix socket /run/msget-ipc/broker.sock, on the shared msget-ipc volume. It cannot read /state, listens on no network port, and accepts only the core's user (UID 65532). It takes no arguments. Keep both images on the same version.

The browser dashboard is a third image, msget/msget-dashboard⁠. It contains only the dashboard files and serves linux/amd64 and linux/arm64 hosts alike. Do not run it as a container or add it as a third service. The core mounts it read-only at /usr/share/msget/dashboard and checks every file at startup. If the dashboard does not support the core's version, the core stops with a dashboard packaging error. The latest tags of the three images work together.

Save the following as compose.yaml:

services:
  msget:
    image: msget/msget-app:latest
    restart: unless-stopped
    user: "65532:65532" # Keep as written: required for the broker connection and your saved data.
    group_add:
      - "65534" # Keep as written: required for sign-in and activation through the broker.
    ports:
      - "127.0.0.1:8739:8739"
    volumes:
      - msget-state:/state
      - msget-ipc:/run/msget-ipc
      - type: image # Keep as written: the browser dashboard, read-only.
        source: msget/msget-dashboard:latest
        target: /usr/share/msget/dashboard
    networks:
      - msget-core
    depends_on:
      - msget-broker

  msget-broker:
    image: msget/msget-broker:latest
    restart: unless-stopped
    user: "65533:65534" # Keep as written: the broker's own user; it cannot read your saved data.
    read_only: true # Keep as written: the broker saves nothing and needs no writable files.
    cap_drop:
      - ALL # Keep as written: the broker needs no extra system permissions.
    volumes:
      - msget-ipc:/run/msget-ipc
    networks:
      - msget-broker

volumes:
  msget-state:
  msget-ipc:

networks:
  msget-core:
  msget-broker:

depends_on only sets start order. If the broker is not ready, sign-in or activation may report unavailable. Retry the step.

The host needs normal outbound internet access and system DNS that returns real answers:

  • Core: TCP 80 to init-p01st.push.apple.com, TCP 5223 to *.push.apple.com, and TCP 443 to Apple services.
  • Broker: TCP 443 to auth.msget.app and relay.msget.app.

MSGET has no proxy settings. It does not support hosts that force traffic through an intercepting proxy (including some managed bot VMs), fake-IP DNS, or 443-only egress.

This is the Standard setup. For the Docker-only Strong setup, which also blocks direct core access to MSGET's services at the host firewall, see apps/deployment/docs/network-isolation.md.

For rootless Podman, separate network names may not isolate the networks. Add this as compose.podman.yaml:

networks:
  msget-core:
    driver_opts:
      isolate: "strict"
  msget-broker:
    driver_opts:
      isolate: "strict"

Start with podman compose -f compose.yaml -f compose.podman.yaml up -d.

  • Use Podman and Netavark versions that enforce isolate=strict (checked with Podman 5.8.7 and Netavark 1.17.2). Some older releases accept it without enforcing it. Run the broker-namespace probes in apps/deployment/docs/network-isolation.md; if a probe reaches the dashboard, the setup is not isolated.
  • Keep user: and group_add: as written. Rootless Podman maps them into your user namespace. Your account needs subuid and subgid ranges of at least 65536 each, the usual default.
  • Prefer named volumes. For bind mounts, use :U or a compatible keep-id mapping so 65532:65532 can write /state and 65533:65534 can write /run/msget-ipc.
  • For autostart, use loginctl enable-linger "$USER" with a user systemd service, convert both services to Quadlet units, or run rootful Podman under systemd.
  • Your compose provider must pass the type: image volume to Podman (checked with Podman 5.8.9 and podman-compose 1.6.0). Without the mount, the core stops with a dashboard packaging error.
  • Do not add fixed bridge names or subnets. Those are only for Docker Strong; there is no Podman Strong setup.

Keep 127.0.0.1 in host port mappings for local use. A mapping without it, such as 8739:8739, or one using 0.0.0.0, is reachable from other machines. Use that only for remote access, with firewall and access controls. MSGET listens on 0.0.0.0:8739 inside the container so Docker can forward it; the host mapping sets who can reach it.

No environment variables are needed. Settings, including log level (off, error, warn, info, debug, or trace; default info), are in the dashboard. Only the owner can change the log level. The broker's optional MSGET_BROKER_EXTRA_ROOT_CA_FILE is only for traffic capture; see apps/deployment/docs/traffic-capture.md.

⁠2. Start

From the folder with compose.yaml, run:

docker compose up -d
docker compose ps

When both are running, open http://localhost:8739⁠. If setup does not open, see Troubleshooting⁠.

⁠3. Activate and connect

In the browser:

  1. Run docker compose logs msget, then enter the setup code in the dashboard. Keep it secret: that browser can claim the deployment for 30 minutes. Restarting msget replaces the code and cancels unused grants.
  2. Sign in to your MSGET account to claim ownership. Deployments that already have an owner skip the setup code.
  3. Set the hardware profile, connect your Apple Account, and follow the activation prompts.
  4. Turn on the interfaces you need. For MCP, set its permissions.
  5. When the dashboard reports an interface ready, connect with this deployment's endpoint and credentials.

Setup is done when the client connects. Port mappings make an interface reachable; the dashboard turns it on or off.

⁠Onboard from a terminal

For terminal setup, the image includes msgetctl. It connects to the running service through a local socket in the container, with no setup code, separate install, or extra port.

# Prompts in your terminal. Passwords are hidden.
docker compose exec msget /usr/local/bin/msgetctl onboard --interactive

# Current stage and the next permitted commands, as JSON.
docker compose exec -T msget /usr/local/bin/msgetctl status --json

Telegram sign-in and account sign-in changes still need the dashboard. For agent setup, install the msget Agent Skill from https://github.com/msget-app/msget and see "Setup guide for agents" below. A read-only root filesystem also needs a writable /tmp, such as tmpfs: [/tmp].

⁠Interfaces

InterfaceContainer portPurpose
Web dashboard8739Account access, guided setup, configuration, and status
JSON-RPC over TCP8741OpenClaw-compatible messaging interface
MCP over Streamable HTTP8742MCP endpoint at /mcp
BlueBubbles-compatible gateway1234Hermes Agent integration

Publish only the interfaces you enable, and keep the dashboard mapping:

      - "127.0.0.1:8741:8741" # JSON-RPC
      - "127.0.0.1:8742:8742" # MCP
      - "127.0.0.1:1234:1234" # BlueBubbles

MCP attachments, including symlink targets, must be inside /state/attachments. Grant access through dashboard permissions.

All interfaces share one MSGET service. Its BlueBubbles support is aimed at Hermes Agent and does not cover the full BlueBubbles Server.

MSGET runs as a persistent service. Clients do not own the service or its Apple connection. Use JSON-RPC over TCP or MCP over Streamable HTTP. Their stdio forms are retired; do not pass --mcp or --mcp=stdio.

With the loopback mapping above, the MCP endpoint is http://localhost:8742/mcp. A stdio-only client needs an external stdio-to-HTTP bridge connected to the running service. Do not start another MSGET for it.

⁠Remote access

The example keeps host ports on this computer. For tools on another machine, route the ports they need through a private network or proxy.

To reach the dashboard over SSH, run this on your computer and keep the session open:

ssh -L 8739:127.0.0.1:8739 user@your-server

Then open http://localhost:8739⁠ locally. This forwards only the dashboard.

For LAN access, publish 8739 on the host's LAN address and open that address. For an HTTPS reverse proxy, send traffic to 8739, preserve the browser-facing Host header (including a non-default port), and do not trust forwarded headers. No public URL setting is needed.

Sessions are tied to the origin used at sign-in, so switching between localhost, LAN, and proxy addresses means signing in again. HTTPS origins get Secure cookies. The dashboard requires sign-in, same-origin browser changes, and CSRF protection. Because it validates the request Host instead of a fixed allowlist, DNS-rebinding protection is weaker. Limit network exposure.

⁠Persistent data

  • /state holds deployment ownership, settings, and saved Apple connection state. MSGET manages its file paths and hosted account and relay endpoints. Treat it as sensitive.
  • /run/msget-ipc holds only the broker's live socket. It has no durable data; the broker recreates the socket on start.

The core runs as 65532:65532 plus group 65534 for the socket directory. The broker runs as 65533:65534 and cannot read /state. Named volumes get these owners from the images. With host bind mounts, give those users write access; broker user 65533 must own /run/msget-ipc, with no access for other users (chmod 0750).

Upgrades preserve default filenames and existing /state volumes. Move files from custom paths in older setups into the standard layout before upgrading.

Recreating containers keeps named volumes. docker compose down removes containers but keeps volumes; adding -v deletes them and the saved data. For backup, restore, and deletion, see apps/deployment/docs/backup-and-deletion.md.

⁠Privacy: what leaves your host

Message contents pass between the core and Apple, never through MSGET's hosted services. The broker performs only a fixed set of 29 operations there: account sign-in, session checks, activation, Telegram linking, and relay setup.

The dashboard owner view shows the broker's contact count for each operation. Run docker compose exec msget /usr/local/bin/msgetctl privacy check to test from the core's network whether MSGET's services are directly reachable.

  • apps/deployment/docs/broker-data.md: each operation's destination and the data sent, returned, and stored.
  • apps/deployment/docs/network-isolation.md: Standard and Docker Strong setups.
  • apps/deployment/docs/traffic-capture.md: inspect broker TLS traffic with your own CA and proxy.
  • apps/deployment/docs/backup-and-deletion.md: back up, restore, or wipe local data.

⁠Updates

latest follows published releases of msget/msget-app, msget/msget-broker and msget/msget-dashboard. To pin a version, set the same tag or digest for the core and the broker in compose.yaml, using the Image tags⁠ page. The dashboard has its own versions on its tags page⁠; pin the tag or digest of a dashboard version that supports the core's version in the image volume's source:.

Release indexes are signed, and each platform image has a signed SPDX JSON SBOM attestation. Pin updates by digest. Before first use of a new digest, get the public key at apps/deployment/docs/msget-image.pub in the release source. Verify the index, list each platform digest, then verify the SBOM on your platform digest:

cosign verify --insecure-ignore-tlog=true \
  --key msget-image.pub \
  docker.io/msget/msget-app@sha256:<index-digest>
docker buildx imagetools inspect \
  docker.io/msget/msget-app@sha256:<index-digest>
cosign verify-attestation --insecure-ignore-tlog=true \
  --key msget-image.pub \
  --type spdxjson \
  docker.io/msget/msget-app@sha256:<platform-digest>

Repeat for the broker and the dashboard, replacing docker.io/msget/msget-app@sha256:<digest> with docker.io/msget/msget-broker@sha256:<digest> or docker.io/msget/msget-dashboard@sha256:<digest> in each command.

Back up the state volume, then pull and restart:

docker compose pull
docker pull msget/msget-dashboard:latest
docker compose up -d --force-recreate msget

docker compose pull does not pull the dashboard image, so pull it by name. docker compose up pulls it only when it is missing. Recreate the core after a dashboard update so that it mounts the new dashboard image.

Then check that the dashboard opens, your setup is intact, and your interfaces are ready.

⁠Troubleshooting

To read the logs, run:

docker compose logs --tail=100 -f msget
SymptomCheck
Container exits or restartsRead the startup error in the logs. With bind mounts, check that 65532:65532 can write /state and 65533:65534 can write /run/msget-ipc. Broker user 65533 must own /run/msget-ipc, with no access for others (chmod 0750).
Core stops with a dashboard packaging errorCheck that the type: image volume is present as written and that your Docker or Podman version supports image mounts. Pull msget/msget-dashboard again, and use a dashboard version that supports the core's version (the latest tags work together).
Sign-in or activation unavailableCheck msget-broker with docker compose ps and docker compose logs msget-broker. The core reaches MSGET's hosted services only through the broker.
Dashboard does not openCheck the port mapping or SSH/proxy route. A reverse proxy must preserve the browser's Host header.
Interface is unavailableCheck Apple activation and whether the interface is enabled and ready in the dashboard. Then check the client endpoint and route.
Client expects a stdio commandUse JSON-RPC over TCP or MCP over Streamable HTTP. For a stdio-only MCP client, use a stdio-to-HTTP bridge.

⁠Setup guide for agents

Install the msget Agent Skill and follow it:

npx skills add msget-app/msget   # or any Agent Skills installer
docker compose exec -T msget /usr/local/bin/msgetctl --help
  1. Create the Compose file above and start both services. Keep existing state volumes.
  2. Run msgetctl status --json. Follow awaiting and nextActions: do agent steps yourself and stop for the user at human steps. Keep the user involved, especially for Apple verification.
  3. Pass MSGET account fields in a 0600 file with --env-file PATH|-, or let the user run onboard --interactive. For Apple activation, ask for the Apple ID in plaintext, place the password file at a private path inside the container, and use --apple-id EMAIL with --apple-password-file PATH. The msget skill covers the file format, upload route, and a dangerous plaintext-password argument. Use that argument only with the user's explicit consent.
  4. Get verification codes from the user. Submit Apple codes with --code-stdin; submit MSGET email codes as MSGET_EMAIL_CODE in the same --env-file - input as the account email. Never repeat codes in reports.
  5. Use msgetctl wait for background steps. Do not write sleep loops.
  6. Never reset ownership to bypass sign-in.
  7. Enable only requested interfaces and publish only needed ports. Use JSON-RPC over TCP or MCP over Streamable HTTP. Do not start another MSGET process with docker exec.
  8. Check readiness with status, then test with a harmless status or capability request. Do not send a live message.
  9. Keep setup codes, passwords, session tokens, and message data out of reports.

Tag summary

Content type

Image

Digest

sha256:34dcd7df9…

Size

37.1 MB

Last updated

12 days ago

docker pull msget/msget-app