@charlie.act7/canvas-mcp-server 1.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/README.md +117 -0
- package/dist/common/config-manager.js +28 -0
- package/dist/common/helpers.js +46 -0
- package/dist/common/tool-model.js +1 -0
- package/dist/common/types.js +1 -0
- package/dist/http-server.js +760 -0
- package/dist/index.js +168 -0
- package/dist/prompts/canvas-prompts.js +64 -0
- package/dist/resources/canvas-resources.js +55 -0
- package/dist/services/canvas-client.js +459 -0
- package/dist/tools/assignment-tools.js +626 -0
- package/dist/tools/calendar-tools.js +240 -0
- package/dist/tools/communication-tools.js +130 -0
- package/dist/tools/config-tools.js +39 -0
- package/dist/tools/course-tools.js +123 -0
- package/dist/tools/create-tools.js +76 -0
- package/dist/tools/file-tools.js +229 -0
- package/dist/tools/grading-tools.js +187 -0
- package/dist/tools/group-tools.js +192 -0
- package/dist/tools/module-tools.js +269 -0
- package/dist/tools/question-bank-tools.js +238 -0
- package/dist/tools/quiz-question-tools.js +303 -0
- package/dist/tools/quiz-tools.js +184 -0
- package/dist/tools/rubric-tools.js +145 -0
- package/dist/tools/student-tools.js +172 -0
- package/package.json +65 -0
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export const calendarTools = [
|
|
3
|
+
{
|
|
4
|
+
name: "canvas_list_appointment_groups",
|
|
5
|
+
tool: {
|
|
6
|
+
name: "canvas_list_appointment_groups",
|
|
7
|
+
description: "List appointment groups",
|
|
8
|
+
inputSchema: {
|
|
9
|
+
type: "object",
|
|
10
|
+
properties: {
|
|
11
|
+
scope: { type: "string", enum: ["all", "manageable"], description: "Scope of appointment groups to list" },
|
|
12
|
+
include: { type: "array", items: { type: "string" }, description: "Additional associations to include" }
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
handler: async (client, args) => {
|
|
17
|
+
const input = z.object({
|
|
18
|
+
scope: z.enum(["all", "manageable"]).optional().default("all"),
|
|
19
|
+
include: z.array(z.string()).optional()
|
|
20
|
+
}).parse(args);
|
|
21
|
+
const groups = await client.listAppointmentGroups(input.scope, input.include);
|
|
22
|
+
return {
|
|
23
|
+
content: [{ type: "text", text: JSON.stringify(groups, null, 2) }],
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
name: "canvas_get_appointment_group",
|
|
29
|
+
tool: {
|
|
30
|
+
name: "canvas_get_appointment_group",
|
|
31
|
+
description: "Get a single appointment group by ID",
|
|
32
|
+
inputSchema: {
|
|
33
|
+
type: "object",
|
|
34
|
+
properties: {
|
|
35
|
+
id: { type: "number", description: "The ID of the appointment group" },
|
|
36
|
+
include: { type: "array", items: { type: "string" }, description: "Additional associations to include" }
|
|
37
|
+
},
|
|
38
|
+
required: ["id"],
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
handler: async (client, args) => {
|
|
42
|
+
const input = z.object({
|
|
43
|
+
id: z.coerce.number(),
|
|
44
|
+
include: z.array(z.string()).optional()
|
|
45
|
+
}).parse(args);
|
|
46
|
+
const group = await client.getAppointmentGroup(input.id, input.include);
|
|
47
|
+
return {
|
|
48
|
+
content: [{ type: "text", text: JSON.stringify(group, null, 2) }],
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: "canvas_create_appointment_group",
|
|
54
|
+
tool: {
|
|
55
|
+
name: "canvas_create_appointment_group",
|
|
56
|
+
description: "Create a new appointment group",
|
|
57
|
+
inputSchema: {
|
|
58
|
+
type: "object",
|
|
59
|
+
properties: {
|
|
60
|
+
context_codes: { type: "array", items: { type: "string" }, description: "Array of context codes (e.g. course_123)" },
|
|
61
|
+
title: { type: "string", description: "Title of the appointment group" },
|
|
62
|
+
description: { type: "string", description: "Description of the appointment group" },
|
|
63
|
+
location_name: { type: "string", description: "Name of the location" },
|
|
64
|
+
location_address: { type: "string", description: "Address of the location" },
|
|
65
|
+
publish: { type: "boolean", description: "Whether to publish the group immediately" },
|
|
66
|
+
participants_per_appointment: { type: "number", description: "Max participants per slot" },
|
|
67
|
+
min_appointments_per_participant: { type: "number", description: "Min slots per participant" },
|
|
68
|
+
max_appointments_per_participant: { type: "number", description: "Max slots per participant" },
|
|
69
|
+
new_appointments: {
|
|
70
|
+
type: "array",
|
|
71
|
+
items: {
|
|
72
|
+
type: "array",
|
|
73
|
+
items: { type: "string" },
|
|
74
|
+
minItems: 2,
|
|
75
|
+
maxItems: 2,
|
|
76
|
+
description: "[start_time, end_time] pair"
|
|
77
|
+
},
|
|
78
|
+
description: "Nested array of start/end time pairs"
|
|
79
|
+
},
|
|
80
|
+
participant_visibility: { type: "string", enum: ["private", "protected"] }
|
|
81
|
+
},
|
|
82
|
+
required: ["context_codes", "title"],
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
handler: async (client, args) => {
|
|
86
|
+
const input = z.object({
|
|
87
|
+
context_codes: z.array(z.string()),
|
|
88
|
+
title: z.string(),
|
|
89
|
+
description: z.string().optional(),
|
|
90
|
+
location_name: z.string().optional(),
|
|
91
|
+
location_address: z.string().optional(),
|
|
92
|
+
publish: z.boolean().optional(),
|
|
93
|
+
participants_per_appointment: z.number().optional(),
|
|
94
|
+
min_appointments_per_participant: z.number().optional(),
|
|
95
|
+
max_appointments_per_participant: z.number().optional(),
|
|
96
|
+
new_appointments: z.array(z.tuple([z.string(), z.string()])).optional(),
|
|
97
|
+
participant_visibility: z.enum(["private", "protected"]).optional()
|
|
98
|
+
}).parse(args);
|
|
99
|
+
const group = await client.createAppointmentGroup(input);
|
|
100
|
+
return {
|
|
101
|
+
content: [{ type: "text", text: JSON.stringify(group, null, 2) }],
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
name: "canvas_update_appointment_group",
|
|
107
|
+
tool: {
|
|
108
|
+
name: "canvas_update_appointment_group",
|
|
109
|
+
description: "Update an existing appointment group",
|
|
110
|
+
inputSchema: {
|
|
111
|
+
type: "object",
|
|
112
|
+
properties: {
|
|
113
|
+
id: { type: "number", description: "The ID of the appointment group" },
|
|
114
|
+
context_codes: { type: "array", items: { type: "string" }, description: "Array of context codes" },
|
|
115
|
+
title: { type: "string", description: "Title of the appointment group" },
|
|
116
|
+
description: { type: "string", description: "Description of the appointment group" },
|
|
117
|
+
location_name: { type: "string", description: "Name of the location" },
|
|
118
|
+
location_address: { type: "string", description: "Address of the location" },
|
|
119
|
+
publish: { type: "boolean", description: "Whether to publish the group" },
|
|
120
|
+
participants_per_appointment: { type: "number", description: "Max participants per slot" },
|
|
121
|
+
min_appointments_per_participant: { type: "number", description: "Min slots per participant" },
|
|
122
|
+
max_appointments_per_participant: { type: "number", description: "Max slots per participant" },
|
|
123
|
+
new_appointments: {
|
|
124
|
+
type: "array",
|
|
125
|
+
items: {
|
|
126
|
+
type: "array",
|
|
127
|
+
items: { type: "string" },
|
|
128
|
+
minItems: 2,
|
|
129
|
+
maxItems: 2
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
participant_visibility: { type: "string", enum: ["private", "protected"] }
|
|
133
|
+
},
|
|
134
|
+
required: ["id"],
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
handler: async (client, args) => {
|
|
138
|
+
const input = z.object({
|
|
139
|
+
id: z.coerce.number(),
|
|
140
|
+
context_codes: z.array(z.string()).optional(),
|
|
141
|
+
title: z.string().optional(),
|
|
142
|
+
description: z.string().optional(),
|
|
143
|
+
location_name: z.string().optional(),
|
|
144
|
+
location_address: z.string().optional(),
|
|
145
|
+
publish: z.boolean().optional(),
|
|
146
|
+
participants_per_appointment: z.number().optional(),
|
|
147
|
+
min_appointments_per_participant: z.number().optional(),
|
|
148
|
+
max_appointments_per_participant: z.number().optional(),
|
|
149
|
+
new_appointments: z.array(z.tuple([z.string(), z.string()])).optional(),
|
|
150
|
+
participant_visibility: z.enum(["private", "protected"]).optional()
|
|
151
|
+
}).parse(args);
|
|
152
|
+
const { id, ...data } = input;
|
|
153
|
+
const group = await client.updateAppointmentGroup(id, data);
|
|
154
|
+
return {
|
|
155
|
+
content: [{ type: "text", text: JSON.stringify(group, null, 2) }],
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
name: "canvas_delete_appointment_group",
|
|
161
|
+
tool: {
|
|
162
|
+
name: "canvas_delete_appointment_group",
|
|
163
|
+
description: "Delete an appointment group",
|
|
164
|
+
inputSchema: {
|
|
165
|
+
type: "object",
|
|
166
|
+
properties: {
|
|
167
|
+
id: { type: "number", description: "The ID of the appointment group" },
|
|
168
|
+
cancel_reason: { type: "string", description: "Reason for canceling the appointment group" }
|
|
169
|
+
},
|
|
170
|
+
required: ["id"],
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
handler: async (client, args) => {
|
|
174
|
+
const input = z.object({
|
|
175
|
+
id: z.coerce.number(),
|
|
176
|
+
cancel_reason: z.string().optional()
|
|
177
|
+
}).parse(args);
|
|
178
|
+
const result = await client.deleteAppointmentGroup(input.id, input.cancel_reason);
|
|
179
|
+
return {
|
|
180
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
name: "canvas_list_appointment_group_users",
|
|
186
|
+
tool: {
|
|
187
|
+
name: "canvas_list_appointment_group_users",
|
|
188
|
+
description: "List users participating in an appointment group",
|
|
189
|
+
inputSchema: {
|
|
190
|
+
type: "object",
|
|
191
|
+
properties: {
|
|
192
|
+
id: { type: "number", description: "The ID of the appointment group" }
|
|
193
|
+
},
|
|
194
|
+
required: ["id"],
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
handler: async (client, args) => {
|
|
198
|
+
const input = z.object({ id: z.coerce.number() }).parse(args);
|
|
199
|
+
const users = await client.listAppointmentGroupUsers(input.id);
|
|
200
|
+
return {
|
|
201
|
+
content: [{ type: "text", text: JSON.stringify(users, null, 2) }],
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
name: "canvas_list_appointment_group_groups",
|
|
207
|
+
tool: {
|
|
208
|
+
name: "canvas_list_appointment_group_groups",
|
|
209
|
+
description: "List student groups participating in an appointment group",
|
|
210
|
+
inputSchema: {
|
|
211
|
+
type: "object",
|
|
212
|
+
properties: {
|
|
213
|
+
id: { type: "number", description: "The ID of the appointment group" }
|
|
214
|
+
},
|
|
215
|
+
required: ["id"],
|
|
216
|
+
},
|
|
217
|
+
},
|
|
218
|
+
handler: async (client, args) => {
|
|
219
|
+
const input = z.object({ id: z.coerce.number() }).parse(args);
|
|
220
|
+
const groups = await client.listAppointmentGroupGroups(input.id);
|
|
221
|
+
return {
|
|
222
|
+
content: [{ type: "text", text: JSON.stringify(groups, null, 2) }],
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
name: "canvas_get_next_appointment",
|
|
228
|
+
tool: {
|
|
229
|
+
name: "canvas_get_next_appointment",
|
|
230
|
+
description: "Get the next appointment group for the current user",
|
|
231
|
+
inputSchema: { type: "object", properties: {} },
|
|
232
|
+
},
|
|
233
|
+
handler: async (client) => {
|
|
234
|
+
const group = await client.getNextAppointment();
|
|
235
|
+
return {
|
|
236
|
+
content: [{ type: "text", text: JSON.stringify(group, null, 2) }],
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
];
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export const communicationTools = [
|
|
3
|
+
{
|
|
4
|
+
name: "canvas_list_announcements",
|
|
5
|
+
tool: {
|
|
6
|
+
name: "canvas_list_announcements",
|
|
7
|
+
description: "List announcements for one or more courses",
|
|
8
|
+
inputSchema: {
|
|
9
|
+
type: "object",
|
|
10
|
+
properties: {
|
|
11
|
+
course_ids: {
|
|
12
|
+
type: "array",
|
|
13
|
+
items: { type: "number" },
|
|
14
|
+
description: "List of course IDs"
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
required: ["course_ids"],
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
handler: async (client, args) => {
|
|
21
|
+
const input = z.object({
|
|
22
|
+
course_ids: z.array(z.number())
|
|
23
|
+
}).parse(args);
|
|
24
|
+
const announcements = await client.getAnnouncements(input.course_ids);
|
|
25
|
+
return {
|
|
26
|
+
content: [{ type: "text", text: JSON.stringify(announcements, null, 2) }],
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
name: "canvas_list_discussions",
|
|
32
|
+
tool: {
|
|
33
|
+
name: "canvas_list_discussions",
|
|
34
|
+
description: "List discussion topics in a course",
|
|
35
|
+
inputSchema: {
|
|
36
|
+
type: "object",
|
|
37
|
+
properties: {
|
|
38
|
+
course_id: { type: "number", description: "The ID of the course" },
|
|
39
|
+
},
|
|
40
|
+
required: ["course_id"],
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
handler: async (client, args) => {
|
|
44
|
+
const input = z.object({ course_id: z.coerce.number() }).parse(args);
|
|
45
|
+
const discussions = await client.getDiscussionTopics(input.course_id);
|
|
46
|
+
return {
|
|
47
|
+
content: [{ type: "text", text: JSON.stringify(discussions, null, 2) }],
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: "canvas_get_discussion_entries",
|
|
53
|
+
tool: {
|
|
54
|
+
name: "canvas_get_discussion_entries",
|
|
55
|
+
description: "Read replies/entries in a discussion topic",
|
|
56
|
+
inputSchema: {
|
|
57
|
+
type: "object",
|
|
58
|
+
properties: {
|
|
59
|
+
course_id: { type: "number", description: "The ID of the course" },
|
|
60
|
+
topic_id: { type: "number", description: "The ID of the discussion topic" },
|
|
61
|
+
},
|
|
62
|
+
required: ["course_id", "topic_id"],
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
handler: async (client, args) => {
|
|
66
|
+
const input = z.object({
|
|
67
|
+
course_id: z.coerce.number(),
|
|
68
|
+
topic_id: z.coerce.number()
|
|
69
|
+
}).parse(args);
|
|
70
|
+
const entries = await client.getDiscussionEntries(input.course_id, input.topic_id);
|
|
71
|
+
return {
|
|
72
|
+
content: [{ type: "text", text: JSON.stringify(entries, null, 2) }],
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
name: "canvas_post_announcement",
|
|
78
|
+
tool: {
|
|
79
|
+
name: "canvas_post_announcement",
|
|
80
|
+
description: "Post a new announcement to a course",
|
|
81
|
+
inputSchema: {
|
|
82
|
+
type: "object",
|
|
83
|
+
properties: {
|
|
84
|
+
course_id: { type: "number", description: "The ID of the course" },
|
|
85
|
+
title: { type: "string", description: "The title of the announcement" },
|
|
86
|
+
message: { type: "string", description: "The content/message of the announcement" },
|
|
87
|
+
},
|
|
88
|
+
required: ["course_id", "title", "message"],
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
handler: async (client, args) => {
|
|
92
|
+
const input = z.object({
|
|
93
|
+
course_id: z.coerce.number(),
|
|
94
|
+
title: z.string(),
|
|
95
|
+
message: z.string()
|
|
96
|
+
}).parse(args);
|
|
97
|
+
const result = await client.postAnnouncement(input.course_id, input.title, input.message);
|
|
98
|
+
return {
|
|
99
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
name: "canvas_post_discussion_reply",
|
|
105
|
+
tool: {
|
|
106
|
+
name: "canvas_post_discussion_reply",
|
|
107
|
+
description: "Post a reply to a discussion topic",
|
|
108
|
+
inputSchema: {
|
|
109
|
+
type: "object",
|
|
110
|
+
properties: {
|
|
111
|
+
course_id: { type: "number", description: "The ID of the course" },
|
|
112
|
+
topic_id: { type: "number", description: "The ID of the discussion topic" },
|
|
113
|
+
message: { type: "string", description: "The reply message" },
|
|
114
|
+
},
|
|
115
|
+
required: ["course_id", "topic_id", "message"],
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
handler: async (client, args) => {
|
|
119
|
+
const input = z.object({
|
|
120
|
+
course_id: z.coerce.number(),
|
|
121
|
+
topic_id: z.coerce.number(),
|
|
122
|
+
message: z.string()
|
|
123
|
+
}).parse(args);
|
|
124
|
+
const result = await client.postDiscussionReply(input.course_id, input.topic_id, input.message);
|
|
125
|
+
return {
|
|
126
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
];
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { ConfigManager } from "../common/config-manager.js";
|
|
2
|
+
const configManager = new ConfigManager();
|
|
3
|
+
export const configTools = [
|
|
4
|
+
{
|
|
5
|
+
name: "set_canvas_config",
|
|
6
|
+
tool: {
|
|
7
|
+
name: "set_canvas_config",
|
|
8
|
+
description: "Update Canvas API configuration (token and domain). This change is persistent.",
|
|
9
|
+
inputSchema: {
|
|
10
|
+
type: "object",
|
|
11
|
+
properties: {
|
|
12
|
+
domain: {
|
|
13
|
+
type: "string",
|
|
14
|
+
description: "Canvas Domain (e.g., uide.instructure.com)"
|
|
15
|
+
},
|
|
16
|
+
token: {
|
|
17
|
+
type: "string",
|
|
18
|
+
description: "Canvas API Access Token"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
required: ["domain", "token"]
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
handler: async (client, args) => {
|
|
25
|
+
const { domain, token } = args;
|
|
26
|
+
// Update the running client
|
|
27
|
+
client.updateConfig(token, domain);
|
|
28
|
+
// Persist the changes
|
|
29
|
+
configManager.set("CANVAS_API_DOMAIN", domain);
|
|
30
|
+
configManager.set("CANVAS_API_TOKEN", token);
|
|
31
|
+
return {
|
|
32
|
+
content: [{
|
|
33
|
+
type: "text",
|
|
34
|
+
text: `✅ Configuration updated and persisted successfully.\nDomain: ${domain}\nToken: updated (hidden)`
|
|
35
|
+
}]
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
];
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { resolveCourseId } from "../common/helpers.js";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
export const courseTools = [
|
|
4
|
+
{
|
|
5
|
+
name: "canvas_list_courses",
|
|
6
|
+
tool: {
|
|
7
|
+
name: "canvas_list_courses",
|
|
8
|
+
description: "List active courses for the current user in Canvas",
|
|
9
|
+
inputSchema: { type: "object", properties: {} },
|
|
10
|
+
},
|
|
11
|
+
handler: async (client, args) => {
|
|
12
|
+
const courses = await client.getCourses();
|
|
13
|
+
return {
|
|
14
|
+
content: [{ type: "text", text: JSON.stringify(courses, null, 2) }],
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
name: "canvas_list_pages",
|
|
20
|
+
tool: {
|
|
21
|
+
name: "canvas_list_pages",
|
|
22
|
+
description: "List pages in a course",
|
|
23
|
+
inputSchema: {
|
|
24
|
+
type: "object",
|
|
25
|
+
properties: {
|
|
26
|
+
course_id: {
|
|
27
|
+
anyOf: [{ type: "number" }, { type: "string" }],
|
|
28
|
+
description: "The ID or name of the course"
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
required: ["course_id"],
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
handler: async (client, args) => {
|
|
35
|
+
const input = z.object({ course_id: z.union([z.number(), z.string()]) }).parse(args);
|
|
36
|
+
const courseId = await resolveCourseId(client, input.course_id);
|
|
37
|
+
const pages = await client.getPages(courseId);
|
|
38
|
+
return {
|
|
39
|
+
content: [{ type: "text", text: JSON.stringify(pages, null, 2) }],
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: "canvas_get_page_content",
|
|
45
|
+
tool: {
|
|
46
|
+
name: "canvas_get_page_content",
|
|
47
|
+
description: "Get the content of a specific page",
|
|
48
|
+
inputSchema: {
|
|
49
|
+
type: "object",
|
|
50
|
+
properties: {
|
|
51
|
+
course_id: {
|
|
52
|
+
anyOf: [{ type: "number" }, { type: "string" }],
|
|
53
|
+
description: "The ID or name of the course"
|
|
54
|
+
},
|
|
55
|
+
page_id: { type: "string", description: "The ID or URL-slug of the page" },
|
|
56
|
+
},
|
|
57
|
+
required: ["course_id", "page_id"],
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
handler: async (client, args) => {
|
|
61
|
+
const input = z.object({
|
|
62
|
+
course_id: z.union([z.number(), z.string()]),
|
|
63
|
+
page_id: z.union([z.string(), z.number()])
|
|
64
|
+
}).parse(args);
|
|
65
|
+
const courseId = await resolveCourseId(client, input.course_id);
|
|
66
|
+
const pageId = String(input.page_id);
|
|
67
|
+
const page = await client.getPage(courseId, pageId);
|
|
68
|
+
return {
|
|
69
|
+
content: [{ type: "text", text: page.body || page.title + "\n(No content)" }],
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
name: "canvas_list_files",
|
|
75
|
+
tool: {
|
|
76
|
+
name: "canvas_list_files",
|
|
77
|
+
description: "List files in a course",
|
|
78
|
+
inputSchema: {
|
|
79
|
+
type: "object",
|
|
80
|
+
properties: {
|
|
81
|
+
course_id: {
|
|
82
|
+
anyOf: [{ type: "number" }, { type: "string" }],
|
|
83
|
+
description: "The ID or name of the course"
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
required: ["course_id"],
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
handler: async (client, args) => {
|
|
90
|
+
const input = z.object({ course_id: z.union([z.number(), z.string()]) }).parse(args);
|
|
91
|
+
const courseId = await resolveCourseId(client, input.course_id);
|
|
92
|
+
const files = await client.getFiles(courseId);
|
|
93
|
+
return {
|
|
94
|
+
content: [{ type: "text", text: JSON.stringify(files, null, 2) }],
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
name: "canvas_list_students",
|
|
100
|
+
tool: {
|
|
101
|
+
name: "canvas_list_students",
|
|
102
|
+
description: "List all students enrolled in a course",
|
|
103
|
+
inputSchema: {
|
|
104
|
+
type: "object",
|
|
105
|
+
properties: {
|
|
106
|
+
course_id: {
|
|
107
|
+
anyOf: [{ type: "number" }, { type: "string" }],
|
|
108
|
+
description: "The ID or name of the course"
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
required: ["course_id"],
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
handler: async (client, args) => {
|
|
115
|
+
const input = z.object({ course_id: z.union([z.number(), z.string()]) }).parse(args);
|
|
116
|
+
const courseId = await resolveCourseId(client, input.course_id);
|
|
117
|
+
const students = await client.getEnrollments(courseId);
|
|
118
|
+
return {
|
|
119
|
+
content: [{ type: "text", text: JSON.stringify(students, null, 2) }],
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
];
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { resolveCourseId } from "../common/helpers.js";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
export const createTools = [
|
|
4
|
+
{
|
|
5
|
+
name: "canvas_create_page",
|
|
6
|
+
tool: {
|
|
7
|
+
name: "canvas_create_page",
|
|
8
|
+
description: "Create a new page in a course",
|
|
9
|
+
inputSchema: {
|
|
10
|
+
type: "object",
|
|
11
|
+
properties: {
|
|
12
|
+
course_id: {
|
|
13
|
+
anyOf: [{ type: "number" }, { type: "string" }],
|
|
14
|
+
description: "The ID or name of the course"
|
|
15
|
+
},
|
|
16
|
+
title: { type: "string", description: "The title of the page" },
|
|
17
|
+
body: { type: "string", description: "The HTML body of the page" },
|
|
18
|
+
published: { type: "boolean", description: "Whether the page updates are published" }
|
|
19
|
+
},
|
|
20
|
+
required: ["course_id", "title", "body"],
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
handler: async (client, args) => {
|
|
24
|
+
const input = z.object({
|
|
25
|
+
course_id: z.union([z.number(), z.string()]),
|
|
26
|
+
title: z.string(),
|
|
27
|
+
body: z.string(),
|
|
28
|
+
published: z.boolean().optional().default(false)
|
|
29
|
+
}).parse(args);
|
|
30
|
+
const courseId = await resolveCourseId(client, input.course_id);
|
|
31
|
+
const page = await client.createPage(courseId, input.title, input.body, input.published);
|
|
32
|
+
return {
|
|
33
|
+
content: [{ type: "text", text: JSON.stringify(page, null, 2) }],
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: "canvas_update_page",
|
|
39
|
+
tool: {
|
|
40
|
+
name: "canvas_update_page",
|
|
41
|
+
description: "Update an existing page in a course",
|
|
42
|
+
inputSchema: {
|
|
43
|
+
type: "object",
|
|
44
|
+
properties: {
|
|
45
|
+
course_id: {
|
|
46
|
+
anyOf: [{ type: "number" }, { type: "string" }],
|
|
47
|
+
description: "The ID or name of the course"
|
|
48
|
+
},
|
|
49
|
+
page_url_or_id: { type: "string", description: "The URL or ID of the page to update" },
|
|
50
|
+
title: { type: "string", description: "The new title of the page" },
|
|
51
|
+
body: { type: "string", description: "The new HTML body of the page" },
|
|
52
|
+
published: { type: "boolean", description: "Whether the page is published" }
|
|
53
|
+
},
|
|
54
|
+
required: ["course_id", "page_url_or_id"],
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
handler: async (client, args) => {
|
|
58
|
+
const input = z.object({
|
|
59
|
+
course_id: z.union([z.number(), z.string()]),
|
|
60
|
+
page_url_or_id: z.union([z.string(), z.number()]),
|
|
61
|
+
title: z.string().optional(),
|
|
62
|
+
body: z.string().optional(),
|
|
63
|
+
published: z.boolean().optional()
|
|
64
|
+
}).parse(args);
|
|
65
|
+
const courseId = await resolveCourseId(client, input.course_id);
|
|
66
|
+
const page = await client.updatePage(courseId, input.page_url_or_id, {
|
|
67
|
+
title: input.title,
|
|
68
|
+
body: input.body,
|
|
69
|
+
published: input.published
|
|
70
|
+
});
|
|
71
|
+
return {
|
|
72
|
+
content: [{ type: "text", text: JSON.stringify(page, null, 2) }],
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
];
|