induslms-agent 0.3.0__py3-none-any.whl
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.
- induslms_agent-0.3.0.dist-info/METADATA +252 -0
- induslms_agent-0.3.0.dist-info/RECORD +11 -0
- induslms_agent-0.3.0.dist-info/WHEEL +5 -0
- induslms_agent-0.3.0.dist-info/entry_points.txt +6 -0
- induslms_agent-0.3.0.dist-info/licenses/LICENSE +21 -0
- induslms_agent-0.3.0.dist-info/top_level.txt +5 -0
- lms.py +854 -0
- mailapp.py +201 -0
- outlook.py +256 -0
- server.py +231 -0
- sharepoint.py +228 -0
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: induslms-agent
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Read-only agent access to Indus LMS academics: announcements, assignments, shared resources, attendance
|
|
5
|
+
Author: IndusLMS Agent contributors
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/StrangeSid/induslms-agent
|
|
8
|
+
Project-URL: Repository, https://github.com/StrangeSid/induslms-agent
|
|
9
|
+
Project-URL: Issues, https://github.com/StrangeSid/induslms-agent/issues
|
|
10
|
+
Keywords: lms,mcp,education,school,agent
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Education
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Topic :: Education
|
|
17
|
+
Classifier: Topic :: Scientific/Engineering :: Interface Engine/Protocol Translator
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Requires-Dist: requests>=2.31
|
|
22
|
+
Requires-Dist: mcp<2,>=1.0
|
|
23
|
+
Requires-Dist: msal>=1.30
|
|
24
|
+
Requires-Dist: python-dotenv>=1.0
|
|
25
|
+
Dynamic: license-file
|
|
26
|
+
|
|
27
|
+
# IndusLMS Agent
|
|
28
|
+
|
|
29
|
+
Read-only agent access to Indus LMS academics: **announcements, assignments, shared resources, notifications, attendance**. For `pi` + `opencode` harnesses via **MCP + Skill + CLI**.
|
|
30
|
+
|
|
31
|
+
## Quickstart (one command)
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
git clone https://github.com/StrangeSid/induslms-agent.git
|
|
35
|
+
cd induslms-agent
|
|
36
|
+
./install.sh
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
This creates `.venv`, installs the package, runs `lms.py login`,
|
|
40
|
+
merges MCP configs for pi + opencode, installs the skill, and runs
|
|
41
|
+
`lms.py doctor`. Restart your agent host afterwards.
|
|
42
|
+
|
|
43
|
+
Manual setup (if you prefer):
|
|
44
|
+
|
|
45
|
+
> Replace `/path/to/induslms-agent` with your checkout path and
|
|
46
|
+
> `you@indusschool.com` with your school email.
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
cd /path/to/induslms-agent
|
|
50
|
+
python3 -m venv .venv && source .venv/bin/activate
|
|
51
|
+
pip install -e . # or: pip install -r requirements.txt
|
|
52
|
+
|
|
53
|
+
cp .env.example .env # then fill INDUSLMS_EMAIL/PASS/TENANT (.env auto-loaded)
|
|
54
|
+
# Authenticate once (token saved OUTSIDE the repo)
|
|
55
|
+
python3 lms.py login you@indusschool.com
|
|
56
|
+
# or: INDUSLMS_EMAIL=... INDUSLMS_PASS=... python3 lms.py login
|
|
57
|
+
|
|
58
|
+
# Health check
|
|
59
|
+
python3 lms.py doctor
|
|
60
|
+
# CLI
|
|
61
|
+
python3 lms.py courses
|
|
62
|
+
python3 lms.py assignments --course <course_id>
|
|
63
|
+
python3 lms.py resources --course <course_id>
|
|
64
|
+
python3 lms.py children <folder_id>
|
|
65
|
+
python3 lms.py download <resource_id> <file_id> --out /tmp/induslms-test
|
|
66
|
+
python3 lms.py notifications --unread-only --limit 5
|
|
67
|
+
python3 lms.py attendance && python3 lms.py attendance-day
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Tokens live at `~/.induslms_token.json` (override with `INDUSLMS_TOKEN_FILE`). Never committed — see `.gitignore`.
|
|
71
|
+
|
|
72
|
+
## Credentials (`.env`) — used by programs, never sent to the LLM
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
cp .env.example .env # then fill in your own values
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
| Variable | Used by | Never leaves your machine |
|
|
79
|
+
|---|---|---|
|
|
80
|
+
| `INDUSLMS_EMAIL` / `INDUSLMS_PASS` | `lms.py login` only (one POST, then discarded) | ✅ |
|
|
81
|
+
| `INDUSLMS_TENANT` | Tenant fallback when the token has no roles | ✅ |
|
|
82
|
+
| `INDUSLMS_TOKEN_FILE` | Where the JWT is cached (`~/.induslms_token.json`) | ✅ |
|
|
83
|
+
| `INDUS_OUTLOOK_CLIENT_ID` | Graph device-code login (`outlook.py login`) | ✅ |
|
|
84
|
+
|
|
85
|
+
How it stays private:
|
|
86
|
+
|
|
87
|
+
* `lms.py`, `outlook.py`, `server.py` load `.env` via `python-dotenv` at startup — values live only in the local process environment.
|
|
88
|
+
* The MCP server exposes **no** login/token tools, and no tool ever returns passwords, tokens, or client IDs — tools return school data (assignments, mail, attendance) only.
|
|
89
|
+
* `.gitignore` blocks `.env`, `*token*.json`, and downloads, so credentials can't be committed by accident. Share only `.env.example` (empty values).
|
|
90
|
+
|
|
91
|
+
PyPI (after release): `pipx install induslms-agent` or `uvx induslms-agent doctor`,
|
|
92
|
+
then `induslms login you@indusschool.com` + `induslms-server` as your MCP command.
|
|
93
|
+
|
|
94
|
+
## MCP server (recommended for agents)
|
|
95
|
+
|
|
96
|
+
Stdio, read-only tools only (no login, no mark-read, no submissions):
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
python3 server.py
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Tools: `get_profile`, `list_courses`, `list_resources`, `get_resource`, `download_resource`, `assignments_overview`, `list_eol`, `list_assessments`, `list_notifications`, `get_attendance`, `get_attendance_day`, `list_announcements`, `list_calendar`, `schoolmail_search`, `schoolmail_read`, `schoolmail_folders`, `outlook_search`, `outlook_read`, `outlook_folders`, `od_resolve_link`, `od_browse`, `od_download`.
|
|
103
|
+
|
|
104
|
+
Run with `python3 server.py` (or `induslms-server` after `pip install`). Copy-paste
|
|
105
|
+
configs live in `examples/`: `.mcp.json` (Claude Code project scope),
|
|
106
|
+
`claude_desktop_config.json.example`, `opencode.jsonc.example`,
|
|
107
|
+
`mcp-uvx.json.example` (PyPI/uvx form).
|
|
108
|
+
|
|
109
|
+
## School email (Apple Mail.app — macOS only)
|
|
110
|
+
|
|
111
|
+
Mail.app already holds the `School` account, so agents read it via osascript (JXA). No credentials, no app registration. On Linux/Windows `schoolmail_*` reports unavailable — use `outlook_*` instead:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
python3 mailapp.py folders
|
|
115
|
+
python3 mailapp.py search "assignment" --top 5
|
|
116
|
+
python3 mailapp.py search --sender teacher@indusschool.com --since 2026-09-01
|
|
117
|
+
python3 mailapp.py read Inbox:24203
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Refs are `Mailbox:id`. Override account/mailbox with `SCHOOL_MAIL_ACCOUNT` / `SCHOOL_MAILBOX`.
|
|
121
|
+
|
|
122
|
+
### Register in pi
|
|
123
|
+
|
|
124
|
+
Create `~/.pi/agent/mcp.json` (same shape as `mcp.json` in this repo,
|
|
125
|
+
with `/path/to/induslms-agent` replaced by your checkout path):
|
|
126
|
+
|
|
127
|
+
```json
|
|
128
|
+
{ "mcpServers": { "induslms-academics": {
|
|
129
|
+
"command": "/path/to/induslms-agent/.venv/bin/python",
|
|
130
|
+
"args": ["/path/to/induslms-agent/server.py"],
|
|
131
|
+
"cwd": "/path/to/induslms-agent"
|
|
132
|
+
} } }
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Use the venv python — system python lacks `mcp`/`msal`. Restart pi afterwards.
|
|
136
|
+
|
|
137
|
+
### Register in opencode
|
|
138
|
+
|
|
139
|
+
In `~/.config/opencode/opencode.jsonc` under `mcp` (replace
|
|
140
|
+
`/path/to/induslms-agent` with your checkout path):
|
|
141
|
+
|
|
142
|
+
```json
|
|
143
|
+
"induslms-academics": {
|
|
144
|
+
"type": "local",
|
|
145
|
+
"command": ["/path/to/induslms-agent/.venv/bin/python", "/path/to/induslms-agent/server.py"],
|
|
146
|
+
"cwd": "/path/to/induslms-agent",
|
|
147
|
+
"enabled": true,
|
|
148
|
+
"timeout": 15000
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Restart opencode afterwards. Verify with a prompt like
|
|
153
|
+
"list my courses using induslms-academics".
|
|
154
|
+
|
|
155
|
+
### Claude Code
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
claude mcp add induslms-academics -- /path/to/induslms-agent/.venv/bin/python /path/to/induslms-agent/server.py
|
|
159
|
+
# or project scope: copy .mcp.json (replace paths), then: claude mcp list
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Skill: `bash scripts/install-skill.sh` also copies to `~/.claude/skills/`
|
|
163
|
+
(`INSTALL_PROJECT_SKILL=1` for `.claude/skills/`).
|
|
164
|
+
|
|
165
|
+
### Claude Desktop
|
|
166
|
+
|
|
167
|
+
Copy `examples/claude_desktop_config.json.example` into
|
|
168
|
+
`~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
169
|
+
(macOS; see file for Win/Linux paths), replace paths, relaunch.
|
|
170
|
+
|
|
171
|
+
### OpenAI-compatible agents (code, no config file)
|
|
172
|
+
|
|
173
|
+
```python
|
|
174
|
+
from agents.mcp import MCPServerStdio
|
|
175
|
+
async with MCPServerStdio(
|
|
176
|
+
params={"command": "/path/to/induslms-agent/.venv/bin/python",
|
|
177
|
+
"args": ["/path/to/induslms-agent/server.py"]},
|
|
178
|
+
cache_tools_list=True,
|
|
179
|
+
) as server:
|
|
180
|
+
...
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Hosted MCP / GPT Actions need a public HTTPS endpoint (not provided;
|
|
184
|
+
stdio-only by design).
|
|
185
|
+
|
|
186
|
+
## Skill (workflow guidance)
|
|
187
|
+
|
|
188
|
+
`skills/induslms-academics/SKILL.md` teaches the workflow:
|
|
189
|
+
announcements → assignments → resources/download → attendance,
|
|
190
|
+
plus School inbox. Install (copies to pi, opencode, and Claude skills):
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
bash scripts/install-skill.sh
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### End-user prompt: refresh local school materials
|
|
197
|
+
|
|
198
|
+
`examples/update-resources.prompt.md` is a copy-paste template that
|
|
199
|
+
checks LMS + the School mailbox for new teacher materials, downloads
|
|
200
|
+
only what's missing into a `School/` folder, and parses everything to
|
|
201
|
+
text. Fill in your subjects/teachers, paste it into a fresh agent
|
|
202
|
+
session.
|
|
203
|
+
|
|
204
|
+
## Key API notes (reverse-engineered, verified live)
|
|
205
|
+
|
|
206
|
+
* Base `https://api.induslms.com`, `Authorization: Bearer <access>` from `POST /api/v1/auth/login/`.
|
|
207
|
+
* Resources: `GET /api/v1/tenants/{tid}/resources/?course_id=` for top level; children via `?parent_resource_id={rid}` (NOT `?parent=`, which returns unfiltered results). Files: `.../resources/{rid}/files/{fid}/content/?disposition=attachment|inline` (binary, streamed).
|
|
208
|
+
* Assignments = EOL tests (`/eol-tests/my/`, 23 items) + student assessments (`/student/assessments/`, 6 items) + resources. `test-marks/me` is PYP-only (DP gets `BAD_REQUEST`) — handled gracefully.
|
|
209
|
+
* DP projects endpoint returns `[]` for this student; section fetcher ready for when IDs exist.
|
|
210
|
+
* Notifications support `?limit=&offset=`; unread filter is client-side (`is_read`) so `--limit 5 --unread-only` may return fewer rows — use a larger limit.
|
|
211
|
+
* Attendance has two shapes: session summary (`/students/me/attendance/`) and day breakdown (`/tenants/{tid}/students/me/attendance/day/`).
|
|
212
|
+
|
|
213
|
+
## Security
|
|
214
|
+
|
|
215
|
+
* Read-only by design. The only POSTs in the codebase are `login` and the (CLI-unused) token-refresh helper — the MCP server exposes neither.
|
|
216
|
+
* Credentials via env/prompt only; tokens outside the repo; `.gitignore` blocks `*token*.json`, `.env`, downloads.
|
|
217
|
+
|
|
218
|
+
## Outlook (school inbox via Microsoft Graph)
|
|
219
|
+
|
|
220
|
+
Read-only (`Mail.Read` delegated, device-code flow). Token cache at
|
|
221
|
+
`~/.indus_outlook_token.json` — never in repo.
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
# 1. Entra ID -> App registrations -> New: allow public client flows,
|
|
225
|
+
# add delegated Mail.Read. Multitenant OK.
|
|
226
|
+
export INDUS_OUTLOOK_CLIENT_ID=<app/client id>
|
|
227
|
+
# ..or skip registration: export INDUS_USE_BUILTIN_CLIENT=1 (sign in as yourself)
|
|
228
|
+
python3 outlook.py login # approve code in browser
|
|
229
|
+
python3 outlook.py search "assignment" --top 5
|
|
230
|
+
python3 outlook.py search --sender teacher@indusschool.com --since 2026-09-01
|
|
231
|
+
python3 outlook.py read <message_id>
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
MCP tools: `outlook_search`, `outlook_read`, `outlook_folders`
|
|
235
|
+
(same coverage; unconfigured → clear error, not crash).
|
|
236
|
+
School tenant blocks user consent → IT admin must grant admin consent first
|
|
237
|
+
(not needed with `INDUS_USE_BUILTIN_CLIENT=1`).
|
|
238
|
+
|
|
239
|
+
## OneDrive / SharePoint (school files via Microsoft Graph)
|
|
240
|
+
|
|
241
|
+
Read-only (`Files.Read` + `Sites.Read.All`, same device-code flow and token
|
|
242
|
+
cache as Outlook — re-run login once to consent to the new scopes):
|
|
243
|
+
|
|
244
|
+
```bash
|
|
245
|
+
python3 sharepoint.py login
|
|
246
|
+
python3 sharepoint.py resolve <sharing-link-from-mail> # shared file/folder metadata
|
|
247
|
+
python3 sharepoint.py browse / # your OneDrive root
|
|
248
|
+
python3 sharepoint.py download <item-id-or-link> --out /tmp/school
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
MCP tools: `od_resolve_link`, `od_browse`, `od_download`. No local OneDrive
|
|
252
|
+
sync client needed — pure HTTPS, works on any OS.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
lms.py,sha256=tp06cHe4tRVfBYl4LiQ7jnkRfWWC7pLJLP3Et7paaks,32669
|
|
2
|
+
mailapp.py,sha256=Eiy_cKzIcbgfRyESOg2J2m-bTyUF1vrZffQY9Cq0q8U,7699
|
|
3
|
+
outlook.py,sha256=ZndF2-8Fq_h-gGPd7MUc0vK7TXaJySmdfa-PF5Az3rM,9402
|
|
4
|
+
server.py,sha256=5bIefr-Lz20y4QYsGfxTOdAMq3tVxvctRpWDWe2mXNk,6863
|
|
5
|
+
sharepoint.py,sha256=MGVjjbVIfd8mtyf8HrnbruFDhCYvCdNG5XSUhPFNZFE,7960
|
|
6
|
+
induslms_agent-0.3.0.dist-info/licenses/LICENSE,sha256=N9SVKT0xZ44AytlOQZzpHrnfRw3d7BmPNzy85mI40LU,1084
|
|
7
|
+
induslms_agent-0.3.0.dist-info/METADATA,sha256=on_587aO9ctbWsE20AvXHQzEN-DU1PKl9sA1rMg28DA,10423
|
|
8
|
+
induslms_agent-0.3.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
9
|
+
induslms_agent-0.3.0.dist-info/entry_points.txt,sha256=pOutrRGtDuyVRIcKn608-a3nWcjfyr7A8JWmi4Cht1E,170
|
|
10
|
+
induslms_agent-0.3.0.dist-info/top_level.txt,sha256=UnzuU2XlGh3HKSj6AjlCMTlhERTERRzeysCOzZIrWaQ,38
|
|
11
|
+
induslms_agent-0.3.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 IndusLMS Agent contributors
|
|
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.
|