canvas-parent-mcp 2.0.0 → 2.1.0
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/bundle.js +668 -12
- package/dist/index.js +1 -1
- package/package.json +2 -2
- 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": "2.
|
|
10
|
+
"version": "2.1.0"
|
|
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.
|
|
18
|
+
"version": "2.1.0",
|
|
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.
|
|
4
|
+
"version": "2.1.0",
|
|
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
|
@@ -28162,6 +28162,7 @@ function missingClientCapabilities(required2, declared) {
|
|
|
28162
28162
|
return Object.keys(missing).length > 0 ? missing : void 0;
|
|
28163
28163
|
}
|
|
28164
28164
|
var FIRST_MODERN_PROTOCOL_VERSION = "2026-07-28";
|
|
28165
|
+
var SUPPORTED_MODERN_PROTOCOL_VERSIONS = [FIRST_MODERN_PROTOCOL_VERSION];
|
|
28165
28166
|
function isModernProtocolVersion(version2) {
|
|
28166
28167
|
return version2 >= FIRST_MODERN_PROTOCOL_VERSION;
|
|
28167
28168
|
}
|
|
@@ -30720,6 +30721,25 @@ function isSpecNotificationMethod(method) {
|
|
|
30720
30721
|
return ALL_CODECS.some((codec2) => codec2.hasNotificationMethod(method));
|
|
30721
30722
|
}
|
|
30722
30723
|
var ALL_CODECS = [rev2025Codec, rev2026Codec];
|
|
30724
|
+
function isPlainObject$3(value) {
|
|
30725
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
30726
|
+
}
|
|
30727
|
+
function requestMetaOf(params) {
|
|
30728
|
+
if (!isPlainObject$3(params)) return void 0;
|
|
30729
|
+
const meta3 = params["_meta"];
|
|
30730
|
+
return isPlainObject$3(meta3) ? meta3 : void 0;
|
|
30731
|
+
}
|
|
30732
|
+
function hasEnvelopeClaim(params) {
|
|
30733
|
+
const meta3 = requestMetaOf(params);
|
|
30734
|
+
return meta3 !== void 0 && PROTOCOL_VERSION_META_KEY in meta3;
|
|
30735
|
+
}
|
|
30736
|
+
function envelopeClaimVersion(params) {
|
|
30737
|
+
const value = requestMetaOf(params)?.[PROTOCOL_VERSION_META_KEY];
|
|
30738
|
+
return typeof value === "string" ? value : void 0;
|
|
30739
|
+
}
|
|
30740
|
+
function validateEnvelopeMeta(meta3) {
|
|
30741
|
+
return codecForVersion(MODERN_WIRE_REVISION).validateEnvelopeMeta(meta3);
|
|
30742
|
+
}
|
|
30723
30743
|
var schemas_exports = /* @__PURE__ */ __exportAll({
|
|
30724
30744
|
AnnotationsSchema: () => AnnotationsSchema,
|
|
30725
30745
|
AudioContentSchema: () => AudioContentSchema,
|
|
@@ -31070,6 +31090,45 @@ var LADDER_ERROR_HTTP_STATUS = {
|
|
|
31070
31090
|
[ProtocolErrorCode.MissingRequiredClientCapability]: 400,
|
|
31071
31091
|
[HEADER_MISMATCH_ERROR_CODE]: 400
|
|
31072
31092
|
};
|
|
31093
|
+
function rejection(rung, cell, httpStatus, error62, settled) {
|
|
31094
|
+
return {
|
|
31095
|
+
kind: "reject",
|
|
31096
|
+
rung,
|
|
31097
|
+
cell,
|
|
31098
|
+
httpStatus,
|
|
31099
|
+
code: error62.code,
|
|
31100
|
+
message: error62.message,
|
|
31101
|
+
...error62.data !== void 0 && { data: error62.data },
|
|
31102
|
+
settled
|
|
31103
|
+
};
|
|
31104
|
+
}
|
|
31105
|
+
function carriesValidModernEnvelopeClaim(params) {
|
|
31106
|
+
if (!hasEnvelopeClaim(params)) return false;
|
|
31107
|
+
const claimedVersion = envelopeClaimVersion(params);
|
|
31108
|
+
if (claimedVersion === void 0 || !isModernProtocolVersion(claimedVersion)) return false;
|
|
31109
|
+
const meta3 = requestMetaOf(params);
|
|
31110
|
+
return meta3 !== void 0 && validateEnvelopeMeta(meta3).length === 0;
|
|
31111
|
+
}
|
|
31112
|
+
function modernOnlyStrictRejection(route, supportedVersions) {
|
|
31113
|
+
switch (route.reason) {
|
|
31114
|
+
case "http-method":
|
|
31115
|
+
return rejection("http-method", "modern-only-method-not-allowed", 405, new ProtocolError(-32e3, "Method not allowed."), true);
|
|
31116
|
+
case "batch":
|
|
31117
|
+
return rejection("jsonrpc-shape", "modern-only-batch-not-supported", 400, new ProtocolError(ProtocolErrorCode.InvalidRequest, "Bad Request: JSON-RPC batches are not supported by this endpoint"), true);
|
|
31118
|
+
case "response":
|
|
31119
|
+
return rejection("jsonrpc-shape", "modern-only-response-post", 400, new ProtocolError(ProtocolErrorCode.InvalidRequest, "Bad Request: JSON-RPC responses cannot be posted to this endpoint"), true);
|
|
31120
|
+
case "notification":
|
|
31121
|
+
return;
|
|
31122
|
+
case "initialize":
|
|
31123
|
+
case "no-claim": {
|
|
31124
|
+
const requested = route.requestedVersion;
|
|
31125
|
+
return rejection("era-classification", "modern-only-missing-envelope", 400, requested === void 0 ? new ProtocolError(ProtocolErrorCode.UnsupportedProtocolVersion, "Unsupported protocol version: the request did not name a protocol version", { supported: [...supportedVersions] }) : new UnsupportedProtocolVersionError({
|
|
31126
|
+
supported: [...supportedVersions],
|
|
31127
|
+
requested
|
|
31128
|
+
}), true);
|
|
31129
|
+
}
|
|
31130
|
+
}
|
|
31131
|
+
}
|
|
31073
31132
|
function parseSchema(schema, data) {
|
|
31074
31133
|
return z2.safeParse(schema, data);
|
|
31075
31134
|
}
|
|
@@ -31631,6 +31690,9 @@ function withRequestStateValue(ctx, value) {
|
|
|
31631
31690
|
};
|
|
31632
31691
|
}
|
|
31633
31692
|
var writeNegotiatedProtocolVersion;
|
|
31693
|
+
function setNegotiatedProtocolVersion(instance, version2) {
|
|
31694
|
+
writeNegotiatedProtocolVersion(instance, version2);
|
|
31695
|
+
}
|
|
31634
31696
|
var Protocol = class {
|
|
31635
31697
|
_transport;
|
|
31636
31698
|
_requestMessageId = 0;
|
|
@@ -39574,6 +39636,190 @@ function getCompleter(schema) {
|
|
|
39574
39636
|
return schema[COMPLETABLE_SYMBOL]?.complete;
|
|
39575
39637
|
}
|
|
39576
39638
|
var MAX_TIMER_DELAY_MS = 2 ** 31 - 1;
|
|
39639
|
+
function listenFilterAccepts(filter, event) {
|
|
39640
|
+
switch (event.kind) {
|
|
39641
|
+
case "tools_list_changed":
|
|
39642
|
+
return filter.toolsListChanged === true;
|
|
39643
|
+
case "prompts_list_changed":
|
|
39644
|
+
return filter.promptsListChanged === true;
|
|
39645
|
+
case "resources_list_changed":
|
|
39646
|
+
return filter.resourcesListChanged === true;
|
|
39647
|
+
case "resource_updated":
|
|
39648
|
+
return filter.resourceSubscriptions !== void 0 && filter.resourceSubscriptions.includes(event.uri);
|
|
39649
|
+
}
|
|
39650
|
+
}
|
|
39651
|
+
function honoredSubset(requested, capabilities) {
|
|
39652
|
+
const honored = {};
|
|
39653
|
+
const allow = (bit) => capabilities === void 0 || bit === true;
|
|
39654
|
+
if (requested.toolsListChanged === true && allow(capabilities?.tools?.listChanged)) honored.toolsListChanged = true;
|
|
39655
|
+
if (requested.promptsListChanged === true && allow(capabilities?.prompts?.listChanged)) honored.promptsListChanged = true;
|
|
39656
|
+
if (requested.resourcesListChanged === true && allow(capabilities?.resources?.listChanged)) honored.resourcesListChanged = true;
|
|
39657
|
+
if (requested.resourceSubscriptions !== void 0 && requested.resourceSubscriptions.length > 0 && allow(capabilities?.resources?.subscribe)) honored.resourceSubscriptions = [...requested.resourceSubscriptions];
|
|
39658
|
+
return honored;
|
|
39659
|
+
}
|
|
39660
|
+
var DEFAULT_MAX_SUBSCRIPTIONS = 1024;
|
|
39661
|
+
function stampSubscriptionId(notification, subscriptionId) {
|
|
39662
|
+
return {
|
|
39663
|
+
method: notification.method,
|
|
39664
|
+
params: {
|
|
39665
|
+
...notification.params,
|
|
39666
|
+
_meta: {
|
|
39667
|
+
...notification.params?._meta,
|
|
39668
|
+
[SUBSCRIPTION_ID_META_KEY]: subscriptionId
|
|
39669
|
+
}
|
|
39670
|
+
}
|
|
39671
|
+
};
|
|
39672
|
+
}
|
|
39673
|
+
function parseListenFilter(message) {
|
|
39674
|
+
const outcome = codecForVersion(MODERN_WIRE_REVISION).validateRequest("subscriptions/listen", message);
|
|
39675
|
+
return outcome.ok ? outcome.value.params?.notifications : void 0;
|
|
39676
|
+
}
|
|
39677
|
+
var CHANGE_NOTIFICATION_METHODS = /* @__PURE__ */ new Set([
|
|
39678
|
+
"notifications/tools/list_changed",
|
|
39679
|
+
"notifications/prompts/list_changed",
|
|
39680
|
+
"notifications/resources/list_changed",
|
|
39681
|
+
"notifications/resources/updated"
|
|
39682
|
+
]);
|
|
39683
|
+
var StdioListenRouter = class {
|
|
39684
|
+
/** Active subscriptions, keyed by the listen request's JSON-RPC id verbatim. */
|
|
39685
|
+
_subs = /* @__PURE__ */ new Map();
|
|
39686
|
+
/**
|
|
39687
|
+
* The serving instance's declared capabilities. Filled in by the entry
|
|
39688
|
+
* once the modern instance is constructed (the router is created before
|
|
39689
|
+
* the instance exists), so the acknowledged filter is narrowed against
|
|
39690
|
+
* what the server can actually deliver.
|
|
39691
|
+
*/
|
|
39692
|
+
_serverCapabilities;
|
|
39693
|
+
/**
|
|
39694
|
+
* The serving instance's identity, stamped onto the graceful-close
|
|
39695
|
+
* results' `_meta` (the spec's `SubscriptionsListenResultMeta` extends
|
|
39696
|
+
* `ResultMetaObject`). Handed over together with the capabilities.
|
|
39697
|
+
*/
|
|
39698
|
+
_serverInfo;
|
|
39699
|
+
constructor(_maxSubscriptions = DEFAULT_MAX_SUBSCRIPTIONS, serverCapabilities, serverInfo) {
|
|
39700
|
+
this._maxSubscriptions = _maxSubscriptions;
|
|
39701
|
+
this._serverCapabilities = serverCapabilities;
|
|
39702
|
+
this._serverInfo = serverInfo;
|
|
39703
|
+
}
|
|
39704
|
+
/**
|
|
39705
|
+
* Record the serving instance's declared capabilities and identity once
|
|
39706
|
+
* it has been constructed. Called by `serveStdio`'s connect path;
|
|
39707
|
+
* subsequent `serve()` calls narrow the honored filter against the
|
|
39708
|
+
* capabilities, and `teardownAll()` stamps the identity.
|
|
39709
|
+
*/
|
|
39710
|
+
setServerCapabilities(capabilities, serverInfo) {
|
|
39711
|
+
this._serverCapabilities = capabilities;
|
|
39712
|
+
if (serverInfo !== void 0) this._serverInfo = serverInfo;
|
|
39713
|
+
}
|
|
39714
|
+
/** Whether `id` is an active listen subscription on this connection. */
|
|
39715
|
+
has(id) {
|
|
39716
|
+
return this._subs.has(id);
|
|
39717
|
+
}
|
|
39718
|
+
/**
|
|
39719
|
+
* Serve one inbound `subscriptions/listen` request: registers the
|
|
39720
|
+
* subscription and returns the stamped acknowledged notification (or, on
|
|
39721
|
+
* capacity / params rejection, the in-band JSON-RPC error response).
|
|
39722
|
+
*
|
|
39723
|
+
* @throws when called before {@linkcode setServerCapabilities} (or the
|
|
39724
|
+
* constructor) has supplied the serving instance's capabilities. Honoring a
|
|
39725
|
+
* filter without knowing the server's advertised capabilities would fail
|
|
39726
|
+
* open (deliver unadvertised types); the entry guarantees capabilities are
|
|
39727
|
+
* set before any listen request is routed here.
|
|
39728
|
+
*/
|
|
39729
|
+
serve(message) {
|
|
39730
|
+
if (this._serverCapabilities === void 0) throw new Error("StdioListenRouter.serve() called before setServerCapabilities(); refusing to honor a filter without capabilities");
|
|
39731
|
+
if (this._subs.size >= this._maxSubscriptions) return {
|
|
39732
|
+
jsonrpc: "2.0",
|
|
39733
|
+
id: message.id,
|
|
39734
|
+
error: {
|
|
39735
|
+
code: -32603,
|
|
39736
|
+
message: "Subscription limit reached"
|
|
39737
|
+
}
|
|
39738
|
+
};
|
|
39739
|
+
const filter = parseListenFilter(message);
|
|
39740
|
+
if (filter === void 0) return {
|
|
39741
|
+
jsonrpc: "2.0",
|
|
39742
|
+
id: message.id,
|
|
39743
|
+
error: {
|
|
39744
|
+
code: -32602,
|
|
39745
|
+
message: "Invalid params: 'notifications' is required and must be a valid SubscriptionFilter"
|
|
39746
|
+
}
|
|
39747
|
+
};
|
|
39748
|
+
const honored = honoredSubset(filter, this._serverCapabilities);
|
|
39749
|
+
this._subs.set(message.id, honored);
|
|
39750
|
+
return stampSubscriptionId({
|
|
39751
|
+
method: "notifications/subscriptions/acknowledged",
|
|
39752
|
+
params: { notifications: honored }
|
|
39753
|
+
}, message.id);
|
|
39754
|
+
}
|
|
39755
|
+
/**
|
|
39756
|
+
* Tear down one subscription (inbound `notifications/cancelled`). Returns
|
|
39757
|
+
* `true` when a subscription was removed. After this call NOTHING further
|
|
39758
|
+
* is delivered for that subscription id (the post-cancel hardening).
|
|
39759
|
+
*/
|
|
39760
|
+
cancel(id) {
|
|
39761
|
+
return this._subs.delete(id);
|
|
39762
|
+
}
|
|
39763
|
+
/**
|
|
39764
|
+
* Route an outbound notification through the active subscriptions.
|
|
39765
|
+
*
|
|
39766
|
+
* - For a subscription-gated change notification, returns one stamped copy
|
|
39767
|
+
* per subscription that opted in to it (an empty array means it is
|
|
39768
|
+
* dropped — the modern era never delivers an un-requested change type).
|
|
39769
|
+
* - For any other outbound message, returns `'passthrough'` (the entry
|
|
39770
|
+
* forwards it as-is).
|
|
39771
|
+
*/
|
|
39772
|
+
routeOutbound(message) {
|
|
39773
|
+
if (!CHANGE_NOTIFICATION_METHODS.has(message.method)) return "passthrough";
|
|
39774
|
+
const uriParam = message.params?.["uri"];
|
|
39775
|
+
const uri = typeof uriParam === "string" ? uriParam : void 0;
|
|
39776
|
+
const event = notificationToServerEvent(message.method, uri);
|
|
39777
|
+
const out = [];
|
|
39778
|
+
for (const [subscriptionId, filter] of this._subs) if (listenFilterAccepts(filter, event)) out.push(stampSubscriptionId({
|
|
39779
|
+
method: message.method,
|
|
39780
|
+
params: message.params ?? {}
|
|
39781
|
+
}, subscriptionId));
|
|
39782
|
+
return out;
|
|
39783
|
+
}
|
|
39784
|
+
/**
|
|
39785
|
+
* Server-side graceful teardown of every active subscription: returns the
|
|
39786
|
+
* empty `subscriptions/listen` JSON-RPC result for each subscription id —
|
|
39787
|
+
* the spec's graceful-close signal, `_meta` carrying the subscription id
|
|
39788
|
+
* and the serving instance's identity — for the entry to emit before
|
|
39789
|
+
* closing the wire. Clears the set so nothing further is delivered.
|
|
39790
|
+
*/
|
|
39791
|
+
teardownAll() {
|
|
39792
|
+
const out = [];
|
|
39793
|
+
for (const id of this._subs.keys()) out.push({
|
|
39794
|
+
jsonrpc: "2.0",
|
|
39795
|
+
id,
|
|
39796
|
+
result: {
|
|
39797
|
+
resultType: "complete",
|
|
39798
|
+
_meta: {
|
|
39799
|
+
[SUBSCRIPTION_ID_META_KEY]: id,
|
|
39800
|
+
...this._serverInfo !== void 0 && { [SERVER_INFO_META_KEY]: this._serverInfo }
|
|
39801
|
+
}
|
|
39802
|
+
}
|
|
39803
|
+
});
|
|
39804
|
+
this._subs.clear();
|
|
39805
|
+
return out;
|
|
39806
|
+
}
|
|
39807
|
+
};
|
|
39808
|
+
function notificationToServerEvent(method, uri) {
|
|
39809
|
+
switch (method) {
|
|
39810
|
+
case "notifications/tools/list_changed":
|
|
39811
|
+
return { kind: "tools_list_changed" };
|
|
39812
|
+
case "notifications/prompts/list_changed":
|
|
39813
|
+
return { kind: "prompts_list_changed" };
|
|
39814
|
+
case "notifications/resources/list_changed":
|
|
39815
|
+
return { kind: "resources_list_changed" };
|
|
39816
|
+
default:
|
|
39817
|
+
return {
|
|
39818
|
+
kind: "resource_updated",
|
|
39819
|
+
uri: uri ?? ""
|
|
39820
|
+
};
|
|
39821
|
+
}
|
|
39822
|
+
}
|
|
39577
39823
|
var DEFAULT_LEGACY_SHIM_MAX_ROUNDS = 8;
|
|
39578
39824
|
var DEFAULT_LEGACY_SHIM_ROUND_TIMEOUT_MS = 6e5;
|
|
39579
39825
|
function resolveLegacyShimOptions(options) {
|
|
@@ -39711,6 +39957,12 @@ var INPUT_REQUIRED_CAPABLE_METHODS = /* @__PURE__ */ new Set([
|
|
|
39711
39957
|
var writeClientIdentity;
|
|
39712
39958
|
var installDiscoverHandler;
|
|
39713
39959
|
var readServerIdentity;
|
|
39960
|
+
function installModernOnlyHandlers(server, servedModernVersions) {
|
|
39961
|
+
installDiscoverHandler(server, servedModernVersions);
|
|
39962
|
+
}
|
|
39963
|
+
function serverIdentityOf(server) {
|
|
39964
|
+
return readServerIdentity(server);
|
|
39965
|
+
}
|
|
39714
39966
|
var Server = class extends Protocol {
|
|
39715
39967
|
_clientCapabilities;
|
|
39716
39968
|
_clientVersion;
|
|
@@ -40985,6 +41237,400 @@ var StdioServerTransport = class {
|
|
|
40985
41237
|
});
|
|
40986
41238
|
}
|
|
40987
41239
|
};
|
|
41240
|
+
var DISCARD_ANSWER_TIMEOUT_MS = 3e3;
|
|
41241
|
+
var StdioConnectionChannel = class {
|
|
41242
|
+
onclose;
|
|
41243
|
+
onerror;
|
|
41244
|
+
onmessage;
|
|
41245
|
+
_closed = false;
|
|
41246
|
+
/** Request ids the entry delivered to the instance that the instance has not yet answered. */
|
|
41247
|
+
_pendingRequests = /* @__PURE__ */ new Set();
|
|
41248
|
+
_drainWaiters = [];
|
|
41249
|
+
constructor(_wire, _onInstanceClose, _outboundIntercept) {
|
|
41250
|
+
this._wire = _wire;
|
|
41251
|
+
this._onInstanceClose = _onInstanceClose;
|
|
41252
|
+
this._outboundIntercept = _outboundIntercept;
|
|
41253
|
+
}
|
|
41254
|
+
async start() {
|
|
41255
|
+
}
|
|
41256
|
+
async send(message, options) {
|
|
41257
|
+
if (isJSONRPCResultResponse(message) || isJSONRPCErrorResponse(message)) {
|
|
41258
|
+
const { id } = message;
|
|
41259
|
+
if (id !== void 0) this._settle(id);
|
|
41260
|
+
}
|
|
41261
|
+
if (this._closed) return;
|
|
41262
|
+
if (this._outboundIntercept?.(message) === "handled") return;
|
|
41263
|
+
return this._wire.send(message, options);
|
|
41264
|
+
}
|
|
41265
|
+
setProtocolVersion = (version2) => {
|
|
41266
|
+
this._wire.setProtocolVersion?.(version2);
|
|
41267
|
+
};
|
|
41268
|
+
/** Forwards one inbound message to the connected instance. */
|
|
41269
|
+
deliver(message, extra) {
|
|
41270
|
+
if (this._closed) return;
|
|
41271
|
+
if (isJSONRPCRequest(message)) this._pendingRequests.add(message.id);
|
|
41272
|
+
else if (isJSONRPCNotification(message) && message.method === "notifications/cancelled") {
|
|
41273
|
+
const cancelledId = message.params?.requestId;
|
|
41274
|
+
if (cancelledId !== void 0) this._settle(cancelledId);
|
|
41275
|
+
}
|
|
41276
|
+
this.onmessage?.(message, extra);
|
|
41277
|
+
}
|
|
41278
|
+
/**
|
|
41279
|
+
* Resolves once every request delivered to the instance has been answered
|
|
41280
|
+
* through {@linkcode send}, settled by a delivered cancellation, or the
|
|
41281
|
+
* channel has been closed and nothing further can be answered. The wait is
|
|
41282
|
+
* bounded by `timeoutMs` as a backstop so no edge can hold the caller
|
|
41283
|
+
* indefinitely; resolves `false` only when the bound elapsed with requests
|
|
41284
|
+
* still unanswered. Used by the probe-discard path so a probe request the
|
|
41285
|
+
* entry accepted is never silently dropped.
|
|
41286
|
+
*/
|
|
41287
|
+
async whenRequestsAnswered(timeoutMs) {
|
|
41288
|
+
if (this._closed || this._pendingRequests.size === 0) return true;
|
|
41289
|
+
return await new Promise((resolve2) => {
|
|
41290
|
+
const waiter = () => {
|
|
41291
|
+
clearTimeout(timer);
|
|
41292
|
+
resolve2(true);
|
|
41293
|
+
};
|
|
41294
|
+
const timer = setTimeout(() => {
|
|
41295
|
+
this._drainWaiters = this._drainWaiters.filter((pending) => pending !== waiter);
|
|
41296
|
+
resolve2(false);
|
|
41297
|
+
}, timeoutMs);
|
|
41298
|
+
this._drainWaiters.push(waiter);
|
|
41299
|
+
});
|
|
41300
|
+
}
|
|
41301
|
+
async close() {
|
|
41302
|
+
if (this._closed) return;
|
|
41303
|
+
this._closed = true;
|
|
41304
|
+
this._pendingRequests.clear();
|
|
41305
|
+
this._releaseDrainWaiters();
|
|
41306
|
+
try {
|
|
41307
|
+
this._onInstanceClose();
|
|
41308
|
+
} finally {
|
|
41309
|
+
this.onclose?.();
|
|
41310
|
+
}
|
|
41311
|
+
}
|
|
41312
|
+
_settle(id) {
|
|
41313
|
+
this._pendingRequests.delete(id);
|
|
41314
|
+
if (this._pendingRequests.size === 0) this._releaseDrainWaiters();
|
|
41315
|
+
}
|
|
41316
|
+
_releaseDrainWaiters() {
|
|
41317
|
+
const waiters = this._drainWaiters;
|
|
41318
|
+
this._drainWaiters = [];
|
|
41319
|
+
for (const waiter of waiters) waiter();
|
|
41320
|
+
}
|
|
41321
|
+
};
|
|
41322
|
+
function classifyOpeningMessage(message) {
|
|
41323
|
+
const params = message.params;
|
|
41324
|
+
if (message.method === "initialize" && !carriesValidModernEnvelopeClaim(params)) {
|
|
41325
|
+
const requestedVersion = params !== null && typeof params === "object" && typeof params.protocolVersion === "string" ? params.protocolVersion : void 0;
|
|
41326
|
+
return {
|
|
41327
|
+
kind: "legacy",
|
|
41328
|
+
reason: "initialize",
|
|
41329
|
+
...requestedVersion !== void 0 && { requestedVersion }
|
|
41330
|
+
};
|
|
41331
|
+
}
|
|
41332
|
+
if (!hasEnvelopeClaim(params)) return {
|
|
41333
|
+
kind: "legacy",
|
|
41334
|
+
reason: "no-claim"
|
|
41335
|
+
};
|
|
41336
|
+
const meta3 = requestMetaOf(params);
|
|
41337
|
+
const firstIssue = (meta3 === void 0 ? [] : validateEnvelopeMeta(meta3))[0];
|
|
41338
|
+
if (firstIssue !== void 0) return {
|
|
41339
|
+
kind: "invalid-envelope",
|
|
41340
|
+
issue: firstIssue
|
|
41341
|
+
};
|
|
41342
|
+
const claimedVersion = envelopeClaimVersion(params);
|
|
41343
|
+
if (claimedVersion === void 0 || !SUPPORTED_MODERN_PROTOCOL_VERSIONS.includes(claimedVersion)) return {
|
|
41344
|
+
kind: "unsupported-revision",
|
|
41345
|
+
requested: claimedVersion ?? "unknown"
|
|
41346
|
+
};
|
|
41347
|
+
return {
|
|
41348
|
+
kind: "modern",
|
|
41349
|
+
revision: claimedVersion,
|
|
41350
|
+
classification: {
|
|
41351
|
+
era: "modern",
|
|
41352
|
+
revision: claimedVersion
|
|
41353
|
+
}
|
|
41354
|
+
};
|
|
41355
|
+
}
|
|
41356
|
+
function serveStdio(factory, options = {}) {
|
|
41357
|
+
const legacyMode = options.legacy ?? "serve";
|
|
41358
|
+
const wire = options.transport ?? new StdioServerTransport();
|
|
41359
|
+
let state = { phase: "opening" };
|
|
41360
|
+
let discarding;
|
|
41361
|
+
let closing = false;
|
|
41362
|
+
const isTornDown = () => closing || state.phase === "closed";
|
|
41363
|
+
const reportError = (error62) => {
|
|
41364
|
+
try {
|
|
41365
|
+
options.onerror?.(error62);
|
|
41366
|
+
} catch {
|
|
41367
|
+
}
|
|
41368
|
+
};
|
|
41369
|
+
const writeErrorResponse = (id, code, message, data) => wire.send({
|
|
41370
|
+
jsonrpc: "2.0",
|
|
41371
|
+
id,
|
|
41372
|
+
error: {
|
|
41373
|
+
code,
|
|
41374
|
+
message,
|
|
41375
|
+
...data !== void 0 && { data }
|
|
41376
|
+
}
|
|
41377
|
+
}).catch((error62) => reportError(toError(error62)));
|
|
41378
|
+
const listenRouter = new StdioListenRouter(options.maxSubscriptions ?? DEFAULT_MAX_SUBSCRIPTIONS);
|
|
41379
|
+
const modernOutboundIntercept = (message) => {
|
|
41380
|
+
if (!isJSONRPCNotification(message)) return void 0;
|
|
41381
|
+
const routed = listenRouter.routeOutbound(message);
|
|
41382
|
+
if (routed === "passthrough") return void 0;
|
|
41383
|
+
for (const stamped of routed) wire.send({
|
|
41384
|
+
jsonrpc: "2.0",
|
|
41385
|
+
...stamped
|
|
41386
|
+
}).catch((error62) => reportError(toError(error62)));
|
|
41387
|
+
return "handled";
|
|
41388
|
+
};
|
|
41389
|
+
const tryServeListen = async (message) => {
|
|
41390
|
+
if (isJSONRPCRequest(message) && message.method === "subscriptions/listen") {
|
|
41391
|
+
const meta3 = requestMetaOf(message.params);
|
|
41392
|
+
const issue2 = hasEnvelopeClaim(message.params) ? (meta3 === void 0 ? [] : validateEnvelopeMeta(meta3))[0] : {
|
|
41393
|
+
key: "_meta",
|
|
41394
|
+
problem: "the per-request envelope is required on protocol revision 2026-07-28"
|
|
41395
|
+
};
|
|
41396
|
+
const claimedVersion = envelopeClaimVersion(message.params);
|
|
41397
|
+
let reply;
|
|
41398
|
+
if (issue2 !== void 0) reply = {
|
|
41399
|
+
jsonrpc: "2.0",
|
|
41400
|
+
id: message.id,
|
|
41401
|
+
error: {
|
|
41402
|
+
code: -32602,
|
|
41403
|
+
message: `Invalid _meta envelope: ${issue2.key}: ${issue2.problem}`
|
|
41404
|
+
}
|
|
41405
|
+
};
|
|
41406
|
+
else if (claimedVersion === void 0 || !SUPPORTED_MODERN_PROTOCOL_VERSIONS.includes(claimedVersion)) {
|
|
41407
|
+
const error62 = new UnsupportedProtocolVersionError({
|
|
41408
|
+
supported: [...SUPPORTED_MODERN_PROTOCOL_VERSIONS],
|
|
41409
|
+
requested: claimedVersion ?? "unknown"
|
|
41410
|
+
});
|
|
41411
|
+
reply = {
|
|
41412
|
+
jsonrpc: "2.0",
|
|
41413
|
+
id: message.id,
|
|
41414
|
+
error: {
|
|
41415
|
+
code: error62.code,
|
|
41416
|
+
message: error62.message,
|
|
41417
|
+
data: error62.data
|
|
41418
|
+
}
|
|
41419
|
+
};
|
|
41420
|
+
} else reply = listenRouter.serve(message);
|
|
41421
|
+
await wire.send("error" in reply ? reply : {
|
|
41422
|
+
jsonrpc: "2.0",
|
|
41423
|
+
method: reply.method,
|
|
41424
|
+
params: reply.params
|
|
41425
|
+
}).catch((error62) => reportError(toError(error62)));
|
|
41426
|
+
return true;
|
|
41427
|
+
}
|
|
41428
|
+
if (isJSONRPCNotification(message) && message.method === "notifications/cancelled") {
|
|
41429
|
+
const cancelledId = message.params?.requestId;
|
|
41430
|
+
if (cancelledId !== void 0 && listenRouter.cancel(cancelledId)) return true;
|
|
41431
|
+
}
|
|
41432
|
+
return false;
|
|
41433
|
+
};
|
|
41434
|
+
const answerLegacyRejection = (request, reason, requestedVersion) => {
|
|
41435
|
+
const rejection2 = modernOnlyStrictRejection({
|
|
41436
|
+
kind: "legacy",
|
|
41437
|
+
reason,
|
|
41438
|
+
...requestedVersion !== void 0 && { requestedVersion }
|
|
41439
|
+
}, SUPPORTED_MODERN_PROTOCOL_VERSIONS);
|
|
41440
|
+
if (rejection2 === void 0) return Promise.resolve();
|
|
41441
|
+
reportError(/* @__PURE__ */ new Error(`Rejected 2025-era request on a modern-only stdio connection (${rejection2.cell}): ${rejection2.message}`));
|
|
41442
|
+
return writeErrorResponse(request.id, rejection2.code, rejection2.message, rejection2.data);
|
|
41443
|
+
};
|
|
41444
|
+
const onInstanceClosed = (channel) => {
|
|
41445
|
+
if (closing || channel === discarding) return;
|
|
41446
|
+
closeAll();
|
|
41447
|
+
};
|
|
41448
|
+
const connectInstance = async (era, revision) => {
|
|
41449
|
+
const product = await factory({ era });
|
|
41450
|
+
const server = product instanceof McpServer ? product.server : product;
|
|
41451
|
+
if (era === "modern") {
|
|
41452
|
+
setNegotiatedProtocolVersion(server, revision);
|
|
41453
|
+
installModernOnlyHandlers(server, SUPPORTED_MODERN_PROTOCOL_VERSIONS);
|
|
41454
|
+
listenRouter.setServerCapabilities(server.getCapabilities(), serverIdentityOf(server));
|
|
41455
|
+
}
|
|
41456
|
+
const channel = new StdioConnectionChannel(wire, () => onInstanceClosed(channel), era === "modern" ? modernOutboundIntercept : void 0);
|
|
41457
|
+
await product.connect(channel);
|
|
41458
|
+
return {
|
|
41459
|
+
product,
|
|
41460
|
+
channel
|
|
41461
|
+
};
|
|
41462
|
+
};
|
|
41463
|
+
const disposeLateInstance = (instance) => instance.product.close().catch((error62) => reportError(toError(error62)));
|
|
41464
|
+
const discardProbeInstance = async (instance) => {
|
|
41465
|
+
discarding = instance.channel;
|
|
41466
|
+
try {
|
|
41467
|
+
if (!await instance.channel.whenRequestsAnswered(DISCARD_ANSWER_TIMEOUT_MS)) reportError(/* @__PURE__ */ new Error(`Discarded the probe instance with requests still unanswered after ${DISCARD_ANSWER_TIMEOUT_MS}ms; continuing with the fallback`));
|
|
41468
|
+
await instance.product.close();
|
|
41469
|
+
} catch (error62) {
|
|
41470
|
+
reportError(toError(error62));
|
|
41471
|
+
} finally {
|
|
41472
|
+
discarding = void 0;
|
|
41473
|
+
}
|
|
41474
|
+
};
|
|
41475
|
+
const processMessage = async (message) => {
|
|
41476
|
+
if (state.phase === "closed") return;
|
|
41477
|
+
if (state.phase === "pinned") {
|
|
41478
|
+
if (state.era === "modern" && isJSONRPCRequest(message) && message.method === "initialize" && !carriesValidModernEnvelopeClaim(message.params)) {
|
|
41479
|
+
await answerLegacyRejection(message, "initialize", message.params !== null && typeof message.params === "object" && typeof message.params.protocolVersion === "string" ? message.params.protocolVersion : void 0);
|
|
41480
|
+
return;
|
|
41481
|
+
}
|
|
41482
|
+
if (state.era === "modern" && await tryServeListen(message)) return;
|
|
41483
|
+
state.instance.channel.deliver(message);
|
|
41484
|
+
return;
|
|
41485
|
+
}
|
|
41486
|
+
if (!isJSONRPCRequest(message) && !isJSONRPCNotification(message)) {
|
|
41487
|
+
reportError(/* @__PURE__ */ new Error("Discarded a JSON-RPC response received before the connection negotiated an era"));
|
|
41488
|
+
return;
|
|
41489
|
+
}
|
|
41490
|
+
const opening = classifyOpeningMessage(message);
|
|
41491
|
+
switch (opening.kind) {
|
|
41492
|
+
case "invalid-envelope": {
|
|
41493
|
+
const detail = `Invalid _meta envelope for protocol revision 2026-07-28: ${opening.issue.key}: ${opening.issue.problem}`;
|
|
41494
|
+
if (isJSONRPCRequest(message)) await writeErrorResponse(message.id, ProtocolErrorCode.InvalidParams, detail, { envelope: opening.issue });
|
|
41495
|
+
else reportError(/* @__PURE__ */ new Error(`Discarded a notification with a malformed envelope: ${detail}`));
|
|
41496
|
+
return;
|
|
41497
|
+
}
|
|
41498
|
+
case "unsupported-revision":
|
|
41499
|
+
if (isJSONRPCRequest(message)) {
|
|
41500
|
+
const error62 = new UnsupportedProtocolVersionError({
|
|
41501
|
+
supported: [...SUPPORTED_MODERN_PROTOCOL_VERSIONS],
|
|
41502
|
+
requested: opening.requested
|
|
41503
|
+
});
|
|
41504
|
+
reportError(error62);
|
|
41505
|
+
await writeErrorResponse(message.id, error62.code, error62.message, error62.data);
|
|
41506
|
+
} else reportError(/* @__PURE__ */ new Error(`Discarded a notification claiming unsupported protocol revision ${opening.requested}`));
|
|
41507
|
+
return;
|
|
41508
|
+
case "modern":
|
|
41509
|
+
if (isJSONRPCRequest(message) && message.method === "server/discover") {
|
|
41510
|
+
if (state.phase === "probe") {
|
|
41511
|
+
state.instance.channel.deliver(message, { classification: opening.classification });
|
|
41512
|
+
return;
|
|
41513
|
+
}
|
|
41514
|
+
const instance = await connectInstance("modern", opening.revision);
|
|
41515
|
+
if (isTornDown()) {
|
|
41516
|
+
await disposeLateInstance(instance);
|
|
41517
|
+
return;
|
|
41518
|
+
}
|
|
41519
|
+
state = {
|
|
41520
|
+
phase: "probe",
|
|
41521
|
+
instance
|
|
41522
|
+
};
|
|
41523
|
+
instance.channel.deliver(message, { classification: opening.classification });
|
|
41524
|
+
return;
|
|
41525
|
+
}
|
|
41526
|
+
if (state.phase === "probe") {
|
|
41527
|
+
if (isJSONRPCNotification(message)) {
|
|
41528
|
+
state.instance.channel.deliver(message, { classification: opening.classification });
|
|
41529
|
+
return;
|
|
41530
|
+
}
|
|
41531
|
+
state = {
|
|
41532
|
+
phase: "pinned",
|
|
41533
|
+
era: "modern",
|
|
41534
|
+
instance: state.instance
|
|
41535
|
+
};
|
|
41536
|
+
} else {
|
|
41537
|
+
const instance = await connectInstance("modern", opening.revision);
|
|
41538
|
+
if (isTornDown()) {
|
|
41539
|
+
await disposeLateInstance(instance);
|
|
41540
|
+
return;
|
|
41541
|
+
}
|
|
41542
|
+
state = {
|
|
41543
|
+
phase: "pinned",
|
|
41544
|
+
era: "modern",
|
|
41545
|
+
instance
|
|
41546
|
+
};
|
|
41547
|
+
}
|
|
41548
|
+
if (await tryServeListen(message)) return;
|
|
41549
|
+
state.instance.channel.deliver(message, { classification: opening.classification });
|
|
41550
|
+
return;
|
|
41551
|
+
case "legacy": {
|
|
41552
|
+
if (legacyMode === "reject") {
|
|
41553
|
+
if (isJSONRPCRequest(message)) await answerLegacyRejection(message, opening.reason, opening.requestedVersion);
|
|
41554
|
+
return;
|
|
41555
|
+
}
|
|
41556
|
+
if (state.phase === "probe") {
|
|
41557
|
+
await discardProbeInstance(state.instance);
|
|
41558
|
+
if (isTornDown()) return;
|
|
41559
|
+
state = { phase: "opening" };
|
|
41560
|
+
}
|
|
41561
|
+
const instance = await connectInstance("legacy");
|
|
41562
|
+
if (isTornDown()) {
|
|
41563
|
+
await disposeLateInstance(instance);
|
|
41564
|
+
return;
|
|
41565
|
+
}
|
|
41566
|
+
state = {
|
|
41567
|
+
phase: "pinned",
|
|
41568
|
+
era: "legacy",
|
|
41569
|
+
instance
|
|
41570
|
+
};
|
|
41571
|
+
state.instance.channel.deliver(message);
|
|
41572
|
+
return;
|
|
41573
|
+
}
|
|
41574
|
+
}
|
|
41575
|
+
};
|
|
41576
|
+
const queue = [];
|
|
41577
|
+
let pumping = false;
|
|
41578
|
+
const pump = async () => {
|
|
41579
|
+
if (pumping) return;
|
|
41580
|
+
pumping = true;
|
|
41581
|
+
try {
|
|
41582
|
+
while (queue.length > 0) {
|
|
41583
|
+
const message = queue.shift();
|
|
41584
|
+
try {
|
|
41585
|
+
await processMessage(message);
|
|
41586
|
+
} catch (error62) {
|
|
41587
|
+
if (isJSONRPCRequest(message)) await writeErrorResponse(message.id, ProtocolErrorCode.InternalError, "Internal server error");
|
|
41588
|
+
reportError(toError(error62));
|
|
41589
|
+
}
|
|
41590
|
+
}
|
|
41591
|
+
} finally {
|
|
41592
|
+
pumping = false;
|
|
41593
|
+
}
|
|
41594
|
+
};
|
|
41595
|
+
const closeAll = async () => {
|
|
41596
|
+
if (closing || state.phase === "closed") return;
|
|
41597
|
+
closing = true;
|
|
41598
|
+
const current = state;
|
|
41599
|
+
state = { phase: "closed" };
|
|
41600
|
+
for (const result of listenRouter.teardownAll()) await wire.send(result).catch((error62) => reportError(toError(error62)));
|
|
41601
|
+
if (current.phase === "probe" || current.phase === "pinned") await current.instance.product.close().catch((error62) => reportError(toError(error62)));
|
|
41602
|
+
await wire.close().catch((error62) => reportError(toError(error62)));
|
|
41603
|
+
};
|
|
41604
|
+
wire.onmessage = (message) => {
|
|
41605
|
+
queue.push(message);
|
|
41606
|
+
pump();
|
|
41607
|
+
};
|
|
41608
|
+
wire.onerror = (error62) => {
|
|
41609
|
+
reportError(error62);
|
|
41610
|
+
if (state.phase === "probe" || state.phase === "pinned") state.instance.channel.onerror?.(error62);
|
|
41611
|
+
};
|
|
41612
|
+
wire.onclose = () => {
|
|
41613
|
+
if (closing || state.phase === "closed") return;
|
|
41614
|
+
closing = true;
|
|
41615
|
+
const current = state;
|
|
41616
|
+
state = { phase: "closed" };
|
|
41617
|
+
if (current.phase === "probe" || current.phase === "pinned") current.instance.product.close().catch((error62) => reportError(toError(error62)));
|
|
41618
|
+
};
|
|
41619
|
+
const started = wire.start().catch((error62) => {
|
|
41620
|
+
reportError(toError(error62));
|
|
41621
|
+
throw error62;
|
|
41622
|
+
});
|
|
41623
|
+
started.catch(() => {
|
|
41624
|
+
});
|
|
41625
|
+
return { close: async () => {
|
|
41626
|
+
await started.catch(() => {
|
|
41627
|
+
});
|
|
41628
|
+
await closeAll();
|
|
41629
|
+
} };
|
|
41630
|
+
}
|
|
41631
|
+
function toError(value) {
|
|
41632
|
+
return value instanceof Error ? value : new Error(String(value));
|
|
41633
|
+
}
|
|
40988
41634
|
|
|
40989
41635
|
// node_modules/@chrischall/mcp-utils/dist/errors/index.js
|
|
40990
41636
|
var DEFAULT_ERROR_MESSAGE_MAX = 500;
|
|
@@ -60838,7 +61484,7 @@ async function createMcpServer(opts) {
|
|
|
60838
61484
|
}
|
|
60839
61485
|
return server;
|
|
60840
61486
|
}
|
|
60841
|
-
function withGracefulShutdown(
|
|
61487
|
+
function withGracefulShutdown(target, opts = {}) {
|
|
60842
61488
|
const shouldExit = opts.exit ?? true;
|
|
60843
61489
|
let shuttingDown = false;
|
|
60844
61490
|
const handler = (signal) => {
|
|
@@ -60849,7 +61495,7 @@ function withGracefulShutdown(server, opts = {}) {
|
|
|
60849
61495
|
try {
|
|
60850
61496
|
if (opts.onSignal)
|
|
60851
61497
|
await opts.onSignal(signal);
|
|
60852
|
-
await
|
|
61498
|
+
await target.close();
|
|
60853
61499
|
} catch (err) {
|
|
60854
61500
|
console.error(`[mcp-utils] error during graceful shutdown on ${signal}: ${err instanceof Error ? err.message : String(err)}`);
|
|
60855
61501
|
} finally {
|
|
@@ -60861,16 +61507,26 @@ function withGracefulShutdown(server, opts = {}) {
|
|
|
60861
61507
|
process.on("SIGINT", () => handler("SIGINT"));
|
|
60862
61508
|
process.on("SIGTERM", () => handler("SIGTERM"));
|
|
60863
61509
|
}
|
|
60864
|
-
|
|
60865
|
-
|
|
61510
|
+
function runMcp(opts) {
|
|
61511
|
+
if (opts.banner !== void 0) {
|
|
61512
|
+
console.error(opts.banner);
|
|
61513
|
+
}
|
|
61514
|
+
const spec = opts.transport ?? "stdio";
|
|
61515
|
+
const handle = serveStdio(() => createMcpServer({ ...opts, banner: void 0 }), {
|
|
61516
|
+
legacy: opts.legacy ?? "serve",
|
|
61517
|
+
onerror: opts.onerror ?? ((error62) => {
|
|
61518
|
+
console.error(`[mcp-utils] stdio server error: ${redactSecrets(error62.message)}`);
|
|
61519
|
+
}),
|
|
61520
|
+
// `'stdio'` means "let the entry make its own StdioServerTransport over
|
|
61521
|
+
// this process"; anything else is the caller's transport, which the entry
|
|
61522
|
+
// then owns (it starts it, pumps it, and closes it with the handle).
|
|
61523
|
+
...spec === "stdio" ? {} : { transport: spec }
|
|
61524
|
+
});
|
|
60866
61525
|
const shutdown = opts.shutdown ?? true;
|
|
60867
61526
|
if (shutdown !== false) {
|
|
60868
|
-
withGracefulShutdown(
|
|
61527
|
+
withGracefulShutdown(handle, shutdown === true ? {} : shutdown);
|
|
60869
61528
|
}
|
|
60870
|
-
|
|
60871
|
-
const transport = spec === "stdio" ? new StdioServerTransport() : spec;
|
|
60872
|
-
await server.connect(transport);
|
|
60873
|
-
return server;
|
|
61529
|
+
return handle;
|
|
60874
61530
|
}
|
|
60875
61531
|
|
|
60876
61532
|
// node_modules/@chrischall/mcp-utils/dist/config/index.js
|
|
@@ -66243,7 +66899,7 @@ function loadAccount(env = process.env) {
|
|
|
66243
66899
|
// package.json
|
|
66244
66900
|
var package_default = {
|
|
66245
66901
|
name: "canvas-parent-mcp",
|
|
66246
|
-
version: "2.
|
|
66902
|
+
version: "2.1.0",
|
|
66247
66903
|
mcpName: "io.github.chrischall/canvas-parent-mcp",
|
|
66248
66904
|
description: "Canvas LMS (Instructure) MCP server \u2014 student/observer read access with optional file download",
|
|
66249
66905
|
author: "Claude Code (AI) <https://www.anthropic.com/claude>",
|
|
@@ -66290,7 +66946,7 @@ var package_default = {
|
|
|
66290
66946
|
typecheck: "tsc -p tsconfig.json --noEmit"
|
|
66291
66947
|
},
|
|
66292
66948
|
dependencies: {
|
|
66293
|
-
"@chrischall/mcp-utils": "^0.
|
|
66949
|
+
"@chrischall/mcp-utils": "^1.0.0",
|
|
66294
66950
|
"@fetchproxy/bootstrap": "^3.0.1",
|
|
66295
66951
|
"@fetchproxy/server": "^3.0.1",
|
|
66296
66952
|
"@modelcontextprotocol/server": "^2.0.0",
|
|
@@ -67714,7 +68370,7 @@ try {
|
|
|
67714
68370
|
}
|
|
67715
68371
|
await runMcp({
|
|
67716
68372
|
name: "canvas",
|
|
67717
|
-
version: "2.
|
|
68373
|
+
version: "2.1.0",
|
|
67718
68374
|
// x-release-please-version
|
|
67719
68375
|
tools: [
|
|
67720
68376
|
// Outside the `if (resolved)` on purpose: an unconfigured server must
|
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.
|
|
50
|
+
version: '2.1.0', // 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.
|
|
3
|
+
"version": "2.1.0",
|
|
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,7 +47,7 @@
|
|
|
47
47
|
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@chrischall/mcp-utils": "^0.
|
|
50
|
+
"@chrischall/mcp-utils": "^1.0.0",
|
|
51
51
|
"@fetchproxy/bootstrap": "^3.0.1",
|
|
52
52
|
"@fetchproxy/server": "^3.0.1",
|
|
53
53
|
"@modelcontextprotocol/server": "^2.0.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.
|
|
9
|
+
"version": "2.1.0",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"identifier": "canvas-parent-mcp",
|
|
14
|
-
"version": "2.
|
|
14
|
+
"version": "2.1.0",
|
|
15
15
|
"transport": {
|
|
16
16
|
"type": "stdio"
|
|
17
17
|
},
|