Fixes test_dashboard_v2.py::test_spa_dist_dir_exists_as_placeholder.
Directory must exist for package_data to include it; Docker build
populates it via npm run build.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Settings fixes:
- MAX_SITES_PER_USER, USER_RATE_LIMIT_PER_MIN/HR now read from DB settings
table (DB > ENV > default), so dashboard/settings changes apply without
restart. Sync cache refreshed on every save or delete.
- /api/me reports the live DB value for max_sites_per_user.
Admin improvements:
- Admin users bypass per-user rate limiting entirely (role=admin or ADMIN_EMAILS).
- Admin Overview now shows platform stats: registered users, new users (7d),
total user sites, available tools.
Plugin cleanup:
- Appwrite and Directus plugins removed from the active registry (8 plugins
now: WordPress, WooCommerce, WordPress Specialist, Gitea, n8n, Supabase,
OpenPanel, Coolify). Plugin code is retained for future re-enabling.
- Settings page plugin visibility list updated to match.
Mobile onboarding:
- Stepper steps on narrow viewports stack vertically with correct full border
and rounded corners on each step.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Added update_webhook and delete_label tools (58 total Gitea tools)
- 97 unit tests (test_gitea_plugin.py)
- Gitea now public for all users (DEFAULT_PUBLIC_PLUGINS)
- Fixed merge_pull_request optional field handling
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove env-based site discovery from SiteManager and ProjectManager
- Unify admin and user OAuth Clients into single role-based page
- Update all documentation to reflect DB-based site management
- Clean up env.example, README, ARCHITECTURE docs
- Improve Projects page empty state with link to My Sites
- Remove obsolete env discovery tests
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
OpenPanel product analytics plugin fully reviewed, tested, and published.
Works with both self-hosted and cloud (openpanel.dev) instances.
- 42 tools: event tracking, data export, analytics, project/client management
- All tools use public REST APIs (Track, Export, Insights, Manage)
- Client modes: write (tracking), read (analytics), root (full access)
- Service page with description, setup notes, WordPress plugin download
- Dynamic URL hints in Add Site form
- 62 unit tests
- ENABLED_PLUGINS default now includes openpanel
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- fix(seo): REST API namespace seo-api-bridge/v1 → airano-mcp-seo-bridge/v1
- fix(config): add transport type field (streamableHttp/http) to config snippets
- feat(dashboard): support section for OAuth users, connect page guidance
- docs: hosted option, test count 481, WP plugin link, OAuth env vars, per-user endpoints
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Three bugs fixed for social-login users connecting Claude.ai via OAuth:
1. User OAuth clients now allow 'admin' scope by default — previously
defaulted to ['read', 'write'], causing invalid_scope when Claude.ai
requests 'admin' scope during authorization.
2. Fix JWT tokens with 'aud' claim being rejected by middleware — when
Claude.ai sends RFC 8707 resource parameter, the issued JWT gets an
aud claim. validate_access_token() now sets verify_aud=False to
prevent PyJWT InvalidAudienceError from silently marking valid tokens
as invalid in _is_valid_token().
3. Fix NameError in user_mcp_handler tools/call scope check — key_info
was only defined in the mhu_ auth path but referenced in tools/call
for both paths. Replaced with key_scopes variable set by both mhu_
and JWT auth paths.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Enable dashboard users (GitHub/Google social login) to approve OAuth
consent without needing to create and paste an API key. Adds mhu_ user
key support, session-based consent with __session__ marker, social login
links on the consent page, and return URL redirect after login.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- SUG-6: Replace auto-closing inline banner with persistent modal on Connect
page — key stays visible until user clicks "Done"
- SUG-4: Filter health_metric_recorded/health_check from project detail activity
- WooCommerce: Accept consumer_key/consumer_secret credentials (preferred) with
username/app_password fallback; fix health check to use WC endpoint and creds
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- BUG-12: ENCRYPTION_KEY validation now exits with sys.exit(1) on invalid key
- BUG-11: WP Advanced health check adds authenticated fallback with auth_valid
- BUG-7: Catch-all GET route serves styled 404 HTML instead of plain text
- BUG-10: Recent Activity fetches extra entries before filtering, fixes None project
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Bug fixes (ordered by priority):
- BUG-14 (P1): Fix ImportError in per-user MCP endpoint
- BUG-8 (P2): Raise clear error when PUBLIC_URL missing for OAuth
- BUG-12 (P3): Validate ENCRYPTION_KEY at startup
- BUG-13 (P4): Handle stale JWT gracefully on site creation
- BUG-11 (P5): Add auth validation to WordPress health checks
- BUG-15 (P6): Fix copy button showing Python repr (dict method shadow)
- BUG-1 (P7): Dynamic version from pyproject.toml instead of hardcoded
- BUG-5 (P8): Fix server mode default (sse → streamable-http)
- BUG-9 (P9): Plugin-specific example tools in endpoint instructions
- BUG-4 (P10): Fix settings page sidebar RBAC (session type mismatch)
- BUG-6 (P11): Show real plugin descriptions instead of 'No description'
- BUG-2 (P12): Remove stale 'phase: X.3' from system info
- BUG-10 (P13): Guard timestamps against None in Recent Activity
- BUG-3 (P14): Guard timestamps against None in audit logs
- BUG-7 (P15): Styled 404 page instead of plain text
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Major release introducing the Live Platform architecture:
- SQLite database backend with async operations and migrations (E.1)
- AES-256-GCM credential encryption with HKDF key derivation (E.1)
- OAuth Social Login with GitHub and Google (E.2)
- Site management API with encrypted credential storage (E.3)
- Per-user MCP endpoints at /u/{user_id}/{alias}/mcp (E.3)
- User API keys with bcrypt hashing (E.3)
- Auto-generated config snippets for 5 MCP clients (E.3)
- Dashboard: dark/light mode, RBAC, My Sites, Connect page
- Active background health checks
- 452 tests (up from 303), all passing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
WordPress client improvements:
- Add ConnectionError exception for network-level failures
- Differentiate DNS, SSL, timeout, and connection refused errors
- Add retry with exponential backoff for transient errors (502, 503, 504, 429)
- Auth/config errors are never retried
- Add request timeout (30s default)
Health check improvements:
- Detect REST API disabled (403/404 on /wp-json)
- Classify errors by type: dns_failure, ssl_error, timeout, connection_refused
Bare except cleanup:
- Replaced all bare except: with except Exception: across 12 files
Tests: 303 passed (13 new tests for error handling)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- routes.py: fallback reads from importlib.metadata instead of hardcoded
- login.html: remove hardcoded default version
- README: use dynamic GitHub Release badge from shields.io
- DOCKER_README: remove hardcoded version string
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The health monitor's _basic_site_health_check() used split("_", 1) to parse
project IDs like "wordpress_advanced_site1", incorrectly yielding
plugin_type="wordpress" and site_id="advanced_site1". Now uses SiteManager's
list_all_sites() for proper full_id lookup, and creates a temporary plugin
instance for proper health checks (REST API, WP-CLI) instead of basic HTTP.
Also fixes the same split bug in SiteManager.get_effective_path_suffix().
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- WP Advanced health_check uses aiohttp to /wp-json/ directly
- SEO Bridge admin notice only on Plugins page
- SEO Bridge README.md consolidated, changelog complete
- OpenPanel Self-Hosted README.md created
- Dashboard sidebar uses actual logo.svg
- docker-compose: expose instead of ports for Coolify
- README: version badge, wordpress_advanced endpoint, env var table
- Docs: SSE references fixed to streamable-http
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Health monitor now uses SiteManager for complete site discovery
- SEO Bridge: GPLv2+ license, Tested up to 6.9, fix escaping
- OpenPanel: fix wp_unslash, reduce tags, update branding
- Add logo.svg favicon, static file serving, plugin ZIPs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
CI: Fix black formatting in core/site_registry.py
Code: list_projects uses SiteManager, WP Advanced health uses REST API
Docs: Fix transport types, endpoint guide, env var reference for all plugins
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Code fixes:
- Rename "Coolify Admin" to "MCP Hub Admin" in endpoints
- Enrich list_projects with alias and endpoint URL
- Downgrade OAuth InvalidTokenError log from WARNING to DEBUG
- Add 7 missing health tools to /system/mcp endpoint (now 24 tools)
- Remove "Phase 7.2" from health monitor log
- Fix WP Advanced health check to pass with REST API only
- Downgrade duplicate alias warnings to INFO
Documentation fixes:
- Document SSE transport and Bearer auth requirement
- Recommend plugin-specific endpoints to save tokens
- Document plugin vs project endpoint differences
- WordPress plugin requirements for SEO/WP-CLI tools
- Docker socket mounting guide for WP-CLI
- Mark MASTER_API_KEY as recommended (auto-generates temp key)
- Env var naming convention with prefix table
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ProjectManager and SiteManager now skip env vars that belong to a more
specific plugin type (e.g. WORDPRESS_ADVANCED_*) when discovering sites
for a shorter prefix (WORDPRESS_). This prevents ghost projects, ERROR
logs, and false health alerts on startup.
Also downgrades Docker socket errors in WP-CLI to warnings — if Docker
socket is not mounted, WP-CLI features are silently unavailable instead
of logging ERROR and triggering health alerts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previously any Bearer token (even invalid) passed the HTTP middleware and
got a session with access to tools/list and resources/list. Now the
OAuthRequiredMiddleware validates tokens against master key, API keys,
and OAuth JWT before allowing initialize.
Also fixes:
- WordPress Advanced env prefix: WORDPRESS_ → WORDPRESS_ADVANCED_ in docs
- Bump version to 3.0.1
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When no MASTER_API_KEY env var is set, AuthManager generates a temp key
but DashboardAuth didn't know about it. Now validate_api_key() also
checks AuthManager as a fallback, so temp key login works for first-time
Docker users.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
validate_key() requires project_id argument but was called without it
in dashboard auth. Fixed by passing skip_project_check=True.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Show full temporary API key in logs (not masked) so users can log in
- Redirect root URL / to /dashboard (was 404)
- Add setup guidance and docs link to login page
- Make footer version dynamic (read from pyproject.toml)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Templates were at project root (templates/) which is outside the Python
package, so `pip install mcphub-server` would not include them. Moved to
core/templates/ and updated path references in server.py and
core/dashboard/routes.py. Also added py-modules for server.py and
server_multi.py to pyproject.toml.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Both JSONStorage and ClientRegistry now use ./data when /app doesn't
exist (Docker vs local/CI environments).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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>