-
Notifications
You must be signed in to change notification settings - Fork 3
Open
Description
Description
Once the generic mcpR package is developed, integrate moodleR to expose its functionality via MCP for Claude Desktop and other AI assistants.
Integration Approach
Option 1: Decorator File (Recommended)
Create R/mcp_functions.R with decorated versions of key functions:
#* @mcp_tool
#* @description Analyze grades for a specific course
#* @param course_id [integer] The course to analyze
#* @param summary_type [enum: basic,detailed,visual] Type of summary
#* @returns Analysis results with optional visualization
mcp_analyze_course_grades <- function(course_id, summary_type = "basic") {
con <- mdl_get_connection()
grades <- mdl_grades(con) %>%
filter(courseid == course_id) %>%
collect()
result <- list(
course_id = course_id,
student_count = n_distinct(grades$userid),
grade_count = nrow(grades)
)
if (summary_type %in% c("detailed", "visual")) {
result$summary <- summary(grades)
}
if (summary_type == "visual") {
result$plot <- plot(grades)
}
result
}
#* @mcp_resource
#* @description Access course listing with details
#* @param limit [integer = 100] Maximum courses to return
#* @param category_id [integer] Filter by category (optional)
#* @returns Data frame of courses with category information
mcp_get_courses <- function(limit = 100, category_id = NULL) {
con <- mdl_get_connection()
courses <- mdl_courses(con)
if (\!is.null(category_id)) {
courses <- courses %>% filter(categoryid == category_id)
}
courses %>%
limit(limit) %>%
collect()
}
#* @mcp_tool
#* @description Generate forum activity word cloud
#* @param forum_id [integer] Forum to analyze (optional)
#* @param days_back [integer = 30] Number of days to include
#* @param min_words [integer = 20] Minimum words for cloud
#* @returns Base64 encoded word cloud image
mcp_forum_wordcloud <- function(forum_id = NULL, days_back = 30, min_words = 20) {
con <- mdl_get_connection()
posts <- mdl_forum_posts(con)
if (\!is.null(forum_id)) {
posts <- posts %>% filter(forum == forum_id)
}
cutoff_date <- Sys.Date() - days_back
posts <- posts %>%
filter(created >= cutoff_date) %>%
collect()
if (nrow(posts) < min_words) {
return(list(error = "Insufficient posts for word cloud"))
}
plot(posts) # Returns base64 image via mcpR type conversion
}Option 2: Package-Level Registration
Add to R/zzz.R:
.onLoad <- function(libname, pkgname) {
if (requireNamespace("mcpR", quietly = TRUE)) {
# Auto-register specific functions
mcpR::mcp_register_package("moodleR",
tools = c("mdl_create_cache", "summary.mdl_*", "plot.mdl_*"),
resources = c("mdl_courses", "mdl_users", "mdl_grades", "mdl_forum_posts", "mdl_log"),
exclude = c("*_query", "mdl_get_connection") # Internal functions
)
}
}Option 3: Configuration File
Create inst/mcp/config.yml:
tools:
- name: analyze_grades
function: mdl_grades
wrapper: |
function(course_id = NULL) {
grades <- mdl_grades()
if (\!is.null(course_id)) {
grades <- grades %>% filter(courseid == course_id)
}
summary(collect(grades))
}
description: "Analyze grade distribution"
resources:
- name: courses
function: mdl_courses
pagination: true
default_limit: 100
- name: users
function: mdl_users
filters:
- field: "deleted"
default: 0Claude Desktop Configuration
Basic Setup
{
"mcpServers": {
"moodleR": {
"command": "Rscript",
"args": ["-e", "moodleR::mcp_serve()"],
"env": {
"R_CONFIG_ACTIVE": "default"
}
}
}
}With Custom Config
{
"mcpServers": {
"moodleR": {
"command": "Rscript",
"args": [
"-e",
"moodleR::mcp_serve(config = '~/.moodleR/config.yml')"
]
}
}
}Helper Functions for moodleR
1. Connection Management
# Ensure connection is available for MCP calls
mcp_ensure_connection <- function() {
if (\!exists(".moodle_connection", envir = .GlobalEnv)) {
.GlobalEnv$.moodle_connection <- mdl_get_connection()
}
.GlobalEnv$.moodle_connection
}2. Error Handling
# Wrap functions with moodleR-specific error handling
mcp_safe_query <- function(expr) {
tryCatch({
expr
}, error = function(e) {
if (grepl("connection", e$message)) {
list(error = "Database connection failed", details = e$message)
} else if (grepl("permission", e$message)) {
list(error = "Insufficient permissions", details = e$message)
} else {
list(error = "Query failed", details = e$message)
}
})
}3. Result Formatting
# Format results for AI consumption
mcp_format_result <- function(data, include_summary = TRUE) {
result <- list(
row_count = nrow(data),
column_names = names(data)
)
if (include_summary && nrow(data) > 0) {
result$preview <- head(data, 10)
result$summary <- summary(data)
}
result
}Testing Integration
Test File: tests/testthat/test-mcp.R
test_that("MCP functions are properly exposed", {
skip_if_not_installed("mcpR")
# Check function registration
registry <- mcpR::mcp_get_registry()
expect_true("mcp_analyze_course_grades" %in% names(registry$tools))
expect_true("mcp_get_courses" %in% names(registry$resources))
# Test function execution
result <- mcp_analyze_course_grades(course_id = 1)
expect_type(result, "list")
expect_true(all(c("course_id", "student_count") %in% names(result)))
})Documentation Updates
1. Add MCP Section to README
## Using with Claude Desktop
moodleR can be used with Claude Desktop via the Model Context Protocol:
1. Install moodleR and mcpR packages
2. Configure your Moodle database connection
3. Add to Claude Desktop config:
```json
{
"mcpServers": {
"moodleR": {
"command": "Rscript",
"args": ["-e", "moodleR::mcp_serve()"]
}
}
}- Ask Claude to analyze your Moodle data!
### 2. Create Vignette
`vignettes/mcp-integration.Rmd`:
- Setup instructions
- Example prompts
- Best practices
- Troubleshooting
## Implementation Steps
1. [ ] Wait for mcpR package to be functional
2. [ ] Create mcp_functions.R with decorated functions
3. [ ] Add mcp_serve() wrapper function
4. [ ] Test with Claude Desktop
5. [ ] Document integration
6. [ ] Create example prompts
7. [ ] Add to package tests
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels