canvas-parent-mcp 1.0.0 → 1.0.1

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.0.0"
10
+ "version": "1.0.1"
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.0.0",
18
+ "version": "1.0.1",
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.0.0",
4
+ "version": "1.0.1",
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/bundle.js CHANGED
@@ -30860,8 +30860,16 @@ var StdioServerTransport = class {
30860
30860
  };
30861
30861
 
30862
30862
  // src/config.ts
30863
+ function readVar(env, key) {
30864
+ const raw = env[key];
30865
+ if (typeof raw !== "string") return void 0;
30866
+ const trimmed = raw.trim();
30867
+ if (trimmed.length === 0) return void 0;
30868
+ if (/^\$\{[^}]*\}$/.test(trimmed)) return void 0;
30869
+ return trimmed;
30870
+ }
30863
30871
  function loadAccount(env = process.env) {
30864
- const baseUrl = env.CANVAS_BASE_URL;
30872
+ const baseUrl = readVar(env, "CANVAS_BASE_URL");
30865
30873
  if (!baseUrl) {
30866
30874
  throw new Error(
30867
30875
  "Missing required env var: CANVAS_BASE_URL. Set CANVAS_BASE_URL (e.g. https://cms.instructure.com) plus an auth mode."
@@ -30871,13 +30879,13 @@ function loadAccount(env = process.env) {
30871
30879
  throw new Error(`CANVAS_BASE_URL must be an https URL, got: '${baseUrl}'`);
30872
30880
  }
30873
30881
  const cleanBaseUrl = baseUrl.replace(/\/$/, "");
30874
- const name = env.CANVAS_NAME || new URL(cleanBaseUrl).host;
30875
- const token = env.CANVAS_TOKEN;
30876
- const username = env.CANVAS_USERNAME;
30877
- const password = env.CANVAS_PASSWORD;
30878
- const clientId = env.CANVAS_CLIENT_ID;
30879
- const clientSecret = env.CANVAS_CLIENT_SECRET;
30880
- const refreshToken = env.CANVAS_REFRESH_TOKEN;
30882
+ const name = readVar(env, "CANVAS_NAME") ?? new URL(cleanBaseUrl).host;
30883
+ const token = readVar(env, "CANVAS_TOKEN");
30884
+ const username = readVar(env, "CANVAS_USERNAME");
30885
+ const password = readVar(env, "CANVAS_PASSWORD");
30886
+ const clientId = readVar(env, "CANVAS_CLIENT_ID");
30887
+ const clientSecret = readVar(env, "CANVAS_CLIENT_SECRET");
30888
+ const refreshToken = readVar(env, "CANVAS_REFRESH_TOKEN");
30881
30889
  const oauthSet = [clientId, clientSecret, refreshToken].filter((v) => !!v);
30882
30890
  const hasFullOAuth = oauthSet.length === 3;
30883
30891
  const hasPartialOAuth = oauthSet.length > 0 && oauthSet.length < 3;
@@ -30930,7 +30938,7 @@ function loadAccount(env = process.env) {
30930
30938
  clientId,
30931
30939
  clientSecret,
30932
30940
  refreshToken,
30933
- accessToken: env.CANVAS_ACCESS_TOKEN
30941
+ accessToken: readVar(env, "CANVAS_ACCESS_TOKEN")
30934
30942
  };
30935
30943
  }
30936
30944
  throw new Error(
@@ -31634,7 +31642,7 @@ try {
31634
31642
  }
31635
31643
  var account = loadAccount();
31636
31644
  var client = new CanvasClient(account);
31637
- var server = new McpServer({ name: "canvas", version: "1.0.0" });
31645
+ var server = new McpServer({ name: "canvas", version: "1.0.1" });
31638
31646
  registerProfileTools(server, client);
31639
31647
  registerObserveeTools(server, client);
31640
31648
  registerCourseTools(server, client);
package/dist/config.js CHANGED
@@ -1,5 +1,23 @@
1
+ /**
2
+ * Read an env var, trim whitespace, and treat the empty string as unset. Also
3
+ * defensively rejects values that look like an unsubstituted shell placeholder
4
+ * (e.g. "${CANVAS_TOKEN}") — these can leak through .mcp.json env blocks when
5
+ * the host (Claude Code / Desktop) doesn't expand them, and would otherwise
6
+ * be sent to Canvas as a literal token and rejected with a confusing 401.
7
+ */
8
+ function readVar(env, key) {
9
+ const raw = env[key];
10
+ if (typeof raw !== 'string')
11
+ return undefined;
12
+ const trimmed = raw.trim();
13
+ if (trimmed.length === 0)
14
+ return undefined;
15
+ if (/^\$\{[^}]*\}$/.test(trimmed))
16
+ return undefined;
17
+ return trimmed;
18
+ }
1
19
  export function loadAccount(env = process.env) {
2
- const baseUrl = env.CANVAS_BASE_URL;
20
+ const baseUrl = readVar(env, 'CANVAS_BASE_URL');
3
21
  if (!baseUrl) {
4
22
  throw new Error('Missing required env var: CANVAS_BASE_URL. ' +
5
23
  'Set CANVAS_BASE_URL (e.g. https://cms.instructure.com) plus an auth mode.');
@@ -8,13 +26,13 @@ export function loadAccount(env = process.env) {
8
26
  throw new Error(`CANVAS_BASE_URL must be an https URL, got: '${baseUrl}'`);
9
27
  }
10
28
  const cleanBaseUrl = baseUrl.replace(/\/$/, '');
11
- const name = env.CANVAS_NAME || new URL(cleanBaseUrl).host;
12
- const token = env.CANVAS_TOKEN;
13
- const username = env.CANVAS_USERNAME;
14
- const password = env.CANVAS_PASSWORD;
15
- const clientId = env.CANVAS_CLIENT_ID;
16
- const clientSecret = env.CANVAS_CLIENT_SECRET;
17
- const refreshToken = env.CANVAS_REFRESH_TOKEN;
29
+ const name = readVar(env, 'CANVAS_NAME') ?? new URL(cleanBaseUrl).host;
30
+ const token = readVar(env, 'CANVAS_TOKEN');
31
+ const username = readVar(env, 'CANVAS_USERNAME');
32
+ const password = readVar(env, 'CANVAS_PASSWORD');
33
+ const clientId = readVar(env, 'CANVAS_CLIENT_ID');
34
+ const clientSecret = readVar(env, 'CANVAS_CLIENT_SECRET');
35
+ const refreshToken = readVar(env, 'CANVAS_REFRESH_TOKEN');
18
36
  const oauthSet = [clientId, clientSecret, refreshToken].filter((v) => !!v);
19
37
  const hasFullOAuth = oauthSet.length === 3;
20
38
  const hasPartialOAuth = oauthSet.length > 0 && oauthSet.length < 3;
@@ -70,7 +88,7 @@ export function loadAccount(env = process.env) {
70
88
  clientId: clientId,
71
89
  clientSecret: clientSecret,
72
90
  refreshToken: refreshToken,
73
- accessToken: env.CANVAS_ACCESS_TOKEN,
91
+ accessToken: readVar(env, 'CANVAS_ACCESS_TOKEN'),
74
92
  };
75
93
  }
76
94
  throw new Error('Missing Canvas auth config. Set one of: CANVAS_TOKEN (personal access token), ' +
package/dist/index.js CHANGED
@@ -29,7 +29,7 @@ import { registerDiscussionTools } from './tools/discussions.js';
29
29
  import { registerFileTools } from './tools/files.js';
30
30
  const account = loadAccount();
31
31
  const client = new CanvasClient(account);
32
- const server = new McpServer({ name: 'canvas', version: '1.0.0' });
32
+ const server = new McpServer({ name: 'canvas', version: '1.0.1' });
33
33
  registerProfileTools(server, client);
34
34
  registerObserveeTools(server, client);
35
35
  registerCourseTools(server, client);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "canvas-parent-mcp",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
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.0.0",
9
+ "version": "1.0.1",
10
10
  "packages": [
11
11
  {
12
12
  "registryType": "npm",
13
13
  "identifier": "canvas-parent-mcp",
14
- "version": "1.0.0",
14
+ "version": "1.0.1",
15
15
  "transport": {
16
16
  "type": "stdio"
17
17
  },