canvas-lms-mcp 1.17.0 → 1.19.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.
Files changed (47) hide show
  1. package/README.md +10 -0
  2. package/dist/canvas/index.cjs +3 -3
  3. package/dist/canvas/index.js +2 -2
  4. package/dist/{chunk-Z3YUWFEE.js → chunk-5P4FUG7Q.js} +2 -2
  5. package/dist/{chunk-C55DPF4U.cjs → chunk-CDWLOZQ2.cjs} +146 -74
  6. package/dist/chunk-CDWLOZQ2.cjs.map +1 -0
  7. package/dist/{chunk-EPBWT2FM.cjs → chunk-EXAIZYJY.cjs} +2 -2
  8. package/dist/chunk-EXAIZYJY.cjs.map +1 -0
  9. package/dist/{chunk-GS52LL5U.cjs → chunk-LTBTS6YA.cjs} +3 -3
  10. package/dist/{chunk-GS52LL5U.cjs.map → chunk-LTBTS6YA.cjs.map} +1 -1
  11. package/dist/{chunk-KE4SUTYQ.js → chunk-YQY5WM7K.js} +123 -51
  12. package/dist/chunk-YQY5WM7K.js.map +1 -0
  13. package/dist/{chunk-FUNEDFU6.js → chunk-Z5EZRC5F.js} +2 -2
  14. package/dist/chunk-Z5EZRC5F.js.map +1 -0
  15. package/dist/http.cjs +5 -5
  16. package/dist/http.js +3 -3
  17. package/dist/init.cjs +3 -3
  18. package/dist/init.js +1 -1
  19. package/dist/server.cjs +4 -4
  20. package/dist/server.js +3 -3
  21. package/dist/stdio.cjs +4 -4
  22. package/dist/stdio.js +3 -3
  23. package/dist/tools/accounts.d.ts +2 -1
  24. package/dist/tools/accounts.d.ts.map +1 -1
  25. package/dist/tools/catalog.d.ts +2 -1
  26. package/dist/tools/catalog.d.ts.map +1 -1
  27. package/dist/tools/conversations.d.ts +2 -1
  28. package/dist/tools/conversations.d.ts.map +1 -1
  29. package/dist/tools/enrollments.d.ts +2 -1
  30. package/dist/tools/enrollments.d.ts.map +1 -1
  31. package/dist/tools/gradebook-history.d.ts +2 -1
  32. package/dist/tools/gradebook-history.d.ts.map +1 -1
  33. package/dist/tools/groups.d.ts +2 -1
  34. package/dist/tools/groups.d.ts.map +1 -1
  35. package/dist/tools/index.d.ts.map +1 -1
  36. package/dist/tools/outcomes.d.ts +2 -1
  37. package/dist/tools/outcomes.d.ts.map +1 -1
  38. package/dist/tools/submissions.d.ts +2 -1
  39. package/dist/tools/submissions.d.ts.map +1 -1
  40. package/dist/tools/users.d.ts +2 -1
  41. package/dist/tools/users.d.ts.map +1 -1
  42. package/package.json +2 -1
  43. package/dist/chunk-C55DPF4U.cjs.map +0 -1
  44. package/dist/chunk-EPBWT2FM.cjs.map +0 -1
  45. package/dist/chunk-FUNEDFU6.js.map +0 -1
  46. package/dist/chunk-KE4SUTYQ.js.map +0 -1
  47. /package/dist/{chunk-Z3YUWFEE.js.map → chunk-5P4FUG7Q.js.map} +0 -0
