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,68 @@
"""
WordPress Pydantic Schemas
Type-safe validation schemas for WordPress data structures.
Part of Option B clean architecture refactoring.
"""
from plugins.wordpress.schemas.common import (
ErrorResponse,
PaginationParams,
StatusFilter,
SuccessResponse,
)
from plugins.wordpress.schemas.media import MediaBase, MediaResponse, MediaUpdate, MediaUpload
from plugins.wordpress.schemas.order import (
OrderBase,
OrderCreate,
OrderLineItem,
OrderResponse,
OrderUpdate,
)
from plugins.wordpress.schemas.post import PostBase, PostCreate, PostResponse, PostUpdate
from plugins.wordpress.schemas.product import (
ProductBase,
ProductCategory,
ProductCreate,
ProductResponse,
ProductUpdate,
ProductVariation,
)
from plugins.wordpress.schemas.seo import SEOData, SEOUpdate
# Note: Database, Bulk, and System schemas moved to wordpress_advanced plugin
__all__ = [
# Common
"PaginationParams",
"StatusFilter",
"ErrorResponse",
"SuccessResponse",
# Posts
"PostBase",
"PostCreate",
"PostUpdate",
"PostResponse",
# Media
"MediaBase",
"MediaUpload",
"MediaUpdate",
"MediaResponse",
# Products
"ProductBase",
"ProductCreate",
"ProductUpdate",
"ProductResponse",
"ProductCategory",
"ProductVariation",
# Orders
"OrderBase",
"OrderCreate",
"OrderUpdate",
"OrderResponse",
"OrderLineItem",
# SEO
"SEOData",
"SEOUpdate",
# Note: Database, Bulk, and System schemas moved to wordpress_advanced plugin
]

View File

@@ -0,0 +1,45 @@
"""
Common Pydantic Schemas
Shared validation schemas used across WordPress handlers.
"""
from typing import Any
from pydantic import BaseModel, ConfigDict, Field, field_validator
class PaginationParams(BaseModel):
"""Pagination parameters for list endpoints"""
per_page: int = Field(default=10, ge=1, le=100, description="Number of items per page (1-100)")
page: int = Field(default=1, ge=1, description="Page number (starts at 1)")
model_config = ConfigDict(extra="forbid")
class StatusFilter(BaseModel):
"""Status filter for posts/pages/products"""
status: str = Field(default="any", description="Filter by status")
@classmethod
@field_validator("status")
def validate_status(cls, v):
allowed = ["publish", "draft", "pending", "private", "any", "future", "trash"]
if v not in allowed:
raise ValueError(f"Status must be one of: {', '.join(allowed)}")
return v
class ErrorResponse(BaseModel):
"""Standard error response"""
error: bool = Field(default=True)
message: str = Field(..., description="Error message")
code: str | None = Field(None, description="Error code")
details: dict[str, Any] | None = Field(None, description="Additional error details")
class SuccessResponse(BaseModel):
"""Standard success response"""
success: bool = Field(default=True)
message: str = Field(..., description="Success message")
data: dict[str, Any] | None = Field(None, description="Response data")

View File

@@ -0,0 +1,56 @@
"""
Media Pydantic Schemas
Validation schemas for WordPress media library operations.
"""
from pydantic import BaseModel, ConfigDict, Field, HttpUrl, field_validator
class MediaBase(BaseModel):
"""Base media schema"""
model_config = ConfigDict(extra="allow")
title: str | None = Field(None, description="Media title")
alt_text: str | None = Field(None, description="Alternative text")
caption: str | None = Field(None, description="Media caption")
description: str | None = Field(None, description="Media description")
class MediaUpload(MediaBase):
"""Schema for uploading media from URL"""
url: HttpUrl = Field(..., description="Source URL of the media file")
filename: str | None = Field(None, description="Desired filename")
@classmethod
@field_validator("filename")
def validate_filename(cls, v):
if v is not None:
# Basic filename validation
if "/" in v or "\\" in v:
raise ValueError("Filename cannot contain path separators")
if len(v) > 255:
raise ValueError("Filename too long (max 255 characters)")
return v
class MediaUpdate(MediaBase):
"""Schema for updating media metadata"""
# All fields optional for updates
pass
class MediaResponse(BaseModel):
"""Schema for media response data"""
model_config = ConfigDict(extra="allow")
id: int
title: str
alt_text: str
caption: str
description: str
mime_type: str
media_type: str
source_url: str
link: str
date: str

