canvas-lms-mcp 1.2.2 → 1.3.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/README.md CHANGED
@@ -10,7 +10,7 @@
10
10
 
11
11
  MCP server for [Canvas LMS](https://www.instructure.com/canvas). Read courses, assignments, submissions, rubrics, quizzes; grade, comment, manage course content, and handle Canvas admin workflows from any AI agent.
12
12
 
13
- 88 tools across Canvas courses, assignments, submissions, rubrics, quizzes, files, users, groups, enrollments, discussions, modules, pages, calendar, conversations, peer reviews, accounts, analytics, student workflows, dashboard, and health checks. Three deployment modes: stdio, HTTP, and library import.
13
+ 100 tools across Canvas courses, assignments, submissions, rubrics, quizzes, 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.
14
14
 
15
15
  ## Comparison
16
16
 
@@ -173,7 +173,7 @@ Once configured, try these prompts with your AI client:
173
173
 
174
174
  ## Tool Inventory
175
175
 
176
- ### All Registered Tools (88)
176
+ ### All Registered Tools (100)
177
177
 
178
178
  | Category | Tools |
179
179
  |----------|-------|
@@ -195,10 +195,11 @@ Once configured, try these prompts with your AI client:
195
195
  | Peer Reviews | `list_peer_reviews`, `get_submission_peer_reviews`, `create_peer_review`, `delete_peer_review` |
196
196
  | Accounts | `get_account`, `list_accounts`, `list_sub_accounts`, `list_account_courses`, `list_account_users`, `get_account_reports` |
197
197
  | Analytics | `search_course_content`, `get_course_analytics`, `get_student_analytics`, `get_course_activity_stream` |
198
+ | Outcomes | `get_root_outcome_group`, `list_outcome_groups`, `list_outcome_group_links`, `get_outcome_group`, `list_outcome_group_outcomes`, `list_outcome_group_subgroups`, `get_outcome`, `get_outcome_alignments`, `get_outcome_results`, `get_outcome_rollups`, `get_outcome_contributing_scores`, `get_outcome_mastery_distribution` |
198
199
  | Student | `get_my_courses`, `get_my_grades`, `get_my_submissions`, `get_my_upcoming_assignments` |
199
200
  | Dashboard | `get_dashboard_cards`, `get_todo_items`, `get_upcoming_events`, `get_missing_submissions` |
200
201
 
201
- 60 tools are read-only and 28 tools perform Canvas write operations.
202
+ 72 tools are read-only and 28 tools perform Canvas write operations.
202
203
 
203
204
  All write tools require appropriate Canvas permissions. Canvas enforces its own permission model -- the MCP server does not bypass it.
204
205
 
@@ -2,10 +2,10 @@
2
2
 
3
3
 
4
4
 
5
- var _chunk4P7LR66Vcjs = require('../chunk-4P7LR66V.cjs');
5
+ var _chunkXAOI3FO6cjs = require('../chunk-XAOI3FO6.cjs');
6
6
 
7
7
 
8
8
 
9
9
 
10
- exports.CanvasApiError = _chunk4P7LR66Vcjs.CanvasApiError; exports.CanvasClient = _chunk4P7LR66Vcjs.CanvasClient; exports.CanvasHttpClient = _chunk4P7LR66Vcjs.CanvasHttpClient;
10
+ exports.CanvasApiError = _chunkXAOI3FO6cjs.CanvasApiError; exports.CanvasClient = _chunkXAOI3FO6cjs.CanvasClient; exports.CanvasHttpClient = _chunkXAOI3FO6cjs.CanvasHttpClient;
11
11
  //# sourceMappingURL=index.cjs.map
@@ -2,7 +2,7 @@ import {
2
2
  CanvasApiError,
3
3
  CanvasClient,
4
4
  CanvasHttpClient
5
- } from "../chunk-H4CEPP26.js";
5
+ } from "../chunk-XP3FFZQV.js";
6
6
  export {
7
7
  CanvasApiError,
8
8
  CanvasClient,
@@ -2,14 +2,20 @@
2
2
 
3
3
 
4
4
 
5
- var _chunk4P7LR66Vcjs = require('./chunk-4P7LR66V.cjs');
5
+
6
+
7
+
8
+
9
+
10
+
11
+ var _chunkXAOI3FO6cjs = require('./chunk-XAOI3FO6.cjs');
6
12
 
7
13
  // src/server.ts
8
14
  var _mcpjs = require('@modelcontextprotocol/sdk/server/mcp.js');
9
15
 
10
16
  // src/tools/errors.ts
11
17
  function formatError(error) {
12
- if (error instanceof _chunk4P7LR66Vcjs.CanvasApiError) {
18
+ if (error instanceof _chunkXAOI3FO6cjs.CanvasApiError) {
13
19
  const status = error.status;
14
20
  const message = error.message;
15
21
  switch (status) {
@@ -1580,7 +1586,7 @@ function analyticsTools(canvas) {
1580
1586
  inputSchema: {
1581
1587
  course_id: _zod.z.number().describe("The Canvas course ID"),
1582
1588
  search_term: _zod.z.string().describe("The keyword or phrase to search for"),
1583
- content_types: _zod.z.array(_zod.z.enum(_chunk4P7LR66Vcjs.SEARCH_CONTENT_TYPES)).optional().describe(
1589
+ content_types: _zod.z.array(_zod.z.enum(_chunkXAOI3FO6cjs.SEARCH_CONTENT_TYPES)).optional().describe(
1584
1590
  "Content types to search. Defaults to all types: pages, discussions, assignments, announcements."
1585
1591
  )
1586
1592
  },
@@ -1592,7 +1598,7 @@ function analyticsTools(canvas) {
1592
1598
  const courseId = params.course_id;
1593
1599
  const searchTerm = params.search_term;
1594
1600
  const types = _nullishCoalesce(params.content_types, () => ( [
1595
- ..._chunk4P7LR66Vcjs.SEARCH_CONTENT_TYPES
1601
+ ..._chunkXAOI3FO6cjs.SEARCH_CONTENT_TYPES
1596
1602
  ]));
1597
1603
  if (types.length === 0) return { results: [] };
1598
1604
  const settled = await Promise.allSettled(
@@ -1780,6 +1786,228 @@ function dashboardTools(canvas) {
1780
1786
  ];
1781
1787
  }
1782
1788
 
1789
+ // src/tools/outcomes.ts
1790
+
1791
+ function outcomeTools(canvas) {
1792
+ return [
1793
+ {
1794
+ name: "get_root_outcome_group",
1795
+ description: "Get the root outcome group for an account or course context.",
1796
+ inputSchema: {
1797
+ context_type: _zod.z.enum(_chunkXAOI3FO6cjs.OUTCOME_CONTEXT_TYPES).describe("Whether to read outcomes from an account or course context."),
1798
+ context_id: _zod.z.number().describe("The Canvas account ID or course ID for the context.")
1799
+ },
1800
+ annotations: { readOnlyHint: true, openWorldHint: true },
1801
+ handler: async (params) => canvas.outcomes.getRootOutcomeGroup(
1802
+ params.context_type,
1803
+ params.context_id
1804
+ )
1805
+ },
1806
+ {
1807
+ name: "list_outcome_groups",
1808
+ description: "List all outcome groups for an account or course context.",
1809
+ inputSchema: {
1810
+ context_type: _zod.z.enum(_chunkXAOI3FO6cjs.OUTCOME_CONTEXT_TYPES).describe("Whether to read outcome groups from an account or course context."),
1811
+ context_id: _zod.z.number().describe("The Canvas account ID or course ID for the context.")
1812
+ },
1813
+ annotations: { readOnlyHint: true, openWorldHint: true },
1814
+ handler: async (params) => canvas.outcomes.listOutcomeGroups(
1815
+ params.context_type,
1816
+ params.context_id
1817
+ )
1818
+ },
1819
+ {
1820
+ name: "list_outcome_group_links",
1821
+ description: "List all outcome links in an account or course context.",
1822
+ inputSchema: {
1823
+ context_type: _zod.z.enum(_chunkXAOI3FO6cjs.OUTCOME_CONTEXT_TYPES).describe("Whether to read outcome links from an account or course context."),
1824
+ context_id: _zod.z.number().describe("The Canvas account ID or course ID for the context."),
1825
+ outcome_style: _zod.z.enum(_chunkXAOI3FO6cjs.OUTCOME_DETAIL_LEVELS).optional().describe('Outcome detail level. Use "full" to include expanded outcome fields.'),
1826
+ outcome_group_style: _zod.z.enum(_chunkXAOI3FO6cjs.OUTCOME_DETAIL_LEVELS).optional().describe(
1827
+ 'Outcome group detail level. Use "full" to include expanded outcome group fields.'
1828
+ )
1829
+ },
1830
+ annotations: { readOnlyHint: true, openWorldHint: true },
1831
+ handler: async (params) => canvas.outcomes.listOutcomeGroupLinks(
1832
+ params.context_type,
1833
+ params.context_id,
1834
+ {
1835
+ outcome_style: params.outcome_style,
1836
+ outcome_group_style: params.outcome_group_style
1837
+ }
1838
+ )
1839
+ },
1840
+ {
1841
+ name: "get_outcome_group",
1842
+ description: "Get details for a specific outcome group in an account or course context.",
1843
+ inputSchema: {
1844
+ context_type: _zod.z.enum(_chunkXAOI3FO6cjs.OUTCOME_CONTEXT_TYPES).describe("The outcome group context type."),
1845
+ context_id: _zod.z.number().describe("The Canvas account ID or course ID for the context."),
1846
+ outcome_group_id: _zod.z.number().describe("The Canvas outcome group ID.")
1847
+ },
1848
+ annotations: { readOnlyHint: true, openWorldHint: true },
1849
+ handler: async (params) => canvas.outcomes.getOutcomeGroup(
1850
+ params.context_type,
1851
+ params.context_id,
1852
+ params.outcome_group_id
1853
+ )
1854
+ },
1855
+ {
1856
+ name: "list_outcome_group_outcomes",
1857
+ description: "List the linked outcomes directly under a specific outcome group.",
1858
+ inputSchema: {
1859
+ context_type: _zod.z.enum(_chunkXAOI3FO6cjs.OUTCOME_CONTEXT_TYPES).describe("The outcome group context type."),
1860
+ context_id: _zod.z.number().describe("The Canvas account ID or course ID for the context."),
1861
+ outcome_group_id: _zod.z.number().describe("The Canvas outcome group ID."),
1862
+ outcome_style: _zod.z.enum(_chunkXAOI3FO6cjs.OUTCOME_DETAIL_LEVELS).optional().describe('Outcome detail level. Use "full" to include expanded outcome fields.')
1863
+ },
1864
+ annotations: { readOnlyHint: true, openWorldHint: true },
1865
+ handler: async (params) => canvas.outcomes.listGroupOutcomes(
1866
+ params.context_type,
1867
+ params.context_id,
1868
+ params.outcome_group_id,
1869
+ {
1870
+ outcome_style: params.outcome_style
1871
+ }
1872
+ )
1873
+ },
1874
+ {
1875
+ name: "list_outcome_group_subgroups",
1876
+ description: "List the immediate child outcome groups under a specific outcome group.",
1877
+ inputSchema: {
1878
+ context_type: _zod.z.enum(_chunkXAOI3FO6cjs.OUTCOME_CONTEXT_TYPES).describe("The outcome group context type."),
1879
+ context_id: _zod.z.number().describe("The Canvas account ID or course ID for the context."),
1880
+ outcome_group_id: _zod.z.number().describe("The Canvas outcome group ID.")
1881
+ },
1882
+ annotations: { readOnlyHint: true, openWorldHint: true },
1883
+ handler: async (params) => canvas.outcomes.listGroupSubgroups(
1884
+ params.context_type,
1885
+ params.context_id,
1886
+ params.outcome_group_id
1887
+ )
1888
+ },
1889
+ {
1890
+ name: "get_outcome",
1891
+ description: "Get the full details for a specific learning outcome by ID.",
1892
+ inputSchema: {
1893
+ outcome_id: _zod.z.number().describe("The Canvas outcome ID."),
1894
+ add_defaults: _zod.z.boolean().optional().describe("Include default mastery colors and levels when Canvas supports it.")
1895
+ },
1896
+ annotations: { readOnlyHint: true, openWorldHint: true },
1897
+ handler: async (params) => canvas.outcomes.getOutcome(params.outcome_id, {
1898
+ add_defaults: params.add_defaults
1899
+ })
1900
+ },
1901
+ {
1902
+ name: "get_outcome_alignments",
1903
+ description: "Get outcome alignments for a course, optionally filtered to a specific student or assignment.",
1904
+ inputSchema: {
1905
+ course_id: _zod.z.number().describe("The Canvas course ID."),
1906
+ student_id: _zod.z.number().optional().describe("Optional Canvas user ID of the student to filter alignments by."),
1907
+ assignment_id: _zod.z.number().optional().describe("Optional Canvas assignment ID to filter alignments by.")
1908
+ },
1909
+ annotations: { readOnlyHint: true, openWorldHint: true },
1910
+ handler: async (params) => canvas.outcomes.getOutcomeAlignments(params.course_id, {
1911
+ student_id: params.student_id,
1912
+ assignment_id: params.assignment_id
1913
+ })
1914
+ },
1915
+ {
1916
+ name: "get_outcome_results",
1917
+ description: "Get per-student outcome results for a course, with optional outcome, student, and alignment filters.",
1918
+ inputSchema: {
1919
+ course_id: _zod.z.number().describe("The Canvas course ID."),
1920
+ 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:".'),
1921
+ outcome_ids: _zod.z.array(_zod.z.number()).optional().describe("Optional outcome IDs to restrict the results."),
1922
+ include_alignments: _zod.z.boolean().optional().describe("Include linked alignment details in the response."),
1923
+ include_hidden: _zod.z.boolean().optional().describe("Include hidden outcomes when Canvas supports it.")
1924
+ },
1925
+ annotations: { readOnlyHint: true, openWorldHint: true },
1926
+ handler: async (params) => canvas.outcomes.getOutcomeResults(params.course_id, {
1927
+ user_ids: params.user_ids,
1928
+ outcome_ids: params.outcome_ids,
1929
+ include_alignments: params.include_alignments,
1930
+ include_hidden: params.include_hidden
1931
+ })
1932
+ },
1933
+ {
1934
+ name: "get_outcome_rollups",
1935
+ description: "Get outcome rollups for a course, optionally aggregated or filtered by students, outcomes, and sort options.",
1936
+ inputSchema: {
1937
+ course_id: _zod.z.number().describe("The Canvas course ID."),
1938
+ aggregate: _zod.z.enum(["course"]).optional().describe("Aggregate all student rollups into a single course-level rollup."),
1939
+ aggregate_stat: _zod.z.enum(_chunkXAOI3FO6cjs.OUTCOME_ROLLUP_AGGREGATE_STATS).optional().describe('Statistic to use when aggregate="course".'),
1940
+ 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:".'),
1941
+ outcome_ids: _zod.z.array(_zod.z.number()).optional().describe("Optional outcome IDs to restrict the rollups."),
1942
+ include_courses: _zod.z.boolean().optional().describe("Include linked course details in the response payload."),
1943
+ exclude: _zod.z.array(_zod.z.enum(_chunkXAOI3FO6cjs.OUTCOME_EXCLUDE_OPTIONS)).optional().describe("Optional rollup exclusions for missing users or missing outcome results."),
1944
+ sort_by: _zod.z.enum(_chunkXAOI3FO6cjs.OUTCOME_ROLLUP_SORT_BY).optional().describe("Sort rollups by student name or by a specific outcome score."),
1945
+ sort_outcome_id: _zod.z.number().optional().describe('Outcome ID to sort by when sort_by="outcome".'),
1946
+ sort_order: _zod.z.enum(_chunkXAOI3FO6cjs.OUTCOME_SORT_ORDER).optional().describe("Sort order to apply when sorting rollups."),
1947
+ add_defaults: _zod.z.boolean().optional().describe("Include default mastery colors and levels when Canvas supports it.")
1948
+ },
1949
+ annotations: { readOnlyHint: true, openWorldHint: true },
1950
+ handler: async (params) => canvas.outcomes.getOutcomeRollups(params.course_id, {
1951
+ aggregate: params.aggregate,
1952
+ aggregate_stat: params.aggregate_stat,
1953
+ user_ids: params.user_ids,
1954
+ outcome_ids: params.outcome_ids,
1955
+ include_courses: params.include_courses,
1956
+ exclude: params.exclude,
1957
+ sort_by: params.sort_by,
1958
+ sort_outcome_id: params.sort_outcome_id,
1959
+ sort_order: params.sort_order,
1960
+ add_defaults: params.add_defaults
1961
+ })
1962
+ },
1963
+ {
1964
+ name: "get_outcome_contributing_scores",
1965
+ description: "Get assignment or quiz scores that contributed to a specific outcome for one or more students in a course.",
1966
+ inputSchema: {
1967
+ course_id: _zod.z.number().describe("The Canvas course ID."),
1968
+ outcome_id: _zod.z.number().describe("The Canvas outcome ID."),
1969
+ 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:".'),
1970
+ only_assignment_alignments: _zod.z.boolean().optional().describe("Limit results to assignment alignments only."),
1971
+ show_unpublished_assignments: _zod.z.boolean().optional().describe("Include unpublished assignments in the contributing score results.")
1972
+ },
1973
+ annotations: { readOnlyHint: true, openWorldHint: true },
1974
+ handler: async (params) => canvas.outcomes.getOutcomeContributingScores(
1975
+ params.course_id,
1976
+ params.outcome_id,
1977
+ {
1978
+ user_ids: params.user_ids,
1979
+ only_assignment_alignments: params.only_assignment_alignments,
1980
+ show_unpublished_assignments: params.show_unpublished_assignments
1981
+ }
1982
+ )
1983
+ },
1984
+ {
1985
+ name: "get_outcome_mastery_distribution",
1986
+ description: "Get mastery distribution analytics for outcomes in a course, optionally filtered by students or outcomes.",
1987
+ inputSchema: {
1988
+ course_id: _zod.z.number().describe("The Canvas course ID."),
1989
+ exclude: _zod.z.array(_zod.z.enum(_chunkXAOI3FO6cjs.OUTCOME_EXCLUDE_OPTIONS)).optional().describe("Optional exclusions for missing users or missing outcome results."),
1990
+ outcome_ids: _zod.z.array(_zod.z.number()).optional().describe("Optional outcome IDs to restrict the distribution results."),
1991
+ 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:".'),
1992
+ include_alignment_distributions: _zod.z.boolean().optional().describe("Include contributing score distributions for alignments."),
1993
+ only_assignment_alignments: _zod.z.boolean().optional().describe("When including alignment distributions, limit them to assignments only."),
1994
+ show_unpublished_assignments: _zod.z.boolean().optional().describe("Include unpublished assignments in alignment distributions."),
1995
+ add_defaults: _zod.z.boolean().optional().describe("Include default mastery colors and levels when Canvas supports it.")
1996
+ },
1997
+ annotations: { readOnlyHint: true, openWorldHint: true },
1998
+ handler: async (params) => canvas.outcomes.getOutcomeMasteryDistribution(params.course_id, {
1999
+ exclude: params.exclude,
2000
+ outcome_ids: params.outcome_ids,
2001
+ student_ids: params.student_ids,
2002
+ include_alignment_distributions: params.include_alignment_distributions,
2003
+ only_assignment_alignments: params.only_assignment_alignments,
2004
+ show_unpublished_assignments: params.show_unpublished_assignments,
2005
+ add_defaults: params.add_defaults
2006
+ })
2007
+ }
2008
+ ];
2009
+ }
2010
+
1783
2011
  // src/tools/index.ts
1784
2012
  function getAllTools(canvas) {
1785
2013
  return [
@@ -1801,6 +2029,7 @@ function getAllTools(canvas) {
1801
2029
  ...peerReviewTools(canvas),
1802
2030
  ...accountTools(canvas),
1803
2031
  ...analyticsTools(canvas),
2032
+ ...outcomeTools(canvas),
1804
2033
  ...studentTools(canvas),
1805
2034
  ...dashboardTools(canvas)
1806
2035
  ];
@@ -1816,7 +2045,7 @@ function registerAllTools(server, canvas) {
1816
2045
  content: [{ type: "text", text }]
1817
2046
  };
1818
2047
  } catch (error) {
1819
- if (error instanceof _chunk4P7LR66Vcjs.CanvasApiError) {
2048
+ if (error instanceof _chunkXAOI3FO6cjs.CanvasApiError) {
1820
2049
  } else {
1821
2050
  console.error(`Unexpected error in tool "${tool.name}":`, error);
1822
2051
  }
@@ -1864,7 +2093,7 @@ function registerSyllabusResource(server, canvas) {
1864
2093
  ]
1865
2094
  };
1866
2095
  } catch (error) {
1867
- if (!(error instanceof _chunk4P7LR66Vcjs.CanvasApiError)) {
2096
+ if (!(error instanceof _chunkXAOI3FO6cjs.CanvasApiError)) {
1868
2097
  console.error("Unexpected error in syllabus resource:", error);
1869
2098
  }
1870
2099
  return {
@@ -1913,7 +2142,7 @@ function registerAssignmentDescriptionResource(server, canvas) {
1913
2142
  ]
1914
2143
  };
1915
2144
  } catch (error) {
1916
- if (!(error instanceof _chunk4P7LR66Vcjs.CanvasApiError)) {
2145
+ if (!(error instanceof _chunkXAOI3FO6cjs.CanvasApiError)) {
1917
2146
  console.error("Unexpected error in assignment-description resource:", error);
1918
2147
  }
1919
2148
  return {
@@ -1932,7 +2161,7 @@ function registerAllResources(server, canvas) {
1932
2161
 
1933
2162
  // src/server.ts
1934
2163
  function createCanvasMCPServer(config) {
1935
- const canvas = new (0, _chunk4P7LR66Vcjs.CanvasClient)({
2164
+ const canvas = new (0, _chunkXAOI3FO6cjs.CanvasClient)({
1936
2165
  token: config.token,
1937
2166
  baseUrl: config.baseUrl
1938
2167
  });
@@ -1948,4 +2177,4 @@ function createCanvasMCPServer(config) {
1948
2177
 
1949
2178
 
1950
2179
  exports.createCanvasMCPServer = createCanvasMCPServer;
1951
- //# sourceMappingURL=chunk-VOQ5A7CA.cjs.map
2180
+ //# sourceMappingURL=chunk-VDHNHHYO.cjs.map