package/README.md CHANGED
@@ -13,6 +13,16 @@ MCP server for [Canvas LMS](https://www.instructure.com/canvas). Read courses, a
13
13
 
14
14
  116 tools across Canvas courses, assignments, submissions, gradebook history, rubrics, quizzes, New Quizzes (LTI), files, users, groups, enrollments, discussions, modules, pages, calendar, conversations, peer reviews, accounts, analytics, outcomes, student workflows, dashboard, and health checks. Three deployment modes: stdio, HTTP, and library import.
15
15
 
16
+ ## One-click install (Claude Desktop)
17
+
18
+ 1. **[Download `canvas-lms-mcp.mcpb`](https://github.com/bruchris/canvas-lms-mcp/releases/latest/download/canvas-lms-mcp.mcpb)** from the latest release.
19
+ 2. Double-click the file (or drag it into Claude Desktop's Extensions settings).
20
+ 3. When prompted, paste your Canvas API token and Canvas API base URL (e.g. `https://school.instructure.com/api/v1`).
21
+
22
+ No terminal, no Node.js install, no config-file editing — Claude Desktop bundles the runtime and handles config for you. The same `.mcpb` works in Claude Code and MCP for Windows.
23
+
24
+ Prefer the terminal? Use the [Quick Start](#quick-start) below.
25
+
16
26
  ## Comparison
17
27
 
18
28
  | | canvas-lms-mcp | [vishalsachdev/canvas-mcp](https://github.com/vishalsachdev/canvas-mcp) | [DMontgomery40/mcp-canvas-lms](https://github.com/DMontgomery40/mcp-canvas-lms) |
@@ -1,17 +1,17 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
2
 
3
- var _chunkGS52LL5Ucjs = require('../chunk-GS52LL5U.cjs');
3
+ var _chunkLTBTS6YAcjs = require('../chunk-LTBTS6YA.cjs');
4
4
 
5
5
 
6
6
 
7
7
 
8
8
 
9
- var _chunkEPBWT2FMcjs = require('../chunk-EPBWT2FM.cjs');
9
+ var _chunkEXAIZYJYcjs = require('../chunk-EXAIZYJY.cjs');
10
10
 
11
11
 
12
12
 
13
13
 
14
14
 
15
15
 
16
- exports.CanvasApiError = _chunkEPBWT2FMcjs.CanvasApiError; exports.CanvasClient = _chunkGS52LL5Ucjs.CanvasClient; exports.CanvasHttpClient = _chunkEPBWT2FMcjs.CanvasHttpClient; exports.appendCanvasQuery = _chunkEPBWT2FMcjs.appendCanvasQuery; exports.toCanvasQuery = _chunkEPBWT2FMcjs.toCanvasQuery;
16
+ exports.CanvasApiError = _chunkEXAIZYJYcjs.CanvasApiError; exports.CanvasClient = _chunkLTBTS6YAcjs.CanvasClient; exports.CanvasHttpClient = _chunkEXAIZYJYcjs.CanvasHttpClient; exports.appendCanvasQuery = _chunkEXAIZYJYcjs.appendCanvasQuery; exports.toCanvasQuery = _chunkEXAIZYJYcjs.toCanvasQuery;
17
17
  //# sourceMappingURL=index.cjs.map
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  CanvasClient
3
- } from "../chunk-Z3YUWFEE.js";
3
+ } from "../chunk-5P4FUG7Q.js";
4
4
  import {
5
5
  CanvasApiError,
6
6
  CanvasHttpClient,
7
7
  appendCanvasQuery,
8
8
  toCanvasQuery
9
- } from "../chunk-FUNEDFU6.js";
9
+ } from "../chunk-Z5EZRC5F.js";
10
10
  export {
11
11
  CanvasApiError,
12
12
  CanvasClient,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  CanvasHttpClient
3
- } from "./chunk-FUNEDFU6.js";
3
+ } from "./chunk-Z5EZRC5F.js";
4
4
 
5
5
  // src/canvas/courses.ts
6
6
  var DEFAULT_LIST_INCLUDE = ["term"];
@@ -1395,4 +1395,4 @@ export {
1395
1395
  OUTCOME_EXCLUDE_OPTIONS,
1396
1396
  CanvasClient
1397
1397
  };
1398
- //# sourceMappingURL=chunk-Z3YUWFEE.js.map
1398
+ //# sourceMappingURL=chunk-5P4FUG7Q.js.map
@@ -7,11 +7,11 @@
7
7
 
8
8
 
9
9
 
10
- var _chunkGS52LL5Ucjs = require('./chunk-GS52LL5U.cjs');
10
+ var _chunkLTBTS6YAcjs = require('./chunk-LTBTS6YA.cjs');
11
11
 
12
12
 
13
13
 
14
- var _chunkEPBWT2FMcjs = require('./chunk-EPBWT2FM.cjs');
14
+ var _chunkEXAIZYJYcjs = require('./chunk-EXAIZYJY.cjs');
15
15
 
16
16
  // src/server.ts
17
17
  var _mcpjs = require('@modelcontextprotocol/sdk/server/mcp.js');
@@ -446,7 +446,7 @@ async function appendAuditFile(filePath, line) {
446
446
 
447
447
  // src/tools/accounts.ts
448
448
  var _zod = require('zod');
449
- function accountTools(canvas) {
449
+ function accountTools(canvas, pseudonymizer) {
450
450
  return [
451
451
  {
452
452
  name: "get_account",
@@ -517,9 +517,12 @@ function accountTools(canvas) {
517
517
  openWorldHint: true
518
518
  },
519
519
  handler: async (params) => {
520
- return canvas.accounts.listUsers(params.account_id, {
520
+ const account_id = params.account_id;
521
+ const users = await canvas.accounts.listUsers(account_id, {
521
522
  search_term: params.search_term
522
523
  });
524
+ if (!_optionalChain([pseudonymizer, 'optionalAccess', _6 => _6.isEnabled, 'call', _7 => _7()])) return users;
525
+ return pseudonymizer.anonymizeUsers(String(account_id), users);
523
526
  }
524
527
  },
525
528
  {
@@ -544,7 +547,7 @@ function accountTools(canvas) {
544
547
 
545
548
  // src/tools/errors.ts
546
549
  function formatError(error) {
547
- if (error instanceof _chunkEPBWT2FMcjs.CanvasApiError) {
550
+ if (error instanceof _chunkEXAIZYJYcjs.CanvasApiError) {
548
551
  const status = error.status;
549
552
  const message = error.message;
550
553
  const ltiMarkers = ["Tool not configured", "tool is not configured"];
@@ -596,7 +599,7 @@ function analyticsTools(canvas) {
596
599
  inputSchema: {
597
600
  course_id: _zod.z.number().describe("The Canvas course ID"),
598
601
  search_term: _zod.z.string().describe("The keyword or phrase to search for"),
599
- content_types: _zod.z.array(_zod.z.enum(_chunkGS52LL5Ucjs.SEARCH_CONTENT_TYPES)).optional().describe(
602
+ content_types: _zod.z.array(_zod.z.enum(_chunkLTBTS6YAcjs.SEARCH_CONTENT_TYPES)).optional().describe(
600
603
  "Content types to search. Defaults to all types: pages, discussions, assignments, announcements."
601
604
  )
602
605
  },
@@ -608,7 +611,7 @@ function analyticsTools(canvas) {
608
611
  const courseId = params.course_id;
609
612
  const searchTerm = params.search_term;
610
613
  const types = _nullishCoalesce(params.content_types, () => ( [
611
- ..._chunkGS52LL5Ucjs.SEARCH_CONTENT_TYPES
614
+ ..._chunkLTBTS6YAcjs.SEARCH_CONTENT_TYPES
612
615
  ]));
613
616
  if (types.length === 0) return { results: [] };
614
617
  const settled = await Promise.allSettled(
@@ -970,7 +973,7 @@ function calendarTools(canvas) {
970
973
 
971
974
  // src/tools/conversations.ts
972
975
 
973
- function conversationTools(canvas) {
976
+ function conversationTools(canvas, pseudonymizer) {
974
977
  return [
975
978
  {
976
979
  name: "list_conversations",
@@ -981,7 +984,9 @@ function conversationTools(canvas) {
981
984
  openWorldHint: true
982
985
  },
983
986
  handler: async () => {
984
- return canvas.conversations.list();
987
+ const conversations = await canvas.conversations.list();
988
+ if (!_optionalChain([pseudonymizer, 'optionalAccess', _8 => _8.isEnabled, 'call', _9 => _9()])) return conversations;
989
+ return Promise.all(conversations.map((c) => pseudonymizer.anonymizeConversation(c)));
985
990
  }
986
991
  },
987
992
  {
@@ -995,7 +1000,9 @@ function conversationTools(canvas) {
995
1000
  openWorldHint: true
996
1001
  },
997
1002
  handler: async (params) => {
998
- return canvas.conversations.get(params.conversation_id);
1003
+ const conversation = await canvas.conversations.get(params.conversation_id);
1004
+ if (!_optionalChain([pseudonymizer, 'optionalAccess', _10 => _10.isEnabled, 'call', _11 => _11()])) return conversation;
1005
+ return pseudonymizer.anonymizeConversation(conversation);
999
1006
  }
1000
1007
  },
1001
1008
  {
@@ -1401,7 +1408,7 @@ var ENROLLMENT_INCLUDE = [
1401
1408
  "current_points",
1402
1409
  "grades"
1403
1410
  ];
1404
- function enrollmentTools(canvas) {
1411
+ function enrollmentTools(canvas, pseudonymizer) {
1405
1412
  return [
1406
1413
  {
1407
1414
  name: "list_enrollments",
@@ -1429,7 +1436,11 @@ function enrollmentTools(canvas) {
1429
1436
  opts.grading_period_id = params.grading_period_id;
1430
1437
  if (params.enrollment_term_id !== void 0)
1431
1438
  opts.enrollment_term_id = params.enrollment_term_id;
1432
- return canvas.enrollments.list(opts);
1439
+ const enrollments = await canvas.enrollments.list(opts);
1440
+ if (!_optionalChain([pseudonymizer, 'optionalAccess', _12 => _12.isEnabled, 'call', _13 => _13()])) return enrollments;
1441
+ return Promise.all(
1442
+ enrollments.map((e) => pseudonymizer.anonymizeEnrollment(e.course_id, e))
1443
+ );
1433
1444
  }
1434
1445
  },
1435
1446
  {
@@ -1450,6 +1461,7 @@ function enrollmentTools(canvas) {
1450
1461
  openWorldHint: true
1451
1462
  },
1452
1463
  handler: async (params) => {
1464
+ const course_id = params.course_id;
1453
1465
  const opts = {};
1454
1466
  if (params.type !== void 0) opts.type = params.type;
1455
1467
  if (params.state !== void 0) opts.state = params.state;
@@ -1461,7 +1473,9 @@ function enrollmentTools(canvas) {
1461
1473
  opts.grading_period_id = params.grading_period_id;
1462
1474
  if (params.enrollment_term_id !== void 0)
1463
1475
  opts.enrollment_term_id = params.enrollment_term_id;
1464
- return canvas.enrollments.listForCourse(params.course_id, opts);
1476
+ const enrollments = await canvas.enrollments.listForCourse(course_id, opts);
1477
+ if (!_optionalChain([pseudonymizer, 'optionalAccess', _14 => _14.isEnabled, 'call', _15 => _15()])) return enrollments;
1478
+ return Promise.all(enrollments.map((e) => pseudonymizer.anonymizeEnrollment(course_id, e)));
1465
1479
  }
1466
1480
  },
1467
1481
  {
@@ -1626,7 +1640,18 @@ function fileTools(canvas) {
1626
1640
 
1627
1641
  // src/tools/gradebook-history.ts
1628
1642
 
1629
- function gradebookHistoryTools(canvas) {
1643
+ async function anonymizeHistoryVersion(courseId, version2, pseudonymizer) {
1644
+ if (!version2.user_name || !version2.user_id) return version2;
1645
+ const minimalUser = {
1646
+ id: version2.user_id,
1647
+ name: version2.user_name,
1648
+ sortable_name: version2.user_name,
1649
+ short_name: version2.user_name
1650
+ };
1651
+ const pseudo = await pseudonymizer.anonymizeUser(courseId, minimalUser);
1652
+ return { ...version2, user_name: pseudo.name };
1653
+ }
1654
+ function gradebookHistoryTools(canvas, pseudonymizer) {
1630
1655
  return [
1631
1656
  {
1632
1657
  name: "list_gradebook_history_days",
@@ -1678,7 +1703,21 @@ function gradebookHistoryTools(canvas) {
1678
1703
  const date = params.date;
1679
1704
  const grader_id = params.grader_id;
1680
1705
  const assignment_id = params.assignment_id;
1681
- return canvas.gradebookHistory.listSubmissions(course_id, date, grader_id, assignment_id);
1706
+ const submissions = await canvas.gradebookHistory.listSubmissions(
1707
+ course_id,
1708
+ date,
1709
+ grader_id,
1710
+ assignment_id
1711
+ );
1712
+ if (!_optionalChain([pseudonymizer, 'optionalAccess', _16 => _16.isEnabled, 'call', _17 => _17()])) return submissions;
1713
+ return Promise.all(
1714
+ submissions.map(async (s) => ({
1715
+ ...s,
1716
+ versions: s.versions ? await Promise.all(
1717
+ s.versions.map((v) => anonymizeHistoryVersion(course_id, v, pseudonymizer))
1718
+ ) : s.versions
1719
+ }))
1720
+ );
1682
1721
  }
1683
1722
  },
1684
1723
  {
@@ -1699,7 +1738,15 @@ function gradebookHistoryTools(canvas) {
1699
1738
  const assignment_id = params.assignment_id;
1700
1739
  const user_id = params.user_id;
1701
1740
  const ascending = params.ascending;
1702
- return canvas.gradebookHistory.getFeed(course_id, { assignment_id, user_id, ascending });
1741
+ const versions = await canvas.gradebookHistory.getFeed(course_id, {
1742
+ assignment_id,
1743
+ user_id,
1744
+ ascending
1745
+ });
1746
+ if (!_optionalChain([pseudonymizer, 'optionalAccess', _18 => _18.isEnabled, 'call', _19 => _19()])) return versions;
1747
+ return Promise.all(
1748
+ versions.map((v) => anonymizeHistoryVersion(course_id, v, pseudonymizer))
1749
+ );
1703
1750
  }
1704
1751
  }
1705
1752
  ];
@@ -1707,7 +1754,7 @@ function gradebookHistoryTools(canvas) {
1707
1754
 
1708
1755
  // src/tools/groups.ts
1709
1756
 
1710
- function groupTools(canvas) {
1757
+ function groupTools(canvas, pseudonymizer) {
1711
1758
  return [
1712
1759
  {
1713
1760
  name: "list_groups",
@@ -1736,7 +1783,9 @@ function groupTools(canvas) {
1736
1783
  },
1737
1784
  handler: async (params) => {
1738
1785
  const group_id = params.group_id;
1739
- return canvas.groups.listMembers(group_id);
1786
+ const users = await canvas.groups.listMembers(group_id);
1787
+ if (!_optionalChain([pseudonymizer, 'optionalAccess', _20 => _20.isEnabled, 'call', _21 => _21()])) return users;
1788
+ return pseudonymizer.anonymizeUsers(`_group_${group_id}`, users);
1740
1789
  }
1741
1790
  }
1742
1791
  ];
@@ -1928,13 +1977,13 @@ function moduleTools(canvas) {
1928
1977
 
1929
1978
  // src/tools/outcomes.ts
1930
1979
 
1931
- function outcomeTools(canvas) {
1980
+ function outcomeTools(canvas, pseudonymizer) {
1932
1981
  return [
1933
1982
  {
1934
1983
  name: "get_root_outcome_group",
1935
1984
  description: "Get the root outcome group for an account or course context.",
1936
1985
  inputSchema: {
1937
- context_type: _zod.z.enum(_chunkGS52LL5Ucjs.OUTCOME_CONTEXT_TYPES).describe("Whether to read outcomes from an account or course context."),
1986
+ context_type: _zod.z.enum(_chunkLTBTS6YAcjs.OUTCOME_CONTEXT_TYPES).describe("Whether to read outcomes from an account or course context."),
1938
1987
  context_id: _zod.z.number().describe("The Canvas account ID or course ID for the context.")
1939
1988
  },
1940
1989
  annotations: { readOnlyHint: true, openWorldHint: true },
@@ -1947,7 +1996,7 @@ function outcomeTools(canvas) {
1947
1996
  name: "list_outcome_groups",
1948
1997
  description: "List all outcome groups for an account or course context.",
1949
1998
  inputSchema: {
1950
- context_type: _zod.z.enum(_chunkGS52LL5Ucjs.OUTCOME_CONTEXT_TYPES).describe("Whether to read outcome groups from an account or course context."),
1999
+ context_type: _zod.z.enum(_chunkLTBTS6YAcjs.OUTCOME_CONTEXT_TYPES).describe("Whether to read outcome groups from an account or course context."),
1951
2000
  context_id: _zod.z.number().describe("The Canvas account ID or course ID for the context.")
1952
2001
  },
1953
2002
  annotations: { readOnlyHint: true, openWorldHint: true },
@@ -1960,10 +2009,10 @@ function outcomeTools(canvas) {
1960
2009
  name: "list_outcome_group_links",
1961
2010
  description: "List all outcome links in an account or course context.",
1962
2011
  inputSchema: {
1963
- context_type: _zod.z.enum(_chunkGS52LL5Ucjs.OUTCOME_CONTEXT_TYPES).describe("Whether to read outcome links from an account or course context."),
2012
+ context_type: _zod.z.enum(_chunkLTBTS6YAcjs.OUTCOME_CONTEXT_TYPES).describe("Whether to read outcome links from an account or course context."),
1964
2013
  context_id: _zod.z.number().describe("The Canvas account ID or course ID for the context."),
1965
- outcome_style: _zod.z.enum(_chunkGS52LL5Ucjs.OUTCOME_DETAIL_LEVELS).optional().describe('Outcome detail level. Use "full" to include expanded outcome fields.'),
1966
- outcome_group_style: _zod.z.enum(_chunkGS52LL5Ucjs.OUTCOME_DETAIL_LEVELS).optional().describe(
2014
+ outcome_style: _zod.z.enum(_chunkLTBTS6YAcjs.OUTCOME_DETAIL_LEVELS).optional().describe('Outcome detail level. Use "full" to include expanded outcome fields.'),
2015
+ outcome_group_style: _zod.z.enum(_chunkLTBTS6YAcjs.OUTCOME_DETAIL_LEVELS).optional().describe(
1967
2016
  'Outcome group detail level. Use "full" to include expanded outcome group fields.'
1968
2017
  )
1969
2018
  },
@@ -1981,7 +2030,7 @@ function outcomeTools(canvas) {
1981
2030
  name: "get_outcome_group",
1982
2031
  description: "Get details for a specific outcome group in an account or course context.",
1983
2032
  inputSchema: {
1984
- context_type: _zod.z.enum(_chunkGS52LL5Ucjs.OUTCOME_CONTEXT_TYPES).describe("The outcome group context type."),
2033
+ context_type: _zod.z.enum(_chunkLTBTS6YAcjs.OUTCOME_CONTEXT_TYPES).describe("The outcome group context type."),
1985
2034
  context_id: _zod.z.number().describe("The Canvas account ID or course ID for the context."),
1986
2035
  outcome_group_id: _zod.z.number().describe("The Canvas outcome group ID.")
1987
2036
  },
@@ -1996,10 +2045,10 @@ function outcomeTools(canvas) {
1996
2045
  name: "list_outcome_group_outcomes",
1997
2046
  description: "List the linked outcomes directly under a specific outcome group.",
1998
2047
  inputSchema: {
1999
- context_type: _zod.z.enum(_chunkGS52LL5Ucjs.OUTCOME_CONTEXT_TYPES).describe("The outcome group context type."),
2048
+ context_type: _zod.z.enum(_chunkLTBTS6YAcjs.OUTCOME_CONTEXT_TYPES).describe("The outcome group context type."),
2000
2049
  context_id: _zod.z.number().describe("The Canvas account ID or course ID for the context."),
2001
2050
  outcome_group_id: _zod.z.number().describe("The Canvas outcome group ID."),
2002
- outcome_style: _zod.z.enum(_chunkGS52LL5Ucjs.OUTCOME_DETAIL_LEVELS).optional().describe('Outcome detail level. Use "full" to include expanded outcome fields.')
2051
+ outcome_style: _zod.z.enum(_chunkLTBTS6YAcjs.OUTCOME_DETAIL_LEVELS).optional().describe('Outcome detail level. Use "full" to include expanded outcome fields.')
2003
2052
  },
2004
2053
  annotations: { readOnlyHint: true, openWorldHint: true },
2005
2054
  handler: async (params) => canvas.outcomes.listGroupOutcomes(
@@ -2015,7 +2064,7 @@ function outcomeTools(canvas) {
2015
2064
  name: "list_outcome_group_subgroups",
2016
2065
  description: "List the immediate child outcome groups under a specific outcome group.",
2017
2066
  inputSchema: {
2018
- context_type: _zod.z.enum(_chunkGS52LL5Ucjs.OUTCOME_CONTEXT_TYPES).describe("The outcome group context type."),
2067
+ context_type: _zod.z.enum(_chunkLTBTS6YAcjs.OUTCOME_CONTEXT_TYPES).describe("The outcome group context type."),
2019
2068
  context_id: _zod.z.number().describe("The Canvas account ID or course ID for the context."),
2020
2069
  outcome_group_id: _zod.z.number().describe("The Canvas outcome group ID.")
2021
2070
  },
@@ -2063,12 +2112,17 @@ function outcomeTools(canvas) {
2063
2112
  include_hidden: _zod.z.boolean().optional().describe("Include hidden outcomes when Canvas supports it.")
2064
2113
  },
2065
2114
  annotations: { readOnlyHint: true, openWorldHint: true },
2066
- handler: async (params) => canvas.outcomes.getOutcomeResults(params.course_id, {
2067
- user_ids: params.user_ids,
2068
- outcome_ids: params.outcome_ids,
2069
- include_alignments: params.include_alignments,
2070
- include_hidden: params.include_hidden
2071
- })
2115
+ handler: async (params) => {
2116
+ const course_id = params.course_id;
2117
+ const response = await canvas.outcomes.getOutcomeResults(course_id, {
2118
+ user_ids: params.user_ids,
2119
+ outcome_ids: params.outcome_ids,
2120
+ include_alignments: params.include_alignments,
2121
+ include_hidden: params.include_hidden
2122
+ });
2123
+ if (!_optionalChain([pseudonymizer, 'optionalAccess', _22 => _22.isEnabled, 'call', _23 => _23()])) return response;
2124
+ return pseudonymizer.anonymizeOutcomeResults(course_id, response);
2125
+ }
2072
2126
  },
2073
2127
  {
2074
2128
  name: "get_outcome_rollups",
@@ -2076,29 +2130,34 @@ function outcomeTools(canvas) {
2076
2130
  inputSchema: {
2077
2131
  course_id: _zod.z.number().describe("The Canvas course ID."),
2078
2132
  aggregate: _zod.z.enum(["course"]).optional().describe("Aggregate all student rollups into a single course-level rollup."),
2079
- aggregate_stat: _zod.z.enum(_chunkGS52LL5Ucjs.OUTCOME_ROLLUP_AGGREGATE_STATS).optional().describe('Statistic to use when aggregate="course".'),
2133
+ aggregate_stat: _zod.z.enum(_chunkLTBTS6YAcjs.OUTCOME_ROLLUP_AGGREGATE_STATS).optional().describe('Statistic to use when aggregate="course".'),
2080
2134
  user_ids: _zod.z.array(_zod.z.union([_zod.z.number(), _zod.z.string()])).optional().describe('Optional Canvas user IDs or SIS user IDs prefixed with "sis_user_id:".'),
2081
2135
  outcome_ids: _zod.z.array(_zod.z.number()).optional().describe("Optional outcome IDs to restrict the rollups."),
2082
2136
  include_courses: _zod.z.boolean().optional().describe("Include linked course details in the response payload."),
2083
- exclude: _zod.z.array(_zod.z.enum(_chunkGS52LL5Ucjs.OUTCOME_EXCLUDE_OPTIONS)).optional().describe("Optional rollup exclusions for missing users or missing outcome results."),
2084
- sort_by: _zod.z.enum(_chunkGS52LL5Ucjs.OUTCOME_ROLLUP_SORT_BY).optional().describe("Sort rollups by student name or by a specific outcome score."),
2137
+ exclude: _zod.z.array(_zod.z.enum(_chunkLTBTS6YAcjs.OUTCOME_EXCLUDE_OPTIONS)).optional().describe("Optional rollup exclusions for missing users or missing outcome results."),
2138
+ sort_by: _zod.z.enum(_chunkLTBTS6YAcjs.OUTCOME_ROLLUP_SORT_BY).optional().describe("Sort rollups by student name or by a specific outcome score."),
2085
2139
  sort_outcome_id: _zod.z.number().optional().describe('Outcome ID to sort by when sort_by="outcome".'),
2086
- sort_order: _zod.z.enum(_chunkGS52LL5Ucjs.OUTCOME_SORT_ORDER).optional().describe("Sort order to apply when sorting rollups."),
2140
+ sort_order: _zod.z.enum(_chunkLTBTS6YAcjs.OUTCOME_SORT_ORDER).optional().describe("Sort order to apply when sorting rollups."),
2087
2141
  add_defaults: _zod.z.boolean().optional().describe("Include default mastery colors and levels when Canvas supports it.")
2088
2142
  },
2089
2143
  annotations: { readOnlyHint: true, openWorldHint: true },
2090
- handler: async (params) => canvas.outcomes.getOutcomeRollups(params.course_id, {
2091
- aggregate: params.aggregate,
2092
- aggregate_stat: params.aggregate_stat,
2093
- user_ids: params.user_ids,
2094
- outcome_ids: params.outcome_ids,
2095
- include_courses: params.include_courses,
2096
- exclude: params.exclude,
2097
- sort_by: params.sort_by,
2098
- sort_outcome_id: params.sort_outcome_id,
2099
- sort_order: params.sort_order,
2100
- add_defaults: params.add_defaults
2101
- })
2144
+ handler: async (params) => {
2145
+ const course_id = params.course_id;
2146
+ const response = await canvas.outcomes.getOutcomeRollups(course_id, {
2147
+ aggregate: params.aggregate,
2148
+ aggregate_stat: params.aggregate_stat,
2149
+ user_ids: params.user_ids,
2150
+ outcome_ids: params.outcome_ids,
2151
+ include_courses: params.include_courses,
2152
+ exclude: params.exclude,
2153
+ sort_by: params.sort_by,
2154
+ sort_outcome_id: params.sort_outcome_id,
2155
+ sort_order: params.sort_order,
2156
+ add_defaults: params.add_defaults
2157
+ });
2158
+ if (!_optionalChain([pseudonymizer, 'optionalAccess', _24 => _24.isEnabled, 'call', _25 => _25()])) return response;
2159
+ return pseudonymizer.anonymizeOutcomeResults(course_id, response);
2160
+ }
2102
2161
  },
2103
2162
  {
2104
2163
  name: "get_outcome_contributing_scores",
@@ -2126,7 +2185,7 @@ function outcomeTools(canvas) {
2126
2185
  description: "Get mastery distribution analytics for outcomes in a course, optionally filtered by students or outcomes.",
2127
2186
  inputSchema: {
2128
2187
  course_id: _zod.z.number().describe("The Canvas course ID."),
2129
- exclude: _zod.z.array(_zod.z.enum(_chunkGS52LL5Ucjs.OUTCOME_EXCLUDE_OPTIONS)).optional().describe("Optional exclusions for missing users or missing outcome results."),
2188
+ exclude: _zod.z.array(_zod.z.enum(_chunkLTBTS6YAcjs.OUTCOME_EXCLUDE_OPTIONS)).optional().describe("Optional exclusions for missing users or missing outcome results."),
2130
2189
  outcome_ids: _zod.z.array(_zod.z.number()).optional().describe("Optional outcome IDs to restrict the distribution results."),
2131
2190
  student_ids: _zod.z.array(_zod.z.union([_zod.z.number(), _zod.z.string()])).optional().describe('Optional Canvas student IDs or SIS user IDs prefixed with "sis_user_id:".'),
2132
2191
  include_alignment_distributions: _zod.z.boolean().optional().describe("Include contributing score distributions for alignments."),
@@ -2898,7 +2957,7 @@ var SUBMISSION_GET_INCLUDE = [
2898
2957
  "read_status"
2899
2958
  ];
2900
2959
  var SUBMISSION_WORKFLOW_STATE = ["submitted", "unsubmitted", "graded", "pending_review"];
2901
- function submissionTools(canvas) {
2960
+ function submissionTools(canvas, pseudonymizer) {
2902
2961
  return [
2903
2962
  {
2904
2963
  name: "list_submissions",
@@ -2922,6 +2981,7 @@ function submissionTools(canvas) {
2922
2981
  openWorldHint: true
2923
2982
  },
2924
2983
  handler: async (params) => {
2984
+ const course_id = params.course_id;
2925
2985
  const opts = {};
2926
2986
  if (params.include !== void 0)
2927
2987
  opts.include = params.include;
@@ -2934,11 +2994,13 @@ function submissionTools(canvas) {
2934
2994
  opts.workflow_state = params.workflow_state;
2935
2995
  if (params.grading_period_id !== void 0)
2936
2996
  opts.grading_period_id = params.grading_period_id;
2937
- return canvas.submissions.list(
2938
- params.course_id,
2997
+ const submissions = await canvas.submissions.list(
2998
+ course_id,
2939
2999
  params.assignment_id,
2940
3000
  opts
2941
3001
  );
3002
+ if (!_optionalChain([pseudonymizer, 'optionalAccess', _26 => _26.isEnabled, 'call', _27 => _27()])) return submissions;
3003
+ return Promise.all(submissions.map((s) => pseudonymizer.anonymizeSubmission(course_id, s)));
2942
3004
  }
2943
3005
  },
2944
3006
  {
@@ -2957,15 +3019,18 @@ function submissionTools(canvas) {
2957
3019
  openWorldHint: true
2958
3020
  },
2959
3021
  handler: async (params) => {
3022
+ const course_id = params.course_id;
2960
3023
  const opts = {};
2961
3024
  if (params.include !== void 0)
2962
3025
  opts.include = params.include;
2963
- return canvas.submissions.get(
2964
- params.course_id,
3026
+ const submission = await canvas.submissions.get(
3027
+ course_id,
2965
3028
  params.assignment_id,
2966
3029
  params.user_id,
2967
3030
  opts
2968
3031
  );
3032
+ if (!_optionalChain([pseudonymizer, 'optionalAccess', _28 => _28.isEnabled, 'call', _29 => _29()])) return submission;
3033
+ return pseudonymizer.anonymizeSubmission(course_id, submission);
2969
3034
  }
2970
3035
  },
2971
3036
  {
@@ -3037,7 +3102,7 @@ var COURSE_USER_INCLUDE = [
3037
3102
  ];
3038
3103
  var USER_SORT = ["username", "email", "sis_id", "integration_id", "last_login"];
3039
3104
  var SEARCH_USER_INCLUDE = ["email", "last_login", "avatar_url", "time_zone", "uuid"];
3040
- function userTools(canvas) {
3105
+ function userTools(canvas, pseudonymizer) {
3041
3106
  return [
3042
3107
  {
3043
3108
  name: "list_students",
@@ -3051,7 +3116,9 @@ function userTools(canvas) {
3051
3116
  },
3052
3117
  handler: async (params) => {
3053
3118
  const course_id = params.course_id;
3054
- return canvas.users.listStudents(course_id);
3119
+ const users = await canvas.users.listStudents(course_id);
3120
+ if (!_optionalChain([pseudonymizer, 'optionalAccess', _30 => _30.isEnabled, 'call', _31 => _31()])) return users;
3121
+ return pseudonymizer.anonymizeUsers(course_id, users);
3055
3122
  }
3056
3123
  },
3057
3124
  {
@@ -3065,8 +3132,9 @@ function userTools(canvas) {
3065
3132
  openWorldHint: true
3066
3133
  },
3067
3134
  handler: async (params) => {
3068
- const user_id = params.user_id;
3069
- return canvas.users.get(user_id);
3135
+ const user = await canvas.users.get(params.user_id);
3136
+ if (!_optionalChain([pseudonymizer, 'optionalAccess', _32 => _32.isEnabled, 'call', _33 => _33()])) return user;
3137
+ return pseudonymizer.anonymizeUser("_global", user);
3070
3138
  }
3071
3139
  },
3072
3140
  {
@@ -3096,16 +3164,15 @@ function userTools(canvas) {
3096
3164
  openWorldHint: true
3097
3165
  },
3098
3166
  handler: async (params) => {
3167
+ const account_id = params.account_id;
3099
3168
  const opts = {};
3100
3169
  if (params.sort !== void 0) opts.sort = params.sort;
3101
3170
  if (params.order !== void 0) opts.order = params.order;
3102
3171
  if (params.include !== void 0)
3103
3172
  opts.include = params.include;
3104
- return canvas.users.searchUsers(
3105
- params.account_id,
3106
- params.search_term,
3107
- opts
3108
- );
3173
+ const users = await canvas.users.searchUsers(account_id, params.search_term, opts);
3174
+ if (!_optionalChain([pseudonymizer, 'optionalAccess', _34 => _34.isEnabled, 'call', _35 => _35()])) return users;
3175
+ return pseudonymizer.anonymizeUsers(String(account_id), users);
3109
3176
  }
3110
3177
  },
3111
3178
  {
@@ -3126,6 +3193,7 @@ function userTools(canvas) {
3126
3193
  openWorldHint: true
3127
3194
  },
3128
3195
  handler: async (params) => {
3196
+ const course_id = params.course_id;
3129
3197
  const opts = {};
3130
3198
  if (params.enrollment_type !== void 0)
3131
3199
  opts.enrollment_type = params.enrollment_type;
@@ -3138,7 +3206,9 @@ function userTools(canvas) {
3138
3206
  if (params.search_term !== void 0) opts.search_term = params.search_term;
3139
3207
  if (params.sort !== void 0) opts.sort = params.sort;
3140
3208
  if (params.order !== void 0) opts.order = params.order;
3141
- return canvas.users.listCourseUsers(params.course_id, opts);
3209
+ const users = await canvas.users.listCourseUsers(course_id, opts);
3210
+ if (!_optionalChain([pseudonymizer, 'optionalAccess', _36 => _36.isEnabled, 'call', _37 => _37()])) return users;
3211
+ return pseudonymizer.anonymizeUsers(course_id, users);
3142
3212
  }
3143
3213
  }
3144
3214
  ];
@@ -3304,7 +3374,9 @@ function pseudonymTools(pseudonymizer) {
3304
3374
  // src/tools/index.ts
3305
3375
  var PSEUDONYM_META_NOTE = "Student names and contact info in this response have been replaced with stable pseudonyms (CANVAS_PSEUDONYMIZE_STUDENTS=true). Real names are not available to this tool.";
3306
3376
  function getAllTools(canvas, pseudonymizer) {
3307
- const domainTools = toolDomainCatalog.flatMap((registration) => registration.getTools(canvas));
3377
+ const domainTools = toolDomainCatalog.flatMap(
3378
+ (registration) => registration.getTools(canvas, pseudonymizer)
3379
+ );
3308
3380
  const conditional = pseudonymizer ? pseudonymTools(pseudonymizer) : [];
3309
3381
  return [...domainTools, ...conditional];
3310
3382
  }
@@ -3318,12 +3390,12 @@ function registerAllTools(server, canvas, pseudonymizer) {
3318
3390
  const response = {
3319
3391
  content: [{ type: "text", text }]
3320
3392
  };
3321
- if (_optionalChain([pseudonymizer, 'optionalAccess', _6 => _6.isEnabled, 'call', _7 => _7()])) {
3393
+ if (_optionalChain([pseudonymizer, 'optionalAccess', _38 => _38.isEnabled, 'call', _39 => _39()])) {
3322
3394
  response._meta = { pseudonymized: true, note: PSEUDONYM_META_NOTE };
3323
3395
  }
3324
3396
  return response;
3325
3397
  } catch (error) {
3326
- if (error instanceof _chunkEPBWT2FMcjs.CanvasApiError) {
3398
+ if (error instanceof _chunkEXAIZYJYcjs.CanvasApiError) {
3327
3399
  } else {
3328
3400
  console.error(`Unexpected error in tool "${tool.name}":`, error);
3329
3401
  }
@@ -3371,7 +3443,7 @@ function registerSyllabusResource(server, canvas) {
3371
3443
  ]
3372
3444
  };
3373
3445
  } catch (error) {
3374
- if (!(error instanceof _chunkEPBWT2FMcjs.CanvasApiError)) {
3446
+ if (!(error instanceof _chunkEXAIZYJYcjs.CanvasApiError)) {
3375
3447
  console.error("Unexpected error in syllabus resource:", error);
3376
3448
  }
3377
3449
  return {
@@ -3420,7 +3492,7 @@ function registerAssignmentDescriptionResource(server, canvas) {
3420
3492
  ]
3421
3493
  };
3422
3494
  } catch (error) {
3423
- if (!(error instanceof _chunkEPBWT2FMcjs.CanvasApiError)) {
3495
+ if (!(error instanceof _chunkEXAIZYJYcjs.CanvasApiError)) {
3424
3496
  console.error("Unexpected error in assignment-description resource:", error);
3425
3497
  }
3426
3498
  return {
@@ -3439,14 +3511,14 @@ function registerAllResources(server, canvas) {
3439
3511
 
3440
3512
  // src/server.ts
3441
3513
  function createCanvasMCPServer(config) {
3442
- const canvas = new (0, _chunkGS52LL5Ucjs.CanvasClient)({
3514
+ const canvas = new (0, _chunkLTBTS6YAcjs.CanvasClient)({
3443
3515
  token: config.token,
3444
3516
  baseUrl: config.baseUrl
3445
3517
  });
3446
3518
  const pseudonymizer = _nullishCoalesce(config.pseudonymizer, () => ( new Pseudonymizer({ baseUrl: config.baseUrl })));
3447
3519
  const server = new (0, _mcpjs.McpServer)({
3448
3520
  name: "canvas-lms-mcp",
3449
- version: _chunkEPBWT2FMcjs.version
3521
+ version: _chunkEXAIZYJYcjs.version
3450
3522
  });
3451
3523
  registerAllTools(server, canvas, pseudonymizer);
3452
3524
  registerAllResources(server, canvas);
@@ -3457,4 +3529,4 @@ function createCanvasMCPServer(config) {
3457
3529
 
3458
3530
 
3459
3531
  exports.Pseudonymizer = Pseudonymizer; exports.createCanvasMCPServer = createCanvasMCPServer;
3460
- //# sourceMappingURL=chunk-C55DPF4U.cjs.map
3532
+ //# sourceMappingURL=chunk-CDWLOZQ2.cjs.map