canvas-parent-mcp 1.0.3 → 1.1.2

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.3"
10
+ "version": "1.1.2"
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.3",
18
+ "version": "1.1.2",
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.3",
4
+ "version": "1.1.2",
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/README.md CHANGED
@@ -108,3 +108,27 @@ This reuses the same SSO + OAuth endpoints the official Canvas Student/Parent ap
108
108
  ## Status
109
109
 
110
110
  Unofficial — not affiliated with Instructure. AI-maintained.
111
+
112
+ ## Acknowledgement of Terms
113
+
114
+ By using this MCP server, you acknowledge and agree to the following:
115
+
116
+ **1. This server accesses your own Canvas account via the official Canvas REST API.** Auth happens via your own personal access token, issued by your institution. It does not — and cannot — access anyone else's enrollments, grades, or messages.
117
+
118
+ **2. [Instructure's Canvas API Policy](https://www.instructure.com/policies/canvas-api-policy) governs your use of this server**, in addition to your institution's own acceptable-use policy. The clauses most relevant here:
119
+
120
+ > You may not use our APIs on behalf of any third-party… You may not use or access our APIs for competitive purposes… You may not interfere with our APIs, our systems, or other users… You may not circumvent any contractual usage limits.
121
+
122
+ On rate limits: *"limits are enforced per user access token… with dynamic throttling."* On data: *"Any user information retrieved through the API—including course enrollments, grades, and profile information—should be considered and treated as private information."*
123
+
124
+ You are agreeing to those terms — read by the maintainer 2026-05-23 — every time you invoke a tool in this server.
125
+
126
+ **3. Personal, observer/student/parent use only.** This project is not affiliated with, endorsed by, sponsored by, or in partnership with Instructure, Inc. or any school district. It is a personal automation tool for an authenticated Canvas user (typically a parent observer) to read their own (or their student's) enrollments, assignments, grades, and announcements. Do not use it to bulk-extract a district's course content, redistribute student data, or train AI models on student records.
127
+
128
+ **4. FERPA + your institution's AUP apply.** Student educational records are protected under the federal Family Educational Rights and Privacy Act (FERPA). Even though your token grants you lawful access, **how you store, redistribute, or feed that data into LLMs is regulated**. Treat any output (grades, assignments, comments, conversations) as confidential student data. Your institution's acceptable-use policy may add further restrictions on automated access — check before automating.
129
+
130
+ **5. Your token is yours alone.** **Do not commit `CANVAS_API_TOKEN` to git**, do not paste it in shared chats, and rotate it if it's ever exposed. A leaked token grants full Canvas access scoped to your user.
131
+
132
+ **6. You accept full responsibility** for any consequences of using this server in connection with your Canvas account — rate limiting (dynamic throttling kicks in well below documented limits when Canvas is under load), token revocation, account warnings, institution-admin investigations, or any enforcement action. If Instructure or your institution objects to your use, stop using this server.
133
+
134
+ This section is the maintainer's good-faith summary of the terms — it is not legal advice and does not modify or supersede Instructure's actual Canvas API Policy or your institution's policies.
package/dist/bundle.js CHANGED
@@ -7572,6 +7572,10 @@ var require_receiver = __commonJS({
7572
7572
  * extensions
7573
7573
  * @param {Boolean} [options.isServer=false] Specifies whether to operate in
7574
7574
  * client or server mode
7575
+ * @param {Number} [options.maxBufferedChunks=0] The maximum number of
7576
+ * buffered data chunks
7577
+ * @param {Number} [options.maxFragments=0] The maximum number of message
7578
+ * fragments
7575
7579
  * @param {Number} [options.maxPayload=0] The maximum allowed message length
7576
7580
  * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
7577
7581
  * not to skip UTF-8 validation for text and close messages
@@ -7582,6 +7586,8 @@ var require_receiver = __commonJS({
7582
7586
  this._binaryType = options.binaryType || BINARY_TYPES[0];
7583
7587
  this._extensions = options.extensions || {};
7584
7588
  this._isServer = !!options.isServer;
7589
+ this._maxBufferedChunks = options.maxBufferedChunks | 0;
7590
+ this._maxFragments = options.maxFragments | 0;
7585
7591
  this._maxPayload = options.maxPayload | 0;
7586
7592
  this._skipUTF8Validation = !!options.skipUTF8Validation;
7587
7593
  this[kWebSocket] = void 0;
@@ -7611,6 +7617,18 @@ var require_receiver = __commonJS({
7611
7617
  */
7612
7618
  _write(chunk, encoding, cb) {
7613
7619
  if (this._opcode === 8 && this._state == GET_INFO) return cb();
7620
+ if (this._maxBufferedChunks > 0 && this._buffers.length >= this._maxBufferedChunks) {
7621
+ cb(
7622
+ this.createError(
7623
+ RangeError,
7624
+ "Too many buffered chunks",
7625
+ false,
7626
+ 1008,
7627
+ "WS_ERR_TOO_MANY_BUFFERED_PARTS"
7628
+ )
7629
+ );
7630
+ return;
7631
+ }
7614
7632
  this._bufferedBytes += chunk.length;
7615
7633
  this._buffers.push(chunk);
7616
7634
  this.startLoop(cb);
@@ -7940,6 +7958,17 @@ var require_receiver = __commonJS({
7940
7958
  return;
7941
7959
  }
7942
7960
  if (data.length) {
7961
+ if (this._maxFragments > 0 && this._fragments.length >= this._maxFragments) {
7962
+ const error51 = this.createError(
7963
+ RangeError,
7964
+ "Too many message fragments",
7965
+ false,
7966
+ 1008,
7967
+ "WS_ERR_TOO_MANY_BUFFERED_PARTS"
7968
+ );
7969
+ cb(error51);
7970
+ return;
7971
+ }
7943
7972
  this._messageLength = this._totalPayloadLength;
7944
7973
  this._fragments.push(data);
7945
7974
  }
@@ -7969,6 +7998,17 @@ var require_receiver = __commonJS({
7969
7998
  cb(error51);
7970
7999
  return;
7971
8000
  }
8001
+ if (this._maxFragments > 0 && this._fragments.length >= this._maxFragments) {
8002
+ const error51 = this.createError(
8003
+ RangeError,
8004
+ "Too many message fragments",
8005
+ false,
8006
+ 1008,
8007
+ "WS_ERR_TOO_MANY_BUFFERED_PARTS"
8008
+ );
8009
+ cb(error51);
8010
+ return;
8011
+ }
7972
8012
  this._fragments.push(buf);
7973
8013
  }
7974
8014
  this.dataMessage(cb);
@@ -9175,6 +9215,10 @@ var require_websocket = __commonJS({
9175
9215
  * multiple times in the same tick
9176
9216
  * @param {Function} [options.generateMask] The function used to generate the
9177
9217
  * masking key
9218
+ * @param {Number} [options.maxBufferedChunks=0] The maximum number of
9219
+ * buffered data chunks
9220
+ * @param {Number} [options.maxFragments=0] The maximum number of message
9221
+ * fragments
9178
9222
  * @param {Number} [options.maxPayload=0] The maximum allowed message size
9179
9223
  * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
9180
9224
  * not to skip UTF-8 validation for text and close messages
@@ -9186,6 +9230,8 @@ var require_websocket = __commonJS({
9186
9230
  binaryType: this.binaryType,
9187
9231
  extensions: this._extensions,
9188
9232
  isServer: this._isServer,
9233
+ maxBufferedChunks: options.maxBufferedChunks,
9234
+ maxFragments: options.maxFragments,
9189
9235
  maxPayload: options.maxPayload,
9190
9236
  skipUTF8Validation: options.skipUTF8Validation
9191
9237
  });
@@ -9485,6 +9531,8 @@ var require_websocket = __commonJS({
9485
9531
  autoPong: true,
9486
9532
  closeTimeout: CLOSE_TIMEOUT,
9487
9533
  protocolVersion: protocolVersions[1],
9534
+ maxBufferedChunks: 1024 * 1024,
9535
+ maxFragments: 128 * 1024,
9488
9536
  maxPayload: 100 * 1024 * 1024,
9489
9537
  skipUTF8Validation: false,
9490
9538
  perMessageDeflate: true,
@@ -9727,6 +9775,8 @@ var require_websocket = __commonJS({
9727
9775
  websocket.setSocket(socket, head, {
9728
9776
  allowSynchronousEvents: opts.allowSynchronousEvents,
9729
9777
  generateMask: opts.generateMask,
9778
+ maxBufferedChunks: opts.maxBufferedChunks,
9779
+ maxFragments: opts.maxFragments,
9730
9780
  maxPayload: opts.maxPayload,
9731
9781
  skipUTF8Validation: opts.skipUTF8Validation
9732
9782
  });
@@ -10069,6 +10119,10 @@ var require_websocket_server = __commonJS({
10069
10119
  * called
10070
10120
  * @param {Function} [options.handleProtocols] A hook to handle protocols
10071
10121
  * @param {String} [options.host] The hostname where to bind the server
10122
+ * @param {Number} [options.maxBufferedChunks=1048576] The maximum number of
10123
+ * buffered data chunks
10124
+ * @param {Number} [options.maxFragments=131072] The maximum number of message
10125
+ * fragments
10072
10126
  * @param {Number} [options.maxPayload=104857600] The maximum allowed message
10073
10127
  * size
10074
10128
  * @param {Boolean} [options.noServer=false] Enable no server mode
@@ -10090,6 +10144,8 @@ var require_websocket_server = __commonJS({
10090
10144
  options = {
10091
10145
  allowSynchronousEvents: true,
10092
10146
  autoPong: true,
10147
+ maxBufferedChunks: 1024 * 1024,
10148
+ maxFragments: 128 * 1024,
10093
10149
  maxPayload: 100 * 1024 * 1024,
10094
10150
  skipUTF8Validation: false,
10095
10151
  perMessageDeflate: false,
@@ -10369,6 +10425,8 @@ var require_websocket_server = __commonJS({
10369
10425
  socket.removeListener("error", socketOnError);
10370
10426
  ws.setSocket(socket, head, {
10371
10427
  allowSynchronousEvents: this.options.allowSynchronousEvents,
10428
+ maxBufferedChunks: this.options.maxBufferedChunks,
10429
+ maxFragments: this.options.maxFragments,
10372
10430
  maxPayload: this.options.maxPayload,
10373
10431
  skipUTF8Validation: this.options.skipUTF8Validation
10374
10432
  });
@@ -34495,6 +34553,7 @@ var StdioServerTransport = class {
34495
34553
 
34496
34554
  // node_modules/@fetchproxy/protocol/dist/frames.js
34497
34555
  var PROTOCOL_VERSION = 2;
34556
+ var HKDF_SESSION_INFO = "fetchproxy/1.0.0/session";
34498
34557
  var KNOWN_CAPABILITIES = /* @__PURE__ */ new Set([
34499
34558
  "fetch",
34500
34559
  "read_cookies",
@@ -34569,7 +34628,7 @@ var ProtocolError = class extends Error {
34569
34628
  var FORBIDDEN_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
34570
34629
  var BASE64_RE = /^[A-Za-z0-9+/]*={0,2}$/;
34571
34630
  var SCOPE_KEY_RE = /^[A-Za-z0-9_.\-]{1,256}$/;
34572
- var SCOPE_KEY_GLOB_RE = /^[A-Za-z0-9_.\-]{1,255}\*?$/;
34631
+ var SCOPE_KEY_GLOB_RE = /^[A-Za-z0-9_.\-]{1,256}\*?$/;
34573
34632
  var HEADER_NAME_RE = /^[A-Za-z0-9_\-]{1,128}$/;
34574
34633
  var HOSTNAME_RE = /^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?(\.[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)+$/i;
34575
34634
  function assertObject(x, label) {
@@ -34698,7 +34757,7 @@ function assertStoragePointersArray(value, label, declaredKeys) {
34698
34757
  if (entry.jsonPointer === void 0) {
34699
34758
  throw new ProtocolError(`${label}[${i}].jsonPointer: missing`);
34700
34759
  }
34701
- if (typeof entry.key !== "string" || !SCOPE_KEY_GLOB_RE.test(entry.key)) {
34760
+ if (typeof entry.key !== "string" || !SCOPE_KEY_RE.test(entry.key)) {
34702
34761
  throw new ProtocolError(`${label}[${i}].key: invalid key ${JSON.stringify(entry.key)}`);
34703
34762
  }
34704
34763
  if (typeof entry.jsonPointer !== "string" || !isValidJsonPointer(entry.jsonPointer)) {
@@ -35480,15 +35539,20 @@ async function startHost(opts) {
35480
35539
  let extensionWs = null;
35481
35540
  const peers = /* @__PURE__ */ new Map();
35482
35541
  const ownInnerListeners = [];
35542
+ const disconnectListeners = [];
35483
35543
  let ownSession = null;
35484
35544
  let resolveOwnSession;
35485
35545
  let rejectOwnSession;
35486
- const ownSessionReady = new Promise((resolve, reject) => {
35487
- resolveOwnSession = resolve;
35488
- rejectOwnSession = reject;
35489
- });
35490
- ownSessionReady.catch(() => {
35491
- });
35546
+ let ownSessionReady;
35547
+ function resetSessionPromise() {
35548
+ ownSessionReady = new Promise((resolve, reject) => {
35549
+ resolveOwnSession = resolve;
35550
+ rejectOwnSession = reject;
35551
+ });
35552
+ ownSessionReady.catch(() => {
35553
+ });
35554
+ }
35555
+ resetSessionPromise();
35492
35556
  let extensionHello = null;
35493
35557
  wss.on("connection", (ws) => {
35494
35558
  let identified = null;
@@ -35557,11 +35621,11 @@ async function startHost(opts) {
35557
35621
  }
35558
35622
  const extPub = fromB64(frame.extensionSessionPub);
35559
35623
  const shared = await ecdhX25519(opts.ownIdentity.x25519Priv, extPub);
35560
- const key = await hkdfSha256(shared, ownSessionNonce, enc2.encode("fetchproxy/0.1.0/session"), 32);
35561
- if (!ownSession) {
35562
- ownSession = new SessionState(key);
35563
- resolveOwnSession(ownSession);
35564
- }
35624
+ const key = await hkdfSha256(shared, ownSessionNonce, enc2.encode(HKDF_SESSION_INFO), 32);
35625
+ if (extensionWs !== ws)
35626
+ return;
35627
+ ownSession = new SessionState(key);
35628
+ resolveOwnSession(ownSession);
35565
35629
  } else {
35566
35630
  const slot = peers.get(frame.mcpId);
35567
35631
  if (slot)
@@ -35603,6 +35667,9 @@ async function startHost(opts) {
35603
35667
  if (!ownSession) {
35604
35668
  rejectOwnSession(new Error("extension disconnected before ready"));
35605
35669
  }
35670
+ ownSession = null;
35671
+ resetSessionPromise();
35672
+ disconnectListeners.forEach((cb) => cb());
35606
35673
  }
35607
35674
  if (identified === "peer" && peerMcpId)
35608
35675
  peers.delete(peerMcpId);
@@ -35627,6 +35694,9 @@ async function startHost(opts) {
35627
35694
  },
35628
35695
  onOwnInner: (cb) => {
35629
35696
  ownInnerListeners.push(cb);
35697
+ },
35698
+ onExtensionDisconnect: (cb) => {
35699
+ disconnectListeners.push(cb);
35630
35700
  }
35631
35701
  };
35632
35702
  }
@@ -35666,7 +35736,7 @@ async function startPeer(opts) {
35666
35736
  if (frame.type === "ready" && frame.mcpId === opts.mcpId) {
35667
35737
  const extPub = fromB64(frame.extensionSessionPub);
35668
35738
  const shared = await ecdhX25519(opts.identity.x25519Priv, extPub);
35669
- const sessionKey = await hkdfSha256(shared, sessionNonce, enc3.encode("fetchproxy/0.1.0/session"), 32);
35739
+ const sessionKey = await hkdfSha256(shared, sessionNonce, enc3.encode(HKDF_SESSION_INFO), 32);
35670
35740
  session = new SessionState(sessionKey);
35671
35741
  resolve(session);
35672
35742
  return;
@@ -35757,6 +35827,32 @@ async function loadOrCreateIdentity(serverName, dir = defaultIdentityDir()) {
35757
35827
  return id;
35758
35828
  }
35759
35829
 
35830
+ // node_modules/@fetchproxy/server/dist/error-kind.js
35831
+ function classifyFetchError(error51) {
35832
+ if (/Could not establish connection/i.test(error51) || /Receiving end does not exist/i.test(error51)) {
35833
+ return "content_script_unreachable";
35834
+ }
35835
+ if (/^tab fetch failed:/.test(error51)) {
35836
+ return "tab_fetch_failed";
35837
+ }
35838
+ if (/^fetch threw:/.test(error51)) {
35839
+ return "tab_fetch_failed";
35840
+ }
35841
+ if (/^no tab matching /.test(error51)) {
35842
+ return "no_tab";
35843
+ }
35844
+ if (/not in domains \[/.test(error51)) {
35845
+ return "domain_denied";
35846
+ }
35847
+ if (/^capability .+ not granted/.test(error51)) {
35848
+ return "capability_denied";
35849
+ }
35850
+ if (/^(request|response) body too large:/.test(error51)) {
35851
+ return "body_too_large";
35852
+ }
35853
+ return "other";
35854
+ }
35855
+
35760
35856
  // node_modules/@fetchproxy/server/dist/ws-server.js
35761
35857
  var FetchproxyProtocolError = class extends Error {
35762
35858
  constructor(message) {
@@ -35903,6 +35999,7 @@ var FetchproxyServer = class {
35903
35999
  onPairCode: this.opts.onPairCode
35904
36000
  });
35905
36001
  this.hostHandle.onOwnInner((inner) => this.onInner(inner));
36002
+ this.hostHandle.onExtensionDisconnect(() => this.rejectAllPending());
35906
36003
  } else {
35907
36004
  this.role = "peer";
35908
36005
  this.peerHandle = await startPeer({
@@ -36321,10 +36418,11 @@ var FetchproxyServer = class {
36321
36418
  if (inner.op === void 0 || inner.op === "fetch") {
36322
36419
  fetchCb({ ok: true, status: inner.status, url: inner.url, body: inner.body });
36323
36420
  } else {
36324
- fetchCb({ ok: false, error: `unexpected ${inner.op} response on fetch awaiter` });
36421
+ const error51 = `unexpected ${inner.op} response on fetch awaiter`;
36422
+ fetchCb({ ok: false, error: error51, kind: classifyFetchError(error51) });
36325
36423
  }
36326
36424
  } else {
36327
- fetchCb({ ok: false, error: inner.error });
36425
+ fetchCb({ ok: false, error: inner.error, kind: classifyFetchError(inner.error) });
36328
36426
  }
36329
36427
  return;
36330
36428
  }
@@ -36391,6 +36489,26 @@ var FetchproxyServer = class {
36391
36489
  }
36392
36490
  }
36393
36491
  }
36492
+ rejectAllPending() {
36493
+ const err = new FetchproxyProtocolError("extension disconnected");
36494
+ for (const cb of this.pending.values()) {
36495
+ cb({ ok: false, error: err.message, kind: classifyFetchError(err.message) });
36496
+ }
36497
+ this.pending.clear();
36498
+ for (const cb of this.pendingReadCookies.values()) {
36499
+ cb({ ok: false, error: err.message });
36500
+ }
36501
+ this.pendingReadCookies.clear();
36502
+ for (const { reject } of this.pendingStorage.values())
36503
+ reject(err);
36504
+ this.pendingStorage.clear();
36505
+ for (const { reject } of this.pendingCapture.values())
36506
+ reject(err);
36507
+ this.pendingCapture.clear();
36508
+ for (const { reject } of this.pendingIdb.values())
36509
+ reject(err);
36510
+ this.pendingIdb.clear();
36511
+ }
36394
36512
  /**
36395
36513
  * Shut down the bridge. Host: terminates the WebSocket server and any
36396
36514
  * still-attached extension/peer clients. Peer: closes the upstream
@@ -36398,6 +36516,7 @@ var FetchproxyServer = class {
36398
36516
  * twice in a row.
36399
36517
  */
36400
36518
  async close() {
36519
+ this.rejectAllPending();
36401
36520
  if (this.hostHandle)
36402
36521
  await this.hostHandle.close();
36403
36522
  if (this.peerHandle)
@@ -36493,8 +36612,7 @@ async function bootstrap(opts) {
36493
36612
  for (const p of localStoragePointers) {
36494
36613
  pointers[p.outputKey] = { storageKey: p.storageKey, jsonPointer: p.jsonPointer };
36495
36614
  }
36496
- const stub = server2;
36497
- localStorage = await stub.readLocalStorage({
36615
+ localStorage = await server2.readLocalStorage({
36498
36616
  keys: allKeys,
36499
36617
  ...storageDomainOpts,
36500
36618
  ...localStoragePointers.length > 0 ? { pointers } : {}
@@ -36507,8 +36625,7 @@ async function bootstrap(opts) {
36507
36625
  for (const p of sessionStoragePointers) {
36508
36626
  pointers[p.outputKey] = { storageKey: p.storageKey, jsonPointer: p.jsonPointer };
36509
36627
  }
36510
- const stub = server2;
36511
- sessionStorage = await stub.readSessionStorage({
36628
+ sessionStorage = await server2.readSessionStorage({
36512
36629
  keys: allKeys,
36513
36630
  ...storageDomainOpts,
36514
36631
  ...sessionStoragePointers.length > 0 ? { pointers } : {}
@@ -36531,9 +36648,6 @@ async function bootstrap(opts) {
36531
36648
  }
36532
36649
  const indexedDbBucket = {};
36533
36650
  for (const d of indexedDb) {
36534
- if (!server2.readIndexedDb) {
36535
- throw new Error("bootstrap: server factory does not implement readIndexedDb (declared indexedDb but server stub omits it)");
36536
- }
36537
36651
  const values = await server2.readIndexedDb({
36538
36652
  database: d.database,
36539
36653
  store: d.store,
@@ -36658,7 +36772,7 @@ function loadAccount(env = process.env) {
36658
36772
  // package.json
36659
36773
  var package_default = {
36660
36774
  name: "canvas-parent-mcp",
36661
- version: "1.0.3",
36775
+ version: "1.1.2",
36662
36776
  mcpName: "io.github.chrischall/canvas-parent-mcp",
36663
36777
  description: "Canvas LMS (Instructure) MCP server \u2014 student/observer read access with optional file download",
36664
36778
  author: "Claude Code (AI) <https://www.anthropic.com/claude>",
@@ -36702,7 +36816,7 @@ var package_default = {
36702
36816
  "test:watch": "vitest"
36703
36817
  },
36704
36818
  dependencies: {
36705
- "@fetchproxy/bootstrap": "^0.4.2",
36819
+ "@fetchproxy/bootstrap": "^0.5.1",
36706
36820
  "@modelcontextprotocol/sdk": "^1.29.0",
36707
36821
  dotenv: "^17.4.0",
36708
36822
  zod: "^4.3.6"
@@ -37504,7 +37618,7 @@ try {
37504
37618
  } catch (e) {
37505
37619
  configError = e;
37506
37620
  }
37507
- var server = new McpServer({ name: "canvas", version: "1.0.3" });
37621
+ var server = new McpServer({ name: "canvas", version: "1.1.2" });
37508
37622
  if (resolved) {
37509
37623
  const client = new CanvasClient(resolved.account, {
37510
37624
  preloaded: resolved.preloaded
package/dist/index.js CHANGED
@@ -44,7 +44,7 @@ try {
44
44
  catch (e) {
45
45
  configError = e;
46
46
  }
47
- const server = new McpServer({ name: 'canvas', version: '1.0.3' });
47
+ const server = new McpServer({ name: 'canvas', version: '1.1.2' }); // x-release-please-version
48
48
  if (resolved) {
49
49
  const client = new CanvasClient(resolved.account, {
50
50
  preloaded: resolved.preloaded,
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "canvas-parent-mcp",
3
- "version": "1.0.3",
3
+ "version": "1.1.2",
4
4
  "mcpName": "io.github.chrischall/canvas-parent-mcp",
5
- "description": "Canvas LMS (Instructure) MCP server \u2014 student/observer read access with optional file download",
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>",
7
7
  "repository": {
8
8
  "type": "git",
@@ -44,7 +44,7 @@
44
44
  "test:watch": "vitest"
45
45
  },
46
46
  "dependencies": {
47
- "@fetchproxy/bootstrap": "^0.4.2",
47
+ "@fetchproxy/bootstrap": "^0.5.1",
48
48
  "@modelcontextprotocol/sdk": "^1.29.0",
49
49
  "dotenv": "^17.4.0",
50
50
  "zod": "^4.3.6"
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.3",
9
+ "version": "1.1.2",
10
10
  "packages": [
11
11
  {
12
12
  "registryType": "npm",
13
13
  "identifier": "canvas-parent-mcp",
14
- "version": "1.0.3",
14
+ "version": "1.1.2",
15
15
  "transport": {
16
16
  "type": "stdio"
17
17
  },