mgraphctl 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 (57) hide show
  1. mgraphctl-0.1.0/LICENSE +21 -0
  2. mgraphctl-0.1.0/PKG-INFO +226 -0
  3. mgraphctl-0.1.0/README.md +192 -0
  4. mgraphctl-0.1.0/pyproject.toml +98 -0
  5. mgraphctl-0.1.0/pyproject.toml.orig +74 -0
  6. mgraphctl-0.1.0/src/mgraphctl/__init__.py +3 -0
  7. mgraphctl-0.1.0/src/mgraphctl/__main__.py +3 -0
  8. mgraphctl-0.1.0/src/mgraphctl/auth.py +395 -0
  9. mgraphctl-0.1.0/src/mgraphctl/cli.py +259 -0
  10. mgraphctl-0.1.0/src/mgraphctl/commands/__init__.py +71 -0
  11. mgraphctl-0.1.0/src/mgraphctl/commands/api.py +164 -0
  12. mgraphctl-0.1.0/src/mgraphctl/commands/calendar.py +491 -0
  13. mgraphctl-0.1.0/src/mgraphctl/commands/chats.py +329 -0
  14. mgraphctl-0.1.0/src/mgraphctl/commands/config_cmd.py +140 -0
  15. mgraphctl-0.1.0/src/mgraphctl/commands/groups.py +65 -0
  16. mgraphctl-0.1.0/src/mgraphctl/commands/mail.py +705 -0
  17. mgraphctl-0.1.0/src/mgraphctl/commands/mailbox.py +176 -0
  18. mgraphctl-0.1.0/src/mgraphctl/commands/meetings.py +294 -0
  19. mgraphctl-0.1.0/src/mgraphctl/commands/onedrive.py +351 -0
  20. mgraphctl-0.1.0/src/mgraphctl/commands/onenote.py +196 -0
  21. mgraphctl-0.1.0/src/mgraphctl/commands/org.py +102 -0
  22. mgraphctl-0.1.0/src/mgraphctl/commands/people.py +201 -0
  23. mgraphctl-0.1.0/src/mgraphctl/commands/planner.py +268 -0
  24. mgraphctl-0.1.0/src/mgraphctl/commands/presence.py +102 -0
  25. mgraphctl-0.1.0/src/mgraphctl/commands/search.py +75 -0
  26. mgraphctl-0.1.0/src/mgraphctl/commands/sharepoint.py +304 -0
  27. mgraphctl-0.1.0/src/mgraphctl/commands/teams.py +235 -0
  28. mgraphctl-0.1.0/src/mgraphctl/commands/todo.py +253 -0
  29. mgraphctl-0.1.0/src/mgraphctl/commands/top.py +284 -0
  30. mgraphctl-0.1.0/src/mgraphctl/config.py +385 -0
  31. mgraphctl-0.1.0/src/mgraphctl/errors.py +276 -0
  32. mgraphctl-0.1.0/src/mgraphctl/fixtures.py +149 -0
  33. mgraphctl-0.1.0/src/mgraphctl/graph/__init__.py +1 -0
  34. mgraphctl-0.1.0/src/mgraphctl/graph/calendar.py +313 -0
  35. mgraphctl-0.1.0/src/mgraphctl/graph/chats.py +447 -0
  36. mgraphctl-0.1.0/src/mgraphctl/graph/files.py +269 -0
  37. mgraphctl-0.1.0/src/mgraphctl/graph/groups.py +55 -0
  38. mgraphctl-0.1.0/src/mgraphctl/graph/mail.py +663 -0
  39. mgraphctl-0.1.0/src/mgraphctl/graph/mailbox.py +89 -0
  40. mgraphctl-0.1.0/src/mgraphctl/graph/meetings.py +269 -0
  41. mgraphctl-0.1.0/src/mgraphctl/graph/onedrive.py +35 -0
  42. mgraphctl-0.1.0/src/mgraphctl/graph/onenote.py +138 -0
  43. mgraphctl-0.1.0/src/mgraphctl/graph/org.py +86 -0
  44. mgraphctl-0.1.0/src/mgraphctl/graph/people.py +83 -0
  45. mgraphctl-0.1.0/src/mgraphctl/graph/planner.py +415 -0
  46. mgraphctl-0.1.0/src/mgraphctl/graph/presence.py +89 -0
  47. mgraphctl-0.1.0/src/mgraphctl/graph/search.py +178 -0
  48. mgraphctl-0.1.0/src/mgraphctl/graph/sharepoint.py +294 -0
  49. mgraphctl-0.1.0/src/mgraphctl/graph/teams.py +240 -0
  50. mgraphctl-0.1.0/src/mgraphctl/graph/todo.py +199 -0
  51. mgraphctl-0.1.0/src/mgraphctl/graph/users.py +85 -0
  52. mgraphctl-0.1.0/src/mgraphctl/html.py +127 -0
  53. mgraphctl-0.1.0/src/mgraphctl/http.py +843 -0
  54. mgraphctl-0.1.0/src/mgraphctl/odata.py +72 -0
  55. mgraphctl-0.1.0/src/mgraphctl/render.py +627 -0
  56. mgraphctl-0.1.0/src/mgraphctl/resolve.py +111 -0
  57. mgraphctl-0.1.0/src/mgraphctl/token_store.py +196 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Sviatoslav Sviridov
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,226 @@
1
+ Metadata-Version: 2.4
2
+ Name: mgraphctl
3
+ Version: 0.1.0
4
+ Summary: Microsoft Graph CLI behind the mgraphctl Claude Code skill
5
+ Keywords: microsoft-graph,microsoft-365,outlook,teams,sharepoint,onedrive,cli
6
+ Author: Sviatoslav Sviridov
7
+ Author-email: Sviatoslav Sviridov <sviridov@gmail.com>
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Intended Audience :: End Users/Desktop
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Communications :: Email
20
+ Classifier: Topic :: Office/Business
21
+ Classifier: Topic :: Utilities
22
+ Requires-Dist: msal>=1.38,<2
23
+ Requires-Dist: httpx>=0.28,<1
24
+ Requires-Dist: typer>=0.27,<1
25
+ Requires-Dist: markdownify>=1.2,<2
26
+ Requires-Dist: keyring>=24,<26
27
+ Requires-Dist: tzdata ; sys_platform == 'win32'
28
+ Requires-Python: >=3.11, <3.14
29
+ Project-URL: Homepage, https://github.com/svd/mgraphctl
30
+ Project-URL: Source, https://github.com/svd/mgraphctl
31
+ Project-URL: Changelog, https://github.com/svd/mgraphctl/blob/main/CHANGELOG.md
32
+ Project-URL: Issues, https://github.com/svd/mgraphctl/issues
33
+ Description-Content-Type: text/markdown
34
+
35
+ # mgraphctl
36
+
37
+ Microsoft 365 access from Claude Code through the Microsoft Graph API: Outlook mail and
38
+ calendar, Teams chats and channel messages, presence, meetings and transcripts, SharePoint,
39
+ OneDrive, OneNote, Planner, Microsoft To Do, AI meeting insights, contacts, and the org chart.
40
+
41
+ The plugin ships a single skill, `mgraphctl`. It is a Python re-implementation of the `msgraph`
42
+ skill, run with `uv`, with a noun-verb command line (`mail list`, `calendar create`, `chats dm`,
43
+ …) instead of Node's flag-driven modes. It is an original design for this repository — not a
44
+ port of, and not tracking, any upstream project — and it extends the Node skill's coverage with
45
+ mail triage, mailbox settings and automatic replies, scheduling (`getSchedule`,
46
+ `findMeetingTimes`), find-or-create Teams DMs, presence, SharePoint lists and uploads, OneDrive
47
+ writes and sharing links, a unified `search` command, and a raw `api` escape hatch. Every write
48
+ verb supports `--dry-run`, and no data command ever opens a browser.
49
+
50
+ ## Install
51
+
52
+ ```bash
53
+ claude plugin marketplace add svd/mgraphctl
54
+ claude plugin install mgraphctl@mgraphctl
55
+ ```
56
+
57
+ The CLI is also on PyPI for use outside Claude Code, under the same version as the plugin:
58
+
59
+ ```bash
60
+ uv tool install mgraphctl # or: pipx install mgraphctl / uvx mgraphctl status
61
+ mgraphctl status
62
+ ```
63
+
64
+ ## Prerequisite: uv
65
+
66
+ The only prerequisite is [`uv`](https://docs.astral.sh/uv/). On first use in a given environment,
67
+ the plugin's shim script creates a Python virtual environment and installs the CLI's dependencies
68
+ automatically — this takes about 10-40 seconds once; every run after that starts immediately.
69
+ Nothing else needs to be installed by hand.
70
+
71
+ ```bash
72
+ curl -LsSf https://astral.sh/uv/install.sh | sh # macOS / Linux
73
+ brew install uv # macOS, via Homebrew
74
+ powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" # Windows
75
+ ```
76
+
77
+ ## First run and login
78
+
79
+ mgraphctl signs in as an Entra application of your own; there is no shared one. Before the
80
+ first login, register a public-client application in your tenant (or ask an administrator for
81
+ the id of one) and tell mgraphctl its client id, once:
82
+
83
+ ```bash
84
+ ${CLAUDE_PLUGIN_ROOT}/mgraphctl config set client_id <application (client) id>
85
+ ```
86
+
87
+ `MGRAPHCTL_CLIENT_ID` in the environment works too. Until one is set, `login` and `status` stop
88
+ with `error[CONFIG]: client_id is not set` rather than an Entra error.
89
+
90
+ Check status first — it never opens a browser and always says what to do next:
91
+
92
+ ```bash
93
+ ${CLAUDE_PLUGIN_ROOT}/mgraphctl status
94
+ ```
95
+
96
+ Signing in is interactive, so run it yourself in your own terminal rather than asking Claude to
97
+ run it for you:
98
+
99
+ ```bash
100
+ ${CLAUDE_PLUGIN_ROOT}/mgraphctl login
101
+ ```
102
+
103
+ By default `login` opens your system browser for a Microsoft sign-in page. On a host with no
104
+ browser (for example over SSH), use the device-code flow instead, which prints a URL and a code
105
+ to enter on another device:
106
+
107
+ ```bash
108
+ ${CLAUDE_PLUGIN_ROOT}/mgraphctl login --device-code
109
+ ```
110
+
111
+ On Windows, or wherever the bash shim cannot run, invoke `uv` directly:
112
+
113
+ ```bat
114
+ set UV_PROJECT_ENVIRONMENT=%LOCALAPPDATA%\mgraphctl\venv
115
+ uv run --project <plugin> --frozen --no-dev mgraphctl login
116
+ ```
117
+
118
+ Every other command reads the cached sign-in silently and never opens a browser or a device-code
119
+ prompt — a missing or expired token fails with an actionable hint instead.
120
+
121
+ ## Where things live
122
+
123
+ - Virtual environment: under `${CLAUDE_PLUGIN_DATA}` when Claude Code sets it, otherwise
124
+ `~/.cache/mgraphctl/venv` (`$XDG_CACHE_HOME/mgraphctl/venv` when that variable is set).
125
+ Persistent across plugin updates; safe to delete, it is rebuilt on the next run.
126
+ - Token cache: the OS keychain (macOS Keychain, Windows Credential Locker, Linux Secret
127
+ Service) when one is available, as a single `mgraphctl` item whose account is the cache path.
128
+ Without one it is `~/.mgraphctl/token_cache.json`, mode `0600`, in a `0700` directory.
129
+ `token_store = auto | keyring | file` in the config file, or `MGRAPHCTL_TOKEN_STORE`, picks;
130
+ `status` shows which store is in use. A cache file left by an earlier version is imported into
131
+ the keychain on the first run and then deleted. When the keychain refuses (locked, denied,
132
+ no session bus), the file takes over for that run with one warning on stderr. On macOS a
133
+ rebuilt Python (a new venv, a `uv` upgrade) asks once for keychain access; answer
134
+ "Always Allow". `token_store = "file"` restores the old behaviour.
135
+ - Config file: `~/.mgraphctl/config.toml`, optional (`--config PATH` or `MGRAPHCTL_CONFIG` to
136
+ point elsewhere). Every `MGRAPHCTL_*` setting can go there as the name without the prefix,
137
+ lower-cased; a flag beats an environment variable, which beats the file. `mgraphctl config init`
138
+ writes a commented template, `mgraphctl config set tz Europe/Warsaw` edits one key, and
139
+ `mgraphctl config show` prints where each value came from.
140
+
141
+ ```toml
142
+ tenant_id = "contoso.onmicrosoft.com"
143
+ scopes = "extended"
144
+ tz = "Europe/Warsaw"
145
+ ```
146
+
147
+ ## Scopes
148
+
149
+ Two named scope sets cover almost everything:
150
+
151
+ - `default` — the 23 scopes the Node `msgraph` skill has always requested: mail read/send,
152
+ calendars, files, sites, chats, channel messages, meeting transcripts, people, contacts, notes,
153
+ tasks, and group membership. This is what `login` requests unless told otherwise.
154
+ - `extended` — `default` plus write access to mail and mailbox settings, presence, directory
155
+ user lookup, shared calendars, chat creation, and team/channel listing. Request it with
156
+ `login --scopes extended`; running it again on an already-consented account adds the new scopes
157
+ with one more consent prompt, no re-login needed.
158
+
159
+ A handful of scopes are on-demand only, requested with `--scope <name>` on the command that needs
160
+ them (`meetings recordings`, `org manager|reports|chain` for another user, `presence get USER`) —
161
+ they are never in `default` or `extended`.
162
+
163
+ Some tenants require an administrator to grant consent once for the app registration. If a
164
+ command fails with `error[CONSENT_REQUIRED]`, the error prints the admin-consent URL to send to
165
+ your Microsoft 365 administrator:
166
+
167
+ ```
168
+ https://login.microsoftonline.com/<tenant>/adminconsent?client_id=<client id>
169
+ ```
170
+
171
+ ## Differences from `msgraph`
172
+
173
+ What differs from the Node `msgraph` skill:
174
+
175
+ - Commands are noun-verb (`mail list`, `calendar create`, `chats send`) instead of Node's
176
+ flag-driven modes (`--emails`, `--calendar --create`, `--send`).
177
+ - `mail list` defaults to the Inbox; `msgraph`'s `emails` mode listed the whole mailbox. Pass
178
+ `--folder all` for the old behaviour.
179
+ - Exit codes differ: this CLI uses 0 (success), 1 (runtime error), 2 (usage error), 3 (auth or
180
+ permission problem), 4 (not found) — `msgraph` was less consistent, including exiting 0 when
181
+ not logged in.
182
+
183
+ ## Troubleshooting
184
+
185
+ - **`mgraphctl: 'uv' is not installed`** — install `uv` (see **Prerequisite** above) and try
186
+ again.
187
+ - **First run is slow** — the shim is building the virtual environment (10-40 seconds); it prints
188
+ a notice to stderr while doing so, and every later run is fast.
189
+ - **`error[CONSENT_REQUIRED]`** — an administrator must grant consent once; the error prints the
190
+ admin-consent URL (see **Scopes** above).
191
+ - **`error[NOT_LOGGED_IN]`** — run `login` yourself in your own terminal; data commands never open
192
+ a browser on their own.
193
+ - **`error[MISSING_SCOPE]`** — the cached sign-in doesn't cover this command; run
194
+ `login --scopes extended`, or `login --scope <name>` for an on-demand scope.
195
+ - **`claims` exits 3 on a stale or missing cache** — it decodes the cached token locally and never
196
+ makes a network call, so it cannot refresh an expired token; run `login` (or `status`, which
197
+ does refresh silently) first.
198
+ - **Device-code login is blocked** — some tenants apply Conditional Access policies that require
199
+ a compliant, registered device; the device-code flow cannot satisfy those and interactive
200
+ browser login is the only option.
201
+ - **Behind a proxy** — set `HTTPS_PROXY` (and `HTTP_PROXY` if needed); the CLI honours the
202
+ standard proxy environment variables.
203
+ - **Times look wrong** — the CLI detects your local IANA time zone automatically; override it with
204
+ `MGRAPHCTL_TZ=Europe/Warsaw` or the global `--tz` option if detection picks the wrong zone.
205
+
206
+ ## Development
207
+
208
+ ```bash
209
+ uv sync
210
+ uv run pytest
211
+ uv run ruff check src tests
212
+ uv run ruff format src tests
213
+ ```
214
+
215
+ The test suite runs entirely offline against recorded fixtures — no Microsoft 365 account or
216
+ network access is needed to run it.
217
+
218
+ CI (`.github/workflows/ci.yml`) runs the suite on Python 3.11–3.13, ruff, `uv lock --check` and a
219
+ credential scan on every push. Releases are annotated `mgraphctl--vX.Y.Z` tags on `main`, cut with
220
+ `claude plugin tag`; the tag publishes the package to PyPI and a GitHub Release. See `VERSIONING.md`.
221
+
222
+ ## Provenance and licence
223
+
224
+ `mgraphctl` is original to this repository: an independent Python re-implementation of the
225
+ `msgraph` skill's feature set, not a port and not tracking any upstream project. Licensed under
226
+ the MIT licence; see `LICENSE`.
@@ -0,0 +1,192 @@
1
+ # mgraphctl
2
+
3
+ Microsoft 365 access from Claude Code through the Microsoft Graph API: Outlook mail and
4
+ calendar, Teams chats and channel messages, presence, meetings and transcripts, SharePoint,
5
+ OneDrive, OneNote, Planner, Microsoft To Do, AI meeting insights, contacts, and the org chart.
6
+
7
+ The plugin ships a single skill, `mgraphctl`. It is a Python re-implementation of the `msgraph`
8
+ skill, run with `uv`, with a noun-verb command line (`mail list`, `calendar create`, `chats dm`,
9
+ …) instead of Node's flag-driven modes. It is an original design for this repository — not a
10
+ port of, and not tracking, any upstream project — and it extends the Node skill's coverage with
11
+ mail triage, mailbox settings and automatic replies, scheduling (`getSchedule`,
12
+ `findMeetingTimes`), find-or-create Teams DMs, presence, SharePoint lists and uploads, OneDrive
13
+ writes and sharing links, a unified `search` command, and a raw `api` escape hatch. Every write
14
+ verb supports `--dry-run`, and no data command ever opens a browser.
15
+
16
+ ## Install
17
+
18
+ ```bash
19
+ claude plugin marketplace add svd/mgraphctl
20
+ claude plugin install mgraphctl@mgraphctl
21
+ ```
22
+
23
+ The CLI is also on PyPI for use outside Claude Code, under the same version as the plugin:
24
+
25
+ ```bash
26
+ uv tool install mgraphctl # or: pipx install mgraphctl / uvx mgraphctl status
27
+ mgraphctl status
28
+ ```
29
+
30
+ ## Prerequisite: uv
31
+
32
+ The only prerequisite is [`uv`](https://docs.astral.sh/uv/). On first use in a given environment,
33
+ the plugin's shim script creates a Python virtual environment and installs the CLI's dependencies
34
+ automatically — this takes about 10-40 seconds once; every run after that starts immediately.
35
+ Nothing else needs to be installed by hand.
36
+
37
+ ```bash
38
+ curl -LsSf https://astral.sh/uv/install.sh | sh # macOS / Linux
39
+ brew install uv # macOS, via Homebrew
40
+ powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" # Windows
41
+ ```
42
+
43
+ ## First run and login
44
+
45
+ mgraphctl signs in as an Entra application of your own; there is no shared one. Before the
46
+ first login, register a public-client application in your tenant (or ask an administrator for
47
+ the id of one) and tell mgraphctl its client id, once:
48
+
49
+ ```bash
50
+ ${CLAUDE_PLUGIN_ROOT}/mgraphctl config set client_id <application (client) id>
51
+ ```
52
+
53
+ `MGRAPHCTL_CLIENT_ID` in the environment works too. Until one is set, `login` and `status` stop
54
+ with `error[CONFIG]: client_id is not set` rather than an Entra error.
55
+
56
+ Check status first — it never opens a browser and always says what to do next:
57
+
58
+ ```bash
59
+ ${CLAUDE_PLUGIN_ROOT}/mgraphctl status
60
+ ```
61
+
62
+ Signing in is interactive, so run it yourself in your own terminal rather than asking Claude to
63
+ run it for you:
64
+
65
+ ```bash
66
+ ${CLAUDE_PLUGIN_ROOT}/mgraphctl login
67
+ ```
68
+
69
+ By default `login` opens your system browser for a Microsoft sign-in page. On a host with no
70
+ browser (for example over SSH), use the device-code flow instead, which prints a URL and a code
71
+ to enter on another device:
72
+
73
+ ```bash
74
+ ${CLAUDE_PLUGIN_ROOT}/mgraphctl login --device-code
75
+ ```
76
+
77
+ On Windows, or wherever the bash shim cannot run, invoke `uv` directly:
78
+
79
+ ```bat
80
+ set UV_PROJECT_ENVIRONMENT=%LOCALAPPDATA%\mgraphctl\venv
81
+ uv run --project <plugin> --frozen --no-dev mgraphctl login
82
+ ```
83
+
84
+ Every other command reads the cached sign-in silently and never opens a browser or a device-code
85
+ prompt — a missing or expired token fails with an actionable hint instead.
86
+
87
+ ## Where things live
88
+
89
+ - Virtual environment: under `${CLAUDE_PLUGIN_DATA}` when Claude Code sets it, otherwise
90
+ `~/.cache/mgraphctl/venv` (`$XDG_CACHE_HOME/mgraphctl/venv` when that variable is set).
91
+ Persistent across plugin updates; safe to delete, it is rebuilt on the next run.
92
+ - Token cache: the OS keychain (macOS Keychain, Windows Credential Locker, Linux Secret
93
+ Service) when one is available, as a single `mgraphctl` item whose account is the cache path.
94
+ Without one it is `~/.mgraphctl/token_cache.json`, mode `0600`, in a `0700` directory.
95
+ `token_store = auto | keyring | file` in the config file, or `MGRAPHCTL_TOKEN_STORE`, picks;
96
+ `status` shows which store is in use. A cache file left by an earlier version is imported into
97
+ the keychain on the first run and then deleted. When the keychain refuses (locked, denied,
98
+ no session bus), the file takes over for that run with one warning on stderr. On macOS a
99
+ rebuilt Python (a new venv, a `uv` upgrade) asks once for keychain access; answer
100
+ "Always Allow". `token_store = "file"` restores the old behaviour.
101
+ - Config file: `~/.mgraphctl/config.toml`, optional (`--config PATH` or `MGRAPHCTL_CONFIG` to
102
+ point elsewhere). Every `MGRAPHCTL_*` setting can go there as the name without the prefix,
103
+ lower-cased; a flag beats an environment variable, which beats the file. `mgraphctl config init`
104
+ writes a commented template, `mgraphctl config set tz Europe/Warsaw` edits one key, and
105
+ `mgraphctl config show` prints where each value came from.
106
+
107
+ ```toml
108
+ tenant_id = "contoso.onmicrosoft.com"
109
+ scopes = "extended"
110
+ tz = "Europe/Warsaw"
111
+ ```
112
+
113
+ ## Scopes
114
+
115
+ Two named scope sets cover almost everything:
116
+
117
+ - `default` — the 23 scopes the Node `msgraph` skill has always requested: mail read/send,
118
+ calendars, files, sites, chats, channel messages, meeting transcripts, people, contacts, notes,
119
+ tasks, and group membership. This is what `login` requests unless told otherwise.
120
+ - `extended` — `default` plus write access to mail and mailbox settings, presence, directory
121
+ user lookup, shared calendars, chat creation, and team/channel listing. Request it with
122
+ `login --scopes extended`; running it again on an already-consented account adds the new scopes
123
+ with one more consent prompt, no re-login needed.
124
+
125
+ A handful of scopes are on-demand only, requested with `--scope <name>` on the command that needs
126
+ them (`meetings recordings`, `org manager|reports|chain` for another user, `presence get USER`) —
127
+ they are never in `default` or `extended`.
128
+
129
+ Some tenants require an administrator to grant consent once for the app registration. If a
130
+ command fails with `error[CONSENT_REQUIRED]`, the error prints the admin-consent URL to send to
131
+ your Microsoft 365 administrator:
132
+
133
+ ```
134
+ https://login.microsoftonline.com/<tenant>/adminconsent?client_id=<client id>
135
+ ```
136
+
137
+ ## Differences from `msgraph`
138
+
139
+ What differs from the Node `msgraph` skill:
140
+
141
+ - Commands are noun-verb (`mail list`, `calendar create`, `chats send`) instead of Node's
142
+ flag-driven modes (`--emails`, `--calendar --create`, `--send`).
143
+ - `mail list` defaults to the Inbox; `msgraph`'s `emails` mode listed the whole mailbox. Pass
144
+ `--folder all` for the old behaviour.
145
+ - Exit codes differ: this CLI uses 0 (success), 1 (runtime error), 2 (usage error), 3 (auth or
146
+ permission problem), 4 (not found) — `msgraph` was less consistent, including exiting 0 when
147
+ not logged in.
148
+
149
+ ## Troubleshooting
150
+
151
+ - **`mgraphctl: 'uv' is not installed`** — install `uv` (see **Prerequisite** above) and try
152
+ again.
153
+ - **First run is slow** — the shim is building the virtual environment (10-40 seconds); it prints
154
+ a notice to stderr while doing so, and every later run is fast.
155
+ - **`error[CONSENT_REQUIRED]`** — an administrator must grant consent once; the error prints the
156
+ admin-consent URL (see **Scopes** above).
157
+ - **`error[NOT_LOGGED_IN]`** — run `login` yourself in your own terminal; data commands never open
158
+ a browser on their own.
159
+ - **`error[MISSING_SCOPE]`** — the cached sign-in doesn't cover this command; run
160
+ `login --scopes extended`, or `login --scope <name>` for an on-demand scope.
161
+ - **`claims` exits 3 on a stale or missing cache** — it decodes the cached token locally and never
162
+ makes a network call, so it cannot refresh an expired token; run `login` (or `status`, which
163
+ does refresh silently) first.
164
+ - **Device-code login is blocked** — some tenants apply Conditional Access policies that require
165
+ a compliant, registered device; the device-code flow cannot satisfy those and interactive
166
+ browser login is the only option.
167
+ - **Behind a proxy** — set `HTTPS_PROXY` (and `HTTP_PROXY` if needed); the CLI honours the
168
+ standard proxy environment variables.
169
+ - **Times look wrong** — the CLI detects your local IANA time zone automatically; override it with
170
+ `MGRAPHCTL_TZ=Europe/Warsaw` or the global `--tz` option if detection picks the wrong zone.
171
+
172
+ ## Development
173
+
174
+ ```bash
175
+ uv sync
176
+ uv run pytest
177
+ uv run ruff check src tests
178
+ uv run ruff format src tests
179
+ ```
180
+
181
+ The test suite runs entirely offline against recorded fixtures — no Microsoft 365 account or
182
+ network access is needed to run it.
183
+
184
+ CI (`.github/workflows/ci.yml`) runs the suite on Python 3.11–3.13, ruff, `uv lock --check` and a
185
+ credential scan on every push. Releases are annotated `mgraphctl--vX.Y.Z` tags on `main`, cut with
186
+ `claude plugin tag`; the tag publishes the package to PyPI and a GitHub Release. See `VERSIONING.md`.
187
+
188
+ ## Provenance and licence
189
+
190
+ `mgraphctl` is original to this repository: an independent Python re-implementation of the
191
+ `msgraph` skill's feature set, not a port and not tracking any upstream project. Licensed under
192
+ the MIT licence; see `LICENSE`.
@@ -0,0 +1,98 @@
1
+ [project]
2
+ name = "mgraphctl"
3
+ version = "0.1.0"
4
+ description = "Microsoft Graph CLI behind the mgraphctl Claude Code skill"
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ license-files = ["LICENSE"]
8
+ requires-python = ">=3.11,<3.14"
9
+ keywords = [
10
+ "microsoft-graph",
11
+ "microsoft-365",
12
+ "outlook",
13
+ "teams",
14
+ "sharepoint",
15
+ "onedrive",
16
+ "cli",
17
+ ]
18
+ classifiers = [
19
+ "Development Status :: 4 - Beta",
20
+ "Environment :: Console",
21
+ "Intended Audience :: Developers",
22
+ "Intended Audience :: End Users/Desktop",
23
+ "Operating System :: OS Independent",
24
+ "Programming Language :: Python :: 3",
25
+ "Programming Language :: Python :: 3.11",
26
+ "Programming Language :: Python :: 3.12",
27
+ "Programming Language :: Python :: 3.13",
28
+ "Topic :: Communications :: Email",
29
+ "Topic :: Office/Business",
30
+ "Topic :: Utilities",
31
+ ]
32
+ dependencies = [
33
+ "msal>=1.38,<2",
34
+ "httpx>=0.28,<1",
35
+ "typer>=0.27,<1",
36
+ "markdownify>=1.2,<2",
37
+ "keyring>=24,<26",
38
+ "tzdata; sys_platform == 'win32'",
39
+ ]
40
+
41
+ [[project.authors]]
42
+ name = "Sviatoslav Sviridov"
43
+ email = "sviridov@gmail.com"
44
+
45
+ [project.urls]
46
+ Homepage = "https://github.com/svd/mgraphctl"
47
+ Source = "https://github.com/svd/mgraphctl"
48
+ Changelog = "https://github.com/svd/mgraphctl/blob/main/CHANGELOG.md"
49
+ Issues = "https://github.com/svd/mgraphctl/issues"
50
+
51
+ [project.scripts]
52
+ mgraphctl = "mgraphctl.cli:main"
53
+
54
+ [dependency-groups]
55
+ dev = [
56
+ "pytest>=8",
57
+ "respx>=0.23",
58
+ "ruff>=0.13",
59
+ ]
60
+
61
+ [build-system]
62
+ requires = ["uv_build>=0.8,<1"]
63
+ build-backend = "uv_build"
64
+
65
+ [tool.uv]
66
+ exclude-newer = "2026-09-01T00:00:00Z"
67
+
68
+ [tool.uv.build-backend]
69
+ module-name = "mgraphctl"
70
+
71
+ [tool.ruff]
72
+ line-length = 100
73
+ target-version = "py311"
74
+ extend-exclude = ["docs"]
75
+
76
+ [tool.ruff.lint]
77
+ select = [
78
+ "E",
79
+ "F",
80
+ "I",
81
+ "UP",
82
+ "B",
83
+ "SIM",
84
+ ]
85
+
86
+ [tool.ruff.lint.isort]
87
+ known-first-party = [
88
+ "mgraphctl",
89
+ "helpers",
90
+ ]
91
+
92
+ [tool.pytest.ini_options]
93
+ testpaths = ["tests"]
94
+ addopts = "-q"
95
+ markers = [
96
+ "real_auth: module tests auth itself; do not install the fake token provider",
97
+ "scopes(list): scopes carried by the synthetic token for this test",
98
+ ]
@@ -0,0 +1,74 @@
1
+ [project]
2
+ name = "mgraphctl"
3
+ version = "0.1.0"
4
+ description = "Microsoft Graph CLI behind the mgraphctl Claude Code skill"
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ license-files = ["LICENSE"]
8
+ authors = [{ name = "Sviatoslav Sviridov", email = "sviridov@gmail.com" }]
9
+ requires-python = ">=3.11,<3.14"
10
+ keywords = ["microsoft-graph", "microsoft-365", "outlook", "teams", "sharepoint", "onedrive", "cli"]
11
+ classifiers = [
12
+ "Development Status :: 4 - Beta",
13
+ "Environment :: Console",
14
+ "Intended Audience :: Developers",
15
+ "Intended Audience :: End Users/Desktop",
16
+ "Operating System :: OS Independent",
17
+ "Programming Language :: Python :: 3",
18
+ "Programming Language :: Python :: 3.11",
19
+ "Programming Language :: Python :: 3.12",
20
+ "Programming Language :: Python :: 3.13",
21
+ "Topic :: Communications :: Email",
22
+ "Topic :: Office/Business",
23
+ "Topic :: Utilities",
24
+ ]
25
+ dependencies = [
26
+ "msal>=1.38,<2",
27
+ "httpx>=0.28,<1",
28
+ "typer>=0.27,<1",
29
+ "markdownify>=1.2,<2",
30
+ "keyring>=24,<26",
31
+ "tzdata; sys_platform == 'win32'",
32
+ ]
33
+
34
+ [project.urls]
35
+ Homepage = "https://github.com/svd/mgraphctl"
36
+ Source = "https://github.com/svd/mgraphctl"
37
+ Changelog = "https://github.com/svd/mgraphctl/blob/main/CHANGELOG.md"
38
+ Issues = "https://github.com/svd/mgraphctl/issues"
39
+
40
+ [project.scripts]
41
+ mgraphctl = "mgraphctl.cli:main"
42
+
43
+ [dependency-groups]
44
+ dev = ["pytest>=8", "respx>=0.23", "ruff>=0.13"]
45
+
46
+ [build-system]
47
+ requires = ["uv_build>=0.8,<1"]
48
+ build-backend = "uv_build"
49
+
50
+ [tool.uv]
51
+ exclude-newer = "2026-09-01T00:00:00Z"
52
+
53
+ [tool.uv.build-backend]
54
+ module-name = "mgraphctl"
55
+
56
+ [tool.ruff]
57
+ line-length = 100
58
+ target-version = "py311"
59
+ # Markdown under docs/ holds illustrative Python blocks; ruff must not rewrite them.
60
+ extend-exclude = ["docs"]
61
+
62
+ [tool.ruff.lint]
63
+ select = ["E", "F", "I", "UP", "B", "SIM"]
64
+
65
+ [tool.ruff.lint.isort]
66
+ known-first-party = ["mgraphctl", "helpers"]
67
+
68
+ [tool.pytest.ini_options]
69
+ testpaths = ["tests"]
70
+ addopts = "-q"
71
+ markers = [
72
+ "real_auth: module tests auth itself; do not install the fake token provider",
73
+ "scopes(list): scopes carried by the synthetic token for this test",
74
+ ]
@@ -0,0 +1,3 @@
1
+ """mgraphctl: Microsoft Graph CLI for the mgraphctl skill."""
2
+
3
+ __version__ = "0.1.0"
@@ -0,0 +1,3 @@
1
+ from .cli import main
2
+
3
+ main()