QuickLab-MCP 0.1.0__tar.gz → 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/PKG-INFO +61 -15
  2. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/README.md +60 -14
  3. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/pyproject.toml +1 -1
  4. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/QuickLab_MCP.egg-info/PKG-INFO +61 -15
  5. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/__init__.py +1 -1
  6. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/application/datasets/service.py +3 -1
  7. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/application/datasets/validator.py +9 -3
  8. quicklab_mcp-0.2.0/src/ml_mcp/application/models/catalog_seed.py +294 -0
  9. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/application/models/service.py +17 -5
  10. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/application/projects/service.py +1 -3
  11. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/config/settings.py +23 -11
  12. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/domain/errors/base.py +3 -1
  13. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/infrastructure/object_storage/s3.py +69 -34
  14. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/infrastructure/postgres/repositories/projects.py +4 -4
  15. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/infrastructure/postgres/session.py +1 -1
  16. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/infrastructure/telemetry/otel.py +6 -4
  17. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/server/app.py +12 -2
  18. quicklab_mcp-0.1.0/src/ml_mcp/application/models/catalog_seed.py +0 -131
  19. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/setup.cfg +0 -0
  20. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/QuickLab_MCP.egg-info/SOURCES.txt +0 -0
  21. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/QuickLab_MCP.egg-info/dependency_links.txt +0 -0
  22. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/QuickLab_MCP.egg-info/entry_points.txt +0 -0
  23. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/QuickLab_MCP.egg-info/requires.txt +0 -0
  24. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/QuickLab_MCP.egg-info/top_level.txt +0 -0
  25. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/application/__init__.py +0 -0
  26. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/application/analysis/__init__.py +0 -0
  27. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/application/analysis/diagnostics.py +0 -0
  28. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/application/analysis/service.py +0 -0
  29. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/application/artifacts/__init__.py +0 -0
  30. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/application/artifacts/service.py +0 -0
  31. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/application/datasets/__init__.py +0 -0
  32. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/application/experiments/__init__.py +0 -0
  33. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/application/experiments/service.py +0 -0
  34. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/application/models/__init__.py +0 -0
  35. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/application/projects/__init__.py +0 -0
  36. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/config/__init__.py +0 -0
  37. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/domain/__init__.py +0 -0
  38. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/domain/errors/__init__.py +0 -0
  39. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/domain/errors/codes.py +0 -0
  40. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/domain/policies/__init__.py +0 -0
  41. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/domain/policies/rbac.py +0 -0
  42. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/domain/policies/tenant_isolation.py +0 -0
  43. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/domain/policies/tool_policy.py +0 -0
  44. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/domain/value_objects/__init__.py +0 -0
  45. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/domain/value_objects/dataset.py +0 -0
  46. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/domain/value_objects/experiment.py +0 -0
  47. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/domain/value_objects/model.py +0 -0
  48. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/infrastructure/__init__.py +0 -0
  49. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/infrastructure/object_storage/__init__.py +0 -0
  50. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/infrastructure/postgres/__init__.py +0 -0
  51. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/infrastructure/postgres/base.py +0 -0
  52. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/infrastructure/postgres/models.py +0 -0
  53. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/infrastructure/postgres/repositories/__init__.py +0 -0
  54. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/infrastructure/postgres/repositories/artifacts.py +0 -0
  55. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/infrastructure/postgres/repositories/audit.py +0 -0
  56. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/infrastructure/postgres/repositories/datasets.py +0 -0
  57. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/infrastructure/postgres/repositories/experiments.py +0 -0
  58. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/infrastructure/postgres/repositories/metrics.py +0 -0
  59. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/infrastructure/postgres/repositories/models.py +0 -0
  60. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/infrastructure/postgres/repositories/outbox.py +0 -0
  61. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/infrastructure/queue/__init__.py +0 -0
  62. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/infrastructure/queue/outbox_processor.py +0 -0
  63. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/infrastructure/queue/task_queue.py +0 -0
  64. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/infrastructure/redis/__init__.py +0 -0
  65. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/infrastructure/redis/client.py +0 -0
  66. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/infrastructure/redis/rate_limiter.py +0 -0
  67. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/infrastructure/telemetry/__init__.py +0 -0
  68. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/infrastructure/telemetry/logging.py +0 -0
  69. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/mcp/__init__.py +0 -0
  70. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/mcp/prompts.py +0 -0
  71. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/mcp/resources.py +0 -0
  72. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/mcp/schemas/__init__.py +0 -0
  73. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/mcp/schemas/tools.py +0 -0
  74. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/mcp/tools/__init__.py +0 -0
  75. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/mcp/tools/analysis.py +0 -0
  76. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/mcp/tools/datasets.py +0 -0
  77. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/mcp/tools/discovery.py +0 -0
  78. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/mcp/tools/experiments.py +0 -0
  79. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/mcp/tools/projects.py +0 -0
  80. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/mcp/tools/results.py +0 -0
  81. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/server/__init__.py +0 -0
  82. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/server/auth.py +0 -0
  83. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/server/context.py +0 -0
  84. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/server/http.py +0 -0
  85. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/server/middleware.py +0 -0
  86. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/server/stdio.py +0 -0
  87. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/workers/__init__.py +0 -0
  88. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/workers/daemon.py +0 -0
  89. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/workers/metrics.py +0 -0
  90. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/workers/preprocessing.py +0 -0
  91. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/workers/runner.py +0 -0
  92. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/workers/sandbox.py +0 -0
  93. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/workers/trainers/__init__.py +0 -0
  94. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/workers/trainers/base.py +0 -0
  95. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/workers/trainers/catboost_model.py +0 -0
  96. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/workers/trainers/lightgbm_model.py +0 -0
  97. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/workers/trainers/sklearn_models.py +0 -0
  98. {quicklab_mcp-0.1.0 → quicklab_mcp-0.2.0}/src/ml_mcp/workers/trainers/xgboost_model.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: QuickLab-MCP