View File

@@ -0,0 +1,152 @@
"""
Order Pydantic Schemas
Validation schemas for WooCommerce orders and related entities.
"""
from typing import Any
from pydantic import BaseModel, ConfigDict, EmailStr, Field, field_validator
class OrderLineItem(BaseModel):
"""Schema for order line item"""
model_config = ConfigDict(extra="allow")
product_id: int = Field(..., description="Product ID")
quantity: int = Field(default=1, ge=1, description="Quantity")
variation_id: int | None = Field(None, description="Variation ID")
subtotal: str | None = Field(None, description="Line subtotal")
total: str | None = Field(None, description="Line total")
class ShippingAddress(BaseModel):
"""Schema for shipping address"""
model_config = ConfigDict(extra="allow")
first_name: str | None = Field(None, description="First name")
last_name: str | None = Field(None, description="Last name")
company: str | None = Field(None, description="Company name")
address_1: str | None = Field(None, description="Address line 1")
address_2: str | None = Field(None, description="Address line 2")
city: str | None = Field(None, description="City")
state: str | None = Field(None, description="State/Province")
postcode: str | None = Field(None, description="Postal code")
country: str | None = Field(None, description="Country code (ISO 3166-1 alpha-2)")
class BillingAddress(ShippingAddress):
"""Schema for billing address (extends shipping)"""
email: EmailStr | None = Field(None, description="Email address")
phone: str | None = Field(None, description="Phone number")
class OrderBase(BaseModel):
"""Base order schema"""
status: str | None = Field("pending", description="Order status")
customer_id: int | None = Field(None, description="Customer user ID")
billing: BillingAddress | None = Field(None, description="Billing address")
shipping: ShippingAddress | None = Field(None, description="Shipping address")
payment_method: str | None = Field(None, description="Payment method ID")
payment_method_title: str | None = Field(None, description="Payment method title")
transaction_id: str | None = Field(None, description="Transaction ID")
customer_note: str | None = Field(None, description="Customer note")
line_items: list[OrderLineItem] | None = Field(None, description="Order line items")
shipping_lines: list[dict[str, Any]] | None = Field(None, description="Shipping lines")
fee_lines: list[dict[str, Any]] | None = Field(None, description="Fee lines")
coupon_lines: list[dict[str, Any]] | None = Field(None, description="Coupon lines")
model_config = ConfigDict(extra="allow")
@classmethod
@field_validator("status")
def validate_status(cls, v):
if v is not None:
allowed = [
"pending",
"processing",
"on-hold",
"completed",
"cancelled",
"refunded",
"failed",
"trash",
]
if v not in allowed:
raise ValueError(f"Status must be one of: {', '.join(allowed)}")
return v
class OrderCreate(OrderBase):
"""Schema for creating a new order"""
line_items: list[OrderLineItem] = Field(
..., min_length=1, description="Order line items (required)"
)
model_config = ConfigDict(extra="allow")
class OrderUpdate(OrderBase):
"""Schema for updating an existing order"""
# All fields optional for updates
pass
class OrderStatusUpdate(BaseModel):
"""Schema for updating order status"""
status: str = Field(..., description="New order status")
@classmethod
@field_validator("status")
def validate_status(cls, v):
allowed = [
"pending",
"processing",
"on-hold",
"completed",
"cancelled",
"refunded",
"failed",
]
if v not in allowed:
raise ValueError(f"Status must be one of: {', '.join(allowed)}")
return v
class OrderResponse(BaseModel):
"""Schema for order response data"""
model_config = ConfigDict(extra="allow")
id: int
number: str
status: str
total: str
date_created: str
billing: dict[str, Any]
shipping: dict[str, Any]
line_items: list[dict[str, Any]]
class CustomerBase(BaseModel):
"""Base customer schema"""
model_config = ConfigDict(extra="allow")
email: EmailStr | None = Field(None, description="Customer email")
first_name: str | None = Field(None, description="First name")
last_name: str | None = Field(None, description="Last name")
username: str | None = Field(None, description="Username")
billing: BillingAddress | None = Field(None, description="Billing address")
shipping: ShippingAddress | None = Field(None, description="Shipping address")
class CustomerCreate(CustomerBase):
"""Schema for creating a new customer"""
email: EmailStr = Field(..., description="Customer email (required)")
model_config = ConfigDict(extra="allow")
class CustomerUpdate(CustomerBase):
"""Schema for updating an existing customer"""
# All fields optional for updates
pass

View File

@@ -0,0 +1,102 @@
"""
Post Pydantic Schemas
Validation schemas for WordPress posts, pages, and custom post types.
"""
from pydantic import BaseModel, ConfigDict, Field, field_validator
class PostBase(BaseModel):
"""Base post schema with common fields"""
title: str | None = Field(None, description="Post title")
content: str | None = Field(None, description="Post content (HTML)")
excerpt: str | None = Field(None, description="Post excerpt")
status: str | None = Field("draft", description="Post status")
slug: str | None = Field(None, description="Post slug (URL-friendly)")
author: int | None = Field(None, description="Author user ID")
featured_media: int | None = Field(None, description="Featured image media ID")
comment_status: str | None = Field(None, description="Comment status (open/closed)")
ping_status: str | None = Field(None, description="Ping status (open/closed)")
format: str | None = Field(None, description="Post format")
meta: dict | None = Field(None, description="Post meta fields")
sticky: bool | None = Field(None, description="Sticky post flag")
categories: list[int] | None = Field(None, description="Category IDs")
tags: list[int] | None = Field(None, description="Tag IDs")
model_config = ConfigDict(extra="allow") # Allow additional fields for custom post types
@classmethod
@field_validator("status")
def validate_status(cls, v):
if v is not None:
allowed = ["publish", "draft", "pending", "private", "future"]
if v not in allowed:
raise ValueError(f"Status must be one of: {', '.join(allowed)}")
return v
@classmethod
@field_validator("comment_status", "ping_status")
def validate_comment_ping_status(cls, v):
if v is not None:
allowed = ["open", "closed"]
if v not in allowed:
raise ValueError("Status must be 'open' or 'closed'")
return v
class PostCreate(PostBase):
"""Schema for creating a new post"""
title: str = Field(..., min_length=1, description="Post title (required)")
content: str = Field(..., description="Post content (required)")
model_config = ConfigDict(extra="allow")
class PostUpdate(PostBase):
"""Schema for updating an existing post"""
# All fields optional for updates
pass
class PostResponse(BaseModel):
"""Schema for post response data"""
model_config = ConfigDict(extra="allow")
id: int
title: str
content: str
excerpt: str
status: str
slug: str
link: str
date: str
modified: str
author: int
featured_media: int
categories: list[int]
tags: list[int]
class PageCreate(PostCreate):
"""Schema for creating a new page"""
parent: int | None = Field(None, description="Parent page ID")
menu_order: int | None = Field(None, description="Menu order")
template: str | None = Field(None, description="Page template")
class PageUpdate(PostUpdate):
"""Schema for updating an existing page"""
parent: int | None = Field(None, description="Parent page ID")
menu_order: int | None = Field(None, description="Menu order")
template: str | None = Field(None, description="Page template")
class CustomPostCreate(PostCreate):
"""Schema for creating custom post types"""
post_type: str = Field(..., description="Custom post type")
class CustomPostUpdate(PostUpdate):
"""Schema for updating custom post types"""
pass

View File

@@ -0,0 +1,140 @@
"""
Product Pydantic Schemas
Validation schemas for WooCommerce products and related entities.
"""
from typing import Any
from pydantic import BaseModel, ConfigDict, Field, field_validator
class ProductBase(BaseModel):
"""Base product schema"""
name: str | None = Field(None, description="Product name")
type: str | None = Field("simple", description="Product type")
status: str | None = Field("draft", description="Product status")
featured: bool | None = Field(False, description="Featured product flag")
catalog_visibility: str | None = Field("visible", description="Catalog visibility")
description: str | None = Field(None, description="Product description (HTML)")
short_description: str | None = Field(None, description="Short description (HTML)")
sku: str | None = Field(None, description="Stock Keeping Unit")
regular_price: str | None = Field(None, description="Regular price")
sale_price: str | None = Field(None, description="Sale price")
manage_stock: bool | None = Field(False, description="Manage stock flag")
stock_quantity: int | None = Field(None, description="Stock quantity")
stock_status: str | None = Field("instock", description="Stock status")
weight: str | None = Field(None, description="Product weight")
length: str | None = Field(None, description="Product length")
width: str | None = Field(None, description="Product width")
height: str | None = Field(None, description="Product height")
categories: list[dict[str, Any]] | None = Field(None, description="Product categories")
tags: list[dict[str, Any]] | None = Field(None, description="Product tags")
images: list[dict[str, Any]] | None = Field(None, description="Product images")
attributes: list[dict[str, Any]] | None = Field(None, description="Product attributes")
model_config = ConfigDict(extra="allow")
@classmethod
@field_validator("type")
def validate_type(cls, v):
if v is not None:
allowed = ["simple", "grouped", "external", "variable", "variation"]
if v not in allowed:
raise ValueError(f"Type must be one of: {', '.join(allowed)}")
return v
@classmethod
@field_validator("status")
def validate_status(cls, v):
if v is not None:
allowed = ["draft", "pending", "private", "publish"]
if v not in allowed:
raise ValueError(f"Status must be one of: {', '.join(allowed)}")
return v
@classmethod
@field_validator("catalog_visibility")
def validate_visibility(cls, v):
if v is not None:
allowed = ["visible", "catalog", "search", "hidden"]
if v not in allowed:
raise ValueError(f"Visibility must be one of: {', '.join(allowed)}")
return v
@classmethod
@field_validator("stock_status")
def validate_stock_status(cls, v):
if v is not None:
allowed = ["instock", "outofstock", "onbackorder"]
if v not in allowed:
raise ValueError(f"Stock status must be one of: {', '.join(allowed)}")
return v
class ProductCreate(ProductBase):
"""Schema for creating a new product"""
name: str = Field(..., min_length=1, description="Product name (required)")
type: str = Field("simple", description="Product type")
class ProductUpdate(ProductBase):
"""Schema for updating an existing product"""
# All fields optional for updates
pass
class ProductResponse(BaseModel):
"""Schema for product response data"""
model_config = ConfigDict(extra="allow")
id: int
name: str
slug: str
type: str
status: str
featured: bool
regular_price: str
sale_price: str
price: str
stock_status: str
permalink: str
class ProductCategory(BaseModel):
"""Schema for product category"""
model_config = ConfigDict(extra="allow")
name: str = Field(..., description="Category name")
slug: str | None = Field(None, description="Category slug")
parent: int | None = Field(None, description="Parent category ID")
description: str | None = Field(None, description="Category description")
display: str | None = Field("default", description="Display type")
image: dict[str, Any] | None = Field(None, description="Category image")
class ProductVariation(BaseModel):
"""Schema for product variation"""
model_config = ConfigDict(extra="allow")
regular_price: str | None = Field(None, description="Regular price")
sale_price: str | None = Field(None, description="Sale price")
description: str | None = Field(None, description="Variation description")
sku: str | None = Field(None, description="Stock Keeping Unit")
manage_stock: bool | None = Field(False, description="Manage stock flag")
stock_quantity: int | None = Field(None, description="Stock quantity")
stock_status: str | None = Field("instock", description="Stock status")
weight: str | None = Field(None, description="Variation weight")
attributes: list[dict[str, Any]] | None = Field(None, description="Variation attributes")
image: dict[str, Any] | None = Field(None, description="Variation image")
class ProductAttribute(BaseModel):
"""Schema for product attribute"""
model_config = ConfigDict(extra="allow")
name: str = Field(..., description="Attribute name")
slug: str | None = Field(None, description="Attribute slug")
type: str | None = Field("select", description="Attribute type")
order_by: str | None = Field("menu_order", description="Sort order")
has_archives: bool | None = Field(False, description="Enable archives")

View File

@@ -0,0 +1,80 @@
"""
SEO Pydantic Schemas
Validation schemas for SEO plugin data (Yoast, RankMath, etc.).
"""
from pydantic import BaseModel, ConfigDict, Field, field_validator
class SEOData(BaseModel):
"""Schema for SEO data (read)"""
model_config = ConfigDict(extra="allow")
title: str | None = Field(None, description="SEO title")
description: str | None = Field(None, description="Meta description")
keywords: str | None = Field(None, description="Focus keywords")
canonical: str | None = Field(None, description="Canonical URL")
og_title: str | None = Field(None, description="Open Graph title")
og_description: str | None = Field(None, description="Open Graph description")
og_image: str | None = Field(None, description="Open Graph image URL")
twitter_title: str | None = Field(None, description="Twitter card title")
twitter_description: str | None = Field(None, description="Twitter card description")
twitter_image: str | None = Field(None, description="Twitter card image URL")
robots: list[str] | None = Field(None, description="Robots meta tags")
class SEOUpdate(BaseModel):
"""Schema for SEO data updates"""
title: str | None = Field(
None, max_length=60, description="SEO title (max 60 chars recommended)"
)
description: str | None = Field(
None, max_length=160, description="Meta description (max 160 chars recommended)"
)
keywords: str | None = Field(None, description="Focus keywords (comma-separated)")
canonical: str | None = Field(None, description="Canonical URL")
og_title: str | None = Field(None, description="Open Graph title")
og_description: str | None = Field(None, description="Open Graph description")
og_image: str | None = Field(None, description="Open Graph image URL")
twitter_title: str | None = Field(None, description="Twitter card title")
twitter_description: str | None = Field(None, description="Twitter card description")
twitter_image: str | None = Field(None, description="Twitter card image URL")
robots_index: bool | None = Field(None, description="Allow search engines to index")
robots_follow: bool | None = Field(None, description="Allow search engines to follow links")
model_config = ConfigDict(extra="allow")
@classmethod
@field_validator("title")
def validate_title_length(cls, v):
if v and len(v) > 70:
# Warning, not error - allow but discourage
pass
return v
@classmethod
@field_validator("description")
def validate_description_length(cls, v):
if v and len(v) > 200:
# Warning, not error - allow but discourage
pass
return v
class YoastSEO(SEOData):
"""Yoast SEO specific data"""
model_config = ConfigDict(extra="allow")
yoast_wpseo_focuskw: str | None = Field(None, description="Yoast focus keyword")
yoast_wpseo_metadesc: str | None = Field(None, description="Yoast meta description")
yoast_wpseo_title: str | None = Field(None, description="Yoast SEO title")
class RankMathSEO(SEOData):
"""RankMath SEO specific data"""
model_config = ConfigDict(extra="allow")
rank_math_focus_keyword: str | None = Field(None, description="RankMath focus keyword")
rank_math_description: str | None = Field(None, description="RankMath meta description")
rank_math_title: str | None = Field(None, description="RankMath SEO title")