MCP ו-OAuth 2.1

מה שרת ה-MCP מציע

Institflow מריצה שרת Model Context Protocol בכתובת /mcp (Streamable HTTP, חסר מצב — כל קריאה עצמאית, ולכן הוא מתרחב כמו כל בקשת API אחרת). הוא חושף את אותם שירותי דומיין שכל נקודת קצה של REST קוראת להם, דרך 74 כלים מוכווני משימה, קומץ משאבים לקריאה בלבד וכמה prompts בסגנון דוחות — כך שסוכן AI (Claude, או כל לקוח MCP) יכול לחפש תלמידים, לבדוק לוח זמנים, לרשום נוכחות או לנסח דוח התקדמות, תוך שימוש בהרשאות של הקורא עצמו בדיוק, לעולם לא יותר.

חיבור לקוח

Institflow היא שרת ההרשאות של OAuth 2.1 עבור זה — אין צורך במפתח API נפרד או בטוקן ידני. לקוח MCP תקני מגלה לבד את כל מה שהוא צריך:

  1. הוא מביא GET /.well-known/oauth-protected-resource (RFC 9728) מתוך אתגר ה-WWW-Authenticate של /mcp, ואז GET /.well-known/oauth-authorization-server (RFC 8414) לנקודות הקצה של הטוקן, הרישום וההרשאה.
  2. אם עדיין אין לו client_id, הוא רושם אחד דינמית: POST /oauth/register (RFC 7591 — לקוח ציבורי, בלי סוד; אפשר לכבות את נקודת הקצה הזו לכל הדייר בהגדרה OAUTH_DYNAMIC_REGISTRATION אם אתם מעדיפים לרשום לקוחות מראש בעצמכם).
  3. הוא פותח GET /oauth/authorize עם PKCE (S256 — חובה, לא רשות, תחת OAuth 2.1) בדפדפן שלכם. אתם מתחברים (אם צריך) ומגיעים למסך הסכמה שמראה בדיוק לאיזה דייר/חברות אתם מתחברים ומה הלקוח יכול לעשות.
  4. אחרי שאישרתם, הלקוח מחליף את קוד ההרשאה — POST /oauth/token עם ה-code_verifier של PKCE — בטוקן גישה (JWT רגיל של Institflow, רק עם typ: "mcp") ובטוקן רענון שתקף ל-30 יום.
mcp request
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6ImF0K2p3dCJ9...

טוקן MCP לעולם אינו מאמת קריאת REST

