Skip to content

Add optional LMS MCP write tools - #122

Open
scottgrayson wants to merge 5 commits into
4.xfrom
CU-868kuzw7c-lms-mcp
Open

Add optional LMS MCP write tools#122
scottgrayson wants to merge 5 commits into
4.xfrom
CU-868kuzw7c-lms-mcp

Conversation

@scottgrayson

Copy link
Copy Markdown
Contributor

Summary

  • Add a package-local Laravel MCP server (filament-lms) with write tools for Course → Lesson → video Step.
  • create_video_course builds a nested private course from YouTube/Vimeo URLs; granular list/get/update/delete tools cover later edits.
  • Hosts opt in with composer require laravel/mcp. The package auto-registers stdio only; web + Sanctum stays in the host app.

Test plan

  • vendor/bin/pest tests/Feature/LmsMcpTest.php
  • Confirm php artisan mcp:start filament-lms works in a host with laravel/mcp
  • Confirm filament-lms.mcp.enabled = false skips local registration
  • Confirm invalid video URLs and duplicate slug/external_id are rejected

Made with Cursor

scottgrayson and others added 5 commits August 24, 2026 05:32
Give AI clients a package-local stdio server to create and edit Course → Lesson → Step data from hosted YouTube/Vimeo URLs, with new courses private by default.

Co-authored-by: Cursor <cursoragent@cursor.com>
Keep the MCP Unreleased entry and the released v4.7.7 dashboard changelog.

Co-authored-by: Cursor <cursoragent@cursor.com>
Require isLmsAdmin for authenticated MCP writes, guard tenant context when
tenancy is enabled, prefix auto external_ids that start with a digit, and
assert on JSON-safe video fields in LmsMcpTest.

Co-authored-by: Cursor <cursoragent@cursor.com>
Assert on the video id and provider name instead of exact JSON key spacing.

Co-authored-by: Cursor <cursoragent@cursor.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 4 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 51e1dc8. Configure here.

Comment thread src/Mcp/LmsTool.php
$videoName = filled($input['video_name'] ?? null) ? (string) $input['video_name'] : $name;
$url = $this->resolveVideoUrl((string) $input['video_url']);

$this->assertUniqueStepSlug($slug);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Step slugs collide across courses

Medium Severity

Auto-generated step slugs are only {lesson-slug}-{name} and then checked for global uniqueness. A second course with similarly named lessons and steps fails that check, so create_video_course rolls back even though learner URLs are scoped by course slug.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 51e1dc8. Configure here.

'name' => $name,
'slug' => filled($validated['slug'] ?? null) ? (string) $validated['slug'] : Str::slug($name),
'order' => $validated['order'] ?? $this->nextLessonOrder($course),
]);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lesson order argument is ignored

Medium Severity

create_lesson accepts order and Lesson::create sets it, but Lesson uses Spatie’s SortableTrait with default sort_when_creating. That creating hook overwrites the column with the global max plus one, so the requested (and per-course) order never sticks.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 51e1dc8. Configure here.


if (isset($validated['video_url']) || isset($validated['video_name'])) {
$video = $step->material instanceof Video ? $step->material : null;
$url = isset($validated['video_url']) ? $this->resolveVideoUrl((string) $validated['video_url']) : $video?->url;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Step update commits before video validation

Medium Severity

update_step writes name, slug, lesson, and text first, then validates video_url. An invalid URL returns an error after those fields are already saved, so the tool can leave a partial update with no transaction to roll back.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 51e1dc8. Configure here.

'material_id' => $video->id,
'material_type' => 'video',
]);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Video update orphans existing materials

Medium Severity

When update_step receives a video_url on a non-video step, it creates a Video and retargets material_id / material_type without removing the previous material. Tests, documents, and other morph records are left orphaned and the step type changes in place.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 51e1dc8. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant