mirror of
https://github.com/alexmickelson/canvasManagement.git
synced 2026-03-25 23:28:33 -06:00
working on mcp
This commit is contained in:
186
src/app/api/mcp/[transport]/route.ts
Normal file
186
src/app/api/mcp/[transport]/route.ts
Normal file
@@ -0,0 +1,186 @@
|
||||
import { assignmentMarkdownSerializer } from "@/models/local/assignment/utils/assignmentMarkdownSerializer";
|
||||
import { groupByStartDate } from "@/models/local/utils/timeUtils";
|
||||
import { fileStorageService } from "@/services/fileStorage/fileStorageService";
|
||||
import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import { createMcpHandler } from "mcp-handler";
|
||||
import { z } from "zod";
|
||||
import { githubClassroomUrlPrompt } from "./github-classroom-prompt";
|
||||
|
||||
const handler = createMcpHandler(
|
||||
(server) => {
|
||||
server.tool(
|
||||
"list_current_courses",
|
||||
"gets courses for the current term",
|
||||
{},
|
||||
async () => {
|
||||
const settingsList =
|
||||
await fileStorageService.settings.getAllCoursesSettings();
|
||||
|
||||
const coursesByStartDate = groupByStartDate(settingsList);
|
||||
|
||||
const sortedDates = Object.keys(coursesByStartDate).sort().reverse();
|
||||
|
||||
const mostRecentStartDate = sortedDates[0];
|
||||
|
||||
const courseNames = coursesByStartDate[mostRecentStartDate].map(
|
||||
(settings) => settings.name
|
||||
);
|
||||
return {
|
||||
content: courseNames.map((name) => ({
|
||||
type: "text",
|
||||
text: JSON.stringify({
|
||||
courseName: name,
|
||||
}),
|
||||
})),
|
||||
};
|
||||
}
|
||||
);
|
||||
server.tool(
|
||||
"list_assignments_for_course",
|
||||
"gets assignments and modules for a course",
|
||||
{
|
||||
courseName: z.string(),
|
||||
},
|
||||
async ({ courseName }) => {
|
||||
const modules = await fileStorageService.modules.getModuleNames(
|
||||
courseName
|
||||
);
|
||||
const assignments = (
|
||||
await Promise.all(
|
||||
modules.map(async (moduleName) => {
|
||||
const assignments =
|
||||
await fileStorageService.assignments.getAssignments(
|
||||
courseName,
|
||||
moduleName
|
||||
);
|
||||
return assignments.map((assignment) => ({
|
||||
assignmentName: assignment.name,
|
||||
moduleName,
|
||||
}));
|
||||
})
|
||||
)
|
||||
).flat();
|
||||
console.log("mcp got assignments", assignments);
|
||||
|
||||
return {
|
||||
//doesn't seem to work with many clients
|
||||
// content: assignments.map((a) => ({
|
||||
// type: "resource_link",
|
||||
// uri: `canvas:///courses/${courseName}/module/${a.moduleName}/assignments/${a.assignmentName}`,
|
||||
// name: `${a.assignmentName}.md`,
|
||||
// mimeType: "text/markdown",
|
||||
// description: "An canvas assignment",
|
||||
// })),
|
||||
|
||||
content: assignments.map((a) => ({
|
||||
type: "text",
|
||||
text: JSON.stringify({
|
||||
assignmentName: a.assignmentName,
|
||||
moduleName: a.moduleName,
|
||||
}),
|
||||
})),
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
server.tool(
|
||||
"get_assignment",
|
||||
"gets a markdown file defining the assignment",
|
||||
{
|
||||
courseName: z.string(),
|
||||
moduleName: z.string(),
|
||||
assignmentName: z.string(),
|
||||
},
|
||||
async ({ courseName, moduleName, assignmentName }) => {
|
||||
if (
|
||||
typeof courseName !== "string" ||
|
||||
typeof moduleName !== "string" ||
|
||||
typeof assignmentName !== "string"
|
||||
) {
|
||||
throw new Error(
|
||||
"courseName, moduleName, and assignmentName must be strings"
|
||||
);
|
||||
}
|
||||
const assignment = await fileStorageService.assignments.getAssignment(
|
||||
courseName,
|
||||
moduleName,
|
||||
assignmentName
|
||||
);
|
||||
|
||||
console.log("mcp assignment", assignment);
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: assignmentMarkdownSerializer.toMarkdown(assignment),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
);
|
||||
server.tool(
|
||||
"get_github_classroom_url_instructions",
|
||||
"gets instructions for creating a GitHub Classroom assignment, call this to get a prompt showing how to create a GitHub Classroom assignment",
|
||||
{},
|
||||
async () => {
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: githubClassroomUrlPrompt,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
// resources dont integrate well right now
|
||||
// server.registerResource(
|
||||
// "course_assignment",
|
||||
// new ResourceTemplate(
|
||||
// "canvas:///courses/{courseName}/module/{moduleName}/assignments/{assignmentName}",
|
||||
// { list: undefined }
|
||||
// ),
|
||||
// {
|
||||
// title: "Course Assignment",
|
||||
// description: "Markdown representation of a course assignment",
|
||||
// },
|
||||
// async (uri, { courseName, moduleName, assignmentName }) => {
|
||||
// if (
|
||||
// typeof courseName !== "string" ||
|
||||
// typeof moduleName !== "string" ||
|
||||
// typeof assignmentName !== "string"
|
||||
// ) {
|
||||
// throw new Error(
|
||||
// "courseName, moduleName, and assignmentName must be strings"
|
||||
// );
|
||||
// }
|
||||
// const assignment = await fileStorageService.assignments.getAssignment(
|
||||
// courseName,
|
||||
// moduleName,
|
||||
// assignmentName
|
||||
// );
|
||||
// return {
|
||||
// contents: [
|
||||
// {
|
||||
// uri: uri.href,
|
||||
// text: assignment.description,
|
||||
// },
|
||||
// ],
|
||||
// };
|
||||
// }
|
||||
// );
|
||||
},
|
||||
{
|
||||
serverInfo: {
|
||||
name: "Canvas Management MCP Server",
|
||||
version: "2.0.0",
|
||||
},
|
||||
},
|
||||
{
|
||||
basePath: "/api/mcp",
|
||||
maxDuration: 60,
|
||||
verboseLogs: true,
|
||||
}
|
||||
);
|
||||
export { handler as GET, handler as POST };
|
||||
Reference in New Issue
Block a user