גם ההפך אינו אפשרי — טוקן עם typ: "mcp" נדחה עם 401 בכל מסלול /api/v1/* רגיל, וטוקן גישה רגיל אינו יכול לפנות אל /mcp. ההפרדה מכוונת.

הרשאות ו-Scopes

עצם קבלת טוקן דורשת את ההרשאה mcp.access על החברות שאיתה אתם מתחברים — חבר צוות שאין לו אותה (רוב תפקידי secretary/teacher כברירת מחדל) נדחה בשלב ההסכמה, לפני שהונפק טוקן כלשהו. בנוסף, כל כלי בודק את ההרשאה המוצהרת שלו בכל קריאה — זהה למה שנקודת הקצה המקבילה ב-REST הייתה דורשת.

כלים המסומנים למטה כהרסניים דורשים גם mcp.destructive. קריאה לכלי כזה בלי confirm: true לעולם אינה משנה דבר — היא מחזירה תצוגה מקדימה של מה היה קורה (למשל “היה משנה את הסטטוס מ-active ל-withdrawn”) ואת requiresConfirmation: true. הסוכן (או האדם שמפעיל אותו) קורא שוב לאותו כלי עם confirm: true כדי לבצע בפועל. כל קריאה — תצוגה מקדימה או ביצוע — נרשמת ביומן הביקורת עם channel: "mcp", שם הכלי, וגיבוב של הארגומנטים שלו (לעולם לא הארגומנטים הגולמיים, שעשויים להכיל מידע אישי).

קטלוג הכלים

כל הכלים, נוצרים ישירות מ-apps/api/src/modules/mcp/tools/*.ts — בדיוק המקור ששרת ה-MCP עצמו רושם באתחול.

Academics

כליתיאורהרשאהפעולה הרסנית
cancel_sessionCancel a scheduled class session, with a reason. Destructive: previews unless confirm: true is passed.groups.writeכן
create_groupCreate a new teaching group (class section) for a course, with an optional weekly schedule.groups.writeלא
drop_enrollmentDrop a student's enrollment from a group. Destructive: previews unless confirm: true is passed.enrollments.writeכן
enroll_studentEnroll a student into a teaching group.enrollments.writeלא
get_groupGet full details for one teaching group by id.groups.readלא
get_scheduleGet scheduled class sessions for a group, teacher, or student within an optional date range. Exactly one of groupId/teacherStaffId/studentId is required.groups.readלא
list_coursesList the course catalogue (subjects/programs offered), optionally filtered by category or active status.courses.readלא
list_groupsList teaching groups (class sections), optionally filtered by branch, course, status, or teacher.groups.readלא
transfer_studentTransfer a student's enrollment from their current group to another group (drop + enroll in one operation). Destructive: previews unless confirm: true is passed.enrollments.writeכן

Admin

כליתיאורהרשאהפעולה הרסנית
dashboard_summaryOwner/manager dashboard summary — currently the tenant-wide billing summary (outstanding balance, collections, overdue).invoices.readלא
get_settingsGet the tenant's effective settings (general, attendance, grading, billing, notifications, curriculum, reminders).settings.manageלא
invite_memberInvite a new member to the tenant by email, with a role. Destructive: previews unless confirm: true is passed.members.manageכן
list_membersList members of the current tenant, with their assigned roles.members.manageלא
list_rolesList every role (system and custom) in the tenant, with its permissions.roles.manageלא
set_member_rolesSet a member's complete role assignment (within one branch scope, or tenant-wide) to exactly the given list of role ids. Destructive: previews the add/remove diff unless confirm: true is passed.members.manageכן
update_settingsUpdate one or more tenant settings keys. Destructive: previews the before/after values unless confirm: true is passed.settings.manageכן

Assessment

כליתיאורהרשאהפעולה הרסנית
create_examCreate a new exam/quiz/homework/project for a group.assessment.writeלא
generate_progress_reportQueue generation of a progress report for a student or an entire group over a period. Asynchronous — returns immediately once queued.assessment.writeלא
get_student_gradesGet a student's grades (per-group weighted average and per-exam breakdown), optionally scoped to one group.assessment.readלא
publish_examPublish an exam so its results become visible to students/guardians. Destructive: previews unless confirm: true is passed.assessment.writeכן
record_resultsBulk-record (or update) student scores for an exam.assessment.writeלא
send_progress_reportsSend every published (not-yet-sent) progress report for a student or group to guardians. Destructive: previews the list unless confirm: true is passed.assessment.writeכן

assignments

כליתיאורהרשאהפעולה הרסנית
curriculum.assignments.createCreate an assignment unit in a course: a lesson of kind "assignment" plus its instructions, due date, max score, late policy and allowed submission kinds, in one transaction.curriculum.writeלא
curriculum.assignments.grade_submissionGrade a submission (score at most the assignment’s max score, optional feedback). Emits assignment.graded.curriculum.assignments.gradeלא
curriculum.assignments.list_submissionsList an assignment’s submissions (cursor-paginated), optionally filtered by status. lessonId is the assignment unit’s id, or the id of the video lesson that carries the task.curriculum.assignments.gradeלא
curriculum.assignments.publish_to_gradebookPublish every currently-graded submission into the gradebook as a "homework" exam per group — upserts on repeat. Destructive: the first publish for a group creates and publishes a real exam, notifying students/guardians, so it previews unless confirm: true is passed.curriculum.assignments.gradeכן
curriculum.assignments.return_submissionSend a submission back to the student for revision (clears any earlier grade).curriculum.assignments.gradeלא
curriculum.assignments.updateUpdate an assignment’s own fields (instructions, due date, max score, late policy, allowed submission kinds). Lesson-shared fields (title, section, drip gate) go through update_lesson.curriculum.writeלא
curriculum.lesson_tasks.removeRemove the task under a video lesson. Destructive: previews (with the number of submissions that would be deleted with it) unless confirm: true is passed, which also confirms deleting those submissions.curriculum.writeכן
curriculum.lesson_tasks.setCreate or replace «مهمة هذا الدرس», the task under a video lesson (instructions, due date, max score, late policy, accepted submission kinds). Submissions, grading and the gradebook publish then use the curriculum.assignments.* tools with the same lessonId.curriculum.writeלא

Attendance

כליתיאורהרשאהפעולה הרסנית
attendance_reportAttendance report for a group (per-student rates) or a single student (full history), within an optional date range.attendance.readלא
get_session_rosterGet the attendance roster for a scheduled session — every enrolled student and their current attendance mark, if any.attendance.readלא
record_attendanceBulk-record (or update) attendance marks for every student on a session's roster.attendance.markלא

Billing

כליתיאורהרשאהפעולה הרסנית
billing_summaryTenant-wide billing summary — outstanding balance, this month's collections, and overdue counts/totals.invoices.readלא
create_invoiceCreate a new draft invoice for a student, with one or more line items.invoices.writeלא
get_invoiceGet full details for one invoice, including its lines and payments.invoices.readלא
list_invoicesList invoices, filterable by status (including an "overdue" shorthand), student, guardian, or due-date range.invoices.readלא
record_paymentRecord a payment against an invoice.payments.recordלא
student_statementGet a student's full billing statement — every invoice/payment entry and the running balance.invoices.readלא
void_invoiceVoid an invoice, with a reason. Destructive: previews unless confirm: true is passed.invoices.writeכן

curriculum

כליתיאורהרשאהפעולה הרסנית
create_lessonCreate a lesson in a course. Omit sectionId to use (or auto-create) the course’s default section. audienceGroupIds restricts it to those groups of the course; omit or null for every group.curriculum.writeלא
delete_lessonDelete a lesson and its video and progress rows. Destructive: previews (with how many students have progress on it) unless confirm: true is passed.curriculum.writeכן
get_lessonGet one lesson by id, including its markdown body and video source.curriculum.readלא
grant_course_accessGrant a student access to a self-paced (video) course. Idempotent — granting twice returns the existing enrollment.enrollments.writeלא
list_course_curriculumList a course’s curriculum: its sections, each with the lessons inside it. Published lessons only unless includeDrafts is true.curriculum.readלא
publish_lessonPublish a lesson so enrolled students can see it. Destructive: notifies real people, so it previews unless confirm: true is passed.curriculum.publishכן
revoke_course_accessRevoke a student’s self-paced course access. Destructive: previews unless confirm: true is passed.enrollments.writeכן
set_lesson_videoAttach a video to a lesson from a YouTube URL. The URL is validated and normalized exactly as the web editor does.curriculum.writeלא
student_course_progressOne student’s progress through their video courses — lessons completed vs. available, and the last lesson they opened.curriculum.readלא
update_lessonUpdate a lesson’s title, summary, markdown body, estimate, release rules or audience (audienceGroupIds: a list of the course’s group ids to restrict the lesson to those groups, null for every group).curriculum.writeלא

Notifications

כליתיאורהרשאהפעולה הרסנית
get_notification_ruleOne notification type: the effective rule, the override the institute made, what the type allows and locks, and per channel whether it can deliver, who bills it and the price per message.notifications.readלא
get_notification_spendNotification usage this month per channel and, when the install is on the Institflow messaging relay, the credit balance.notifications.manageלא
list_notification_rulesThe notification rules of the institute: for every kind of notice the system sends — absence, invoices, payments, grades, lessons, assignments, quizzes, class and deadline reminders, subscription alerts — who receives it, on which channels, and whether the institute changed it from the Institflow default.notifications.readלא
notification_usageNotification channel usage/cost for a billing period (defaults to the current month, format YYYY-MM).notifications.readלא
preview_notification_ruleChanges nothing: the estimated monthly cost (a range, in credit units — 10 000 units per credit), how many people a proposed rule would reach, whether saving it needs cost confirmation, and warnings. Omit `rule` to describe the current rule.notifications.readלא
reset_notification_ruleDeletes the override the institute made for one notification type: it goes back to the Institflow default. Destructive: previews the change unless confirm: true is passed. Going back to the default can switch the type or a paid channel on again; that additionally needs confirmCost: true, exactly like update_notification_rule.notifications.manageכן
send_messageSend a message to a student/guardian/group/branch audience via the notification channel ladder (email/SMS/WhatsApp/push, falling back down the ladder). SMS/WhatsApp are platform/licence-approved per tenant — naming one explicitly in `channels` when it is not approved is rejected; leaving `channels` unset falls through the ladder to an approved channel (in-app always reachable) instead. Destructive: previews recipient count and quota impact unless confirm: true is passed.notifications.sendכן
update_notification_ruleReplaces the override the institute made for one notification type (a field left out goes back to the Institflow default). Destructive: previews before/after AND the estimated cost unless confirm: true is passed. A change that raises what the institute pays for — a paid channel switched on, recipients, lead times or scope added — additionally needs confirmCost: true, so an assistant cannot spend credit by accident even with confirm.notifications.manageכן

quizzes

כליתיאורהרשאהפעולה הרסנית
curriculum.quizzes.add_questionAdd a question to a quiz. Returns the whole quiz (questions included).curriculum.quizzes.manageלא
curriculum.quizzes.createCreate a quiz unit in a course: a lesson of kind "quiz" plus its settings, in one transaction. No questions yet.curriculum.quizzes.manageלא
curriculum.quizzes.delete_questionDelete a quiz question. Returns the whole quiz (questions included).curriculum.quizzes.manageלא
curriculum.quizzes.grade_answerGrade a short-answer (short_text) answer (points at most the question’s own points). Finalises the attempt’s score/passed once nothing is left ungraded. Emits quiz.graded on finalisation.curriculum.assignments.gradeלא
curriculum.quizzes.list_attemptsList a quiz’s attempts (cursor-paginated), optionally filtered by student or status.curriculum.assignments.gradeלא
curriculum.quizzes.publish_to_gradebookPublish each student’s best fully-graded attempt into the gradebook as a "quiz" exam per group — upserts on repeat. Destructive: the first publish for a group creates and publishes a real exam, notifying students/guardians, so it previews unless confirm: true is passed.curriculum.assignments.gradeכן
curriculum.quizzes.reorder_questionsWhole-list reorder of a quiz’s questions. Returns the whole quiz (questions included).curriculum.quizzes.manageלא
curriculum.quizzes.updateUpdate a quiz’s own settings (time limit, attempts allowed, shuffle, show-answers-after, pass score, due date). Lesson-shared fields go through update_lesson.curriculum.quizzes.manageלא
curriculum.quizzes.update_questionUpdate a quiz question. Returns the whole quiz (questions included).curriculum.quizzes.manageלא

Students

כליתיאורהרשאהפעולה הרסנית
add_guardianAttach a guardian to a student — either link an existing guardian by id, or create a new one and link it.guardians.writeלא
create_studentCreate a new student record in the current tenant.students.writeלא
get_studentGet full details for one student by id, including guardians and status.students.readלא
search_studentsSearch/list students in the current tenant, filtered by free-text query, status, branch, group, or tag. Cursor-paginated.students.readלא
set_student_statusChange a student's lifecycle status (lead/active/inactive/graduated/withdrawn). Destructive: previews the transition unless confirm: true is passed.students.writeכן
update_studentUpdate a student's profile fields (name, contact info, tags, ...). Does not change status — use set_student_status for that.students.writeלא

משאבים ו-Prompts

משאבים לקריאה בלבד, ממוענים לפי URI, ללקוח שרוצה לטעון הקשר בלי לקרוא לכלי:

URIמחזיר
institflow://student/{id}פרופיל תלמיד: פרטיו, אפוטרופוסיו ומצבו.
institflow://group/{id}לוח הזמנים של קבוצת לימוד ורשימת תלמידיה.
institflow://invoice/{id}חשבונית עם השורות והתשלומים שלה.
institflow://schedule/todayמפגשי היום בכל הדייר (עד 100).

Prompts — תבניות הנחיה לשימוש חוזר שלקוח יכול להציג כפקודת סלאש או ככפתור:

  • monthly_report (ארגומנטים: groupId או studentId, month)
  • overdue_followup — ניסוח תוכנית מעקב לחשבוניות באיחור.
  • daily_briefing — לוח הזמנים של היום, היעדרויות וכל מה שבאיחור, בתקציר.