creativai-mcp 0.1.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.
- creativai_mcp-0.1.0/.github/workflows/publish.yml +55 -0
- creativai_mcp-0.1.0/.gitignore +47 -0
- creativai_mcp-0.1.0/PKG-INFO +115 -0
- creativai_mcp-0.1.0/README.md +93 -0
- creativai_mcp-0.1.0/creativai_mcp/__init__.py +8 -0
- creativai_mcp-0.1.0/creativai_mcp/auth.py +35 -0
- creativai_mcp-0.1.0/creativai_mcp/prompts/__init__.py +77 -0
- creativai_mcp-0.1.0/creativai_mcp/resources/__init__.py +92 -0
- creativai_mcp-0.1.0/creativai_mcp/server.py +129 -0
- creativai_mcp-0.1.0/creativai_mcp/tools/__init__.py +45 -0
- creativai_mcp-0.1.0/creativai_mcp/tools/agentic_chat.py +129 -0
- creativai_mcp-0.1.0/creativai_mcp/tools/collections.py +85 -0
- creativai_mcp-0.1.0/creativai_mcp/tools/data_plates.py +99 -0
- creativai_mcp-0.1.0/creativai_mcp/tools/indexing.py +98 -0
- creativai_mcp-0.1.0/creativai_mcp/tools/knowledge.py +101 -0
- creativai_mcp-0.1.0/creativai_mcp/tools/live_stream.py +108 -0
- creativai_mcp-0.1.0/creativai_mcp/tools/media.py +73 -0
- creativai_mcp-0.1.0/creativai_mcp/tools/online_search.py +113 -0
- creativai_mcp-0.1.0/creativai_mcp/tools/organizations.py +65 -0
- creativai_mcp-0.1.0/creativai_mcp/tools/search.py +57 -0
- creativai_mcp-0.1.0/creativai_mcp/tools/tasks.py +79 -0
- creativai_mcp-0.1.0/creativai_mcp/tools/users.py +44 -0
- creativai_mcp-0.1.0/creativai_mcp/tools/youtube.py +85 -0
- creativai_mcp-0.1.0/pyproject.toml +37 -0
- creativai_mcp-0.1.0/tests/test_tools.py +245 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*" # trigger on v0.1.0, v1.2.3, etc.
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
id-token: write # required for PyPI trusted publishing (OIDC)
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
build:
|
|
15
|
+
name: Build distribution
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v4
|
|
20
|
+
|
|
21
|
+
- name: Set up Python
|
|
22
|
+
uses: actions/setup-python@v5
|
|
23
|
+
with:
|
|
24
|
+
python-version: "3.11"
|
|
25
|
+
|
|
26
|
+
- name: Install build tools
|
|
27
|
+
run: pip install hatchling build
|
|
28
|
+
|
|
29
|
+
- name: Build wheel and sdist
|
|
30
|
+
run: python -m build
|
|
31
|
+
|
|
32
|
+
- name: Upload dist artifacts
|
|
33
|
+
uses: actions/upload-artifact@v4
|
|
34
|
+
with:
|
|
35
|
+
name: dist
|
|
36
|
+
path: dist/
|
|
37
|
+
|
|
38
|
+
publish:
|
|
39
|
+
name: Publish to PyPI
|
|
40
|
+
needs: build
|
|
41
|
+
runs-on: ubuntu-latest
|
|
42
|
+
# environment: pypi # uncomment once OIDC trusted publisher is configured on pypi.org
|
|
43
|
+
|
|
44
|
+
steps:
|
|
45
|
+
- name: Download dist
|
|
46
|
+
uses: actions/download-artifact@v4
|
|
47
|
+
with:
|
|
48
|
+
name: dist
|
|
49
|
+
path: dist/
|
|
50
|
+
|
|
51
|
+
- name: Publish to PyPI
|
|
52
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
53
|
+
with:
|
|
54
|
+
password: ${{ secrets.PYPI_API_TOKEN }}
|
|
55
|
+
skip-existing: true
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.pyo
|
|
5
|
+
*.pyd
|
|
6
|
+
.Python
|
|
7
|
+
*.egg-info/
|
|
8
|
+
dist/
|
|
9
|
+
build/
|
|
10
|
+
*.egg
|
|
11
|
+
.eggs/
|
|
12
|
+
*.whl
|
|
13
|
+
|
|
14
|
+
# Virtual environments
|
|
15
|
+
.venv/
|
|
16
|
+
venv/
|
|
17
|
+
env/
|
|
18
|
+
.env
|
|
19
|
+
|
|
20
|
+
# Environment / secrets — NEVER commit API keys
|
|
21
|
+
.env
|
|
22
|
+
.env.*
|
|
23
|
+
!.env.example
|
|
24
|
+
|
|
25
|
+
# pytest
|
|
26
|
+
.pytest_cache/
|
|
27
|
+
htmlcov/
|
|
28
|
+
.coverage
|
|
29
|
+
coverage.xml
|
|
30
|
+
*.cover
|
|
31
|
+
|
|
32
|
+
# mypy
|
|
33
|
+
.mypy_cache/
|
|
34
|
+
.dmypy.json
|
|
35
|
+
|
|
36
|
+
# IDEs
|
|
37
|
+
.idea/
|
|
38
|
+
.vscode/
|
|
39
|
+
*.swp
|
|
40
|
+
*~
|
|
41
|
+
|
|
42
|
+
# macOS
|
|
43
|
+
.DS_Store
|
|
44
|
+
|
|
45
|
+
# Distribution / packaging
|
|
46
|
+
MANIFEST
|
|
47
|
+
pip-wheel-metadata/
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: creativai-mcp
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: MCP server for the CreativAI Video Intelligence Platform
|
|
5
|
+
Author-email: CreativAI <support@creativai.io>
|
|
6
|
+
License: Proprietary
|
|
7
|
+
Keywords: ai,creativai,mcp,model-context-protocol,video
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Requires-Python: >=3.10
|
|
13
|
+
Requires-Dist: creativai>=0.1
|
|
14
|
+
Requires-Dist: httpx>=0.27
|
|
15
|
+
Requires-Dist: mcp>=1.0
|
|
16
|
+
Requires-Dist: python-dotenv>=1.0
|
|
17
|
+
Provides-Extra: dev
|
|
18
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
19
|
+
Requires-Dist: pytest-mock>=3.12; extra == 'dev'
|
|
20
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
|
|
23
|
+
# creativai-mcp
|
|
24
|
+
|
|
25
|
+
MCP (Model Context Protocol) server for the [CreativAI](https://creativ-ai.com) Video Intelligence Platform.
|
|
26
|
+
|
|
27
|
+
Connect any MCP-compatible AI assistant (Claude, Cursor, VS Code Copilot, etc.) directly to your CreativAI video library — search, index, extract knowledge, and manage collections through natural language.
|
|
28
|
+
|
|
29
|
+
## Installation
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pip install creativai-mcp
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Quick Start
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
creativai-mcp --api-key YOUR_API_KEY
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Or set the environment variable:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
export CREATIVAI_API_KEY=YOUR_API_KEY
|
|
45
|
+
creativai-mcp
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Claude Desktop
|
|
49
|
+
|
|
50
|
+
Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
|
|
51
|
+
|
|
52
|
+
```json
|
|
53
|
+
{
|
|
54
|
+
"mcpServers": {
|
|
55
|
+
"creativai": {
|
|
56
|
+
"command": "creativai-mcp",
|
|
57
|
+
"args": ["--api-key", "YOUR_API_KEY"]
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### VS Code / GitHub Copilot
|
|
64
|
+
|
|
65
|
+
```json
|
|
66
|
+
{
|
|
67
|
+
"mcp": {
|
|
68
|
+
"servers": {
|
|
69
|
+
"creativai": {
|
|
70
|
+
"type": "stdio",
|
|
71
|
+
"command": "creativai-mcp",
|
|
72
|
+
"args": ["--api-key", "YOUR_API_KEY"]
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Available Tools
|
|
80
|
+
|
|
81
|
+
| Tool | Description |
|
|
82
|
+
|------|-------------|
|
|
83
|
+
| `list_collections` | List all video collections |
|
|
84
|
+
| `get_collection` | Get collection details |
|
|
85
|
+
| `list_media` | List media in a collection |
|
|
86
|
+
| `search_videos` | Semantic search across your library |
|
|
87
|
+
| `start_indexing` | Index a video for AI search |
|
|
88
|
+
| `get_indexing_status` | Check indexing progress |
|
|
89
|
+
| `cancel_indexing` | Cancel an in-progress indexing job |
|
|
90
|
+
| `extract_knowledge` | Extract structured knowledge from video |
|
|
91
|
+
| `list_data_plates` | List all data plates |
|
|
92
|
+
| `get_data_plate_segments` | Get segments from a data plate |
|
|
93
|
+
| `list_organizations` | List organizations |
|
|
94
|
+
| `list_projects` | List projects in an organization |
|
|
95
|
+
|
|
96
|
+
## Transports
|
|
97
|
+
|
|
98
|
+
**stdio** (default — for desktop AI clients):
|
|
99
|
+
```bash
|
|
100
|
+
creativai-mcp --transport stdio --api-key YOUR_API_KEY
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
**HTTP/SSE** (for remote/web clients):
|
|
104
|
+
```bash
|
|
105
|
+
creativai-mcp --transport http --host 0.0.0.0 --port 8080 --api-key YOUR_API_KEY
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Requirements
|
|
109
|
+
|
|
110
|
+
- Python 3.10+
|
|
111
|
+
- A CreativAI API key — get one at [creativ-ai.com](https://creativ-ai.com)
|
|
112
|
+
|
|
113
|
+
## License
|
|
114
|
+
|
|
115
|
+
Proprietary — © CreativAI
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# creativai-mcp
|
|
2
|
+
|
|
3
|
+
MCP (Model Context Protocol) server for the [CreativAI](https://creativ-ai.com) Video Intelligence Platform.
|
|
4
|
+
|
|
5
|
+
Connect any MCP-compatible AI assistant (Claude, Cursor, VS Code Copilot, etc.) directly to your CreativAI video library — search, index, extract knowledge, and manage collections through natural language.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install creativai-mcp
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
creativai-mcp --api-key YOUR_API_KEY
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Or set the environment variable:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
export CREATIVAI_API_KEY=YOUR_API_KEY
|
|
23
|
+
creativai-mcp
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Claude Desktop
|
|
27
|
+
|
|
28
|
+
Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
|
|
29
|
+
|
|
30
|
+
```json
|
|
31
|
+
{
|
|
32
|
+
"mcpServers": {
|
|
33
|
+
"creativai": {
|
|
34
|
+
"command": "creativai-mcp",
|
|
35
|
+
"args": ["--api-key", "YOUR_API_KEY"]
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### VS Code / GitHub Copilot
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"mcp": {
|
|
46
|
+
"servers": {
|
|
47
|
+
"creativai": {
|
|
48
|
+
"type": "stdio",
|
|
49
|
+
"command": "creativai-mcp",
|
|
50
|
+
"args": ["--api-key", "YOUR_API_KEY"]
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Available Tools
|
|
58
|
+
|
|
59
|
+
| Tool | Description |
|
|
60
|
+
|------|-------------|
|
|
61
|
+
| `list_collections` | List all video collections |
|
|
62
|
+
| `get_collection` | Get collection details |
|
|
63
|
+
| `list_media` | List media in a collection |
|
|
64
|
+
| `search_videos` | Semantic search across your library |
|
|
65
|
+
| `start_indexing` | Index a video for AI search |
|
|
66
|
+
| `get_indexing_status` | Check indexing progress |
|
|
67
|
+
| `cancel_indexing` | Cancel an in-progress indexing job |
|
|
68
|
+
| `extract_knowledge` | Extract structured knowledge from video |
|
|
69
|
+
| `list_data_plates` | List all data plates |
|
|
70
|
+
| `get_data_plate_segments` | Get segments from a data plate |
|
|
71
|
+
| `list_organizations` | List organizations |
|
|
72
|
+
| `list_projects` | List projects in an organization |
|
|
73
|
+
|
|
74
|
+
## Transports
|
|
75
|
+
|
|
76
|
+
**stdio** (default — for desktop AI clients):
|
|
77
|
+
```bash
|
|
78
|
+
creativai-mcp --transport stdio --api-key YOUR_API_KEY
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**HTTP/SSE** (for remote/web clients):
|
|
82
|
+
```bash
|
|
83
|
+
creativai-mcp --transport http --host 0.0.0.0 --port 8080 --api-key YOUR_API_KEY
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Requirements
|
|
87
|
+
|
|
88
|
+
- Python 3.10+
|
|
89
|
+
- A CreativAI API key — get one at [creativ-ai.com](https://creativ-ai.com)
|
|
90
|
+
|
|
91
|
+
## License
|
|
92
|
+
|
|
93
|
+
Proprietary — © CreativAI
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CreativAI MCP — auth helper.
|
|
3
|
+
|
|
4
|
+
Resolves the API key from (in order):
|
|
5
|
+
1. Explicit argument
|
|
6
|
+
2. CREATIVAI_API_KEY environment variable
|
|
7
|
+
3. ~/.creativai/config file (key=value format)
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import os
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def resolve_api_key(api_key: str | None = None) -> str:
|
|
17
|
+
"""Return an API key or raise RuntimeError if none is found."""
|
|
18
|
+
if api_key:
|
|
19
|
+
return api_key
|
|
20
|
+
|
|
21
|
+
env_key = os.environ.get("CREATIVAI_API_KEY", "").strip()
|
|
22
|
+
if env_key:
|
|
23
|
+
return env_key
|
|
24
|
+
|
|
25
|
+
config_path = Path.home() / ".creativai" / "config"
|
|
26
|
+
if config_path.exists():
|
|
27
|
+
for line in config_path.read_text().splitlines():
|
|
28
|
+
line = line.strip()
|
|
29
|
+
if line.startswith("api_key") and "=" in line:
|
|
30
|
+
return line.split("=", 1)[1].strip()
|
|
31
|
+
|
|
32
|
+
raise RuntimeError(
|
|
33
|
+
"No CreativAI API key found. "
|
|
34
|
+
"Set the CREATIVAI_API_KEY environment variable or pass api_key= explicitly."
|
|
35
|
+
)
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CreativAI MCP — Prompt templates.
|
|
3
|
+
|
|
4
|
+
Pre-defined prompts that help users get the most out of CreativAI tools.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from mcp.server.fastmcp import FastMCP
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def register(mcp: FastMCP) -> None:
|
|
13
|
+
|
|
14
|
+
@mcp.prompt()
|
|
15
|
+
def video_analysis_workflow(collection_name: str, topic: str) -> str:
|
|
16
|
+
"""Generate a step-by-step workflow to analyze videos on a topic.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
collection_name: Name of the collection to create.
|
|
20
|
+
topic: Topic or domain of the videos (e.g. 'factory safety').
|
|
21
|
+
"""
|
|
22
|
+
return f"""You are a video intelligence analyst using CreativAI tools.
|
|
23
|
+
|
|
24
|
+
Follow this workflow to analyze {topic} videos in the '{collection_name}' collection:
|
|
25
|
+
|
|
26
|
+
1. **Check existing collections** — Call list_collections to see if '{collection_name}' already exists.
|
|
27
|
+
2. **Create collection** — If not found, call create_collection('{collection_name}').
|
|
28
|
+
3. **Add media** — Call get_upload_url to get presigned URLs for your video files, then upload them.
|
|
29
|
+
4. **Index** — Call start_indexing with the collection_id, then poll get_indexing_status until status='completed'.
|
|
30
|
+
5. **Search** — Call search_collection to find relevant clips about {topic}.
|
|
31
|
+
6. **Deep analysis** — Call ask_collection to get an AI-synthesized analysis of {topic} patterns.
|
|
32
|
+
7. **Structured extraction** — Call create_data_plate_from_collection, then add_extraction_columns to extract specific facts about {topic}.
|
|
33
|
+
|
|
34
|
+
Start by calling list_collections to check what already exists."""
|
|
35
|
+
|
|
36
|
+
@mcp.prompt()
|
|
37
|
+
def safety_audit_workflow(collection_id: str) -> str:
|
|
38
|
+
"""Generate a safety audit workflow for a video collection.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
collection_id: The collection to audit.
|
|
42
|
+
"""
|
|
43
|
+
return f"""You are a safety compliance auditor using CreativAI video intelligence.
|
|
44
|
+
|
|
45
|
+
Perform a comprehensive safety audit of collection '{collection_id}':
|
|
46
|
+
|
|
47
|
+
1. **Search for violations** — Call search_collection('{collection_id}', 'safety violation PPE missing hard hat')
|
|
48
|
+
2. **Search for hazards** — Call search_collection('{collection_id}', 'unsafe behavior near machinery equipment')
|
|
49
|
+
3. **Ask for summary** — Call ask_collection('{collection_id}', 'Summarize all safety incidents, PPE compliance rate, and top risk areas observed in the footage')
|
|
50
|
+
4. **Extract structured data** — Call create_data_plate_from_collection('{collection_id}'), then add_extraction_columns with:
|
|
51
|
+
- {{'name': 'ppe_worn', 'question': 'Is the worker wearing required PPE (hard hat, vest, gloves)?'}}
|
|
52
|
+
- {{'name': 'safety_violation', 'question': 'Is there a safety violation visible? Describe it.'}}
|
|
53
|
+
- {{'name': 'risk_level', 'question': 'Rate the safety risk level: low, medium, or high'}}
|
|
54
|
+
5. **Query the data** — Call query_knowledge_plate to ask 'What percentage of segments show PPE violations?'
|
|
55
|
+
|
|
56
|
+
Begin with step 1."""
|
|
57
|
+
|
|
58
|
+
@mcp.prompt()
|
|
59
|
+
def search_and_report(collection_id: str, search_query: str) -> str:
|
|
60
|
+
"""Search a collection and produce a structured report.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
collection_id: Collection to search.
|
|
64
|
+
search_query: What to look for.
|
|
65
|
+
"""
|
|
66
|
+
return f"""Search the collection '{collection_id}' for '{search_query}' and produce a structured report.
|
|
67
|
+
|
|
68
|
+
Steps:
|
|
69
|
+
1. Call search_collection('{collection_id}', '{search_query}', limit=20)
|
|
70
|
+
2. Call ask_collection('{collection_id}', 'Provide a detailed report on {search_query}: frequency, patterns, timestamps, and key observations')
|
|
71
|
+
3. Format the findings as a report with:
|
|
72
|
+
- Executive Summary
|
|
73
|
+
- Key Findings (with timestamps)
|
|
74
|
+
- Frequency / Statistics
|
|
75
|
+
- Recommendations
|
|
76
|
+
|
|
77
|
+
Start with the search."""
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CreativAI MCP — MCP Resources.
|
|
3
|
+
|
|
4
|
+
Exposes collections and search results as readable MCP resources
|
|
5
|
+
at creativai:// URIs.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import json
|
|
11
|
+
from typing import Any
|
|
12
|
+
from mcp.server.fastmcp import FastMCP
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def register(mcp: FastMCP, get_client: Any) -> None:
|
|
16
|
+
|
|
17
|
+
@mcp.resource("creativai://collections")
|
|
18
|
+
def resource_list_collections() -> str:
|
|
19
|
+
"""All video collections in your CreativAI account.
|
|
20
|
+
|
|
21
|
+
Returns JSON list of collections with IDs, names, model, video count.
|
|
22
|
+
"""
|
|
23
|
+
client = get_client()
|
|
24
|
+
result = client.collections.list()
|
|
25
|
+
collections = result if isinstance(result, list) else result.get("collections", result.get("data", []))
|
|
26
|
+
return json.dumps(collections, indent=2)
|
|
27
|
+
|
|
28
|
+
@mcp.resource("creativai://collections/{collection_id}")
|
|
29
|
+
def resource_get_collection(collection_id: str) -> str:
|
|
30
|
+
"""Details and media list for a specific collection.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
collection_id: Collection ID (e.g. 'col_abc123').
|
|
34
|
+
"""
|
|
35
|
+
client = get_client()
|
|
36
|
+
result = client.collections.get(collection_id)
|
|
37
|
+
return json.dumps(result, indent=2)
|
|
38
|
+
|
|
39
|
+
@mcp.resource("creativai://collections/{collection_id}/plates")
|
|
40
|
+
def resource_list_plates(collection_id: str) -> str:
|
|
41
|
+
"""All data plates in a collection.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
collection_id: Collection ID.
|
|
45
|
+
"""
|
|
46
|
+
client = get_client()
|
|
47
|
+
result = client.data_plates.list(collection_id)
|
|
48
|
+
plates = result if isinstance(result, list) else result.get("plates", result.get("data", []))
|
|
49
|
+
return json.dumps(plates, indent=2)
|
|
50
|
+
|
|
51
|
+
@mcp.resource("creativai://account")
|
|
52
|
+
def resource_account_info() -> str:
|
|
53
|
+
"""Your CreativAI account info: credits, plan, usage stats."""
|
|
54
|
+
client = get_client()
|
|
55
|
+
result = client.users.get_users_info()
|
|
56
|
+
return json.dumps(result, indent=2)
|
|
57
|
+
|
|
58
|
+
@mcp.resource("creativai://collections/{collection_id}/videos")
|
|
59
|
+
def resource_collection_videos(collection_id: str) -> str:
|
|
60
|
+
"""All media files in a collection with their preprocessing and indexing status.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
collection_id: Collection ID (e.g. 'col_abc123').
|
|
64
|
+
"""
|
|
65
|
+
client = get_client()
|
|
66
|
+
result = client.media.list(collection_id)
|
|
67
|
+
media = result if isinstance(result, list) else result.get("media", result.get("data", []))
|
|
68
|
+
return json.dumps(media, indent=2)
|
|
69
|
+
|
|
70
|
+
@mcp.resource("creativai://data-plates/{plate_id}")
|
|
71
|
+
def resource_data_plate(plate_id: str) -> str:
|
|
72
|
+
"""A data plate's first page of segments (up to 100 rows).
|
|
73
|
+
|
|
74
|
+
Note: plate_id should be formatted as '{collection_id}:{plate_id}'.
|
|
75
|
+
Args:
|
|
76
|
+
plate_id: Composite ID in the format 'collection_id:plate_id'.
|
|
77
|
+
"""
|
|
78
|
+
client = get_client()
|
|
79
|
+
if ":" in plate_id:
|
|
80
|
+
collection_id, pid = plate_id.split(":", 1)
|
|
81
|
+
else:
|
|
82
|
+
return json.dumps({"error": "plate_id must be 'collection_id:plate_id'"})
|
|
83
|
+
result = client.data_plates.get(collection_id, pid, page=1, page_size=100)
|
|
84
|
+
return json.dumps(result, indent=2)
|
|
85
|
+
|
|
86
|
+
@mcp.resource("creativai://organizations")
|
|
87
|
+
def resource_organizations() -> str:
|
|
88
|
+
"""All organizations you are a member of."""
|
|
89
|
+
client = get_client()
|
|
90
|
+
result = client.organizations.list()
|
|
91
|
+
orgs = result if isinstance(result, list) else result.get("organizations", result.get("data", []))
|
|
92
|
+
return json.dumps(orgs, indent=2)
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CreativAI MCP Server — entry point.
|
|
3
|
+
|
|
4
|
+
Supports two transports:
|
|
5
|
+
stdio (default) — for Claude Desktop, Cursor, Copilot config files
|
|
6
|
+
sse — for HTTP-based MCP clients (set --transport sse)
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
# stdio (Claude Desktop / Cursor)
|
|
10
|
+
creativai-mcp
|
|
11
|
+
|
|
12
|
+
# HTTP/SSE on a custom port
|
|
13
|
+
creativai-mcp --transport sse --host 0.0.0.0 --port 8090
|
|
14
|
+
|
|
15
|
+
# Explicit API key
|
|
16
|
+
creativai-mcp --api-key sk_live_xxx
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
import argparse
|
|
22
|
+
import os
|
|
23
|
+
import sys
|
|
24
|
+
|
|
25
|
+
from dotenv import load_dotenv
|
|
26
|
+
from mcp.server.fastmcp import FastMCP
|
|
27
|
+
|
|
28
|
+
from .auth import resolve_api_key
|
|
29
|
+
from .tools import register_all
|
|
30
|
+
from .resources import register as register_resources
|
|
31
|
+
from .prompts import register as register_prompts
|
|
32
|
+
|
|
33
|
+
load_dotenv()
|
|
34
|
+
|
|
35
|
+
_SERVER_NAME = "CreativAI"
|
|
36
|
+
_SERVER_VERSION = "0.1.0"
|
|
37
|
+
_SERVER_DESCRIPTION = (
|
|
38
|
+
"Video intelligence tools: upload, index, search, chat, extract knowledge, "
|
|
39
|
+
"live stream, and more — powered by CreativAI."
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def build_server(api_key: str | None = None) -> FastMCP:
|
|
44
|
+
"""Build and return a configured FastMCP server instance.
|
|
45
|
+
|
|
46
|
+
This is also importable for use inside the FastAPI backend (SSE transport).
|
|
47
|
+
"""
|
|
48
|
+
resolved_key = resolve_api_key(api_key)
|
|
49
|
+
|
|
50
|
+
# Lazy client factory — one client per server instance, created on first use.
|
|
51
|
+
_client_cache: list = []
|
|
52
|
+
|
|
53
|
+
def get_client():
|
|
54
|
+
if not _client_cache:
|
|
55
|
+
import creativai
|
|
56
|
+
kwargs: dict = {"api_key": resolved_key}
|
|
57
|
+
base_url = os.environ.get("CREATIVAI_BASE_URL", "").strip()
|
|
58
|
+
if base_url:
|
|
59
|
+
kwargs["base_url"] = base_url
|
|
60
|
+
_client_cache.append(creativai.CreativAI(**kwargs))
|
|
61
|
+
return _client_cache[0]
|
|
62
|
+
|
|
63
|
+
mcp = FastMCP(
|
|
64
|
+
name=_SERVER_NAME,
|
|
65
|
+
version=_SERVER_VERSION,
|
|
66
|
+
description=_SERVER_DESCRIPTION,
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
# Register all tools, resources, and prompts
|
|
70
|
+
register_all(mcp, get_client)
|
|
71
|
+
register_resources(mcp, get_client)
|
|
72
|
+
register_prompts(mcp)
|
|
73
|
+
|
|
74
|
+
return mcp
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def main() -> None:
|
|
78
|
+
"""CLI entry point — parses args and runs the server."""
|
|
79
|
+
parser = argparse.ArgumentParser(
|
|
80
|
+
prog="creativai-mcp",
|
|
81
|
+
description="CreativAI MCP server — expose video intelligence to any MCP-compatible AI.",
|
|
82
|
+
)
|
|
83
|
+
parser.add_argument(
|
|
84
|
+
"--api-key",
|
|
85
|
+
default=None,
|
|
86
|
+
help="CreativAI API key (falls back to CREATIVAI_API_KEY env var).",
|
|
87
|
+
)
|
|
88
|
+
parser.add_argument(
|
|
89
|
+
"--base-url",
|
|
90
|
+
default=None,
|
|
91
|
+
help="Override the API base URL (e.g. http://localhost:5000 for local backend).",
|
|
92
|
+
)
|
|
93
|
+
parser.add_argument(
|
|
94
|
+
"--transport",
|
|
95
|
+
choices=["stdio", "sse"],
|
|
96
|
+
default="stdio",
|
|
97
|
+
help="Transport protocol (default: stdio).",
|
|
98
|
+
)
|
|
99
|
+
parser.add_argument(
|
|
100
|
+
"--host",
|
|
101
|
+
default="127.0.0.1",
|
|
102
|
+
help="Host for SSE transport (default: 127.0.0.1).",
|
|
103
|
+
)
|
|
104
|
+
parser.add_argument(
|
|
105
|
+
"--port",
|
|
106
|
+
type=int,
|
|
107
|
+
default=8090,
|
|
108
|
+
help="Port for SSE transport (default: 8090).",
|
|
109
|
+
)
|
|
110
|
+
args = parser.parse_args()
|
|
111
|
+
|
|
112
|
+
# --base-url CLI flag sets the env var so build_server picks it up
|
|
113
|
+
if args.base_url:
|
|
114
|
+
os.environ["CREATIVAI_BASE_URL"] = args.base_url
|
|
115
|
+
|
|
116
|
+
try:
|
|
117
|
+
mcp = build_server(api_key=args.api_key)
|
|
118
|
+
except RuntimeError as exc:
|
|
119
|
+
print(f"ERROR: {exc}", file=sys.stderr)
|
|
120
|
+
sys.exit(1)
|
|
121
|
+
|
|
122
|
+
if args.transport == "sse":
|
|
123
|
+
mcp.run(transport="sse", host=args.host, port=args.port)
|
|
124
|
+
else:
|
|
125
|
+
mcp.run(transport="stdio")
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
if __name__ == "__main__":
|
|
129
|
+
main()
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CreativAI MCP — tools package.
|
|
3
|
+
Exports a single register_all() that wires every tool domain into an mcp instance.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from typing import Any
|
|
9
|
+
from mcp.server.fastmcp import FastMCP
|
|
10
|
+
|
|
11
|
+
from . import (
|
|
12
|
+
collections,
|
|
13
|
+
media,
|
|
14
|
+
indexing,
|
|
15
|
+
search,
|
|
16
|
+
agentic_chat,
|
|
17
|
+
knowledge,
|
|
18
|
+
data_plates,
|
|
19
|
+
tasks,
|
|
20
|
+
live_stream,
|
|
21
|
+
online_search,
|
|
22
|
+
youtube,
|
|
23
|
+
users,
|
|
24
|
+
organizations,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def register_all(mcp: FastMCP, get_client: Any) -> None:
|
|
29
|
+
"""Register all CreativAI tools into the given FastMCP instance."""
|
|
30
|
+
collections.register(mcp, get_client)
|
|
31
|
+
media.register(mcp, get_client)
|
|
32
|
+
indexing.register(mcp, get_client)
|
|
33
|
+
search.register(mcp, get_client)
|
|
34
|
+
agentic_chat.register(mcp, get_client)
|
|
35
|
+
knowledge.register(mcp, get_client)
|
|
36
|
+
data_plates.register(mcp, get_client)
|
|
37
|
+
tasks.register(mcp, get_client)
|
|
38
|
+
live_stream.register(mcp, get_client)
|
|
39
|
+
online_search.register(mcp, get_client)
|
|
40
|
+
youtube.register(mcp, get_client)
|
|
41
|
+
users.register(mcp, get_client)
|
|
42
|
+
organizations.register(mcp, get_client)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
__all__ = ["register_all"]
|