Initial commit: MCP Hub Community Edition v3.0.0

Community edition generated from private repo via sync pipeline.
Includes 9 plugins (WordPress, WooCommerce, WP Advanced, Gitea, n8n,
Supabase, OpenPanel, Appwrite, Directus) with ~587 tools.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
airano
2026-02-17 08:34:44 +03:30
commit cf62e65c55
237 changed files with 87596 additions and 0 deletions

View File

@@ -0,0 +1,34 @@
"""
WordPress Advanced Pydantic Schemas
"""
from .bulk import *
from .database import *
from .system import *
__all__ = [
# Database schemas
"DatabaseExportRequest",
"DatabaseImportRequest",
"DatabaseSizeResponse",
"DatabaseTablesResponse",
"DatabaseSearchRequest",
"DatabaseQueryRequest",
"DatabaseRepairResponse",
# Bulk schemas
"BulkUpdatePostsRequest",
"BulkDeletePostsRequest",
"BulkUpdateProductsRequest",
"BulkDeleteProductsRequest",
"BulkDeleteMediaRequest",
"BulkAssignCategoriesRequest",
"BulkAssignTagsRequest",
"BulkOperationResponse",
# System schemas
"SystemInfoResponse",
"SystemPHPInfoResponse",
"SystemDiskUsageResponse",
"CronListResponse",
"CronRunRequest",
"ErrorLogResponse",
]

View File

@@ -0,0 +1,250 @@
"""
Bulk Operations Schemas
Pydantic models for WordPress bulk operations including:
- Bulk updates for posts/products
- Bulk deletions
- Bulk category/tag assignments
"""
from typing import Any
from pydantic import BaseModel, Field, field_validator
class BulkUpdatePostsParams(BaseModel):
"""Parameters for bulk updating posts"""
post_ids: list[int] = Field(
..., min_length=1, max_length=100, description="List of post IDs to update (max 100)"
)
updates: dict[str, Any] = Field(
..., description="Fields to update (status, author_id, categories, tags, etc.)"
)
@classmethod
@field_validator("post_ids")
def validate_post_ids(cls, v):
"""Ensure all IDs are positive"""
if any(id <= 0 for id in v):
raise ValueError("All post IDs must be positive integers")
return v
@classmethod
@field_validator("updates")
def validate_updates(cls, v):
"""Validate update fields are allowed"""
allowed_fields = {
"status",
"title",
"content",
"excerpt",
"author",
"categories",
"tags",
"featured_media",
"comment_status",
"ping_status",
"sticky",
"format",
"meta",
}
invalid_fields = set(v.keys()) - allowed_fields
if invalid_fields:
raise ValueError(f"Invalid update fields: {', '.join(invalid_fields)}")
return v
class BulkDeletePostsParams(BaseModel):
"""Parameters for bulk deleting posts"""
post_ids: list[int] = Field(
..., min_length=1, max_length=100, description="List of post IDs to delete (max 100)"
)
force: bool = Field(default=False, description="Force permanent deletion (bypass trash)")
@classmethod
@field_validator("post_ids")
def validate_post_ids(cls, v):
"""Ensure all IDs are positive"""
if any(id <= 0 for id in v):
raise ValueError("All post IDs must be positive integers")
return v
class BulkUpdateProductsParams(BaseModel):
"""Parameters for bulk updating WooCommerce products"""
product_ids: list[int] = Field(
..., min_length=1, max_length=100, description="List of product IDs to update (max 100)"
)
updates: dict[str, Any] = Field(
..., description="Fields to update (price, stock_quantity, status, etc.)"
)
@classmethod
@field_validator("product_ids")
def validate_product_ids(cls, v):
"""Ensure all IDs are positive"""
if any(id <= 0 for id in v):
raise ValueError("All product IDs must be positive integers")
return v
@classmethod
@field_validator("updates")
def validate_updates(cls, v):
"""Validate update fields are allowed"""
allowed_fields = {
"name",
"status",
"featured",
"catalog_visibility",
"description",
"short_description",
"sku",
"price",
"regular_price",
"sale_price",
"stock_quantity",
"stock_status",
"manage_stock",
"categories",
"tags",
"images",
"attributes",
"meta_data",
}
invalid_fields = set(v.keys()) - allowed_fields
if invalid_fields:
raise ValueError(f"Invalid update fields: {', '.join(invalid_fields)}")
return v
class BulkDeleteProductsParams(BaseModel):
"""Parameters for bulk deleting products"""
product_ids: list[int] = Field(
..., min_length=1, max_length=100, description="List of product IDs to delete (max 100)"
)
force: bool = Field(default=False, description="Force permanent deletion")
@classmethod
@field_validator("product_ids")
def validate_product_ids(cls, v):
"""Ensure all IDs are positive"""
if any(id <= 0 for id in v):
raise ValueError("All product IDs must be positive integers")
return v
class BulkAssignCategoriesParams(BaseModel):
"""Parameters for bulk assigning categories"""
item_ids: list[int] = Field(
..., min_length=1, max_length=100, description="List of post/product IDs (max 100)"
)
category_ids: list[int] = Field(..., min_length=1, description="List of category IDs to assign")
replace: bool = Field(
default=False, description="Replace existing categories (true) or append (false)"
)
item_type: str = Field(default="post", description="Type of items: 'post' or 'product'")
@classmethod
@field_validator("item_ids", "category_ids")
def validate_ids(cls, v):
"""Ensure all IDs are positive"""
if any(id <= 0 for id in v):
raise ValueError("All IDs must be positive integers")
return v
@classmethod
@field_validator("item_type")
def validate_item_type(cls, v):
"""Validate item type"""
if v not in ["post", "product"]:
raise ValueError("item_type must be 'post' or 'product'")
return v
class BulkAssignTagsParams(BaseModel):
"""Parameters for bulk assigning tags"""
item_ids: list[int] = Field(
..., min_length=1, max_length=100, description="List of post/product IDs (max 100)"
)
tag_ids: list[int] = Field(..., min_length=1, description="List of tag IDs to assign")
replace: bool = Field(
default=False, description="Replace existing tags (true) or append (false)"
)
item_type: str = Field(default="post", description="Type of items: 'post' or 'product'")
@classmethod
@field_validator("item_ids", "tag_ids")
def validate_ids(cls, v):
"""Ensure all IDs are positive"""
if any(id <= 0 for id in v):
raise ValueError("All IDs must be positive integers")
return v
@classmethod
@field_validator("item_type")
def validate_item_type(cls, v):
"""Validate item type"""
if v not in ["post", "product"]:
raise ValueError("item_type must be 'post' or 'product'")
return v
class BulkUpdateMediaParams(BaseModel):
"""Parameters for bulk updating media items"""
media_ids: list[int] = Field(
..., min_length=1, max_length=100, description="List of media IDs to update (max 100)"
)
updates: dict[str, Any] = Field(
..., description="Fields to update (alt_text, title, caption, description)"
)
@classmethod
@field_validator("media_ids")
def validate_media_ids(cls, v):
"""Ensure all IDs are positive"""
if any(id <= 0 for id in v):
raise ValueError("All media IDs must be positive integers")
return v
@classmethod
@field_validator("updates")
def validate_updates(cls, v):
"""Validate update fields are allowed"""
allowed_fields = {"title", "alt_text", "caption", "description", "meta"}
invalid_fields = set(v.keys()) - allowed_fields
if invalid_fields:
raise ValueError(f"Invalid update fields: {', '.join(invalid_fields)}")
return v
class BulkDeleteMediaParams(BaseModel):
"""Parameters for bulk deleting media items"""
media_ids: list[int] = Field(
..., min_length=1, max_length=100, description="List of media IDs to delete (max 100)"
)
force: bool = Field(
default=True, description="Force permanent deletion (media can't be trashed)"
)
@classmethod
@field_validator("media_ids")
def validate_media_ids(cls, v):
"""Ensure all IDs are positive"""
if any(id <= 0 for id in v):
raise ValueError("All media IDs must be positive integers")
return v
class BulkOperationResult(BaseModel):
"""Result of a bulk operation"""
success_count: int = Field(description="Number of successful operations")
failed_count: int = Field(description="Number of failed operations")
total: int = Field(description="Total items processed")
failed_ids: list[int] = Field(default=[], description="IDs that failed to process")
errors: list[dict[str, Any]] = Field(default=[], description="Detailed error information")

View File

@@ -0,0 +1,173 @@
"""
Database Operations Schemas
Pydantic models for WordPress database operations including:
- Database export/import
- Backup/restore
- Optimization and repair
- Search and query operations
"""
from typing import Any
from pydantic import BaseModel, Field, field_validator
class DatabaseExportParams(BaseModel):
"""Parameters for database export"""
tables: list[str] | None = Field(
default=None, description="Specific tables to export (default: all tables)"
)
exclude_tables: list[str] | None = Field(
default=None, description="Tables to exclude from export"
)
add_drop_table: bool = Field(default=True, description="Include DROP TABLE statements")
@classmethod
@field_validator("tables", "exclude_tables")
def validate_table_names(cls, v):
"""Validate table names - no special characters"""
if v:
for table in v:
if not table.replace("_", "").isalnum():
raise ValueError(f"Invalid table name: {table}")
return v
class DatabaseImportParams(BaseModel):
"""Parameters for database import"""
file_path: str | None = Field(default=None, description="Path to SQL file on server")
url: str | None = Field(default=None, description="URL to download SQL file from")
skip_optimization: bool = Field(
default=False, description="Skip database optimization after import"
)
@classmethod
@field_validator("url")
def validate_url(cls, v):
"""Validate URL format"""
if v and not v.startswith(("http://", "https://")):
raise ValueError("URL must start with http:// or https://")
return v
class DatabaseBackupParams(BaseModel):
"""Parameters for creating database backup"""
description: str | None = Field(
default=None, max_length=255, description="Optional description for this backup"
)
compress: bool = Field(default=True, description="Compress backup with gzip")
include_uploads: bool = Field(
default=False, description="Also backup wp-content/uploads directory"
)
class DatabaseRestoreParams(BaseModel):
"""Parameters for restoring database"""
backup_id: str | None = Field(default=None, description="Backup ID to restore")
timestamp: str | None = Field(
default=None, description="Backup timestamp (alternative to backup_id)"
)
confirm: bool = Field(default=False, description="Confirmation required (safety check)")
@classmethod
@field_validator("confirm")
def validate_confirmation(cls, v):
"""Require explicit confirmation for restore"""
if not v:
raise ValueError("Confirmation required: set confirm=true")
return v
class DatabaseSearchParams(BaseModel):
"""Parameters for searching database"""
search_string: str = Field(
..., min_length=1, max_length=255, description="String to search for in database"
)
tables: list[str] | None = Field(
default=None, description="Specific tables to search (default: all tables)"
)
regex: bool = Field(default=False, description="Use regex pattern matching")
case_sensitive: bool = Field(default=False, description="Case-sensitive search")
max_results: int = Field(default=100, ge=1, le=1000, description="Maximum results to return")
class DatabaseQueryParams(BaseModel):
"""Parameters for executing SQL query"""
query: str = Field(
..., min_length=1, max_length=10000, description="SQL query to execute (SELECT only)"
)
max_rows: int = Field(default=1000, ge=1, le=10000, description="Maximum rows to return")
@classmethod
@field_validator("query")
def validate_query(cls, v):
"""
Validate query is safe (read-only SELECT)
Security: Only allow SELECT, SHOW, DESCRIBE statements
Prevent: INSERT, UPDATE, DELETE, DROP, ALTER, CREATE, etc.
"""
query_upper = v.strip().upper()
# Allowed statement types
allowed_starts = ("SELECT", "SHOW", "DESCRIBE", "DESC", "EXPLAIN")
if not any(query_upper.startswith(cmd) for cmd in allowed_starts):
raise ValueError("Only SELECT, SHOW, DESCRIBE, and EXPLAIN queries allowed")
# Forbidden keywords (prevent nested destructive queries)
forbidden = [
"INSERT",
"UPDATE",
"DELETE",
"DROP",
"ALTER",
"CREATE",
"TRUNCATE",
"REPLACE",
"GRANT",
"REVOKE",
]
for keyword in forbidden:
if keyword in query_upper:
raise ValueError(f"Forbidden keyword in query: {keyword}")
return v
class DatabaseSizeResponse(BaseModel):
"""Response model for database size information"""
total_size_mb: float = Field(description="Total database size in MB")
tables: list[dict[str, Any]] = Field(description="List of tables with size information")
row_count: int = Field(description="Total row count across all tables")
class DatabaseTableInfo(BaseModel):
"""Information about a database table"""
name: str
engine: str
rows: int
data_size_mb: float
index_size_mb: float
total_size_mb: float
collation: str
class DatabaseRepairResult(BaseModel):
"""Result of database repair operation"""
table: str
status: str # 'OK', 'Repaired', 'Failed'
message: str | None = None
class DatabaseBackupInfo(BaseModel):
"""Information about a database backup"""
backup_id: str
timestamp: str
size_mb: float
compressed: bool
description: str | None = None
location: str
tables_count: int

View File

@@ -0,0 +1,140 @@
"""
System Operations Schemas
Pydantic models for WordPress system operations including:
- System information
- Disk usage
- Cron management
- Cache operations
- Error logs
"""
from typing import Any
from pydantic import BaseModel, Field, field_validator
class SystemInfoResponse(BaseModel):
"""Comprehensive system information"""
php_version: str = Field(description="PHP version")
mysql_version: str = Field(description="MySQL/MariaDB version")
wordpress_version: str = Field(description="WordPress core version")
server_software: str = Field(description="Web server software")
memory_limit: str = Field(description="PHP memory limit")
max_execution_time: int = Field(description="Max execution time in seconds")
upload_max_filesize: str = Field(description="Maximum upload file size")
post_max_size: str = Field(description="Maximum POST size")
max_input_vars: int = Field(description="Maximum input variables")
php_extensions: list[str] = Field(default=[], description="Loaded PHP extensions")
wp_debug: bool = Field(description="WP_DEBUG constant status")
wp_debug_log: bool = Field(description="WP_DEBUG_LOG constant status")
multisite: bool = Field(description="WordPress Multisite enabled")
active_plugins: int = Field(description="Number of active plugins")
active_theme: str = Field(description="Active theme name")
class PHPInfoResponse(BaseModel):
"""PHP configuration details"""
version: str
sapi: str = Field(description="Server API (e.g., fpm-fcgi, apache2handler)")
extensions: list[str] = Field(description="Loaded PHP extensions")
ini_settings: dict[str, str] = Field(description="Important php.ini settings")
disabled_functions: list[str] = Field(default=[], description="Disabled PHP functions")
class DiskUsageResponse(BaseModel):
"""Disk usage statistics"""
total_size_mb: float = Field(description="Total disk usage in MB")
wordpress_size_mb: float = Field(description="WordPress installation size")
uploads_size_mb: float = Field(description="wp-content/uploads size")
plugins_size_mb: float = Field(description="wp-content/plugins size")
themes_size_mb: float = Field(description="wp-content/themes size")
database_size_mb: float = Field(description="Database size")
available_space_mb: float | None = Field(
default=None, description="Available disk space (if accessible)"
)
breakdown: dict[str, float] = Field(default={}, description="Detailed breakdown by directory")
class CronEvent(BaseModel):
"""WordPress cron event information"""
hook: str = Field(description="Cron hook name")
timestamp: int = Field(description="Unix timestamp of next run")
schedule: str = Field(description="Schedule type (hourly, daily, etc.)")
interval: int | None = Field(
default=None, description="Interval in seconds for recurring events"
)
args: list[Any] = Field(default=[], description="Arguments passed to the hook")
class CronListResponse(BaseModel):
"""List of all cron events"""
events: list[CronEvent] = Field(description="List of cron events")
total: int = Field(description="Total number of events")
schedules: dict[str, dict[str, Any]] = Field(default={}, description="Available cron schedules")
class CronRunParams(BaseModel):
"""Parameters for manually running a cron job"""
hook: str = Field(..., min_length=1, max_length=255, description="Cron hook name to execute")
args: list[Any] = Field(default=[], description="Optional arguments to pass to the hook")
@classmethod
@field_validator("hook")
def validate_hook(cls, v):
"""Validate hook name format"""
# Hook names should be alphanumeric with underscores, hyphens
if not v.replace("_", "").replace("-", "").replace(".", "").isalnum():
raise ValueError(
"Hook name can only contain letters, numbers, underscores, " "hyphens, and dots"
)
return v
class ErrorLogParams(BaseModel):
"""Parameters for retrieving error log"""
lines: int = Field(
default=100, ge=1, le=1000, description="Number of log lines to retrieve (max 1000)"
)
filter: str | None = Field(
default=None, description="Filter logs by keyword (case-insensitive)"
)
level: str | None = Field(
default=None, description="Filter by error level (error, warning, notice)"
)
@classmethod
@field_validator("level")
def validate_level(cls, v):
"""Validate error level"""
if v and v.lower() not in ["error", "warning", "notice", "fatal"]:
raise ValueError("level must be: error, warning, notice, or fatal")
return v.lower() if v else v
class ErrorLogEntry(BaseModel):
"""Single error log entry"""
timestamp: str = Field(description="Error timestamp")
level: str = Field(description="Error level (error, warning, etc.)")
message: str = Field(description="Error message")
file: str | None = Field(default=None, description="File where error occurred")
line: int | None = Field(default=None, description="Line number")
class ErrorLogResponse(BaseModel):
"""Error log retrieval response"""
entries: list[ErrorLogEntry] = Field(description="Log entries")
total_lines: int = Field(description="Total lines in log file")
filtered_lines: int = Field(description="Number of entries returned")
log_size_mb: float = Field(description="Log file size in MB")
class CacheStats(BaseModel):
"""Cache statistics"""
cache_type: str = Field(description="Type of object cache (Redis, Memcached, etc.)")
cache_enabled: bool = Field(description="Is persistent object cache enabled")
transients_count: int = Field(description="Number of transients in database")
opcache_enabled: bool = Field(description="Is OPcache enabled")
opcache_memory_usage: dict[str, Any] | None = Field(
default=None, description="OPcache memory usage statistics"
)