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.
@@ -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.3"
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.3",
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.3",
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 declared domain, built lazily and reused.
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 *.instructure.com tenants share one wildcard — so the lifter cannot be
151
- * a module-level constant. Caching is load-bearing rather than an
152
- * optimization: `createSessionLifter` single-flights concurrent calls, and
153
- * that only helps if renewals share ONE lifter instead of constructing a fresh
154
- * one per call.
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
- const liftersByDomain = new Map();
157
- function lifterFor(declaredDomain) {
158
- let lift = liftersByDomain.get(declaredDomain);
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
- liftersByDomain.set(declaredDomain, lift);
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.3",
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 liftersByDomain = /* @__PURE__ */ new Map();
38826
- function lifterFor(declaredDomain) {
38827
- let lift = liftersByDomain.get(declaredDomain);
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
- liftersByDomain.set(declaredDomain, lift);
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.3",
39723
+ version: "1.2.4",
39718
39724
  // x-release-please-version
39719
39725
  tools: [
39720
39726
  (server) => {
package/dist/index.js CHANGED
@@ -46,7 +46,7 @@ catch (e) {
46
46
  // host's install-time `tools/list` succeeds.
47
47
  await runMcp({
48
48
  name: 'canvas',
49
- version: '1.2.3', // x-release-please-version
49
+ version: '1.2.4', // x-release-please-version
50
50
  tools: [
51
51
  (server) => {
52
52
  if (resolved) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "canvas-parent-mcp",
3
- "version": "1.2.3",
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.3",
9
+ "version": "1.2.4",
10
10
  "packages": [
11
11
  {
12
12
  "registryType": "npm",
13
13
  "identifier": "canvas-parent-mcp",
14
- "version": "1.2.3",
14
+ "version": "1.2.4",
15
15
  "transport": {
16
16
  "type": "stdio"
17
17
  },