switch-parental-controls 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 (25) hide show
  1. switch_parental_controls-0.1.0/LICENSE +21 -0
  2. switch_parental_controls-0.1.0/PKG-INFO +219 -0
  3. switch_parental_controls-0.1.0/README.md +200 -0
  4. switch_parental_controls-0.1.0/pyproject.toml +39 -0
  5. switch_parental_controls-0.1.0/setup.cfg +4 -0
  6. switch_parental_controls-0.1.0/src/nintendo_mcp/__init__.py +1 -0
  7. switch_parental_controls-0.1.0/src/nintendo_mcp/__main__.py +13 -0
  8. switch_parental_controls-0.1.0/src/nintendo_mcp/applications.py +181 -0
  9. switch_parental_controls-0.1.0/src/nintendo_mcp/auth.py +155 -0
  10. switch_parental_controls-0.1.0/src/nintendo_mcp/devices.py +808 -0
  11. switch_parental_controls-0.1.0/src/nintendo_mcp/models.py +326 -0
  12. switch_parental_controls-0.1.0/src/nintendo_mcp/players.py +194 -0
  13. switch_parental_controls-0.1.0/src/nintendo_mcp/server.py +100 -0
  14. switch_parental_controls-0.1.0/src/nintendo_mcp/utils.py +82 -0
  15. switch_parental_controls-0.1.0/src/switch_parental_controls.egg-info/PKG-INFO +219 -0
  16. switch_parental_controls-0.1.0/src/switch_parental_controls.egg-info/SOURCES.txt +23 -0
  17. switch_parental_controls-0.1.0/src/switch_parental_controls.egg-info/dependency_links.txt +1 -0
  18. switch_parental_controls-0.1.0/src/switch_parental_controls.egg-info/entry_points.txt +2 -0
  19. switch_parental_controls-0.1.0/src/switch_parental_controls.egg-info/requires.txt +10 -0
  20. switch_parental_controls-0.1.0/src/switch_parental_controls.egg-info/top_level.txt +1 -0
  21. switch_parental_controls-0.1.0/tests/test_applications.py +156 -0
  22. switch_parental_controls-0.1.0/tests/test_auth.py +108 -0
  23. switch_parental_controls-0.1.0/tests/test_devices.py +587 -0
  24. switch_parental_controls-0.1.0/tests/test_integration.py +132 -0
  25. switch_parental_controls-0.1.0/tests/test_players.py +153 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Daniel Schroeder
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,219 @@
1
+ Metadata-Version: 2.4
2
+ Name: switch-parental-controls
3
+ Version: 0.1.0
4
+ Summary: Nintendo Switch Parental Controls
5
+ License: MIT
6
+ Requires-Python: >=3.12
7
+ Description-Content-Type: text/markdown
8
+ License-File: LICENSE
9
+ Requires-Dist: mcp[cli]>=1.0.0
10
+ Requires-Dist: pydantic>=2.0.0
11
+ Requires-Dist: pynintendoparental>=2.3.4
12
+ Requires-Dist: aiohttp>=3.9.0
13
+ Provides-Extra: dev
14
+ Requires-Dist: pytest>=8.0.0; extra == "dev"
15
+ Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
16
+ Requires-Dist: ruff>=0.4.0; extra == "dev"
17
+ Requires-Dist: python-dotenv>=1.0.0; extra == "dev"
18
+ Dynamic: license-file
19
+
20
+ # Nintendo Switch Parental Controls
21
+
22
+ An [MCP (Model Context Protocol)](https://modelcontextprotocol.io) server that exposes Nintendo Switch Parental Controls as AI-accessible tools. It wraps the [`pynintendoparental`](https://github.com/pantherale0/pynintendoparental) library and allows AI assistants to monitor and manage parental control settings on Nintendo Switch devices.
23
+
24
+ ## Features
25
+
26
+ - **Authentication**: Interactive Nintendo OAuth login flow via MCP tools, or pre-configured session token
27
+ - **Device monitoring**: List devices, view playtime, remaining time, sync status
28
+ - **Playtime controls**: Set daily limits, add extra time, configure per-day-of-week schedules
29
+ - **Bedtime controls**: Set bedtime alarms and end times
30
+ - **Restriction controls**: Set restriction mode (forced termination vs. alarm), content restriction levels
31
+ - **Player tracking**: View player profiles and today's app usage
32
+ - **Application management**: List apps, manage the allow-list (bypass content restrictions)
33
+
34
+ ## Prerequisites
35
+
36
+ - [uv](https://docs.astral.sh/uv/) — install once, no Python or clone needed:
37
+
38
+ ```bash
39
+ curl -LsSf https://astral.sh/uv/install.sh | sh
40
+ ```
41
+
42
+ ## Authentication: Getting Your Nintendo Session Token
43
+
44
+ The server requires a Nintendo session token to access the Parental Controls API. You can obtain one in two ways:
45
+
46
+ ### Method 1: Interactive MCP Tool (Recommended for first-time setup)
47
+
48
+ 1. Start the MCP server (see below)
49
+ 2. Ask your AI assistant to call `nintendo_get_login_url`
50
+ 3. Open the returned URL in your browser
51
+ 4. Log in with your Nintendo Account
52
+ 5. On the "Select this person" page, **right-click** the "Select this person" button and copy the link
53
+ 6. Ask your AI assistant to call `nintendo_complete_login` with the copied URL
54
+ 7. The tool will return your session token — **save it!**
55
+
56
+ ### Method 2: Manual (if you already have a token)
57
+
58
+ If you already have a session token, set it as an environment variable:
59
+
60
+ ```bash
61
+ export NINTENDO_SESSION_TOKEN="your-token-here"
62
+ ```
63
+
64
+ ### Saving Your Token
65
+
66
+ Once you have a session token, add it to your environment so you don't need to log in again:
67
+
68
+ ```bash
69
+ # Add to your shell profile (~/.zshrc, ~/.bashrc, etc.)
70
+ export NINTENDO_SESSION_TOKEN="your-token-here"
71
+
72
+ # Or create a .env file (never commit this!)
73
+ echo 'NINTENDO_SESSION_TOKEN=your-token-here' >> .env
74
+ ```
75
+
76
+ > **Note**: Session tokens can expire. If you get authentication errors, repeat the login flow.
77
+
78
+ ## Running the Server
79
+
80
+ ```bash
81
+ uvx --from switch-parental-controls mcp
82
+ ```
83
+
84
+ No clone or install required — `uvx` fetches the package from PyPI and runs it in an isolated environment.
85
+
86
+ ### Environment Variables
87
+
88
+ | Variable | Required | Default | Description |
89
+ | ------------------------ | -------- | --------------- | --------------------------------------- |
90
+ | `NINTENDO_SESSION_TOKEN` | No\* | — | Nintendo session token |
91
+ | `NINTENDO_TIMEZONE` | No | `Europe/London` | IANA timezone (e.g. `America/New_York`) |
92
+ | `NINTENDO_LANG` | No | `en-GB` | Language code (e.g. `en-US`) |
93
+
94
+ \*Required for any tool that accesses Nintendo data, unless you use the interactive login tools.
95
+
96
+ ### MCP Client Configuration
97
+
98
+ Add to your MCP client configuration (e.g. Claude Desktop `claude_desktop_config.json`):
99
+
100
+ ```json
101
+ {
102
+ "mcpServers": {
103
+ "nintendo": {
104
+ "command": "uvx",
105
+ "args": ["--from", "switch-parental-controls", "mcp"],
106
+ "env": {
107
+ "NINTENDO_SESSION_TOKEN": "your-token-here",
108
+ "NINTENDO_TIMEZONE": "America/New_York",
109
+ "NINTENDO_LANG": "en-US"
110
+ }
111
+ }
112
+ }
113
+ }
114
+ ```
115
+
116
+ ## Available Tools
117
+
118
+ ### Authentication
119
+
120
+ | Tool | Description |
121
+ | ------------------------- | ------------------------------------------------------------- |
122
+ | `nintendo_get_login_url` | Generate the Nintendo login URL and step-by-step instructions |
123
+ | `nintendo_complete_login` | Complete login with the redirect URL from the browser |
124
+
125
+ ### Devices
126
+
127
+ | Tool | Description |
128
+ | ------------------------------ | ----------------------------------------------------------- |
129
+ | `nintendo_list_devices` | List all Nintendo Switch devices on the account |
130
+ | `nintendo_get_device` | Get detailed status for a specific device |
131
+ | `nintendo_get_today_summary` | Get today's usage summary for a device |
132
+ | `nintendo_get_monthly_summary` | Get monthly usage summary (optionally for a specific month) |
133
+
134
+ ### Playtime Controls
135
+
136
+ | Tool | Description |
137
+ | ----------------------------------- | --------------------------------------------------------- |
138
+ | `nintendo_set_daily_playtime_limit` | Set the daily playtime limit (0-360 min, or -1 to remove) |
139
+ | `nintendo_add_extra_time` | Add extra playtime for today |
140
+ | `nintendo_set_timer_mode` | Switch between DAILY and EACH_DAY_OF_THE_WEEK modes |
141
+ | `nintendo_set_day_restrictions` | Set per-day playtime and bedtime restrictions |
142
+
143
+ ### Restriction Controls
144
+
145
+ | Tool | Description |
146
+ | ---------------------------------------- | ---------------------------------------- |
147
+ | `nintendo_set_restriction_mode` | Set FORCED_TERMINATION or ALARM mode |
148
+ | `nintendo_set_content_restriction_level` | Set age-based content restrictions |
149
+ | `nintendo_set_bedtime_alarm` | Set the bedtime alarm time (16:00-23:00) |
150
+ | `nintendo_set_bedtime_end_time` | Set when bedtime ends (05:00-09:00) |
151
+
152
+ ### Players
153
+
154
+ | Tool | Description |
155
+ | ----------------------- | ---------------------------------------------- |
156
+ | `nintendo_list_players` | List all players on a device |
157
+ | `nintendo_get_player` | Get player details including apps played today |
158
+
159
+ ### Applications
160
+
161
+ | Tool | Description |
162
+ | ----------------------------- | --------------------------------------------------------- |
163
+ | `nintendo_list_applications` | List all tracked applications on a device |
164
+ | `nintendo_set_app_allow_list` | Add/remove an app from the content restriction allow-list |
165
+
166
+ ## Development
167
+
168
+ Requires [mise](https://mise.jdx.dev/):
169
+
170
+ ```bash
171
+ # Install dependencies
172
+ mise run install
173
+
174
+ # Run tests
175
+ mise run test
176
+
177
+ # Run linter
178
+ mise run lint
179
+
180
+ # Fix lint issues
181
+ mise run lint-fix
182
+
183
+ # Open MCP Inspector (browser UI to test tools interactively)
184
+ mise run inspect
185
+ ```
186
+
187
+ ### MCP Inspector
188
+
189
+ The `inspect` task launches the [MCP Inspector](https://github.com/modelcontextprotocol/inspector) — a browser-based UI for testing MCP tools interactively without needing a full AI client.
190
+
191
+ ```bash
192
+ mise run inspect
193
+ ```
194
+
195
+ This opens the inspector connected to the nintendo_mcp server. You can call any tool directly from the UI, which is useful for testing the authentication flow and verifying tool responses.
196
+
197
+ ### Testing with opencode locally
198
+
199
+ An example opencode config is provided at [`opencode.jsonc.example`](./opencode.jsonc.example). To use it:
200
+
201
+ ```bash
202
+ # 1. Copy the example config
203
+ cp opencode.jsonc.example opencode.jsonc
204
+
205
+ # 2. Optionally set NINTENDO_SESSION_TOKEN in opencode.jsonc
206
+
207
+ # 3. Open opencode in this project directory — it will pick up the local config
208
+ opencode
209
+ ```
210
+
211
+ The local `opencode.jsonc` is gitignored so your session token stays private.
212
+
213
+ ## CI
214
+
215
+ Tests run automatically on pull requests via GitHub Actions. See [`.github/workflows/test.yml`](.github/workflows/test.yml).
216
+
217
+ ## License
218
+
219
+ MIT
@@ -0,0 +1,200 @@
1
+ # Nintendo Switch Parental Controls
2
+
3
+ An [MCP (Model Context Protocol)](https://modelcontextprotocol.io) server that exposes Nintendo Switch Parental Controls as AI-accessible tools. It wraps the [`pynintendoparental`](https://github.com/pantherale0/pynintendoparental) library and allows AI assistants to monitor and manage parental control settings on Nintendo Switch devices.
4
+
5
+ ## Features
6
+
7
+ - **Authentication**: Interactive Nintendo OAuth login flow via MCP tools, or pre-configured session token
8
+ - **Device monitoring**: List devices, view playtime, remaining time, sync status
9
+ - **Playtime controls**: Set daily limits, add extra time, configure per-day-of-week schedules
10
+ - **Bedtime controls**: Set bedtime alarms and end times
11
+ - **Restriction controls**: Set restriction mode (forced termination vs. alarm), content restriction levels
12
+ - **Player tracking**: View player profiles and today's app usage
13
+ - **Application management**: List apps, manage the allow-list (bypass content restrictions)
14
+
15
+ ## Prerequisites
16
+
17
+ - [uv](https://docs.astral.sh/uv/) — install once, no Python or clone needed:
18
+
19
+ ```bash
20
+ curl -LsSf https://astral.sh/uv/install.sh | sh
21
+ ```
22
+
23
+ ## Authentication: Getting Your Nintendo Session Token
24
+
25
+ The server requires a Nintendo session token to access the Parental Controls API. You can obtain one in two ways:
26
+
27
+ ### Method 1: Interactive MCP Tool (Recommended for first-time setup)
28
+
29
+ 1. Start the MCP server (see below)
30
+ 2. Ask your AI assistant to call `nintendo_get_login_url`
31
+ 3. Open the returned URL in your browser
32
+ 4. Log in with your Nintendo Account
33
+ 5. On the "Select this person" page, **right-click** the "Select this person" button and copy the link
34
+ 6. Ask your AI assistant to call `nintendo_complete_login` with the copied URL
35
+ 7. The tool will return your session token — **save it!**
36
+
37
+ ### Method 2: Manual (if you already have a token)
38
+
39
+ If you already have a session token, set it as an environment variable:
40
+
41
+ ```bash
42
+ export NINTENDO_SESSION_TOKEN="your-token-here"
43
+ ```
44
+
45
+ ### Saving Your Token
46
+
47
+ Once you have a session token, add it to your environment so you don't need to log in again:
48
+
49
+ ```bash
50
+ # Add to your shell profile (~/.zshrc, ~/.bashrc, etc.)
51
+ export NINTENDO_SESSION_TOKEN="your-token-here"
52
+
53
+ # Or create a .env file (never commit this!)
54
+ echo 'NINTENDO_SESSION_TOKEN=your-token-here' >> .env
55
+ ```
56
+
57
+ > **Note**: Session tokens can expire. If you get authentication errors, repeat the login flow.
58
+
59
+ ## Running the Server
60
+
61
+ ```bash
62
+ uvx --from switch-parental-controls mcp
63
+ ```
64
+
65
+ No clone or install required — `uvx` fetches the package from PyPI and runs it in an isolated environment.
66
+
67
+ ### Environment Variables
68
+
69
+ | Variable | Required | Default | Description |
70
+ | ------------------------ | -------- | --------------- | --------------------------------------- |
71
+ | `NINTENDO_SESSION_TOKEN` | No\* | — | Nintendo session token |
72
+ | `NINTENDO_TIMEZONE` | No | `Europe/London` | IANA timezone (e.g. `America/New_York`) |
73
+ | `NINTENDO_LANG` | No | `en-GB` | Language code (e.g. `en-US`) |
74
+
75
+ \*Required for any tool that accesses Nintendo data, unless you use the interactive login tools.
76
+
77
+ ### MCP Client Configuration
78
+
79
+ Add to your MCP client configuration (e.g. Claude Desktop `claude_desktop_config.json`):
80
+
81
+ ```json
82
+ {
83
+ "mcpServers": {
84
+ "nintendo": {
85
+ "command": "uvx",
86
+ "args": ["--from", "switch-parental-controls", "mcp"],
87
+ "env": {
88
+ "NINTENDO_SESSION_TOKEN": "your-token-here",
89
+ "NINTENDO_TIMEZONE": "America/New_York",
90
+ "NINTENDO_LANG": "en-US"
91
+ }
92
+ }
93
+ }
94
+ }
95
+ ```
96
+
97
+ ## Available Tools
98
+
99
+ ### Authentication
100
+
101
+ | Tool | Description |
102
+ | ------------------------- | ------------------------------------------------------------- |
103
+ | `nintendo_get_login_url` | Generate the Nintendo login URL and step-by-step instructions |
104
+ | `nintendo_complete_login` | Complete login with the redirect URL from the browser |
105
+
106
+ ### Devices
107
+
108
+ | Tool | Description |
109
+ | ------------------------------ | ----------------------------------------------------------- |
110
+ | `nintendo_list_devices` | List all Nintendo Switch devices on the account |
111
+ | `nintendo_get_device` | Get detailed status for a specific device |
112
+ | `nintendo_get_today_summary` | Get today's usage summary for a device |
113
+ | `nintendo_get_monthly_summary` | Get monthly usage summary (optionally for a specific month) |
114
+
115
+ ### Playtime Controls
116
+
117
+ | Tool | Description |
118
+ | ----------------------------------- | --------------------------------------------------------- |
119
+ | `nintendo_set_daily_playtime_limit` | Set the daily playtime limit (0-360 min, or -1 to remove) |
120
+ | `nintendo_add_extra_time` | Add extra playtime for today |
121
+ | `nintendo_set_timer_mode` | Switch between DAILY and EACH_DAY_OF_THE_WEEK modes |
122
+ | `nintendo_set_day_restrictions` | Set per-day playtime and bedtime restrictions |
123
+
124
+ ### Restriction Controls
125
+
126
+ | Tool | Description |
127
+ | ---------------------------------------- | ---------------------------------------- |
128
+ | `nintendo_set_restriction_mode` | Set FORCED_TERMINATION or ALARM mode |
129
+ | `nintendo_set_content_restriction_level` | Set age-based content restrictions |
130
+ | `nintendo_set_bedtime_alarm` | Set the bedtime alarm time (16:00-23:00) |
131
+ | `nintendo_set_bedtime_end_time` | Set when bedtime ends (05:00-09:00) |
132
+
133
+ ### Players
134
+
135
+ | Tool | Description |
136
+ | ----------------------- | ---------------------------------------------- |
137
+ | `nintendo_list_players` | List all players on a device |
138
+ | `nintendo_get_player` | Get player details including apps played today |
139
+
140
+ ### Applications
141
+
142
+ | Tool | Description |
143
+ | ----------------------------- | --------------------------------------------------------- |
144
+ | `nintendo_list_applications` | List all tracked applications on a device |
145
+ | `nintendo_set_app_allow_list` | Add/remove an app from the content restriction allow-list |
146
+
147
+ ## Development
148
+
149
+ Requires [mise](https://mise.jdx.dev/):
150
+
151
+ ```bash
152
+ # Install dependencies
153
+ mise run install
154
+
155
+ # Run tests
156
+ mise run test
157
+
158
+ # Run linter
159
+ mise run lint
160
+
161
+ # Fix lint issues
162
+ mise run lint-fix
163
+
164
+ # Open MCP Inspector (browser UI to test tools interactively)
165
+ mise run inspect
166
+ ```
167
+
168
+ ### MCP Inspector
169
+
170
+ The `inspect` task launches the [MCP Inspector](https://github.com/modelcontextprotocol/inspector) — a browser-based UI for testing MCP tools interactively without needing a full AI client.
171
+
172
+ ```bash
173
+ mise run inspect
174
+ ```
175
+
176
+ This opens the inspector connected to the nintendo_mcp server. You can call any tool directly from the UI, which is useful for testing the authentication flow and verifying tool responses.
177
+
178
+ ### Testing with opencode locally
179
+
180
+ An example opencode config is provided at [`opencode.jsonc.example`](./opencode.jsonc.example). To use it:
181
+
182
+ ```bash
183
+ # 1. Copy the example config
184
+ cp opencode.jsonc.example opencode.jsonc
185
+
186
+ # 2. Optionally set NINTENDO_SESSION_TOKEN in opencode.jsonc
187
+
188
+ # 3. Open opencode in this project directory — it will pick up the local config
189
+ opencode
190
+ ```
191
+
192
+ The local `opencode.jsonc` is gitignored so your session token stays private.
193
+
194
+ ## CI
195
+
196
+ Tests run automatically on pull requests via GitHub Actions. See [`.github/workflows/test.yml`](.github/workflows/test.yml).
197
+
198
+ ## License
199
+
200
+ MIT
@@ -0,0 +1,39 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "switch-parental-controls"
7
+ version = "0.1.0"
8
+ description = "Nintendo Switch Parental Controls"
9
+ readme = "README.md"
10
+ license = { text = "MIT" }
11
+ requires-python = ">=3.12"
12
+ dependencies = [
13
+ "mcp[cli]>=1.0.0",
14
+ "pydantic>=2.0.0",
15
+ "pynintendoparental>=2.3.4",
16
+ "aiohttp>=3.9.0",
17
+ ]
18
+
19
+ [project.optional-dependencies]
20
+ dev = ["pytest>=8.0.0", "pytest-asyncio>=0.23.0", "ruff>=0.4.0", "python-dotenv>=1.0.0"]
21
+
22
+ [project.scripts]
23
+ mcp = "nintendo_mcp.server:main"
24
+
25
+ [tool.setuptools.packages.find]
26
+ where = ["src"]
27
+
28
+ [tool.pytest.ini_options]
29
+ asyncio_mode = "auto"
30
+ asyncio_default_fixture_loop_scope = "module"
31
+ testpaths = ["tests"]
32
+ markers = ["integration: mark a test as an integration test requiring real Nintendo API credentials"]
33
+
34
+ [tool.ruff]
35
+ line-length = 120
36
+ target-version = "py312"
37
+
38
+ [tool.ruff.lint]
39
+ select = ["E", "F", "I", "UP"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1 @@
1
+ """Nintendo Switch Parental Controls MCP Server."""
@@ -0,0 +1,13 @@
1
+ """Entry point for running the Nintendo MCP server as a module.
2
+
3
+ This file ensures the server is always imported as 'nintendo_mcp.server'
4
+ (never as '__main__'), so tool registrations from all submodules land on
5
+ the same FastMCP instance that gets served.
6
+
7
+ Usage:
8
+ python -m nintendo_mcp
9
+ """
10
+
11
+ from nintendo_mcp.server import main
12
+
13
+ main()
@@ -0,0 +1,181 @@
1
+ """Application tools for the Nintendo MCP server.
2
+
3
+ Provides tools to read application information and manage the allow-list
4
+ (safe launch settings) for games on Nintendo Switch devices.
5
+ """
6
+
7
+ from mcp.server.fastmcp import Context
8
+ from pynintendoparental.enum import SafeLaunchSetting
9
+
10
+ from nintendo_mcp.models import DeviceInput, ResponseFormat, SetAppAllowListInput
11
+ from nintendo_mcp.server import _state, mcp
12
+ from nintendo_mcp.utils import format_minutes, handle_error, require_client, to_json
13
+
14
+
15
+ def _app_to_dict(app) -> dict:
16
+ """Convert an Application object to a serializable dictionary."""
17
+ return {
18
+ "application_id": app.application_id,
19
+ "name": app.name,
20
+ "image_url": app.image_url,
21
+ "today_time_played_minutes": app.today_time_played,
22
+ "allow_list_status": str(app.safe_launch_setting),
23
+ }
24
+
25
+
26
+ @mcp.tool(
27
+ name="nintendo_list_applications",
28
+ annotations={
29
+ "title": "List Applications on Device",
30
+ "readOnlyHint": True,
31
+ "destructiveHint": False,
32
+ "idempotentHint": True,
33
+ "openWorldHint": True,
34
+ },
35
+ )
36
+ async def nintendo_list_applications(params: DeviceInput, ctx: Context) -> str:
37
+ """List all applications (games) tracked on a Nintendo Switch device.
38
+
39
+ Returns all games and applications that have been played on the device,
40
+ including their names, today's playtime, and allow-list status.
41
+
42
+ The allow-list status indicates whether an application can bypass content
43
+ restrictions (ALLOW) or is subject to normal restrictions (NONE).
44
+
45
+ Args:
46
+ params (DeviceInput): Validated input containing:
47
+ - device_id (str): The unique device ID (from nintendo_list_devices).
48
+ - response_format (str): 'markdown' or 'json' (default: 'markdown').
49
+
50
+ Returns:
51
+ str: List of applications with their status, or an error message.
52
+
53
+ Success response (JSON):
54
+ {
55
+ "count": int,
56
+ "device_name": str,
57
+ "applications": [
58
+ {
59
+ "application_id": str,
60
+ "name": str,
61
+ "image_url": str,
62
+ "today_time_played_minutes": int,
63
+ "allow_list_status": str # "NONE" or "ALLOW"
64
+ }
65
+ ]
66
+ }
67
+
68
+ Error Handling:
69
+ - Returns "Error: Not authenticated..." if no session token is configured.
70
+ - Returns "No applications found..." if no apps have been tracked.
71
+ """
72
+ err = require_client(_state.get("client"))
73
+ if err:
74
+ return err
75
+
76
+ try:
77
+ client = _state["client"]
78
+ device = client.devices.get(params.device_id)
79
+ if device is None:
80
+ return (
81
+ f"Error: Device '{params.device_id}' not found. "
82
+ "Use nintendo_list_devices to see available device IDs."
83
+ )
84
+
85
+ await device.update()
86
+ apps = list(device.applications.values())
87
+
88
+ if not apps:
89
+ return f"No applications tracked on device '{device.name}'."
90
+
91
+ if params.response_format == ResponseFormat.JSON:
92
+ return to_json(
93
+ {
94
+ "count": len(apps),
95
+ "device_name": device.name,
96
+ "applications": [_app_to_dict(a) for a in apps],
97
+ }
98
+ )
99
+
100
+ lines = [f"# Applications on {device.name}", ""]
101
+ for app in apps:
102
+ allow_status = str(app.safe_launch_setting)
103
+ allow_label = "✓ Allow-listed" if allow_status == "ALLOW" else "Normal restrictions"
104
+ lines.append(f"## {app.name}")
105
+ lines.append(f"- **App ID**: `{app.application_id}`")
106
+ lines.append(f"- **Today's playtime**: {format_minutes(app.today_time_played)}")
107
+ lines.append(f"- **Allow-list**: {allow_label}")
108
+ lines.append("")
109
+ return "\n".join(lines)
110
+
111
+ except Exception as e:
112
+ return handle_error(e)
113
+
114
+
115
+ @mcp.tool(
116
+ name="nintendo_set_app_allow_list",
117
+ annotations={
118
+ "title": "Set Application Allow-List Status",
119
+ "readOnlyHint": False,
120
+ "destructiveHint": False,
121
+ "idempotentHint": True,
122
+ "openWorldHint": True,
123
+ },
124
+ )
125
+ async def nintendo_set_app_allow_list(params: SetAppAllowListInput, ctx: Context) -> str:
126
+ """Set whether an application can bypass content restrictions on a Nintendo Switch device.
127
+
128
+ Adding an application to the allow-list lets it be launched regardless of the
129
+ device's content restriction level (age rating filter). This is useful for
130
+ educational apps or games that are safe but might be blocked by strict settings.
131
+
132
+ Args:
133
+ params (SetAppAllowListInput): Validated input containing:
134
+ - device_id (str): The unique device ID (from nintendo_list_devices).
135
+ - application_id (str): The unique app ID (from nintendo_list_applications).
136
+ - allow (bool): True to add to allow-list, False to remove from allow-list.
137
+
138
+ Returns:
139
+ str: Confirmation message, or an error message.
140
+
141
+ Error Handling:
142
+ - Returns "Error: Not authenticated..." if no session token is configured.
143
+ - Returns "Error: ..." if the application_id is not found on the device.
144
+ """
145
+ err = require_client(_state.get("client"))
146
+ if err:
147
+ return err
148
+
149
+ try:
150
+ client = _state["client"]
151
+ device = client.devices.get(params.device_id)
152
+ if device is None:
153
+ return (
154
+ f"Error: Device '{params.device_id}' not found. "
155
+ "Use nintendo_list_devices to see available device IDs."
156
+ )
157
+
158
+ await device.update()
159
+ try:
160
+ app = device.get_application(params.application_id)
161
+ except ValueError:
162
+ return (
163
+ f"Error: Application '{params.application_id}' not found on device '{device.name}'. "
164
+ "Use nintendo_list_applications to see available application IDs."
165
+ )
166
+
167
+ setting = SafeLaunchSetting.ALLOW if params.allow else SafeLaunchSetting.NONE
168
+ await app.set_safe_launch_setting(setting)
169
+
170
+ if params.allow:
171
+ return (
172
+ f"✓ '{app.name}' added to the allow-list on '{device.name}'. "
173
+ "It can now bypass content restrictions."
174
+ )
175
+ return (
176
+ f"✓ '{app.name}' removed from the allow-list on '{device.name}'. "
177
+ "It is now subject to normal content restrictions."
178
+ )
179
+
180
+ except Exception as e:
181
+ return handle_error(e)