3
- Version: 0.1.0
3
+ Version: 0.2.0
4
4
  Summary: QuickLab MCP Server - Production Tabular ML Experimentation Control Plane for AI Agents
5
5
  Author: QuickLab Team
6
6
  License-Expression: Apache-2.0
@@ -57,7 +57,7 @@ Requires-Dist: types-PyYAML>=6.0.0; extra == "dev"
57
57
  [![PyPI](https://img.shields.io/badge/pypi-QuickLab--MCP-blue.svg)](https://pypi.org/project/QuickLab-MCP/)
58
58
  [![MCP Protocol](https://img.shields.io/badge/MCP%20Protocol-2026--07--28-orange.svg)](https://modelcontextprotocol.io/)
59
59
  [![FastMCP](https://img.shields.io/badge/FastMCP-4.0.5%20GA-green.svg)](https://github.com/jlowin/fastmcp)
60
- [![Tests](https://img.shields.io/badge/tests-104%20passed%20%7C%20100%25-brightgreen.svg)]()
60
+ [![Tests](https://img.shields.io/badge/tests-108%20passed%20%7C%20100%25-brightgreen.svg)]()
61
61
  [![Code Style](https://img.shields.io/badge/code%20style-ruff-black.svg)](https://github.com/astral-sh/ruff)
62
62
  [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)
63
63
  [![Security](https://img.shields.io/badge/security-OAuth%202.1%20%2F%20OIDC-purple.svg)]()
@@ -77,7 +77,7 @@ Requires-Dist: types-PyYAML>=6.0.0; extra == "dev"
77
77
  - **OAuth 2.1 & Multi-Tenant Security**: Tenant boundary enforcement, RBAC matrix (`Viewer`, `Researcher`, `Operator`, `Admin`), token scope attenuation, and anti-enumeration protections (HTTP 404 instead of 403 on cross-tenant probes).
78
78
  - **Transactional Outbox Architecture**: Guarantees zero lost experiment submissions using PostgreSQL transactional Outbox events dispatched to Redis queues.
79
79
  - **S3 / MinIO Object Storage**: Immutable tenant-isolated artifact storage with SHA-256 integrity verification, presigned download URLs, and offline memory fallback.
80
- - **Full Test Coverage**: **104 tests passing (100% green)** across unit, integration, security matrix, MCP contract, and full end-to-end experiment lifecycle.
80
+ - **Full Test Coverage**: **108 tests passing (100% green)** across unit, integration, security matrix, MCP contract, zero-config fallbacks, and full end-to-end experiment lifecycle.
81
81
 
82
82
  ---
83
83
 
@@ -304,28 +304,27 @@ ModelLab supports both **STDIO** (local subprocess IPC) and **Streamable HTTP**
304
304
 
305
305
  Select your preferred runtime configuration below:
306
306
 
307
- ### 1. Docker + STDIO
308
- Runs ModelLab inside an isolated Docker container with standard I/O (`sys.stdin` / `sys.stdout`) piped directly to the MCP client.
307
+ ### 1. Docker + STDIO (Pre-Built Image)
308
+ Runs QuickLab inside an isolated Docker container with standard I/O (`sys.stdin` / `sys.stdout`) piped directly to the MCP client:
309
309
 
310
310
  ```json
311
311
  {
312
312
  "mcpServers": {
313
- "modellab": {
313
+ "quicklab": {
314
314
  "command": "docker",
315
315
  "args": [
316
316
  "run",
317
317
  "-i",
318
318
  "--rm",
319
319
  "--entrypoint", "python",
320
- "--network", "host",
321
320
  "-e", "APP_ENV=production",
322
- "-e", "DATABASE_URL=postgresql+asyncpg://postgres:postgres@localhost:5433/modellab",
323
- "-e", "REDIS_URL=redis://localhost:6379/0",
324
- "-e", "OBJECT_STORE_ENDPOINT_URL=http://localhost:9000",
321
+ "-e", "DATABASE_URL=postgresql+asyncpg://postgres:postgres@host.docker.internal:5433/modellab",
322
+ "-e", "REDIS_URL=redis://host.docker.internal:6379/0",
323
+ "-e", "OBJECT_STORE_ENDPOINT_URL=http://host.docker.internal:9000",
325
324
  "-e", "OBJECT_STORE_ACCESS_KEY_ID=minioadmin",
326
325
  "-e", "OBJECT_STORE_SECRET_ACCESS_KEY=minioadmin",
327
326
  "-e", "OBJECT_STORE_BUCKET_NAME=modellab-artifacts",
328
- "modellab-api",
327
+ "ghcr.io/aldrin-joan/quicklab-api:latest",
329
328
  "-m", "ml_mcp.server.stdio"
330
329
  ]
331
330
  }
@@ -333,11 +332,10 @@ Runs ModelLab inside an isolated Docker container with standard I/O (`sys.stdin`
333
332
  }
334
333
  ```
335
334
 
336
- > **Note for Docker Desktop (macOS / Windows)**: If `--network host` is unavailable in your Docker Desktop environment, connect via the shared Docker network:
335
+ > **Note for Docker Networking**: If running local services on your host, `host.docker.internal` allows the container to connect to your host ports seamlessly on macOS, Windows, and Linux. If using Docker Compose, connect via the shared Docker network:
337
336
  > ```json
338
337
  > "args": [
339
338
  > "run", "-i", "--rm",
340
- > "--entrypoint", "python",
341
339
  > "--network", "modellab_default",
342
340
  > "-e", "DATABASE_URL=postgresql+asyncpg://postgres:postgres@postgres:5432/modellab",
343
341
  > "-e", "REDIS_URL=redis://redis:6379/0",
@@ -345,11 +343,42 @@ Runs ModelLab inside an isolated Docker container with standard I/O (`sys.stdin`
345
343
  > "-e", "OBJECT_STORE_ACCESS_KEY_ID=minioadmin",
346
344
  > "-e", "OBJECT_STORE_SECRET_ACCESS_KEY=minioadmin",
347
345
  > "-e", "OBJECT_STORE_BUCKET_NAME=modellab-artifacts",
348
- > "modellab-api",
346
+ > "ghcr.io/aldrin-joan/quicklab-api:latest",
349
347
  > "-m", "ml_mcp.server.stdio"
350
348
  > ]
351
349
  > ```
352
350
 
351
+ ---
352
+
353
+ ### Database Schema Initialization & Migrations
354
+
355
+ When pointing QuickLab to a new PostgreSQL instance (local, AWS RDS, Supabase, Neon, or GCP Cloud SQL), the schema must be initialized with Alembic migrations:
356
+
357
+ #### Option A: Docker Compose (Fully Automated)
358
+ If deploying via [`docker-compose.stdio.yml`](docker-compose.stdio.yml) or [`docker-compose.http.yml`](docker-compose.http.yml), migrations execute automatically prior to application launch via the `db-migrate` service:
359
+ ```bash
360
+ docker compose -f docker-compose.stdio.yml up -d
361
+ ```
362
+
363
+ #### Option B: Standalone Docker (External / Managed Database)
364
+ Run migrations on a remote or standalone PostgreSQL instance without installing Python or cloning the repo:
365
+ ```bash
366
+ docker run --rm \
367
+ -e DATABASE_URL="postgresql+asyncpg://<USER>:<PASSWORD>@<HOST>:<PORT>/<DB_NAME>" \
368
+ ghcr.io/aldrin-joan/quicklab-api:latest \
369
+ -m alembic upgrade head
370
+ ```
371
+
372
+ #### Option C: Local Python / UV (Source Repository)
373
+ If running from source:
374
+ ```bash
375
+ uv run alembic upgrade head
376
+ ```
377
+
378
+ > [!NOTE]
379
+ > **Automatic Seed Data**: Once Alembic creates the schema, QuickLab's startup lifespan automatically seeds the 7 approved tabular ML models and ensures a default project workspace exists for the tenant.
380
+
381
+
353
382
  ---
354
383
 
355
384
  ### 2. Docker + HTTP
@@ -371,7 +400,24 @@ Connects to the ModelLab API service running inside Docker Compose (`docker comp
371
400
  ---
372
401
 
373
402
  ### 3. UVX + STDIO (Recommended Turnkey Setup)
374
- Runs QuickLab globally via `uvx` directly from PyPI:
403
+ Runs QuickLab globally via `uvx` directly from PyPI.
404
+
405
+ #### Zero-Configuration Mode (Zero Dependencies Required)
406
+ If you don't have PostgreSQL or Docker installed, QuickLab automatically provisions an embedded SQLite database (`~/.quicklab/quicklab.db`), local filesystem artifact storage (`~/.quicklab/artifacts`), and an in-process queue:
407
+
408
+ ```json
409
+ {
410
+ "mcpServers": {
411
+ "quicklab": {
412
+ "command": "uvx",
413
+ "args": ["quicklab-mcp"]
414
+ }
415
+ }
416
+ }
417
+ ```
418
+
419
+ #### Production Mode (Connecting to PostgreSQL & MinIO / S3)
420
+ To connect QuickLab to your own PostgreSQL and S3-compatible storage:
375
421
 
376
422
  ```json
377
423
  {
@@ -4,7 +4,7 @@
4
4
  [![PyPI](https://img.shields.io/badge/pypi-QuickLab--MCP-blue.svg)](https://pypi.org/project/QuickLab-MCP/)
5
5
  [![MCP Protocol](https://img.shields.io/badge/MCP%20Protocol-2026--07--28-orange.svg)](https://modelcontextprotocol.io/)
6
6
  [![FastMCP](https://img.shields.io/badge/FastMCP-4.0.5%20GA-green.svg)](https://github.com/jlowin/fastmcp)
7
- [![Tests](https://img.shields.io/badge/tests-104%20passed%20%7C%20100%25-brightgreen.svg)]()
7
+ [![Tests](https://img.shields.io/badge/tests-108%20passed%20%7C%20100%25-brightgreen.svg)]()
8
8
  [![Code Style](https://img.shields.io/badge/code%20style-ruff-black.svg)](https://github.com/astral-sh/ruff)
9
9
  [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)
10
10
  [![Security](https://img.shields.io/badge/security-OAuth%202.1%20%2F%20OIDC-purple.svg)]()
@@ -24,7 +24,7 @@
24
24
  - **OAuth 2.1 & Multi-Tenant Security**: Tenant boundary enforcement, RBAC matrix (`Viewer`, `Researcher`, `Operator`, `Admin`), token scope attenuation, and anti-enumeration protections (HTTP 404 instead of 403 on cross-tenant probes).
25
25
  - **Transactional Outbox Architecture**: Guarantees zero lost experiment submissions using PostgreSQL transactional Outbox events dispatched to Redis queues.
26
26
  - **S3 / MinIO Object Storage**: Immutable tenant-isolated artifact storage with SHA-256 integrity verification, presigned download URLs, and offline memory fallback.
27
- - **Full Test Coverage**: **104 tests passing (100% green)** across unit, integration, security matrix, MCP contract, and full end-to-end experiment lifecycle.
27
+ - **Full Test Coverage**: **108 tests passing (100% green)** across unit, integration, security matrix, MCP contract, zero-config fallbacks, and full end-to-end experiment lifecycle.
28
28
 
29
29
  ---
30
30
 
@@ -251,28 +251,27 @@ ModelLab supports both **STDIO** (local subprocess IPC) and **Streamable HTTP**
251
251
 
252
252
  Select your preferred runtime configuration below:
253
253
 
254
- ### 1. Docker + STDIO
255
- Runs ModelLab inside an isolated Docker container with standard I/O (`sys.stdin` / `sys.stdout`) piped directly to the MCP client.
254
+ ### 1. Docker + STDIO (Pre-Built Image)
255
+ Runs QuickLab inside an isolated Docker container with standard I/O (`sys.stdin` / `sys.stdout`) piped directly to the MCP client:
256
256
 
257
257
  ```json
258
258
  {
259
259
  "mcpServers": {
260
- "modellab": {
260
+ "quicklab": {
261
261
  "command": "docker",
262
262
  "args": [
263
263
  "run",
264
264
  "-i",
265
265
  "--rm",
266
266
  "--entrypoint", "python",
267
- "--network", "host",
268
267
  "-e", "APP_ENV=production",
269
- "-e", "DATABASE_URL=postgresql+asyncpg://postgres:postgres@localhost:5433/modellab",
270
- "-e", "REDIS_URL=redis://localhost:6379/0",
271
- "-e", "OBJECT_STORE_ENDPOINT_URL=http://localhost:9000",
268
+ "-e", "DATABASE_URL=postgresql+asyncpg://postgres:postgres@host.docker.internal:5433/modellab",
269
+ "-e", "REDIS_URL=redis://host.docker.internal:6379/0",
270
+ "-e", "OBJECT_STORE_ENDPOINT_URL=http://host.docker.internal:9000",
272
271
  "-e", "OBJECT_STORE_ACCESS_KEY_ID=minioadmin",
273
272
  "-e", "OBJECT_STORE_SECRET_ACCESS_KEY=minioadmin",
274
273
  "-e", "OBJECT_STORE_BUCKET_NAME=modellab-artifacts",
275
- "modellab-api",
274
+ "ghcr.io/aldrin-joan/quicklab-api:latest",
276
275
  "-m", "ml_mcp.server.stdio"
277
276
  ]
278
277
  }
@@ -280,11 +279,10 @@ Runs ModelLab inside an isolated Docker container with standard I/O (`sys.stdin`
280
279
  }
281
280
  ```
282
281
 
283
- > **Note for Docker Desktop (macOS / Windows)**: If `--network host` is unavailable in your Docker Desktop environment, connect via the shared Docker network:
282
+ > **Note for Docker Networking**: If running local services on your host, `host.docker.internal` allows the container to connect to your host ports seamlessly on macOS, Windows, and Linux. If using Docker Compose, connect via the shared Docker network:
284
283
  > ```json
285
284
  > "args": [
286
285
  > "run", "-i", "--rm",
287
- > "--entrypoint", "python",
288
286
  > "--network", "modellab_default",
289
287
  > "-e", "DATABASE_URL=postgresql+asyncpg://postgres:postgres@postgres:5432/modellab",
290
288
  > "-e", "REDIS_URL=redis://redis:6379/0",
@@ -292,11 +290,42 @@ Runs ModelLab inside an isolated Docker container with standard I/O (`sys.stdin`
292
290
  > "-e", "OBJECT_STORE_ACCESS_KEY_ID=minioadmin",
293
291
  > "-e", "OBJECT_STORE_SECRET_ACCESS_KEY=minioadmin",
294
292
  > "-e", "OBJECT_STORE_BUCKET_NAME=modellab-artifacts",
295
- > "modellab-api",
293
+ > "ghcr.io/aldrin-joan/quicklab-api:latest",
296
294
  > "-m", "ml_mcp.server.stdio"
297
295
  > ]
298
296
  > ```
299
297
 
298
+ ---
299
+
300
+ ### Database Schema Initialization & Migrations
301
+
302
+ When pointing QuickLab to a new PostgreSQL instance (local, AWS RDS, Supabase, Neon, or GCP Cloud SQL), the schema must be initialized with Alembic migrations:
303
+
304
+ #### Option A: Docker Compose (Fully Automated)
305
+ If deploying via [`docker-compose.stdio.yml`](docker-compose.stdio.yml) or [`docker-compose.http.yml`](docker-compose.http.yml), migrations execute automatically prior to application launch via the `db-migrate` service:
306
+ ```bash
307
+ docker compose -f docker-compose.stdio.yml up -d
308
+ ```
309
+
310
+ #### Option B: Standalone Docker (External / Managed Database)
311
+ Run migrations on a remote or standalone PostgreSQL instance without installing Python or cloning the repo:
312
+ ```bash
313
+ docker run --rm \
314
+ -e DATABASE_URL="postgresql+asyncpg://<USER>:<PASSWORD>@<HOST>:<PORT>/<DB_NAME>" \
315
+ ghcr.io/aldrin-joan/quicklab-api:latest \
316
+ -m alembic upgrade head
317
+ ```
318
+
319
+ #### Option C: Local Python / UV (Source Repository)
320
+ If running from source:
321
+ ```bash
322
+ uv run alembic upgrade head
323
+ ```
324
+
325
+ > [!NOTE]
326
+ > **Automatic Seed Data**: Once Alembic creates the schema, QuickLab's startup lifespan automatically seeds the 7 approved tabular ML models and ensures a default project workspace exists for the tenant.
327
+
328
+
300
329
  ---
301
330
 
302
331
  ### 2. Docker + HTTP
@@ -318,7 +347,24 @@ Connects to the ModelLab API service running inside Docker Compose (`docker comp
318
347
  ---
319
348
 
320
349
  ### 3. UVX + STDIO (Recommended Turnkey Setup)
321
- Runs QuickLab globally via `uvx` directly from PyPI:
350
+ Runs QuickLab globally via `uvx` directly from PyPI.
351
+
352
+ #### Zero-Configuration Mode (Zero Dependencies Required)
353
+ If you don't have PostgreSQL or Docker installed, QuickLab automatically provisions an embedded SQLite database (`~/.quicklab/quicklab.db`), local filesystem artifact storage (`~/.quicklab/artifacts`), and an in-process queue:
354
+
355
+ ```json
356
+ {
357
+ "mcpServers": {
358
+ "quicklab": {
359
+ "command": "uvx",
360
+ "args": ["quicklab-mcp"]
361
+ }
362
+ }
363
+ }
364
+ ```
365
+
366
+ #### Production Mode (Connecting to PostgreSQL & MinIO / S3)
367
+ To connect QuickLab to your own PostgreSQL and S3-compatible storage:
322
368
 
323
369
  ```json
324
370
  {
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "QuickLab-MCP"
7
- version = "0.1.0"
7
+ version = "0.2.0"
8
8
  description = "QuickLab MCP Server - Production Tabular ML Experimentation Control Plane for AI Agents"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.13"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: QuickLab-MCP
3
- Version: 0.1.0
3
+ Version: 0.2.0
4
4
  Summary: QuickLab MCP Server - Production Tabular ML Experimentation Control Plane for AI Agents
5
5
  Author: QuickLab Team
6
6
  License-Expression: Apache-2.0
@@ -57,7 +57,7 @@ Requires-Dist: types-PyYAML>=6.0.0; extra == "dev"
57
57
  [![PyPI](https://img.shields.io/badge/pypi-QuickLab--MCP-blue.svg)](https://pypi.org/project/QuickLab-MCP/)
58
58
  [![MCP Protocol](https://img.shields.io/badge/MCP%20Protocol-2026--07--28-orange.svg)](https://modelcontextprotocol.io/)
59
59
  [![FastMCP](https://img.shields.io/badge/FastMCP-4.0.5%20GA-green.svg)](https://github.com/jlowin/fastmcp)
60
- [![Tests](https://img.shields.io/badge/tests-104%20passed%20%7C%20100%25-brightgreen.svg)]()
60
+ [![Tests](https://img.shields.io/badge/tests-108%20passed%20%7C%20100%25-brightgreen.svg)]()
61
61
  [![Code Style](https://img.shields.io/badge/code%20style-ruff-black.svg)](https://github.com/astral-sh/ruff)
62
62
  [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)
63
63
  [![Security](https://img.shields.io/badge/security-OAuth%202.1%20%2F%20OIDC-purple.svg)]()
@@ -77,7 +77,7 @@ Requires-Dist: types-PyYAML>=6.0.0; extra == "dev"
77
77
  - **OAuth 2.1 & Multi-Tenant Security**: Tenant boundary enforcement, RBAC matrix (`Viewer`, `Researcher`, `Operator`, `Admin`), token scope attenuation, and anti-enumeration protections (HTTP 404 instead of 403 on cross-tenant probes).
78
78
  - **Transactional Outbox Architecture**: Guarantees zero lost experiment submissions using PostgreSQL transactional Outbox events dispatched to Redis queues.
79
79
  - **S3 / MinIO Object Storage**: Immutable tenant-isolated artifact storage with SHA-256 integrity verification, presigned download URLs, and offline memory fallback.
80
- - **Full Test Coverage**: **104 tests passing (100% green)** across unit, integration, security matrix, MCP contract, and full end-to-end experiment lifecycle.
80
+ - **Full Test Coverage**: **108 tests passing (100% green)** across unit, integration, security matrix, MCP contract, zero-config fallbacks, and full end-to-end experiment lifecycle.
81
81
 
82
82
  ---
83
83
 
@@ -304,28 +304,27 @@ ModelLab supports both **STDIO** (local subprocess IPC) and **Streamable HTTP**
304
304
 
305
305
  Select your preferred runtime configuration below:
306
306
 
307
- ### 1. Docker + STDIO
308
- Runs ModelLab inside an isolated Docker container with standard I/O (`sys.stdin` / `sys.stdout`) piped directly to the MCP client.
307
+ ### 1. Docker + STDIO (Pre-Built Image)
308
+ Runs QuickLab inside an isolated Docker container with standard I/O (`sys.stdin` / `sys.stdout`) piped directly to the MCP client:
309
309
 
310
310
  ```json
311
311
  {
312
312
  "mcpServers": {
313
- "modellab": {
313
+ "quicklab": {
314
314
  "command": "docker",
315
315
  "args": [
316
316
  "run",
317
317
  "-i",
318
318
  "--rm",
319
319
  "--entrypoint", "python",
320
- "--network", "host",
321
320
  "-e", "APP_ENV=production",
322
- "-e", "DATABASE_URL=postgresql+asyncpg://postgres:postgres@localhost:5433/modellab",
323
- "-e", "REDIS_URL=redis://localhost:6379/0",
324
- "-e", "OBJECT_STORE_ENDPOINT_URL=http://localhost:9000",
321
+ "-e", "DATABASE_URL=postgresql+asyncpg://postgres:postgres@host.docker.internal:5433/modellab",
322
+ "-e", "REDIS_URL=redis://host.docker.internal:6379/0",
323
+ "-e", "OBJECT_STORE_ENDPOINT_URL=http://host.docker.internal:9000",
325
324
  "-e", "OBJECT_STORE_ACCESS_KEY_ID=minioadmin",
326
325
  "-e", "OBJECT_STORE_SECRET_ACCESS_KEY=minioadmin",
327
326
  "-e", "OBJECT_STORE_BUCKET_NAME=modellab-artifacts",
328
- "modellab-api",
327
+ "ghcr.io/aldrin-joan/quicklab-api:latest",
329
328
  "-m", "ml_mcp.server.stdio"
330
329
  ]
331
330
  }
@@ -333,11 +332,10 @@ Runs ModelLab inside an isolated Docker container with standard I/O (`sys.stdin`
333
332
  }
334
333
  ```
335
334
 
336
- > **Note for Docker Desktop (macOS / Windows)**: If `--network host` is unavailable in your Docker Desktop environment, connect via the shared Docker network:
335
+ > **Note for Docker Networking**: If running local services on your host, `host.docker.internal` allows the container to connect to your host ports seamlessly on macOS, Windows, and Linux. If using Docker Compose, connect via the shared Docker network:
337
336
  > ```json
338
337
  > "args": [
339
338
  > "run", "-i", "--rm",
340
- > "--entrypoint", "python",
341
339
  > "--network", "modellab_default",
342
340
  > "-e", "DATABASE_URL=postgresql+asyncpg://postgres:postgres@postgres:5432/modellab",
343
341
  > "-e", "REDIS_URL=redis://redis:6379/0",
@@ -345,11 +343,42 @@ Runs ModelLab inside an isolated Docker container with standard I/O (`sys.stdin`
345
343
  > "-e", "OBJECT_STORE_ACCESS_KEY_ID=minioadmin",
346
344
  > "-e", "OBJECT_STORE_SECRET_ACCESS_KEY=minioadmin",
347
345
  > "-e", "OBJECT_STORE_BUCKET_NAME=modellab-artifacts",
348
- > "modellab-api",
346
+ > "ghcr.io/aldrin-joan/quicklab-api:latest",
349
347
  > "-m", "ml_mcp.server.stdio"
350
348
  > ]
351
349
  > ```
352
350
 
351
+ ---
352
+
353
+ ### Database Schema Initialization & Migrations
354
+
355
+ When pointing QuickLab to a new PostgreSQL instance (local, AWS RDS, Supabase, Neon, or GCP Cloud SQL), the schema must be initialized with Alembic migrations:
356
+
357
+ #### Option A: Docker Compose (Fully Automated)
358
+ If deploying via [`docker-compose.stdio.yml`](docker-compose.stdio.yml) or [`docker-compose.http.yml`](docker-compose.http.yml), migrations execute automatically prior to application launch via the `db-migrate` service:
359
+ ```bash
360
+ docker compose -f docker-compose.stdio.yml up -d
361
+ ```
362
+
363
+ #### Option B: Standalone Docker (External / Managed Database)
364
+ Run migrations on a remote or standalone PostgreSQL instance without installing Python or cloning the repo:
365
+ ```bash
366
+ docker run --rm \
367
+ -e DATABASE_URL="postgresql+asyncpg://<USER>:<PASSWORD>@<HOST>:<PORT>/<DB_NAME>" \
368
+ ghcr.io/aldrin-joan/quicklab-api:latest \
369
+ -m alembic upgrade head
370
+ ```
371
+
372
+ #### Option C: Local Python / UV (Source Repository)
373
+ If running from source:
374
+ ```bash
375
+ uv run alembic upgrade head
376
+ ```
377
+
378
+ > [!NOTE]
379
+ > **Automatic Seed Data**: Once Alembic creates the schema, QuickLab's startup lifespan automatically seeds the 7 approved tabular ML models and ensures a default project workspace exists for the tenant.
380
+
381
+
353
382
  ---
354
383
 
355
384
  ### 2. Docker + HTTP
@@ -371,7 +400,24 @@ Connects to the ModelLab API service running inside Docker Compose (`docker comp
371
400
  ---
372
401
 
373
402
  ### 3. UVX + STDIO (Recommended Turnkey Setup)
374
- Runs QuickLab globally via `uvx` directly from PyPI:
403
+ Runs QuickLab globally via `uvx` directly from PyPI.
404
+
405
+ #### Zero-Configuration Mode (Zero Dependencies Required)
406
+ If you don't have PostgreSQL or Docker installed, QuickLab automatically provisions an embedded SQLite database (`~/.quicklab/quicklab.db`), local filesystem artifact storage (`~/.quicklab/artifacts`), and an in-process queue:
407
+
408
+ ```json
409
+ {
410
+ "mcpServers": {
411
+ "quicklab": {
412
+ "command": "uvx",
413
+ "args": ["quicklab-mcp"]
414
+ }
415
+ }
416
+ }
417
+ ```
418
+
419
+ #### Production Mode (Connecting to PostgreSQL & MinIO / S3)
420
+ To connect QuickLab to your own PostgreSQL and S3-compatible storage:
375
421
 
376
422
  ```json
377
423
  {
@@ -1,3 +1,3 @@
1
1
  """Agentic ML MCP Server (ModelLab)."""
2
2
 
3
- __version__ = "0.1.0"
3
+ __version__ = "0.2.0"
@@ -129,7 +129,9 @@ class DatasetService:
129
129
  ],
130
130
  }
131
131
 
132
- async def list_datasets(self, tenant_id: str, project_id: str | None = None) -> list[dict[str, Any]]:
132
+ async def list_datasets(
133
+ self, tenant_id: str, project_id: str | None = None
134
+ ) -> list[dict[str, Any]]:
133
135
  datasets = await self.repo.list_datasets(tenant_id, project_id)
134
136
  return [
135
137
  {
@@ -61,7 +61,9 @@ class DatasetValidator:
61
61
  try:
62
62
  text_content = raw_bytes.decode("utf-8")
63
63
  except UnicodeDecodeError as exc:
64
- raise DatasetValidationError(f"Malformed encoding: dataset must be valid UTF-8: {exc}") from exc
64
+ raise DatasetValidationError(
65
+ f"Malformed encoding: dataset must be valid UTF-8: {exc}"
66
+ ) from exc
65
67
 
66
68
  reader = csv.reader(io.StringIO(text_content))
67
69
  try:
@@ -89,7 +91,9 @@ class DatasetValidator:
89
91
  elif fmt == DatasetFormat.JSONL.value:
90
92
  df = pd.read_json(bio, lines=True)
91
93
  else:
92
- raise DatasetValidationError(f"Unsupported dataset format '{data_format}'. Allowed: csv, parquet, jsonl")
94
+ raise DatasetValidationError(
95
+ f"Unsupported dataset format '{data_format}'. Allowed: csv, parquet, jsonl"
96
+ )
93
97
  except Exception as exc:
94
98
  raise DatasetValidationError(f"Failed to parse dataset as {fmt}: {exc}") from exc
95
99
 
@@ -148,7 +152,9 @@ class DatasetValidator:
148
152
  df.to_parquet(out_buf, index=False, engine="pyarrow", compression="snappy")
149
153
  return out_buf.getvalue()
150
154
 
151
- def process(self, raw_bytes: bytes, data_format: DatasetFormat | str) -> tuple[pd.DataFrame, bytes, DatasetSchema]:
155
+ def process(
156
+ self, raw_bytes: bytes, data_format: DatasetFormat | str
157
+ ) -> tuple[pd.DataFrame, bytes, DatasetSchema]:
152
158
  """Validate, convert to canonical parquet, and extract complete schema."""
153
159
  df = self.parse_dataframe(raw_bytes, data_format)
154
160
  parquet_bytes = self.canonicalize_to_parquet(df)