canvas-parent-mcp 1.2.3 → 1.2.4
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.
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/dist/auth.js +43 -11
- package/dist/bundle.js +13 -7
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/server.json +2 -2
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
},
|
|
8
8
|
"metadata": {
|
|
9
9
|
"description": "MCP server for Canvas LMS (Instructure) — courses, grades, assignments, announcements, planner, conversations, files",
|
|
10
|
-
"version": "1.2.
|
|
10
|
+
"version": "1.2.4"
|
|
11
11
|
},
|
|
12
12
|
"plugins": [
|
|
13
13
|
{
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"displayName": "Canvas LMS",
|
|
16
16
|
"source": "./",
|
|
17
17
|
"description": "Canvas LMS (Instructure) MCP server for Claude — student/observer access via natural language",
|
|
18
|
-
"version": "1.2.
|
|
18
|
+
"version": "1.2.4",
|
|
19
19
|
"author": {
|
|
20
20
|
"name": "Chris Hall"
|
|
21
21
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "canvas-parent-mcp",
|
|
3
3
|
"displayName": "Canvas LMS",
|
|
4
|
-
"version": "1.2.
|
|
4
|
+
"version": "1.2.4",
|
|
5
5
|
"description": "Canvas LMS (Instructure) MCP server for Claude — courses, grades, assignments, announcements, planner, conversations, files",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Chris Hall",
|
package/dist/auth.js
CHANGED
|
@@ -144,23 +144,55 @@ export async function resolveAuth() {
|
|
|
144
144
|
'(unset CANVAS_DISABLE_FETCHPROXY if it is set).');
|
|
145
145
|
}
|
|
146
146
|
/**
|
|
147
|
-
* One lifter per
|
|
147
|
+
* One lifter per resolved tenant HOST, built lazily and reused.
|
|
148
|
+
*
|
|
149
|
+
* Keyed on the host, not the declared domain: every *.instructure.com tenant
|
|
150
|
+
* declares the same wildcard but holds its own host-only cookies, so a
|
|
151
|
+
* domain-keyed map would hand the second tenant the first one's lifter.
|
|
148
152
|
*
|
|
149
153
|
* The scope is not static — self-hosted Canvas declares its literal hostname
|
|
150
|
-
* while
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
|
|
154
|
+
* while hosted tenants share the wildcard — so the lifter cannot be a
|
|
155
|
+
* module-level constant. Caching is load-bearing rather than an optimization:
|
|
156
|
+
* `createSessionLifter` single-flights concurrent calls, and that only helps
|
|
157
|
+
* if renewals share ONE lifter instead of constructing a fresh one per call.
|
|
158
|
+
*/
|
|
159
|
+
const liftersByHost = new Map();
|
|
160
|
+
/**
|
|
161
|
+
* Split a tenant host into the declared domain and the subdomain that actually
|
|
162
|
+
* holds the cookies.
|
|
163
|
+
*
|
|
164
|
+
* These are NOT the same thing, and conflating them is why the lift silently
|
|
165
|
+
* read nothing. Canvas declares the `instructure.com` wildcard so any district
|
|
166
|
+
* matches without a re-pair, but `canvas_session` / `pseudonym_credentials`
|
|
167
|
+
* are host-only on the tenant (`cms.instructure.com`). The extension resolves
|
|
168
|
+
* the storage origin from domain + subdomain, so declaring the wildcard alone
|
|
169
|
+
* pointed the read at `https://instructure.com` — an apex that holds nothing —
|
|
170
|
+
* and every lift reported the user signed out while they were signed in.
|
|
171
|
+
*
|
|
172
|
+
* Returns undefined for a self-hosted install, where the host IS the domain.
|
|
155
173
|
*/
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
174
|
+
function storageSubdomainFor(declaredDomain, baseHost) {
|
|
175
|
+
// Only two cases exist, because `declaredDomain` is derived FROM `baseHost`
|
|
176
|
+
// a few lines up: either it collapsed to the instructure.com wildcard (so
|
|
177
|
+
// baseHost ends with `.instructure.com`), or it is baseHost itself. A
|
|
178
|
+
// `endsWith` guard here would be a third branch that cannot be reached, and
|
|
179
|
+
// an untestable branch is worse than an asserted invariant.
|
|
180
|
+
if (baseHost === declaredDomain)
|
|
181
|
+
return undefined;
|
|
182
|
+
return baseHost.slice(0, -(declaredDomain.length + 1));
|
|
183
|
+
}
|
|
184
|
+
function lifterFor(declaredDomain, baseHost) {
|
|
185
|
+
// Key on the resolved host: two tenants share one declared domain but hold
|
|
186
|
+
// different cookies, so caching by domain alone would hand the second
|
|
187
|
+
// tenant the first one's lifter.
|
|
188
|
+
const subdomain = storageSubdomainFor(declaredDomain, baseHost);
|
|
189
|
+
let lift = liftersByHost.get(baseHost);
|
|
159
190
|
if (!lift) {
|
|
160
191
|
lift = createSessionLifter({
|
|
161
192
|
serverName: pkg.name,
|
|
162
193
|
version: pkg.version,
|
|
163
194
|
domains: [declaredDomain],
|
|
195
|
+
...(subdomain !== undefined ? { storageSubdomain: subdomain } : {}),
|
|
164
196
|
declare: {
|
|
165
197
|
cookies: ['canvas_session', 'pseudonym_credentials'],
|
|
166
198
|
localStorage: [],
|
|
@@ -168,7 +200,7 @@ function lifterFor(declaredDomain) {
|
|
|
168
200
|
captureHeaders: [],
|
|
169
201
|
},
|
|
170
202
|
});
|
|
171
|
-
|
|
203
|
+
liftersByHost.set(baseHost, lift);
|
|
172
204
|
}
|
|
173
205
|
return lift;
|
|
174
206
|
}
|
|
@@ -180,7 +212,7 @@ function lifterFor(declaredDomain) {
|
|
|
180
212
|
*/
|
|
181
213
|
async function liftBrowserCookie(declaredDomain, baseHost) {
|
|
182
214
|
try {
|
|
183
|
-
const session = await lifterFor(declaredDomain)();
|
|
215
|
+
const session = await lifterFor(declaredDomain, baseHost)();
|
|
184
216
|
const canvasSession = session.cookies['canvas_session'];
|
|
185
217
|
const pseudoCreds = session.cookies['pseudonym_credentials'];
|
|
186
218
|
if (!canvasSession || !pseudoCreds) {
|
package/dist/bundle.js
CHANGED
|
@@ -38720,7 +38720,7 @@ function loadAccount(env = process.env) {
|
|
|
38720
38720
|
// package.json
|
|
38721
38721
|
var package_default = {
|
|
38722
38722
|
name: "canvas-parent-mcp",
|
|
38723
|
-
version: "1.2.
|
|
38723
|
+
version: "1.2.4",
|
|
38724
38724
|
mcpName: "io.github.chrischall/canvas-parent-mcp",
|
|
38725
38725
|
description: "Canvas LMS (Instructure) MCP server \u2014 student/observer read access with optional file download",
|
|
38726
38726
|
author: "Claude Code (AI) <https://www.anthropic.com/claude>",
|
|
@@ -38822,14 +38822,20 @@ async function resolveAuth() {
|
|
|
38822
38822
|
"Missing Canvas auth config. Set one of: CANVAS_TOKEN (personal access token), CANVAS_USERNAME+CANVAS_PASSWORD (auto-login), all three of CANVAS_CLIENT_ID, CANVAS_CLIENT_SECRET, CANVAS_REFRESH_TOKEN (OAuth), or install the fetchproxy extension and sign into your Canvas instance (unset CANVAS_DISABLE_FETCHPROXY if it is set)."
|
|
38823
38823
|
);
|
|
38824
38824
|
}
|
|
38825
|
-
var
|
|
38826
|
-
function
|
|
38827
|
-
|
|
38825
|
+
var liftersByHost = /* @__PURE__ */ new Map();
|
|
38826
|
+
function storageSubdomainFor(declaredDomain, baseHost) {
|
|
38827
|
+
if (baseHost === declaredDomain) return void 0;
|
|
38828
|
+
return baseHost.slice(0, -(declaredDomain.length + 1));
|
|
38829
|
+
}
|
|
38830
|
+
function lifterFor(declaredDomain, baseHost) {
|
|
38831
|
+
const subdomain = storageSubdomainFor(declaredDomain, baseHost);
|
|
38832
|
+
let lift = liftersByHost.get(baseHost);
|
|
38828
38833
|
if (!lift) {
|
|
38829
38834
|
lift = createSessionLifter({
|
|
38830
38835
|
serverName: package_default.name,
|
|
38831
38836
|
version: package_default.version,
|
|
38832
38837
|
domains: [declaredDomain],
|
|
38838
|
+
...subdomain !== void 0 ? { storageSubdomain: subdomain } : {},
|
|
38833
38839
|
declare: {
|
|
38834
38840
|
cookies: ["canvas_session", "pseudonym_credentials"],
|
|
38835
38841
|
localStorage: [],
|
|
@@ -38837,13 +38843,13 @@ function lifterFor(declaredDomain) {
|
|
|
38837
38843
|
captureHeaders: []
|
|
38838
38844
|
}
|
|
38839
38845
|
});
|
|
38840
|
-
|
|
38846
|
+
liftersByHost.set(baseHost, lift);
|
|
38841
38847
|
}
|
|
38842
38848
|
return lift;
|
|
38843
38849
|
}
|
|
38844
38850
|
async function liftBrowserCookie(declaredDomain, baseHost) {
|
|
38845
38851
|
try {
|
|
38846
|
-
const session = await lifterFor(declaredDomain)();
|
|
38852
|
+
const session = await lifterFor(declaredDomain, baseHost)();
|
|
38847
38853
|
const canvasSession = session.cookies["canvas_session"];
|
|
38848
38854
|
const pseudoCreds = session.cookies["pseudonym_credentials"];
|
|
38849
38855
|
if (!canvasSession || !pseudoCreds) {
|
|
@@ -39714,7 +39720,7 @@ try {
|
|
|
39714
39720
|
}
|
|
39715
39721
|
await runMcp({
|
|
39716
39722
|
name: "canvas",
|
|
39717
|
-
version: "1.2.
|
|
39723
|
+
version: "1.2.4",
|
|
39718
39724
|
// x-release-please-version
|
|
39719
39725
|
tools: [
|
|
39720
39726
|
(server) => {
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "canvas-parent-mcp",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.4",
|
|
4
4
|
"mcpName": "io.github.chrischall/canvas-parent-mcp",
|
|
5
5
|
"description": "Canvas LMS (Instructure) MCP server — student/observer read access with optional file download",
|
|
6
6
|
"author": "Claude Code (AI) <https://www.anthropic.com/claude>",
|
package/server.json
CHANGED
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
"url": "https://github.com/chrischall/canvas-parent-mcp",
|
|
7
7
|
"source": "github"
|
|
8
8
|
},
|
|
9
|
-
"version": "1.2.
|
|
9
|
+
"version": "1.2.4",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"identifier": "canvas-parent-mcp",
|
|
14
|
-
"version": "1.2.
|
|
14
|
+
"version": "1.2.4",
|
|
15
15
|
"transport": {
|
|
16
16
|
"type": "stdio"
|
|
17
17
|
},
|