canvas-parent-mcp 2.1.6 → 2.1.8

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": "2.1.6"
10
+ "version": "2.1.8"
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": "2.1.6",
18
+ "version": "2.1.8",
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": "2.1.6",
4
+ "version": "2.1.8",
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
@@ -20693,8 +20693,8 @@ var require_schemas2 = __commonJS({
20693
20693
  return core._stringFormat(exports.ZodCustomStringFormat, "currency_code", regexes.currencyCode, _params);
20694
20694
  }
20695
20695
  function hash2(alg, params) {
20696
- const enc6 = params?.enc ?? "hex";
20697
- const format = `${alg}_${enc6}`;
20696
+ const enc7 = params?.enc ?? "hex";
20697
+ const format = `${alg}_${enc7}`;
20698
20698
  const regex = core.regexes[format];
20699
20699
  if (!regex)
20700
20700
  throw new Error(`Unrecognized hash format: ${format}`);
@@ -25604,11 +25604,23 @@ var require_websocket = __commonJS({
25604
25604
  this._isServer = false;
25605
25605
  this._redirects = 0;
25606
25606
  if (protocols === void 0) {
25607
- protocols = [];
25607
+ if (!options || options.protocols === void 0) {
25608
+ protocols = [];
25609
+ } else if (Array.isArray(options.protocols)) {
25610
+ protocols = options.protocols;
25611
+ } else {
25612
+ protocols = [options.protocols];
25613
+ }
25608
25614
  } else if (!Array.isArray(protocols)) {
25609
25615
  if (typeof protocols === "object" && protocols !== null) {
25610
25616
  options = protocols;
25611
- protocols = [];
25617
+ if (options.protocols === void 0) {
25618
+ protocols = [];
25619
+ } else if (Array.isArray(options.protocols)) {
25620
+ protocols = options.protocols;
25621
+ } else {
25622
+ protocols = [options.protocols];
25623
+ }
25612
25624
  } else {
25613
25625
  protocols = [protocols];
25614
25626
  }
@@ -25805,7 +25817,6 @@ var require_websocket = __commonJS({
25805
25817
  }
25806
25818
  return;
25807
25819
  }
25808
- this._readyState = _WebSocket.CLOSING;
25809
25820
  this._sender.close(code, data, !this._isServer, (err) => {
25810
25821
  if (err) return;
25811
25822
  this._closeFrameSent = true;
@@ -25813,6 +25824,7 @@ var require_websocket = __commonJS({
25813
25824
  this._socket.end();
25814
25825
  }
25815
25826
  });
25827
+ this._readyState = _WebSocket.CLOSING;
25816
25828
  setCloseTimer(this);
25817
25829
  }
25818
25830
  /**
@@ -26037,6 +26049,7 @@ var require_websocket = __commonJS({
26037
26049
  socketPath: void 0,
26038
26050
  hostname: void 0,
26039
26051
  protocol: void 0,
26052
+ protocols: void 0,
26040
26053
  timeout: void 0,
26041
26054
  method: "GET",
26042
26055
  host: void 0,
@@ -27996,7 +28009,7 @@ var OAuthTokenRevocationRequestSchema = z.object({
27996
28009
  token_type_hint: z.string().optional()
27997
28010
  }).strip();
27998
28011
 
27999
- // node_modules/@modelcontextprotocol/server/dist/src-BHSMhZ_W.mjs
28012
+ // node_modules/@modelcontextprotocol/server/dist/src-Cqbh3MYc.mjs
28000
28013
  var z2 = __toESM(require_v4(), 1);
28001
28014
  var BRANDS = /* @__PURE__ */ Symbol.for("mcp.sdk.errorBrands");
28002
28015
  function stampErrorBrands(instance, ctor) {
@@ -30240,7 +30253,8 @@ function build() {
30240
30253
  ListResourceTemplatesResultResponseSchema: wireResultResponse(ListResourceTemplatesResultSchema$1),
30241
30254
  ReadResourceResultResponseSchema: wireResultResponse(z2.union([ReadResourceResultSchema$1, InputRequiredResultSchema])),
30242
30255
  CompleteResultResponseSchema: wireResultResponse(CompleteResultSchema$1),
30243
- DiscoverResultResponseSchema: wireResultResponse(DiscoverResultSchema$1)
30256
+ DiscoverResultResponseSchema: wireResultResponse(DiscoverResultSchema$1),
30257
+ SubscriptionsListenResultResponseSchema: wireResultResponse(SubscriptionsListenResultSchema$1)
30244
30258
  };
30245
30259
  }
30246
30260
  var memo;
@@ -30748,6 +30762,9 @@ function isSpecRequestMethod(method) {
30748
30762
  function isSpecNotificationMethod(method) {
30749
30763
  return ALL_CODECS.some((codec2) => codec2.hasNotificationMethod(method));
30750
30764
  }
30765
+ function isExtensionReusedRequestMethod(method) {
30766
+ return method === "tasks/get" || method === "tasks/cancel";
30767
+ }
30751
30768
  var ALL_CODECS = [rev2025Codec, rev2026Codec];
30752
30769
  function isPlainObject$3(value) {
30753
30770
  return value !== null && typeof value === "object" && !Array.isArray(value);
@@ -31725,6 +31742,8 @@ var Protocol = class {
31725
31742
  _transport;
31726
31743
  _requestMessageId = 0;
31727
31744
  _requestHandlers = /* @__PURE__ */ new Map();
31745
+ /** Methods registered with an explicit schema; the era gate in `_onrequest` reads it for the Tasks extension names. */
31746
+ _customSchemaRequestMethods = /* @__PURE__ */ new Set();
31728
31747
  _requestHandlerAbortControllers = /* @__PURE__ */ new Map();
31729
31748
  _notificationHandlers = /* @__PURE__ */ new Map();
31730
31749
  _responseHandlers = /* @__PURE__ */ new Map();
@@ -32008,7 +32027,7 @@ var Protocol = class {
32008
32027
  return;
32009
32028
  }
32010
32029
  }
32011
- if (isSpecRequestMethod(request.method) && !codec2.hasRequestMethod(request.method)) {
32030
+ if (isSpecRequestMethod(request.method) && !codec2.hasRequestMethod(request.method) && !(isExtensionReusedRequestMethod(request.method) && this._customSchemaRequestMethods.has(request.method))) {
32012
32031
  sendErrorResponse(ProtocolErrorCode.MethodNotFound, "Method not found");
32013
32032
  return;
32014
32033
  }
@@ -32141,8 +32160,11 @@ var Protocol = class {
32141
32160
  }
32142
32161
  request(request, schemaOrOptions, maybeOptions) {
32143
32162
  const codec2 = this._resolveOutboundCodec(request.method);
32163
+ if (isStandardSchema(schemaOrOptions)) {
32164
+ if (!isExtensionReusedRequestMethod(request.method)) this._assertOutboundRequestInEra(codec2, request.method);
32165
+ return this._requestWithSchemaViaCodec(codec2, request, schemaOrOptions, maybeOptions);
32166
+ }
32144
32167
  this._assertOutboundRequestInEra(codec2, request.method);
32145
- if (isStandardSchema(schemaOrOptions)) return this._requestWithSchemaViaCodec(codec2, request, schemaOrOptions, maybeOptions);
32146
32168
  const validate2 = codecResultValidator(codec2, request.method);
32147
32169
  if (validate2 === void 0) throw new TypeError(`'${request.method}' is not a spec method; pass a result schema as the second argument to request().`);
32148
32170
  return this._requestWithSchemaViaCodec(codec2, request, validate2, schemaOrOptions);
@@ -32386,6 +32408,8 @@ var Protocol = class {
32386
32408
  return maybeHandler(parsed.data, ctx);
32387
32409
  };
32388
32410
  else throw new TypeError("setRequestHandler: handler is required");
32411
+ if (typeof schemasOrHandler === "function") this._customSchemaRequestMethods.delete(method);
32412
+ else this._customSchemaRequestMethods.add(method);
32389
32413
  this._requestHandlers.set(method, this._wrapHandler(method, stored));
32390
32414
  }
32391
32415
  /**
@@ -32415,6 +32439,7 @@ var Protocol = class {
32415
32439
  */
32416
32440
  removeRequestHandler(method) {
32417
32441
  this._requestHandlers.delete(method);
32442
+ this._customSchemaRequestMethods.delete(method);
32418
32443
  }
32419
32444
  /**
32420
32445
  * Asserts that a request handler has not already been set for the given method, in preparation for a new one being automatically installed.
@@ -39657,7 +39682,7 @@ var Ajv = import_ajv.Ajv;
39657
39682
  // node_modules/@modelcontextprotocol/server/dist/shimsNode.mjs
39658
39683
  import process2 from "node:process";
39659
39684
 
39660
- // node_modules/@modelcontextprotocol/server/dist/mcp-DYuW2ZSs.mjs
39685
+ // node_modules/@modelcontextprotocol/server/dist/mcp-DIH4cS6P.mjs
39661
39686
  var COMPLETABLE_SYMBOL = /* @__PURE__ */ Symbol.for("mcp.completable");
39662
39687
  function isCompletable(schema) {
39663
39688
  return !!schema && typeof schema === "object" && COMPLETABLE_SYMBOL in schema;
@@ -39722,7 +39747,7 @@ var StdioListenRouter = class {
39722
39747
  _serverCapabilities;
39723
39748
  /**
39724
39749
  * The serving instance's identity, stamped onto the graceful-close
39725
- * results' `_meta` (the spec's `SubscriptionsListenResultMeta` extends
39750
+ * results' `_meta` (the spec's `SubscriptionsListenResultMetaObject` extends
39726
39751
  * `ResultMetaObject`). Handed over together with the capabilities.
39727
39752
  */
39728
39753
  _serverInfo;
@@ -40054,6 +40079,11 @@ var Server = class extends Protocol {
40054
40079
  if (modernProtocolVersions(this._supportedProtocolVersions).length > 0) this.setRequestHandler("server/discover", () => this._ondiscover());
40055
40080
  if (this._capabilities.logging) this._registerLoggingHandler();
40056
40081
  }
40082
+ /** Attaches to the given transport; rejects while this instance is connected to another one. */
40083
+ async connect(transport) {
40084
+ if (this.transport !== void 0) throw new SdkError(SdkErrorCode.AlreadyConnected, "Use a separate Server instance per connection: this instance is already connected to a transport. To connect it to a new transport, call close() first.");
40085
+ await super.connect(transport);
40086
+ }
40057
40087
  /**
40058
40088
  * Registers the built-in `logging/setLevel` request handler.
40059
40089
  *
@@ -40607,21 +40637,41 @@ var Server = class extends Protocol {
40607
40637
  function discoverAdvertisedCapabilities(capabilities) {
40608
40638
  return { ...capabilities };
40609
40639
  }
40640
+ function toolInputElementCount(value, max) {
40641
+ let count = 0;
40642
+ const stack = [value];
40643
+ while (stack.length > 0) {
40644
+ const node2 = stack.pop();
40645
+ if (node2 === null || typeof node2 !== "object") continue;
40646
+ if (Array.isArray(node2)) for (const child of node2) {
40647
+ if (++count > max) return count;
40648
+ if (child !== null && typeof child === "object") stack.push(child);
40649
+ }
40650
+ else for (const key in node2) {
40651
+ if (!Object.prototype.hasOwnProperty.call(node2, key)) continue;
40652
+ if (++count > max) return count;
40653
+ const child = node2[key];
40654
+ if (child !== null && typeof child === "object") stack.push(child);
40655
+ }
40656
+ }
40657
+ return count;
40658
+ }
40659
+ function resolveMaxToolInputElements(value) {
40660
+ if (value === void 0 || value === Infinity) return void 0;
40661
+ if (typeof value !== "number" || Number.isNaN(value) || value < 1) throw new RangeError(`maxToolInputElements must be a number of at least 1, or Infinity, got ${String(value)}`);
40662
+ return value;
40663
+ }
40610
40664
  var McpServer = class {
40611
40665
  /**
40612
40666
  * The underlying {@linkcode Server} instance, useful for advanced operations like sending notifications.
40613
40667
  */
40614
40668
  server;
40669
+ _maxToolInputElements;
40615
40670
  _registeredResources = {};
40616
40671
  _registeredResourceTemplates = {};
40617
40672
  _registeredTools = {};
40618
40673
  _registeredPrompts = {};
40619
- /**
40620
- * Per-tool JSON-converted `inputSchema`, memoized so the SEP-2243
40621
- * registration-time scan and the pre-dispatch validation step share one
40622
- * conversion instead of paying it twice per request under the
40623
- * per-request-factory `createMcpHandler` model.
40624
- */
40674
+ /** Per-tool JSON-converted `inputSchema`, filled on first use by `toolInputSchemaJson()`. */
40625
40675
  _toolInputSchemaJson = {};
40626
40676
  /**
40627
40677
  * The JSON-serialized `inputSchema` of a registered tool, or `undefined`
@@ -40646,6 +40696,7 @@ var McpServer = class {
40646
40696
  }
40647
40697
  constructor(serverInfo, options) {
40648
40698
  this.server = new Server(serverInfo, options);
40699
+ this._maxToolInputElements = resolveMaxToolInputElements(options?.maxToolInputElements);
40649
40700
  if (options?.capabilities?.tools) this.setToolRequestHandlers();
40650
40701
  if (options?.capabilities?.resources) this.setResourceRequestHandlers();
40651
40702
  if (options?.capabilities?.prompts) this.setPromptRequestHandlers();
@@ -40718,7 +40769,7 @@ var McpServer = class {
40718
40769
  name,
40719
40770
  title: tool.title,
40720
40771
  description: tool.description,
40721
- inputSchema: tool.inputSchema ? standardSchemaToJsonSchema(tool.inputSchema, "input") : EMPTY_OBJECT_JSON_SCHEMA,
40772
+ inputSchema: tool.inputSchema ? convertListedInputSchema(name, tool.inputSchema) : EMPTY_OBJECT_JSON_SCHEMA,
40722
40773
  annotations: tool.annotations,
40723
40774
  icons: tool.icons,
40724
40775
  execution: tool.execution,
@@ -40763,6 +40814,7 @@ var McpServer = class {
40763
40814
  * Validates tool input arguments against the tool's input schema.
40764
40815
  */
40765
40816
  async validateToolInput(tool, args, toolName) {
40817
+ if (this._maxToolInputElements !== void 0 && toolInputElementCount(args, this._maxToolInputElements) > this._maxToolInputElements) throw new ProtocolError(ProtocolErrorCode.InvalidParams, `Invalid arguments for tool ${toolName}: arguments contain more than the maximum of ${this._maxToolInputElements} elements`);
40766
40818
  if (!tool.inputSchema) return;
40767
40819
  const parseResult = await validateStandardSchema(tool.inputSchema, args ?? {});
40768
40820
  if (!parseResult.success) throw new ProtocolError(ProtocolErrorCode.InvalidParams, `Input validation error: Invalid arguments for tool ${toolName}: ${parseResult.error}`);
@@ -41037,20 +41089,19 @@ var McpServer = class {
41037
41089
  }
41038
41090
  _createRegisteredTool(name, title, description, inputSchema, outputSchema, annotations, icons, execution, scopeChallenge, _meta, handler) {
41039
41091
  validateAndWarnToolName(name);
41040
- if (inputSchema !== void 0) try {
41041
- const json2 = standardSchemaToJsonSchema(inputSchema, "input");
41042
- this._toolInputSchemaJson[name] = json2;
41043
- const scan = scanXMcpHeaderDeclarations(json2);
41044
- if (!scan.valid) console.warn(`[mcp-sdk] tool '${name}' carries an invalid x-mcp-header declaration and will be excluded by conforming Streamable HTTP clients: ${scan.reason}`);
41045
- } catch {
41046
- }
41047
41092
  let currentHandler = handler;
41093
+ let outputSchemaJson;
41048
41094
  const registeredTool = {
41049
41095
  title,
41050
41096
  description,
41051
41097
  inputSchema,
41052
41098
  outputSchema,
41053
- outputSchemaJson: convertOutputSchemaJson(outputSchema),
41099
+ get outputSchemaJson() {
41100
+ return outputSchemaJson ??= convertOutputSchemaJson(registeredTool.outputSchema);
41101
+ },
41102
+ set outputSchemaJson(value) {
41103
+ outputSchemaJson = value;
41104
+ },
41054
41105
  annotations,
41055
41106
  icons,
41056
41107
  execution,
@@ -41177,6 +41228,12 @@ var EMPTY_OBJECT_JSON_SCHEMA = {
41177
41228
  type: "object",
41178
41229
  properties: {}
41179
41230
  };
41231
+ function convertListedInputSchema(name, inputSchema) {
41232
+ const json2 = standardSchemaToJsonSchema(inputSchema, "input");
41233
+ const scan = scanXMcpHeaderDeclarations(json2);
41234
+ if (!scan.valid) console.warn(`[mcp-sdk] tool '${name}' carries an invalid x-mcp-header declaration and will be excluded by conforming Streamable HTTP clients: ${scan.reason}`);
41235
+ return json2;
41236
+ }
41180
41237
  function convertOutputSchemaJson(outputSchema) {
41181
41238
  if (outputSchema === void 0) return void 0;
41182
41239
  try {
@@ -41189,7 +41246,7 @@ function createPromptHandler(name, argsSchema7, callback) {
41189
41246
  if (argsSchema7) {
41190
41247
  const typedCallback = callback;
41191
41248
  return async (args, ctx) => {
41192
- const parseResult = await validateStandardSchema(argsSchema7, args);
41249
+ const parseResult = await validateStandardSchema(argsSchema7, args ?? {});
41193
41250
  if (!parseResult.success) throw new ProtocolError(ProtocolErrorCode.InvalidParams, `Invalid arguments for prompt ${name}: ${parseResult.error}`);
41194
41251
  return typedCallback(parseResult.data, ctx);
41195
41252
  };
@@ -59549,8 +59606,8 @@ function currencyCode2(_params) {
59549
59606
  return _stringFormat(ZodCustomStringFormat, "currency_code", currencyCode, _params);
59550
59607
  }
59551
59608
  function hash(alg, params) {
59552
- const enc6 = params?.enc ?? "hex";
59553
- const format = `${alg}_${enc6}`;
59609
+ const enc7 = params?.enc ?? "hex";
59610
+ const format = `${alg}_${enc7}`;
59554
59611
  const regex = regexes_exports[format];
59555
59612
  if (!regex)
59556
59613
  throw new Error(`Unrecognized hash format: ${format}`);
@@ -61733,7 +61790,10 @@ function surfaceToolHints(server) {
61733
61790
  ));
61734
61791
  }
61735
61792
  async function createMcpServer(opts) {
61736
- const server = new McpServer({ name: opts.name, version: opts.version }, { supportedProtocolVersions: [...SERVER_PROTOCOL_VERSIONS] });
61793
+ const server = new McpServer({ name: opts.name, version: opts.version }, {
61794
+ supportedProtocolVersions: [...SERVER_PROTOCOL_VERSIONS],
61795
+ ...opts.maxToolInputElements !== void 0 ? { maxToolInputElements: opts.maxToolInputElements } : {}
61796
+ });
61737
61797
  if (opts.surfaceHints !== false)
61738
61798
  surfaceToolHints(server);
61739
61799
  if (opts.banner !== void 0) {
@@ -62431,6 +62491,60 @@ var KNOWN_CAPABILITIES = /* @__PURE__ */ new Set([
62431
62491
  "graphql",
62432
62492
  "write_cookies"
62433
62493
  ]);
62494
+ var ACCOUNT_KEY_FRAME = "account-key";
62495
+ var ACCOUNT_ATTEST_FRAME = "account-attest";
62496
+ var BRIDGE_ROLE_FRAME = "bridge-role";
62497
+ var BRIDGE_SERVE_FRAME = "bridge-serve";
62498
+ var ROOM_PING_FRAME = "room-ping";
62499
+ var ROOM_PONG_FRAME = "room-pong";
62500
+ var BRIDGE_ROLE_LABEL_MAX = 64;
62501
+ var ROOM_FRAME_ACCEPTS = Object.freeze({
62502
+ [BRIDGE_ROLE_FRAME]: BRIDGE_ROLE_FRAME,
62503
+ [BRIDGE_SERVE_FRAME]: BRIDGE_SERVE_FRAME,
62504
+ [ROOM_PING_FRAME]: ROOM_PING_FRAME,
62505
+ [ROOM_PONG_FRAME]: ROOM_PING_FRAME
62506
+ });
62507
+
62508
+ // node_modules/@fetchproxy/protocol/dist/mcp-id.js
62509
+ var ID_RE = /^([^:]+):([^:]+):([0-9a-f]{16})$/;
62510
+ function generateMcpId(serverName, version2) {
62511
+ if (serverName.includes(":")) {
62512
+ throw new Error(`serverName cannot contain ':': ${serverName}`);
62513
+ }
62514
+ if (version2.includes(":")) {
62515
+ throw new Error(`version cannot contain ':': ${version2}`);
62516
+ }
62517
+ const rand = randomHex(8);
62518
+ return `${serverName}:${version2}:${rand}`;
62519
+ }
62520
+ function isValidMcpId(id) {
62521
+ return typeof id === "string" && ID_RE.test(id);
62522
+ }
62523
+ function randomHex(bytes) {
62524
+ const arr = new Uint8Array(bytes);
62525
+ globalThis.crypto.getRandomValues(arr);
62526
+ return Array.from(arr, (b) => b.toString(16).padStart(2, "0")).join("");
62527
+ }
62528
+
62529
+ // node_modules/@fetchproxy/protocol/dist/account-attest.js
62530
+ var ACCOUNT_ATTEST_CONSENTS = Object.freeze([
62531
+ "silent",
62532
+ "confirm",
62533
+ "confirm-each"
62534
+ ]);
62535
+ var NO_SCOPE_DIGEST = "0".repeat(64);
62536
+ var ACCOUNT_ID_RE = /^[A-Za-z0-9_.\-]{1,128}$/;
62537
+ var HEX64_RE = /^[0-9a-f]{64}$/;
62538
+ var ACCOUNT_KID_RE = /^[0-9a-f]{16}$/;
62539
+ var enc2 = new TextEncoder();
62540
+
62541
+ // node_modules/@fetchproxy/protocol/dist/awaiting-approval.js
62542
+ var AWAITING_APPROVAL_REASON_PREFIX = "awaiting-approval:";
62543
+ function parseAwaitingApprovalReason(reason) {
62544
+ if (!reason.startsWith(AWAITING_APPROVAL_REASON_PREFIX))
62545
+ return null;
62546
+ return reason.slice(AWAITING_APPROVAL_REASON_PREFIX.length).trim();
62547
+ }
62434
62548
 
62435
62549
  // node_modules/@fetchproxy/protocol/dist/capability-availability.js
62436
62550
  var CAPABILITY_UNAVAILABLE_CODE = "capability_unavailable";
@@ -62456,27 +62570,6 @@ function parseUnsupportedCapabilityReason(reason) {
62456
62570
  return rest.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
62457
62571
  }
62458
62572
 
62459
- // node_modules/@fetchproxy/protocol/dist/mcp-id.js
62460
- var ID_RE = /^([^:]+):([^:]+):([0-9a-f]{16})$/;
62461
- function generateMcpId(serverName, version2) {
62462
- if (serverName.includes(":")) {
62463
- throw new Error(`serverName cannot contain ':': ${serverName}`);
62464
- }
62465
- if (version2.includes(":")) {
62466
- throw new Error(`version cannot contain ':': ${version2}`);
62467
- }
62468
- const rand = randomHex(8);
62469
- return `${serverName}:${version2}:${rand}`;
62470
- }
62471
- function isValidMcpId(id) {
62472
- return typeof id === "string" && ID_RE.test(id);
62473
- }
62474
- function randomHex(bytes) {
62475
- const arr = new Uint8Array(bytes);
62476
- globalThis.crypto.getRandomValues(arr);
62477
- return Array.from(arr, (b) => b.toString(16).padStart(2, "0")).join("");
62478
- }
62479
-
62480
62573
  // node_modules/@fetchproxy/protocol/dist/json-pointer.js
62481
62574
  function matchesDeclaredKey(requested, declared) {
62482
62575
  for (const decl of declared) {
@@ -63072,6 +63165,16 @@ function validateFrame(raw) {
63072
63165
  return { type: "extension-disconnected" };
63073
63166
  if (t === "peer-gone")
63074
63167
  return validatePeerGone(raw);
63168
+ if (t === ACCOUNT_KEY_FRAME)
63169
+ return validateAccountKey(raw);
63170
+ if (t === ACCOUNT_ATTEST_FRAME)
63171
+ return validateAccountAttest(raw);
63172
+ if (t === BRIDGE_ROLE_FRAME)
63173
+ return validateBridgeRole(raw);
63174
+ if (t === BRIDGE_SERVE_FRAME || t === ROOM_PING_FRAME || t === ROOM_PONG_FRAME) {
63175
+ assertExactFields(raw, TYPE_ONLY_FIELDS, t);
63176
+ return { type: t };
63177
+ }
63075
63178
  throw new ProtocolError3(`unknown frame type: ${String(t)}`);
63076
63179
  }
63077
63180
  function validateHello(raw) {
@@ -63275,6 +63378,165 @@ function validateHelloRejected(raw) {
63275
63378
  }
63276
63379
  return { type: "hello-rejected", mcpId: raw.mcpId, reason: raw.reason };
63277
63380
  }
63381
+ var DISPLAY_FORBIDDEN_RE = /[\u0000-\u001f\u007f-\u009f\u200e\u200f\u202a-\u202e\u2066-\u2069]/;
63382
+ function assertExactFields(raw, allowed, label) {
63383
+ for (const k of Object.keys(raw)) {
63384
+ if (!allowed.includes(k)) {
63385
+ throw new ProtocolError3(`${label}: unexpected field ${JSON.stringify(k)}`);
63386
+ }
63387
+ }
63388
+ }
63389
+ function assertMatch(x, re, label, what) {
63390
+ assertString(x, label);
63391
+ if (!re.test(x))
63392
+ throw new ProtocolError3(`${label}: must be ${what}`);
63393
+ }
63394
+ function assertPositiveSafeInt(x, label) {
63395
+ if (typeof x !== "number" || !Number.isSafeInteger(x) || x <= 0) {
63396
+ throw new ProtocolError3(`${label}: expected positive safe integer`);
63397
+ }
63398
+ }
63399
+ function assertDisplayString(x, label, min, max) {
63400
+ assertString(x, label);
63401
+ if (x.length < min || x.length > max) {
63402
+ throw new ProtocolError3(`${label}: must be ${min}-${max} characters`);
63403
+ }
63404
+ if (DISPLAY_FORBIDDEN_RE.test(x)) {
63405
+ throw new ProtocolError3(`${label}: control or bidi-override character`);
63406
+ }
63407
+ }
63408
+ var ACCOUNT_KEY_FIELDS = [
63409
+ "type",
63410
+ "accountId",
63411
+ "slug",
63412
+ "displayName",
63413
+ "confirmedBy",
63414
+ "tokenId",
63415
+ "kid",
63416
+ "publicKey",
63417
+ "generation",
63418
+ "bridgedRegistrations"
63419
+ ];
63420
+ function validateAccountKey(raw) {
63421
+ const L = "account-key";
63422
+ assertMatch(raw.accountId, ACCOUNT_ID_RE, `${L}.accountId`, "an account id");
63423
+ assertMatch(raw.slug, ACCOUNT_ID_RE, `${L}.slug`, "a slug");
63424
+ assertDisplayString(raw.displayName, `${L}.displayName`, 0, 128);
63425
+ assertDisplayString(raw.confirmedBy, `${L}.confirmedBy`, 1, 256);
63426
+ assertMatch(raw.tokenId, ACCOUNT_ID_RE, `${L}.tokenId`, "a token id");
63427
+ assertMatch(raw.kid, ACCOUNT_KID_RE, `${L}.kid`, "16 lowercase hex");
63428
+ assertBase64Bytes(raw.publicKey, `${L}.publicKey`, 32);
63429
+ assertPositiveSafeInt(raw.generation, `${L}.generation`);
63430
+ const n = raw.bridgedRegistrations;
63431
+ if (typeof n !== "number" || !Number.isSafeInteger(n) || n < 0) {
63432
+ throw new ProtocolError3(`${L}.bridgedRegistrations: expected non-negative safe integer`);
63433
+ }
63434
+ assertExactFields(raw, ACCOUNT_KEY_FIELDS, L);
63435
+ return {
63436
+ type: ACCOUNT_KEY_FRAME,
63437
+ accountId: raw.accountId,
63438
+ slug: raw.slug,
63439
+ displayName: raw.displayName,
63440
+ confirmedBy: raw.confirmedBy,
63441
+ tokenId: raw.tokenId,
63442
+ kid: raw.kid,
63443
+ publicKey: raw.publicKey,
63444
+ generation: raw.generation,
63445
+ bridgedRegistrations: n
63446
+ };
63447
+ }
63448
+ var ACCOUNT_ATTEST_FIELDS = [
63449
+ "type",
63450
+ "mcpId",
63451
+ "accountId",
63452
+ "generation",
63453
+ "tokenId",
63454
+ "kid",
63455
+ "registrationId",
63456
+ "slug",
63457
+ "identityHash",
63458
+ "identityEd25519Pub",
63459
+ "scopeDigest",
63460
+ "consent",
63461
+ "notAfter",
63462
+ "sig"
63463
+ ];
63464
+ function validateAccountAttest(raw) {
63465
+ const L = "account-attest";
63466
+ if (!isValidMcpId(raw.mcpId))
63467
+ throw new ProtocolError3(`${L}.mcpId: invalid format`);
63468
+ assertMatch(raw.accountId, ACCOUNT_ID_RE, `${L}.accountId`, "an account id");
63469
+ assertPositiveSafeInt(raw.generation, `${L}.generation`);
63470
+ assertMatch(raw.tokenId, ACCOUNT_ID_RE, `${L}.tokenId`, "a token id");
63471
+ assertMatch(raw.kid, ACCOUNT_KID_RE, `${L}.kid`, "16 lowercase hex");
63472
+ assertMatch(raw.registrationId, ACCOUNT_ID_RE, `${L}.registrationId`, "a registration id");
63473
+ assertMatch(raw.slug, ACCOUNT_ID_RE, `${L}.slug`, "a slug");
63474
+ assertMatch(raw.identityHash, HEX64_RE, `${L}.identityHash`, "64 lowercase hex");
63475
+ assertBase64Bytes(raw.identityEd25519Pub, `${L}.identityEd25519Pub`, 32);
63476
+ assertMatch(raw.scopeDigest, HEX64_RE, `${L}.scopeDigest`, "64 lowercase hex");
63477
+ assertString(raw.consent, `${L}.consent`);
63478
+ const consent = raw.consent;
63479
+ const known = ACCOUNT_ATTEST_CONSENTS.find((c) => c === consent);
63480
+ if (known === void 0) {
63481
+ throw new ProtocolError3(`${L}.consent: must be one of ${ACCOUNT_ATTEST_CONSENTS.join(", ")}`);
63482
+ }
63483
+ assertPositiveSafeInt(raw.notAfter, `${L}.notAfter`);
63484
+ assertBase64Bytes(raw.sig, `${L}.sig`, 64);
63485
+ assertExactFields(raw, ACCOUNT_ATTEST_FIELDS, L);
63486
+ return {
63487
+ type: ACCOUNT_ATTEST_FRAME,
63488
+ mcpId: raw.mcpId,
63489
+ accountId: raw.accountId,
63490
+ generation: raw.generation,
63491
+ tokenId: raw.tokenId,
63492
+ kid: raw.kid,
63493
+ registrationId: raw.registrationId,
63494
+ slug: raw.slug,
63495
+ identityHash: raw.identityHash,
63496
+ identityEd25519Pub: raw.identityEd25519Pub,
63497
+ scopeDigest: raw.scopeDigest,
63498
+ consent: known,
63499
+ notAfter: raw.notAfter,
63500
+ sig: raw.sig
63501
+ };
63502
+ }
63503
+ var TYPE_ONLY_FIELDS = ["type"];
63504
+ var BRIDGE_ROLE_FIELDS = ["type", "role", "canServe", "serving"];
63505
+ var BRIDGE_ROLE_SERVING_FIELDS = ["label", "since"];
63506
+ function validateBridgeRole(raw) {
63507
+ const L = BRIDGE_ROLE_FRAME;
63508
+ const role = raw.role;
63509
+ if (role !== "serving" && role !== "standby") {
63510
+ throw new ProtocolError3(`${L}.role: must be one of serving, standby`);
63511
+ }
63512
+ const canServe = raw.canServe;
63513
+ assertBoolean(canServe, `${L}.canServe`);
63514
+ assertExactFields(raw, BRIDGE_ROLE_FIELDS, L);
63515
+ const serving = raw.serving;
63516
+ if (role === "serving") {
63517
+ if (serving !== void 0) {
63518
+ throw new ProtocolError3(`${L}.serving: must be absent when role is serving`);
63519
+ }
63520
+ return { type: BRIDGE_ROLE_FRAME, role, canServe };
63521
+ }
63522
+ if (serving === void 0) {
63523
+ throw new ProtocolError3(`${L}.serving: required when role is standby`);
63524
+ }
63525
+ assertObject(serving, `${L}.serving`);
63526
+ const label = serving.label;
63527
+ assertDisplayString(label, `${L}.serving.label`, 1, BRIDGE_ROLE_LABEL_MAX);
63528
+ const since = serving.since;
63529
+ if (typeof since !== "number" || !Number.isSafeInteger(since) || since < 0) {
63530
+ throw new ProtocolError3(`${L}.serving.since: expected non-negative safe integer (Unix ms)`);
63531
+ }
63532
+ assertExactFields(serving, BRIDGE_ROLE_SERVING_FIELDS, `${L}.serving`);
63533
+ return {
63534
+ type: BRIDGE_ROLE_FRAME,
63535
+ role,
63536
+ canServe,
63537
+ serving: { label, since }
63538
+ };
63539
+ }
63278
63540
  function validateInnerFrame(raw) {
63279
63541
  assertObject(raw, "inner");
63280
63542
  const t = raw.type;
@@ -63742,10 +64004,10 @@ function validateInnerResponse(raw) {
63742
64004
  }
63743
64005
 
63744
64006
  // node_modules/@fetchproxy/protocol/dist/pair-code.js
63745
- var enc2 = new TextEncoder();
64007
+ var enc3 = new TextEncoder();
63746
64008
  var PAIR_LABEL = "fetchproxy/4/pair";
63747
64009
  async function pairTranscript(mcpIdentityPub, extIdentityPub, mcpNonce, extNonce, mcpSessionPub) {
63748
- const label = enc2.encode(PAIR_LABEL);
64010
+ const label = enc3.encode(PAIR_LABEL);
63749
64011
  const parts = [mcpIdentityPub, extIdentityPub, mcpNonce, extNonce, mcpSessionPub];
63750
64012
  const out = new Uint8Array(label.length + 1 + parts.reduce((n, p) => n + p.length, 0));
63751
64013
  out.set(label, 0);
@@ -63766,7 +64028,7 @@ function digits(hash2) {
63766
64028
  }
63767
64029
 
63768
64030
  // node_modules/@fetchproxy/protocol/dist/seal.js
63769
- var enc3 = new TextEncoder();
64031
+ var enc4 = new TextEncoder();
63770
64032
  var dec = new TextDecoder();
63771
64033
  function randomIv() {
63772
64034
  const iv = new Uint8Array(12);
@@ -63779,14 +64041,14 @@ function base64Length(byteLength) {
63779
64041
  return Math.ceil(byteLength / 3) * 4;
63780
64042
  }
63781
64043
  function encodeInnerFrame(inner) {
63782
- return enc3.encode(JSON.stringify(inner));
64044
+ return enc4.encode(JSON.stringify(inner));
63783
64045
  }
63784
64046
  function plaintextOf(inner) {
63785
64047
  return inner instanceof Uint8Array ? inner : encodeInnerFrame(inner);
63786
64048
  }
63787
64049
  function sealedFrameWireBytes(mcpId, seq, inner) {
63788
64050
  const plaintext = plaintextOf(inner).length;
63789
- const envelope = enc3.encode(JSON.stringify({ type: "frame", mcpId, seq, iv: "", ciphertext: "" })).length;
64051
+ const envelope = enc4.encode(JSON.stringify({ type: "frame", mcpId, seq, iv: "", ciphertext: "" })).length;
63790
64052
  return envelope + IV_B64_BYTES + base64Length(plaintext + AES_GCM_TAG_BYTES);
63791
64053
  }
63792
64054
  var MAX_FRAME_BYTES = 42 * 1024 * 1024;
@@ -64126,14 +64388,23 @@ var FetchproxyHelloRejectedError = class extends Error {
64126
64388
  platform;
64127
64389
  /**
64128
64390
  * #418: the remedy, when the reason is one this package knows how to
64129
- * explain — today only `unsupported-capability`, which blames the browser
64130
- * rather than the MCP. `null` otherwise.
64391
+ * explain — `unsupported-capability`, which blames the browser rather than
64392
+ * the MCP, and (D12) `awaiting-approval`, which says to approve in the
64393
+ * browser. `null` otherwise.
64131
64394
  */
64132
64395
  hint;
64396
+ /**
64397
+ * D12: `true` only for an `awaiting-approval:` refusal — the extension has
64398
+ * queued an approval card and nobody is at the browser yet, so the same call
64399
+ * succeeds once the person approves. Every other refusal is the extension's
64400
+ * final answer, and retrying unchanged is refused the same way.
64401
+ */
64402
+ retryable;
64133
64403
  constructor(info) {
64134
64404
  const unavailable = parseUnsupportedCapabilityReason(info.reason);
64405
+ const awaiting = parseAwaitingApprovalReason(info.reason);
64135
64406
  const platform = info.platform ?? null;
64136
- const hint = unavailable !== null ? `${platform ? `this browser (${platform})` : "this browser"} cannot serve any of the capabilities this MCP needs (${unavailable.join(", ")}) \u2014 ContextMint Bridge checked for the browser APIs and they are missing. Nothing is wrong with the MCP or your pairing, and updating will not change it: use this MCP from a browser that provides them (for example Chrome).` : null;
64407
+ const hint = awaiting !== null ? `The extension is waiting for you to approve this MCP` + (awaiting !== "" ? ` (${awaiting})` : "") + ` \u2014 open ContextMint Bridge in your browser, approve it there, then retry. Nothing is wrong with the MCP or your sign-in.` : unavailable !== null ? `${platform ? `this browser (${platform})` : "this browser"} cannot serve any of the capabilities this MCP needs (${unavailable.join(", ")}) \u2014 ContextMint Bridge checked for the browser APIs and they are missing. Nothing is wrong with the MCP or your pairing, and updating will not change it: use this MCP from a browser that provides them (for example Chrome).` : null;
64137
64408
  super(`fetchproxy: the extension refused the connection for "${info.mcpId}": ${info.reason}. ` + (hint !== null ? hint : `This is the extension's own reason \u2014 it is not a timeout, and retrying unchanged will be refused the same way.`));
64138
64409
  this.name = "FetchproxyHelloRejectedError";
64139
64410
  this.mcpId = info.mcpId;
@@ -64141,6 +64412,7 @@ var FetchproxyHelloRejectedError = class extends Error {
64141
64412
  this.unavailableCapabilities = unavailable ?? [];
64142
64413
  this.platform = platform;
64143
64414
  this.hint = hint;
64415
+ this.retryable = awaiting !== null;
64144
64416
  Object.setPrototypeOf(this, new.target.prototype);
64145
64417
  }
64146
64418
  };
@@ -64693,7 +64965,7 @@ function originVerdict(origin, allowLocal) {
64693
64965
  }
64694
64966
  var HANDSHAKE_TIMEOUT_MS = 15e3;
64695
64967
  var MAX_PAYLOAD_BYTES = MAX_FRAME_BYTES;
64696
- var enc4 = new TextEncoder();
64968
+ var enc5 = new TextEncoder();
64697
64969
  var OWN_DECRYPT_FAILURES_BEFORE_REHANDSHAKE = 3;
64698
64970
  async function startHost(opts) {
64699
64971
  const allowLocalOrigins = envAllowsLocalOrigins();
@@ -64764,10 +65036,20 @@ async function startHost(opts) {
64764
65036
  let resolveOwnSession;
64765
65037
  let rejectOwnSession;
64766
65038
  let ownSessionReady;
65039
+ let ownRetryableRefusal = false;
65040
+ let ownSessionSettled = false;
64767
65041
  function resetSessionPromise() {
65042
+ ownRetryableRefusal = false;
65043
+ ownSessionSettled = false;
64768
65044
  ownSessionReady = new Promise((resolve5, reject) => {
64769
- resolveOwnSession = resolve5;
64770
- rejectOwnSession = reject;
65045
+ resolveOwnSession = (st) => {
65046
+ ownSessionSettled = true;
65047
+ resolve5(st);
65048
+ };
65049
+ rejectOwnSession = (e) => {
65050
+ ownSessionSettled = true;
65051
+ reject(e);
65052
+ };
64771
65053
  });
64772
65054
  ownSessionReady.catch(() => {
64773
65055
  });
@@ -65034,13 +65316,15 @@ async function startHost(opts) {
65034
65316
  const extPub = fromB64(frame.extensionSessionPub);
65035
65317
  const shared = await ecdhX25519(held.priv, extPub);
65036
65318
  const salt = await transcriptHash(held.nonce, extNonce, held.pub, extPub);
65037
- const key = await hkdfSha256(shared, salt, enc4.encode(HKDF_SESSION_INFO), 32);
65319
+ const key = await hkdfSha256(shared, salt, enc5.encode(HKDF_SESSION_INFO), 32);
65038
65320
  if (extensionWs !== ws)
65039
65321
  return;
65040
65322
  ownSession = new SessionState(key);
65041
65323
  ownSessionInfo = sessionInfoFromHello(verifiedHello);
65042
65324
  ownDecryptFailures = 0;
65043
65325
  ownPendingPairCode = null;
65326
+ if (ownRetryableRefusal)
65327
+ resetSessionPromise();
65044
65328
  resolveOwnSession(ownSession);
65045
65329
  } else {
65046
65330
  const slot = peers.get(frame.mcpId);
@@ -65109,11 +65393,17 @@ async function startHost(opts) {
65109
65393
  }
65110
65394
  if (frame.type === "hello-rejected" && identified === "extension") {
65111
65395
  if (frame.mcpId === opts.ownMcpId) {
65112
- rejectOwnSession(new FetchproxyHelloRejectedError({
65396
+ const refusal = new FetchproxyHelloRejectedError({
65113
65397
  mcpId: frame.mcpId,
65114
65398
  reason: frame.reason,
65115
65399
  platform: extensionHello?.platform ?? null
65116
- }));
65400
+ });
65401
+ if (ownRetryableRefusal)
65402
+ resetSessionPromise();
65403
+ const settlesPending = !ownSessionSettled;
65404
+ rejectOwnSession(refusal);
65405
+ if (refusal.retryable && settlesPending)
65406
+ ownRetryableRefusal = true;
65117
65407
  } else {
65118
65408
  const slot = peers.get(frame.mcpId);
65119
65409
  if (slot?.helloFrame.accepts?.includes("hello-rejected")) {
@@ -65229,7 +65519,7 @@ async function startHost(opts) {
65229
65519
 
65230
65520
  // node_modules/@fetchproxy/server/dist/peer.js
65231
65521
  var PEER_DIAL_TIMEOUT_MS = 5e3;
65232
- var enc5 = new TextEncoder();
65522
+ var enc6 = new TextEncoder();
65233
65523
  function notSentError() {
65234
65524
  return new Error("fetchproxy: request not sent \u2014 the connection to the bridge host closed before it went out, so nothing reached the browser. It is safe to retry.");
65235
65525
  }
@@ -65329,7 +65619,9 @@ async function startPeer(opts) {
65329
65619
  let rejectFirstReady;
65330
65620
  let sessionPromise;
65331
65621
  let sessionPromiseSettled = false;
65622
+ let retryableRefusal = false;
65332
65623
  function resetSessionPromise() {
65624
+ retryableRefusal = false;
65333
65625
  sessionPromiseSettled = false;
65334
65626
  sessionPromise = new Promise((resolve5, reject) => {
65335
65627
  resolveFirstReady = (st) => {
@@ -65426,6 +65718,8 @@ async function startPeer(opts) {
65426
65718
  raw = JSON.parse(data.toString());
65427
65719
  const frame = validateFrame(raw);
65428
65720
  if (frame.type === "hello" && frame.role === "extension") {
65721
+ if (retryableRefusal)
65722
+ resetSessionPromise();
65429
65723
  extensionHello = frame;
65430
65724
  const mintedKeypair = await generateSessionKeypair();
65431
65725
  const mintedHello = await buildServerHello({
@@ -65455,6 +65749,8 @@ async function startPeer(opts) {
65455
65749
  session = null;
65456
65750
  if (sessionPromiseSettled)
65457
65751
  resetSessionPromise();
65752
+ } else if (retryableRefusal) {
65753
+ resetSessionPromise();
65458
65754
  }
65459
65755
  extensionDisconnectListeners.forEach((cb) => cb());
65460
65756
  return;
@@ -65476,7 +65772,7 @@ async function startPeer(opts) {
65476
65772
  const extNonce = fromB64(authenticated.sessionNonce);
65477
65773
  const shared = await ecdhX25519(held.priv, extPub);
65478
65774
  const salt = await transcriptHash(held.nonce, extNonce, held.pub, extPub);
65479
- const sessionKey = await hkdfSha256(shared, salt, enc5.encode(HKDF_SESSION_INFO), 32);
65775
+ const sessionKey = await hkdfSha256(shared, salt, enc6.encode(HKDF_SESSION_INFO), 32);
65480
65776
  if (sessionEphemeral !== held) {
65481
65777
  console.warn(`[fetchproxy] ${opts.serverName}: dropping a session derived against an ephemeral that was superseded while it was being derived`);
65482
65778
  return;
@@ -65489,16 +65785,24 @@ async function startPeer(opts) {
65489
65785
  if (isRenegotiation) {
65490
65786
  renegotiateListeners.forEach((cb) => cb());
65491
65787
  } else {
65788
+ if (retryableRefusal)
65789
+ resetSessionPromise();
65492
65790
  resolveFirstReady(session);
65493
65791
  }
65494
65792
  return;
65495
65793
  }
65496
65794
  if (frame.type === "hello-rejected" && frame.mcpId === opts.mcpId) {
65497
- rejectFirstReady(new FetchproxyHelloRejectedError({
65795
+ const refusal = new FetchproxyHelloRejectedError({
65498
65796
  mcpId: frame.mcpId,
65499
65797
  reason: frame.reason,
65500
65798
  platform: extensionHello?.platform ?? null
65501
- }));
65799
+ });
65800
+ if (retryableRefusal)
65801
+ resetSessionPromise();
65802
+ const settlesPending = !sessionPromiseSettled;
65803
+ rejectFirstReady(refusal);
65804
+ if (refusal.retryable && settlesPending)
65805
+ retryableRefusal = true;
65502
65806
  }
65503
65807
  if (frame.type === "pair-pending" && frame.mcpId === opts.mcpId) {
65504
65808
  const hello2 = extensionHello;
@@ -65662,8 +65966,9 @@ function classifyFetchError(error62, code) {
65662
65966
 
65663
65967
  // node_modules/@fetchproxy/server/dist/classify-bridge-error.js
65664
65968
  function classifyBridgeError(err) {
65665
- if (err instanceof FetchproxyHelloRejectedError)
65666
- return "hello_rejected";
65969
+ if (err instanceof FetchproxyHelloRejectedError) {
65970
+ return err.retryable ? "awaiting_approval" : "hello_rejected";
65971
+ }
65667
65972
  if (err instanceof FetchproxySessionNotReadyError)
65668
65973
  return "session_not_ready";
65669
65974
  if (err instanceof FetchproxyTimeoutError)
@@ -68266,7 +68571,7 @@ function loadAccount(env = process.env) {
68266
68571
  // package.json
68267
68572
  var package_default = {
68268
68573
  name: "canvas-parent-mcp",
68269
- version: "2.1.6",
68574
+ version: "2.1.8",
68270
68575
  mcpName: "io.github.chrischall/canvas-parent-mcp",
68271
68576
  description: "Canvas LMS (Instructure) MCP server \u2014 student/observer read access with optional file download",
68272
68577
  author: "Claude Code (AI) <https://www.anthropic.com/claude>",
@@ -68313,15 +68618,15 @@ var package_default = {
68313
68618
  typecheck: "tsc -p tsconfig.json --noEmit"
68314
68619
  },
68315
68620
  dependencies: {
68316
- "@chrischall/mcp-utils": "^2.13.0",
68317
- "@fetchproxy/bootstrap": "^3.4.1",
68318
- "@fetchproxy/server": "^3.4.1",
68319
- "@modelcontextprotocol/server": "^2.2.0",
68621
+ "@chrischall/mcp-utils": "^2.15.0",
68622
+ "@fetchproxy/bootstrap": "^3.6.0",
68623
+ "@fetchproxy/server": "^3.6.0",
68624
+ "@modelcontextprotocol/server": "^2.3.0",
68320
68625
  dotenv: "^18.0.0",
68321
68626
  zod: "^4.6.5"
68322
68627
  },
68323
68628
  devDependencies: {
68324
- "@modelcontextprotocol/client": "^2.2.0",
68629
+ "@modelcontextprotocol/client": "^2.3.0",
68325
68630
  "@types/node": "^26.0.0",
68326
68631
  "@vitest/coverage-v8": "^5.0.0",
68327
68632
  esbuild: "^0.28.0",
@@ -70062,7 +70367,7 @@ try {
70062
70367
  }
70063
70368
  await runMcp({
70064
70369
  name: "canvas",
70065
- version: "2.1.6",
70370
+ version: "2.1.8",
70066
70371
  // x-release-please-version
70067
70372
  tools: [
70068
70373
  // Outside the `if (resolved)` on purpose: an unconfigured server must
@@ -70098,7 +70403,7 @@ await runMcp({
70098
70403
  });
70099
70404
  /*! Bundled license information:
70100
70405
 
70101
- @modelcontextprotocol/server/dist/src-BHSMhZ_W.mjs:
70406
+ @modelcontextprotocol/server/dist/src-Cqbh3MYc.mjs:
70102
70407
  (*!
70103
70408
  * content-type
70104
70409
  * Copyright(c) 2015 Douglas Christopher Wilson
package/dist/index.js CHANGED
@@ -47,7 +47,7 @@ catch (e) {
47
47
  // host's install-time `tools/list` succeeds.
48
48
  await runMcp({
49
49
  name: 'canvas',
50
- version: '2.1.6', // x-release-please-version
50
+ version: '2.1.8', // x-release-please-version
51
51
  tools: [
52
52
  // Outside the `if (resolved)` on purpose: an unconfigured server must
53
53
  // still expose something that can say WHY (see the tool's docblock).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "canvas-parent-mcp",
3
- "version": "2.1.6",
3
+ "version": "2.1.8",
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>",
@@ -47,15 +47,15 @@
47
47
  "typecheck": "tsc -p tsconfig.json --noEmit"
48
48
  },
49
49
  "dependencies": {
50
- "@chrischall/mcp-utils": "^2.13.0",
51
- "@fetchproxy/bootstrap": "^3.4.1",
52
- "@fetchproxy/server": "^3.4.1",
53
- "@modelcontextprotocol/server": "^2.2.0",
50
+ "@chrischall/mcp-utils": "^2.15.0",
51
+ "@fetchproxy/bootstrap": "^3.6.0",
52
+ "@fetchproxy/server": "^3.6.0",
53
+ "@modelcontextprotocol/server": "^2.3.0",
54
54
  "dotenv": "^18.0.0",
55
55
  "zod": "^4.6.5"
56
56
  },
57
57
  "devDependencies": {
58
- "@modelcontextprotocol/client": "^2.2.0",
58
+ "@modelcontextprotocol/client": "^2.3.0",
59
59
  "@types/node": "^26.0.0",
60
60
  "@vitest/coverage-v8": "^5.0.0",
61
61
  "esbuild": "^0.28.0",
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": "2.1.6",
9
+ "version": "2.1.8",
10
10
  "packages": [
11
11
  {
12
12
  "registryType": "npm",
13
13
  "identifier": "canvas-parent-mcp",
14
- "version": "2.1.6",
14
+ "version": "2.1.8",
15
15
  "transport": {
16
16
  "type": "stdio"
17
17
  },