Skip to main content

mcp-server-webos

An MCP server for LG webOS TVs: status, power, screen, apps and inputs, remote keys, typing into search boxes, YouTube search, playback and volume, from Claude Code, Claude Desktop or the mobile app. It talks to each TV directly over LG's SSAP WebSocket protocol, through aiowebostv (the library Home Assistant uses), with no dependency on Home Assistant.

A sibling of mcp-server-onkyo, mcp-server-shieldtv, mcp-server-harmony and mcp-server-sofabaton, with the same conventions: typed tools with annotations, an ActionResult from every action, dry run, doctor, a wire-level simulator, an assumptions registry, Streamable HTTP behind Cloudflare Access, and an OpenRC service for an Alpine LXC.

Status: alpha, and looking for testers with other LG TVs. It runs daily on the three TVs below: pairing, status, screen off, sources, the text tools and YouTube search have run on real sets (2026-10-14 to 2026-11-10), and the HTTP service runs behind Cloudflare Access. Wake-on-LAN, keys and media controls have so far run only on the 2025 C5, and other models only against the simulator. HARDWARE_VALIDATION.md is the checklist, the table at the end of this README says what has been confirmed, and a hardware report for your TV (working or not) is the most useful thing you can send.

The TVs it targets

The owner's three OLEDs, one per generation. Other webOS TVs (2014 onwards) speak the same protocol and will probably work, but nothing is promised for them.

Room Model Platform Control port Notes
Bedroom OLED65C7P-U (2017 C7) webOS 3.5 (reports 3.9.3) 3000 (ws) no now_playing (no media service)
Family Room OLED77G1PUA (2021 G1) webOS 6.5 (reports 6.5.3) 3000 (ws); 3001 (wss) also open no now_playing (no media service)
Office OLED65C5PUA (2025 C5) webOS 25 (26 on offer) 3001 (wss) webOS 26 changed pairing (see below)

A TV usually sits on one HDMI input from an Onkyo receiver, and volume belongs to the receiver: when a TV's sound goes out over eARC/ARC, this server refuses to change its volume and points at the receiver's own server instead. Going through the TV would bypass the receiver server's volume caps (the TV forwards its volume to the receiver over HDMI-CEC). A separate home-theater Skill coordinates the servers; docs/skill-webos.md is this server's cheat sheet for it.

webOS 26 and pairing

In August 2026 LG's webOS 26 firmware started rejecting the signed registration manifest that every SSAP client had sent since 2014 (403 Pairing rejected: blacklisted certificate detected, before any dialog). aiowebostv 0.9.2 switched to an unsigned manifest, which webOS 26 accepts; this server requires at least that version. LG has been rolling webOS 26 out to 2025 sets since late August, and there is no way back, so HARDWARE_VALIDATION.md captures the C5 on webOS 25 before it updates.

Install

With uv, nothing to install: uvx mcp-server-webos ... fetches it into a cached environment and runs it (uvx mcp-server-webos pair --host <ip> --name <room>). Or in a virtualenv:

python -m venv ~/.venvs/webos && . ~/.venvs/webos/bin/activate
pip install mcp-server-webos

From source instead (for the newest code, or to run the tests):

git clone https://github.com/SDNick484/mcp-server-webos.git && cd mcp-server-webos
python -m venv .venv && . .venv/bin/activate
pip install -e ".[dev]" && pytest

Python 3.11 or newer. Every dependency ships a musl wheel, so Alpine needs no compiler.

Pair each TV

The TV must be on. On a webOS 3.x set (the C7), turn on LG Connect Apps in its network settings first. For webos_set_power on to work, also turn on the setting that lets the network wake it: "Mobile TV On", "TV On With Mobile" or "Turn on via Wi-Fi", depending on the generation.

mcp-server-webos pair --host 192.168.1.50 --name "Family Room" --alias G1

The TV shows a pairing request: accept it with the remote (pair waits up to 60 s). pair reads the TV's identity first (its deviceUUID, from the keyless hello), then saves:

  • the client key, in keys.json (0600), by deviceUUID. It is full control of the TV, so it is never logged, never in config.json, never in a tool result;
  • the TV in config.json: name, aliases (your --aliases and the model), address, MACs for Wake-on-LAN (the connected interface first; --mac if they can't be read), model, platform, and the TLS certificate's fingerprint.

Both live in ~/.config/mcp-server-webos (or $WEBOS_CONFIG_DIR), 0700. A running server notices a new key and connects with it, without a restart. Re-running pair for the same TV updates its entry and keeps your hand edits.

mcp-server-webos check        # connect once to each TV: platform, what works, what doesn't
mcp-server-webos doctor       # layer by layer, read-only; each failure names a validation step
mcp-server-webos discover     # which webOS TVs answer SSDP (TVs that are off don't)

Choose the apps

webos_select_source only opens apps on the allow-list: a few defaults, plus yours. To see what a TV actually has installed, and add from it:

mcp-server-webos apps --tv "Office TV"                 # listed by group, with the name webos_select_source will use
mcp-server-webos apps --tv "Office TV" --add crunchyroll,"Photo & Video"
mcp-server-webos apps --all-tvs --add-all             # every third-party app on any TV
Group Means Added by
Allowed already on the allow-list
Not allowed yet third-party apps --add NAME or --add-all
LG's own apps com.webos., com.palm., com.lge. ids (W-SYSTEM-APP-IDS) --add NAME only
Excluded the web browser (it opens any URL), settings, LG's store (it installs apps), inputs (webos_select_source handles them), Live TV, service menus never

It asks the TV over a short session with the stored key and changes nothing on it. New entries go into config.json's "apps"; restart the server to use them. Run it as the service user on the LXC (su -s /bin/sh mcp-webos -c '…' with WEBOS_CONFIG_DIR=/var/lib/mcp-server-webos), since keys.json and config.json are that user's. There is no tool for this: the model can't widen the allow-list.

config.json

pair writes it; you may edit names, aliases, max_volume and volume_owner:

{
  "tvs": [
    {"name": "Bedroom", "aliases": ["C7", "OLED65C7P-U"], "host": "192.168.1.52",
     "uuid": "...", "macs": ["a8:23:fe:..."], "model": "OLED65C7P-U", "platform": "3.5.0",
     "max_volume": 30, "volume_owner": "auto"}
  ],
  "apps": {"crunchyroll": "crunchyroll.app.id"},
  "max_volume": 40
}
  • max_volume (0-100, default 40): webos_set_volume caps at it, per TV or for all.
  • volume_owner: auto (from the TV's sound output: external outputs mean the receiver owns volume), tv (always allow), or external (never).
  • apps: extra apps for the allow-list, name: app id (ids from webos_list_sources or a capture).
  • wol_broadcast / wol_port: where magic packets go (default 255.255.255.255:9).
  • Hosts must be private IPv4 addresses. A name or alias that would mean two TVs is refused.

Use it from Claude

Claude Code:

claude mcp add webos -- uvx mcp-server-webos                # or the venv's bin/mcp-server-webos

Claude Desktop (claude_desktop_config.json, then restart Claude Desktop):

{
  "mcpServers": {
    "webos": {"command": "uvx", "args": ["mcp-server-webos"]}
  }
}

Claude Desktop doesn't start a login shell, so it may not find uvx on its PATH: if the server doesn't appear, put the full path from which uvx (where uvx on Windows) in command. With a virtualenv instead, command is the full path to its bin/mcp-server-webos and args is []. Both read the TVs and keys that pair saved.

Tools

Fourteen, on purpose: every tool definition costs context in every client.

Tool Does Annotations
webos_list_tvs names and aliases tv accepts, model, platform read-only
webos_get_status power, what is in front, input, now playing, volume, sound output, capabilities and limitations; all TVs when tv is omitted read-only
webos_set_power on (Wake-on-LAN, confirmed) or off (standby); tv="all" for off idempotent
webos_set_screen blank the picture while sound plays, or bring it back idempotent
webos_list_sources allow-listed apps the TV has installed, and its HDMI inputs read-only
webos_select_source open an app or switch input, confirmed in front idempotent
webos_send_key one allow-listed remote key, up to 10 times not idempotent
webos_media_control play, pause, stop, rewind, fast-forward not idempotent
webos_set_volume 0-100, capped; refused when the receiver owns volume idempotent
webos_set_mute mute or unmute; same rule idempotent
webos_insert_text type into the focused system text field (LG's search); replace to overwrite it not idempotent
webos_delete_text delete characters before the cursor in that field not idempotent
webos_submit_text press the keyboard's Enter in that field (runs the search) not idempotent
webos_search_app open YouTube straight on its results for a query idempotent

Typing and searching

Typing a search with webos_send_key means walking an on-screen keyboard one arrow at a time. Where webos_get_status lists text_input, webos_insert_text types the whole string through the TV's input method (IME) service instead:

webos_get_status(tv="Office")                      # capabilities include text_input
webos_send_key(key="HOME") ... open LG's search    # the search box has the cursor
webos_insert_text(text="lofi beats", tv="Office")  # typed, and confirmed by the field's new length
webos_submit_text(tv="Office")                     # the results

What was seen on the three TVs (2026-11-09; details in HARDWARE_VALIDATION.md step 14):

Bedroom C7 (3.9.3) Family Room G1 (6.5.3) Office C5 (10.3.1)
Typing into LG's search works, unconfirmed works, confirmed works, confirmed
Typing into YouTube's or Netflix's search refused refused refused
webos_search_app (YouTube) refused works works
  • Only system text fields take typed text. YouTube and Netflix draw their own keyboards, and the TV answers "ok" to every IME call there (and with nothing focused at all) while typing nothing. So each text tool first asks the TV whether a system text field has focus (W-IME-FOCUS) and refuses, sending nothing, when none does. The refusal points at webos_search_app or webos_send_key.
  • Confirmed where the TV says. The G1 and C5 report the field's length after every change, so the result says whether the text landed; the C7 doesn't, so its results carry an "unconfirmed" warning (W-IME-LENGTH).
  • YouTube search by link, not by typing. webos_search_app launches YouTube with contentTarget=https://www.youtube.com/tv?q=<query>, the only link shape that showed results (W-YOUTUBE-SEARCH). The server builds the link; the model only gives the query. webOS 3.x's YouTube ignores links, so it is refused on the C7; webOS 4 and 5 are untested and allowed.
  • Text is one line of printable characters, at most 200 (a query, 100); no newlines (use webos_submit_text). Typing shares webos_send_key's rate limit.

Nothing is destructiveHint: turning a TV off is undone by turning it on. Every action returns an ActionResult, the siblings' shape:

{"tv": "Bedroom", "outcome": "done", "detail": "Bedroom's volume is 15",
 "sent": ["ssap://audio/setVolume 15"], "warnings": []}

outcome is done, unchanged (already so; nothing sent) or dry_run. Failures are tool errors whose message says what to do ("Which TV? Several are configured: ...", "Volume on Family Room belongs to the receiver ...", "... needs pairing: run pair").

Resources: webos://tvs (capabilities per TV), webos://keys (the key allow-list, and the keys left out with the reason for each), webos://apps (the app allow-list). One prompt, watch.

What the model can't do

  • No raw SSAP or luna calls. The same reasoning as no adb shell on the Shield: one generic call would reach everything the TV exposes, including its internal settings services.
  • No URL tools, and text only where decided: no browser, no "play this URL". The two free-text arguments are webos_insert_text's text, which only reaches a focused system text field, and webos_search_app's query, which the server puts into a link it builds for an allow-listed app.
  • Keys are an allow-list. POWER (a toggle), the IN_START/EZ_ADJUST service menus, settings menus, the volume keys (they would bypass the cap) and app shortcuts (they would bypass the app allow-list) are left out; webos://keys lists why.
  • Apps are an allow-list of ids the TV itself lists. Strings from the TV (app titles, input labels) are cleaned of control characters, bounded, and treated as data.
  • Never guess a TV: with several configured, an action without tv is refused and the TVs are listed. Never guess a source: a name that matches an app and an input is refused.
  • Screen off uses standbyMode "active" only. "passive" can't be undone without unplugging the TV; it isn't an argument anywhere.

docs/OUT_OF_SCOPE.md lists the rest (picture settings, channels, LG's IP control) and why.

Dry run

serve --dry-run (or WEBOS_DRY_RUN=1) reads the TVs but sends nothing that changes anything: every action returns outcome: "dry_run" with what it would have sent.

How it stays connected

Each TV has one long-lived WebSocket (the TV pushes changes over subscriptions) and a supervisor:

  • Off: a TV that is off has no socket. The supervisor retries every ~10 s, so a TV turned on by its remote shows up within ~10 s. webos_get_status on a stale TV first makes one connect attempt of at most 3 s, then answers with stale, as_of and error.
  • Stale key: if the TV no longer accepts the stored key (a reset, or a firmware update), it wants to show its pairing dialog. The server hangs up at once, marks the TV needs_pairing and stops trying until pair writes a new key. That's one dialog, not one every 10 s.
  • Moved: the key is only sent after the TV's hello shows the paired deviceUUID. If another device has the address, the server looks for the TV by SSDP and adopts a new address only on a deviceUUID match.
  • Pointer socket refused: aiowebostv would fail the whole connection; here only the keys stop working (see compat.py).

compat.py holds every dependency on aiowebostv internals, with contract tests; that is why the dependency is pinned <0.11.

HTTP and Cloudflare Access

To share one server between Claude Code, Claude Desktop and the mobile app, run it as a service and reach it through a Cloudflare Tunnel with Access in front, exactly as the siblings do. Claude's connectors reach it from the internet, so the URL is public; Access is what keeps it yours.

Flag Variable Default
--bind MCP_HTTP_BIND 127.0.0.1
--port MCP_HTTP_PORT 8715 (Onkyo 8711, Shield 8712, Harmony 8713, Sofabaton 8714)
--path MCP_HTTP_PATH /webos/mcp
--public-host MCP_PUBLIC_HOSTS none: only loopback Host headers pass, so Cloudflare's requests get 421
CF_ACCESS_TEAM_DOMAIN, CF_ACCESS_AUD none: no Access checks
MCP_ALLOWED_EMAILS anyone Access lets in

With Access configured, every request needs a valid Cf-Access-Jwt-Assertion; anything else gets a plain 403. The server refuses to start on a non-loopback address without Access unless you pass --insecure-no-auth. GET /healthz answers without auth. remote.py and logsafe.py are shared with the sibling servers, from mcp-server-shared.

Setting up Cloudflare

This is the setup that works, verified with Claude Code and the Claude app connector on 2026-10-14. Do the Access application first, so the URL is never public.

  1. One Access application for the whole hostname, shared by every MCP server on it. Zero Trust → Access controls → Applications → Add → Self-hosted:
    • Destination: subdomain mcp, your domain, path empty. Managed OAuth serves its sign-in discovery from the root of the hostname (/.well-known/...), so an app limited to /webos may not cover it; one app also means one sign-in for all the servers.
    • Policy: Allow → Emails → you. Login method: One-time PIN (or your identity provider).
    • Edit the app → Advanced settings → Managed OAuth: on. Allowed redirect URIs: https://claude.ai/*. Turn on Allow localhost clients (Claude Code signs in through localhost). Access token 15 min, grant session 1-2 weeks.
    • Copy the app's Application Audience (AUD) tag.
    • Make sure no other Access app covers a path on the same hostname: Access applies the most specific match, and a Bypass policy there would let requests through without a token.
  2. A route on the tunnel. Networks → Tunnels → the tunnel → Published application routes → Add: hostname mcp.example.com, path ^/webos/ (a regex), service http://<address>:8715. Leave the HTTP Host Header override unset: the server checks the public Host.
    • The service address is resolved where cloudflared runs. If cloudflared is a Docker container (the tunnel page lists the replica's hostname as a 12-character hex container ID), localhost is that container, not the LXC: use the LXC's LAN address or the Docker bridge's (172.17.0.1, reachable only from containers on that host), and set MCP_HTTP_BIND to the same address.
  3. /etc/mcp-server-webos/env (see deploy/alpine/env.example), then rc-service mcp-server-webos restart:
    MCP_HTTP_BIND=192.168.1.10          # e.g. the LXC's address: the one the route points at
    MCP_PUBLIC_HOSTS=mcp.example.com # required: without it every request through Cloudflare gets 421
    CF_ACCESS_TEAM_DOMAIN=<team>.cloudflareaccess.com
    CF_ACCESS_AUD=<the AUD tag from step 1>
    MCP_ALLOWED_EMAILS=<the email you sign in to Access with>
    
  4. Test, then add https://mcp.example.com/webos/mcp as a custom connector in Claude (and claude mcp add --transport http webos <url> for Claude Code):
    curl -s http://192.168.1.10:8715/healthz                               # {"status": "ok"}
    curl -si -X POST https://mcp.example.com/webos/mcp -d '{}' | head -5 # 401 + www-authenticate
    

When it doesn't connect

Watch the server while you press Connect: tail -n 0 -f /var/log/mcp-server-webos/server.log.

You see Cause Fix
The outside curl gets a 302 to …cloudflareaccess.com Managed OAuth is off: Claude gets a login page Turn it on (step 1)
Claude: "couldn't reach" / "authorized, but … returned an error"; Claude Code: HTTP 502; nothing in the log The tunnel can't reach the server: the route's service address isn't where the server listens (usually localhost with cloudflared in a container) Step 2's address and MCP_HTTP_BIND must match
Claude Code: HTTP 421; log: Invalid Host header: mcp.example.com MCP_PUBLIC_HOSTS isn't set Step 3
Log: Denied … no Cloudflare Access assertion The request didn't come through Access: a local test with curl, or another Access app/Bypass policy on the path Ignore it for local tests; otherwise see step 1's last point
Log: Denied … Audience doesn't match / Invalid issuer CF_ACCESS_AUD is another app's tag, or the team domain is wrong Copy both again from the app in step 1
Log: Denied … not in MCP_ALLOWED_EMAILS You signed in to Access with another address Make them match

As a service on Alpine (Proxmox LXC)

sh deploy/alpine/install.sh                      # as root; or: install.sh /path/to/checkout
su -s /bin/sh mcp-webos -c 'WEBOS_CONFIG_DIR=/var/lib/mcp-server-webos \
  /opt/mcp-server-webos/venv/bin/mcp-server-webos pair --host <tv ip> --name "Family Room"'
vi /etc/mcp-server-webos/env                     # HTTP and Access settings
rc-update add mcp-server-webos default && rc-service mcp-server-webos start
Path Owner, mode Holds
/opt/mcp-server-webos/venv root, 0755 The code
/etc/mcp-server-webos/env root:mcp-webos, 0640 HTTP and Access settings
/var/lib/mcp-server-webos/ mcp-webos, 0700 (files 0600) keys.json, config.json
/var/log/mcp-server-webos/server.log mcp-webos, 0750 Logs, redacted
/etc/init.d/mcp-server-webos root, 0755 OpenRC script (supervise-daemon)

Wake-on-LAN from an LXC: the magic packet is a broadcast (plus a copy to the TV's last address), so the container must be bridged onto the TVs' network, not NATed. doctor shows the local address it would leave from.

Logs

stderr only (stdout is the MCP stdio transport). Addresses, MACs, serial numbers, deviceUUIDs and pointer-socket ids are redacted unless --no-redact (or WEBOS_LOG_UNREDACTED=1); client keys, JWTs and certificates always are. --debug (WEBOS_DEBUG=1) adds aiowebostv's protocol traffic.

Testing without a TV

pip install -e ".[dev]" && pytest && ruff check . && ruff format --check . && mypy
mcp-server-webos simulate --profile g1 --config-dir /tmp/sim --paired       # then, in another terminal:
WEBOS_CONFIG_DIR=/tmp/sim mcp-server-webos call webos_get_status
WEBOS_CONFIG_DIR=/tmp/sim mcp-server-webos call webos_select_source source=netflix

The simulator (src/webos_mcp/sim/) speaks SSAP over real WebSockets: the hello, registration and the pairing dialog, requests and subscriptions with pushed updates, the TV's error replies, the pointer socket, and Wake-on-LAN. The real aiowebostv connects to it. Profiles: c7, g1, c5-webos25, c5-webos26, each field naming its source. aiowebostv always dials ports 3000 and 3001, so each simulated TV binds the real ports on its own loopback address (127.0.0.2-5): on Linux all of 127.0.0.0/8 is loopback. (macOS needs loopback aliases for that.)

WSL2 with mirrored networking (networkingMode=mirrored in .wslconfig): Windows then handles loopback and answers only 127.0.0.1, so the simulator tests hang and time out. Run them with scripts/test-wsl.sh [pytest args], which runs pytest in a network namespace of its own (ordinary Linux loopback, no other network; needs unshare and ip, and root or sudo). WSL2's default NAT networking doesn't need it.

mcp-server-webos capture --tv <name> --profile <p> records a real TV's answers to read-only requests, redacted; committed to src/webos_mcp/sim/fixtures/, each capture becomes a contract test against its simulator profile.

What has been confirmed on hardware

Every protocol detail this server relies on is in src/webos_mcp/assumptions.py, with its source and how confident that source is. doctor prints the unconfirmed ones; HARDWARE_VALIDATION.md says which step confirms each.

Assumption Confidence Status
W-MANIFEST high simulator-only
W-SIGNED-403 high simulator-only
W-KEY-SURVIVES low simulator-only
W-REGISTERED-DIRECT high hardware-verified
W-STALE-KEY medium simulator-only
W-PROMPT-DISMISS low simulator-only
W-PAIR-WINDOW low simulator-only
W-HELLO-VERSION high hardware-verified
W-SWINFO-401 high hardware-verified
W-UUID-STABLE medium simulator-only
W-PORTS medium simulator-only
W-PORT3000-CLOSE medium simulator-only
W-TLS-CERT low simulator-only
W-MULTI-CLIENT medium simulator-only
W-INPUT-SOCKET medium hardware-verified
W-SUBSCRIBE high hardware-verified
W-HELLO-1008 medium hardware-verified
W-POWER-STATES high simulator-only
W-C7-NO-POWERSTATE low hardware-contradicted
W-STANDBY-SOCKET low simulator-only
W-OFF-GUARD low simulator-only
W-TURNON-DEAD medium simulator-only
W-WOL medium simulator-only
W-WOL-PATH low simulator-only
W-WAKE-TIME medium hardware-contradicted
W-MAC-SOURCE low simulator-only
W-SCREEN-OFF medium simulator-only
W-KEYS medium simulator-only
W-MEDIA-CONTROLS low simulator-only
W-NOW-PLAYING medium hardware-verified
W-SOUND-OUTPUT medium hardware-verified
W-VOLUME-ARC medium simulator-only
W-APP-IDS low simulator-only
W-SYSTEM-APP-IDS medium simulator-only
W-INPUT-IDS medium hardware-verified
W-SSDP medium hardware-verified
W-IME-FOCUS high hardware-verified
W-IME-TEXT high hardware-verified
W-IME-LENGTH medium hardware-verified
W-YOUTUBE-SEARCH medium hardware-verified

License

MIT

Metadata

Release files for mcp-server-webos 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for mcp-server-webos 0.1.0
File Size Uploaded Provenance Actions
mcp_server_webos-0.1.0.tar.gz 177.9 kB With provenance Details for mcp_server_webos-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for mcp-server-webos 0.1.0
File Interpreter ABI Platform Actions
mcp_server_webos-0.1.0-py3-none-any.whl Python 3 none any Details for mcp_server_webos-0.1.0-py3-none-any.whl

Total release size: 311.0 kB

Release files / mcp_server_webos-0.1.0.tar.gz

Download URL mcp_server_webos-0.1.0.tar.gz
Size 177.9 kB
Tags Source
SHA-256 checksum
How to use checksums
245639f0d928420d1ace858f855df14b278bc3de17123dc22080b674a13a91d8
BLAKE2b-256 checksum
How to use checksums
826b9c0d74d2b7eb35558d25621804842c94139e9d38c073a43982725ac623bd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 11, 2026.

Transparency log

Release files / mcp_server_webos-0.1.0-py3-none-any.whl

Download URL mcp_server_webos-0.1.0-py3-none-any.whl
Size 133.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
dca8f9ac44ee52c6e90de4947f6ef6920e280621e9f19d6d40d2b876b33e4946
BLAKE2b-256 checksum
How to use checksums
4fc196bbdbbd4cdad0e256d77fb83d5cac7d15add911821fc981deb14e02c79c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 11, 2026.

Transparency log

Security for mcp-server-webos 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for mcp_server_webos-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 11, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page