gen-mcp-server 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.
Files changed (27) hide show
  1. gen_mcp_server-0.1.0/.gitignore +7 -0
  2. gen_mcp_server-0.1.0/PKG-INFO +53 -0
  3. gen_mcp_server-0.1.0/README.md +35 -0
  4. gen_mcp_server-0.1.0/pyproject.toml +34 -0
  5. gen_mcp_server-0.1.0/src/gen_mcp_server/__init__.py +3 -0
  6. gen_mcp_server-0.1.0/src/gen_mcp_server/clients/__init__.py +4 -0
  7. gen_mcp_server-0.1.0/src/gen_mcp_server/clients/client.py +101 -0
  8. gen_mcp_server-0.1.0/src/gen_mcp_server/clients/errors.py +118 -0
  9. gen_mcp_server-0.1.0/src/gen_mcp_server/prompts/__init__.py +142 -0
  10. gen_mcp_server-0.1.0/src/gen_mcp_server/resources/__init__.py +5 -0
  11. gen_mcp_server-0.1.0/src/gen_mcp_server/resources/guidance.py +135 -0
  12. gen_mcp_server-0.1.0/src/gen_mcp_server/server.py +27 -0
  13. gen_mcp_server-0.1.0/src/gen_mcp_server/tools/__init__.py +32 -0
  14. gen_mcp_server-0.1.0/src/gen_mcp_server/tools/_helpers.py +32 -0
  15. gen_mcp_server-0.1.0/src/gen_mcp_server/tools/assets.py +51 -0
  16. gen_mcp_server-0.1.0/src/gen_mcp_server/tools/billing.py +76 -0
  17. gen_mcp_server-0.1.0/src/gen_mcp_server/tools/compose.py +67 -0
  18. gen_mcp_server-0.1.0/src/gen_mcp_server/tools/generation.py +119 -0
  19. gen_mcp_server-0.1.0/src/gen_mcp_server/tools/recurring.py +81 -0
  20. gen_mcp_server-0.1.0/src/gen_mcp_server/tools/schedule.py +72 -0
  21. gen_mcp_server-0.1.0/src/gen_mcp_server/tools/setup.py +60 -0
  22. gen_mcp_server-0.1.0/src/gen_mcp_server/tools/templates.py +33 -0
  23. gen_mcp_server-0.1.0/src/gen_mcp_server/tools/vidsheet.py +101 -0
  24. gen_mcp_server-0.1.0/src/gen_mcp_server/tools/voice.py +84 -0
  25. gen_mcp_server-0.1.0/tests/test_errors.py +47 -0
  26. gen_mcp_server-0.1.0/tests/test_server.py +43 -0
  27. gen_mcp_server-0.1.0/tests/test_tool_guard.py +40 -0
@@ -0,0 +1,7 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.egg-info/
4
+ dist/
5
+ build/
6
+ .pytest_cache/
7
+ *.pyc
@@ -0,0 +1,53 @@
1
+ Metadata-Version: 2.4
2
+ Name: gen-mcp-server
3
+ Version: 0.1.0
4
+ Summary: GEN MCP server — exposes the GEN platform (Auto Content Engine + agent chat) to MCP clients like Claude Code, Cursor, and VS Code.
5
+ Project-URL: Homepage, https://api.gen.pro
6
+ Project-URL: Repository, https://github.com/poweredbyGEN/gen-agentic
7
+ Author: GEN
8
+ License: MIT
9
+ Keywords: ai,content,gen,gen-pro,mcp,video
10
+ Requires-Python: >=3.10
11
+ Requires-Dist: fastmcp>=2.0.0
12
+ Requires-Dist: httpx>=0.27.0
13
+ Provides-Extra: dev
14
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
15
+ Requires-Dist: pytest>=8.0; extra == 'dev'
16
+ Requires-Dist: respx>=0.21; extra == 'dev'
17
+ Description-Content-Type: text/markdown
18
+
19
+ # gen-mcp-server
20
+
21
+ MCP server for the **GEN** platform — exposes the GEN Auto Content Engine + agent
22
+ chat to MCP clients (Claude Code, Cursor, VS Code).
23
+
24
+ It mirrors what a user can do through the GEN front end: set up agents, build
25
+ vidsheets, generate images (incl. Nano Banana Pro) and video, voice, render,
26
+ schedule/publish, manage credits, and run daily tasks. The `gen_do` tool
27
+ delegates natural-language goals to the GEN composer for multi-step outcomes.
28
+
29
+ ## Install
30
+
31
+ ```bash
32
+ pip install gen-mcp-server # or: uvx gen-mcp-server
33
+ ```
34
+
35
+ ## Configure (Claude Code)
36
+
37
+ ```bash
38
+ claude mcp add gen --env GEN_API_KEY=your-pat -- gen-mcp-server
39
+ ```
40
+
41
+ Get a Personal Access Token at https://gen.pro (log in → pick an agent → API page).
42
+
43
+ ## Environment
44
+
45
+ - `GEN_API_KEY` (required) — your Personal Access Token
46
+ - `GEN_API_BASE_URL` (default `https://api.gen.pro/v1`)
47
+ - `GEN_AGENT_API_URL` (default `https://agent.gen.pro/v1`)
48
+ - `GEN_AGENT_CORE_API_URL` (default `https://agent-core.gen.pro/v1`)
49
+
50
+ ## Errors & credits
51
+
52
+ Backend errors are surfaced cleanly. If you run out of credits, tools return
53
+ `insufficient_credits: true` with a message pointing to `gen_buy_credits`.
@@ -0,0 +1,35 @@
1
+ # gen-mcp-server
2
+
3
+ MCP server for the **GEN** platform — exposes the GEN Auto Content Engine + agent
4
+ chat to MCP clients (Claude Code, Cursor, VS Code).
5
+
6
+ It mirrors what a user can do through the GEN front end: set up agents, build
7
+ vidsheets, generate images (incl. Nano Banana Pro) and video, voice, render,
8
+ schedule/publish, manage credits, and run daily tasks. The `gen_do` tool
9
+ delegates natural-language goals to the GEN composer for multi-step outcomes.
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ pip install gen-mcp-server # or: uvx gen-mcp-server
15
+ ```
16
+
17
+ ## Configure (Claude Code)
18
+
19
+ ```bash
20
+ claude mcp add gen --env GEN_API_KEY=your-pat -- gen-mcp-server
21
+ ```
22
+
23
+ Get a Personal Access Token at https://gen.pro (log in → pick an agent → API page).
24
+
25
+ ## Environment
26
+
27
+ - `GEN_API_KEY` (required) — your Personal Access Token
28
+ - `GEN_API_BASE_URL` (default `https://api.gen.pro/v1`)
29
+ - `GEN_AGENT_API_URL` (default `https://agent.gen.pro/v1`)
30
+ - `GEN_AGENT_CORE_API_URL` (default `https://agent-core.gen.pro/v1`)
31
+
32
+ ## Errors & credits
33
+
34
+ Backend errors are surfaced cleanly. If you run out of credits, tools return
35
+ `insufficient_credits: true` with a message pointing to `gen_buy_credits`.
@@ -0,0 +1,34 @@
1
+ [project]
2
+ name = "gen-mcp-server"
3
+ version = "0.1.0"
4
+ description = "GEN MCP server — exposes the GEN platform (Auto Content Engine + agent chat) to MCP clients like Claude Code, Cursor, and VS Code."
5
+ readme = "README.md"
6
+ requires-python = ">=3.10"
7
+ license = { text = "MIT" }
8
+ authors = [{ name = "GEN" }]
9
+ keywords = ["mcp", "gen", "gen-pro", "ai", "video", "content"]
10
+ dependencies = [
11
+ "fastmcp>=2.0.0",
12
+ "httpx>=0.27.0",
13
+ ]
14
+
15
+ [project.optional-dependencies]
16
+ dev = ["pytest>=8.0", "pytest-asyncio>=0.23", "respx>=0.21"]
17
+
18
+ [project.scripts]
19
+ gen-mcp-server = "gen_mcp_server.server:main"
20
+
21
+ [project.urls]
22
+ Homepage = "https://api.gen.pro"
23
+ Repository = "https://github.com/poweredbyGEN/gen-agentic"
24
+
25
+ [build-system]
26
+ requires = ["hatchling"]
27
+ build-backend = "hatchling.build"
28
+
29
+ [tool.hatch.build.targets.wheel]
30
+ packages = ["src/gen_mcp_server"]
31
+
32
+ [tool.pytest.ini_options]
33
+ asyncio_mode = "auto"
34
+ testpaths = ["tests"]
@@ -0,0 +1,3 @@
1
+ """gen-mcp-server — MCP server for the GEN platform."""
2
+
3
+ __version__ = "0.1.0"
@@ -0,0 +1,4 @@
1
+ from .client import CLIENT_TAG, agent, agent_core, api
2
+ from .errors import GenApiError, normalize_error
3
+
4
+ __all__ = ["CLIENT_TAG", "GenApiError", "agent", "agent_core", "api", "normalize_error"]
@@ -0,0 +1,101 @@
1
+ """HTTP clients for the three GEN backends.
2
+
3
+ The MCP talks to three base URLs (same split the front end uses):
4
+ * api.gen.pro — Rails: content engine, generations, assets, billing
5
+ * agent.gen.pro — gen-agentic: chat/run, ideas, recurring jobs, schedule
6
+ * agent-core.gen.pro — agent-core: brand/onboarding, watchlists
7
+
8
+ Every outbound request carries:
9
+ * ``X-API-Key`` — the user's PAT (from GEN_API_KEY)
10
+ * ``X-Client`` — usage attribution so existing GEN dashboards can filter MCP
11
+ traffic (no new analytics system needed)
12
+
13
+ Failures are normalized via :func:`normalize_error` into ``GenApiError`` so the
14
+ MCP surfaces backend errors (especially out-of-credits) exactly like the FE.
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ import os
20
+ from typing import Any
21
+
22
+ import httpx
23
+
24
+ from .errors import GenApiError, normalize_error
25
+
26
+ __version__ = "0.1.0"
27
+ CLIENT_TAG = f"gen-mcp-server/{__version__}"
28
+
29
+ API_BASE = os.environ.get("GEN_API_BASE_URL", "https://api.gen.pro/v1")
30
+ AGENT_BASE = os.environ.get("GEN_AGENT_API_URL", "https://agent.gen.pro/v1")
31
+ AGENT_CORE_BASE = os.environ.get("GEN_AGENT_CORE_API_URL", "https://agent-core.gen.pro/v1")
32
+
33
+
34
+ def _api_key() -> str:
35
+ key = os.environ.get("GEN_API_KEY")
36
+ if not key:
37
+ raise GenApiError(
38
+ "GEN_API_KEY is not set. Create a Personal Access Token at "
39
+ "https://gen.pro (log in → pick an agent → API page) and set it as "
40
+ "the GEN_API_KEY environment variable.",
41
+ error_code="missing_api_key",
42
+ )
43
+ return key
44
+
45
+
46
+ class GenClient:
47
+ """A thin async HTTP client for one GEN backend base URL."""
48
+
49
+ def __init__(self, base_url: str) -> None:
50
+ self.base_url = base_url
51
+
52
+ async def request(
53
+ self,
54
+ method: str,
55
+ path: str,
56
+ *,
57
+ params: dict[str, Any] | None = None,
58
+ json: Any | None = None,
59
+ data: Any | None = None,
60
+ ) -> Any:
61
+ headers = {
62
+ "X-API-Key": _api_key(),
63
+ "X-Client": CLIENT_TAG,
64
+ "Accept": "application/json",
65
+ }
66
+ url = f"{self.base_url}{path}"
67
+ try:
68
+ async with httpx.AsyncClient(timeout=120) as http:
69
+ resp = await http.request(
70
+ method, url, params=params, json=json, data=data, headers=headers
71
+ )
72
+ except httpx.TimeoutException as exc:
73
+ raise GenApiError(
74
+ "The GEN service took too long to respond. Try again.",
75
+ error_code="timeout",
76
+ ) from exc
77
+ except httpx.HTTPError as exc:
78
+ raise GenApiError(
79
+ "Could not reach the GEN service.", error_code="network_error"
80
+ ) from exc
81
+
82
+ if resp.is_success:
83
+ if not resp.content:
84
+ return {"ok": True}
85
+ try:
86
+ return resp.json()
87
+ except ValueError:
88
+ return {"ok": True, "raw": resp.text}
89
+
90
+ # Failure → normalize to a user-facing error (handles out-of-credits).
91
+ try:
92
+ body: Any = resp.json()
93
+ except ValueError:
94
+ body = resp.text
95
+ raise normalize_error(resp.status_code, body)
96
+
97
+
98
+ # Singletons for the three backends.
99
+ api = GenClient(API_BASE)
100
+ agent = GenClient(AGENT_BASE)
101
+ agent_core = GenClient(AGENT_CORE_BASE)
@@ -0,0 +1,118 @@
1
+ """Error normalization for the GEN MCP server.
2
+
3
+ The MCP must surface backend errors to the user EXACTLY like the GEN backend
4
+ tells the front end. The backend returns a standard shape on failure:
5
+
6
+ {"error": "<human message>", "error_code": "<machine_code>"}
7
+
8
+ This module turns any HTTP failure into a clean, user-facing ``GenApiError``
9
+ with a friendly message. Out-of-credits is treated specially: it is the most
10
+ common paid-operation failure and the user should be told plainly that they are
11
+ out of credits (and how to buy more), never shown a raw 422/500.
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ from typing import Any
17
+
18
+ # Backend error_codes that mean "not enough credits to run this paid operation".
19
+ INSUFFICIENT_CREDITS_CODES = {
20
+ "insufficient_credits_for_job",
21
+ "insufficient_credits",
22
+ "not_enough_credits",
23
+ "insufficient_generic_credits",
24
+ }
25
+
26
+
27
+ class GenApiError(Exception):
28
+ """A normalized, user-facing GEN API error.
29
+
30
+ Attributes
31
+ ----------
32
+ message: friendly message to show the user
33
+ error_code: the backend machine code (may be None for transport errors)
34
+ status: HTTP status code (may be None)
35
+ insufficient_credits: True when this is an out-of-credits failure
36
+ """
37
+
38
+ def __init__(
39
+ self,
40
+ message: str,
41
+ *,
42
+ error_code: str | None = None,
43
+ status: int | None = None,
44
+ insufficient_credits: bool = False,
45
+ ) -> None:
46
+ super().__init__(message)
47
+ self.message = message
48
+ self.error_code = error_code
49
+ self.status = status
50
+ self.insufficient_credits = insufficient_credits
51
+
52
+ def to_user_text(self) -> str:
53
+ """Render the error the way it should appear to the user via MCP."""
54
+ if self.insufficient_credits:
55
+ return (
56
+ "⚠️ You're out of credits for this operation. "
57
+ "Top up with the `gen_buy_credits` tool (or upgrade your plan with "
58
+ "`gen_upgrade_workspace`), then try again."
59
+ )
60
+ code = f" [{self.error_code}]" if self.error_code else ""
61
+ return f"❌ {self.message}{code}"
62
+
63
+
64
+ def normalize_error(status: int, body: Any) -> GenApiError:
65
+ """Map a failed HTTP response into a GenApiError.
66
+
67
+ ``body`` is whatever the response carried — ideally the standard
68
+ ``{"error", "error_code"}`` dict, but we defend against html/plain/empty.
69
+ """
70
+ error_code: str | None = None
71
+ message: str | None = None
72
+
73
+ if isinstance(body, dict):
74
+ error_code = body.get("error_code") or body.get("code")
75
+ # FastAPI validation errors come back as {"detail": [...]} — handle first.
76
+ detail = body.get("detail")
77
+ if isinstance(detail, list):
78
+ message = (
79
+ "; ".join(str(d.get("msg", d)) if isinstance(d, dict) else str(d) for d in detail)
80
+ or "Validation error"
81
+ )
82
+ else:
83
+ message = (
84
+ body.get("error")
85
+ or body.get("message")
86
+ or (detail if isinstance(detail, str) else None)
87
+ )
88
+ elif isinstance(body, str) and body.strip():
89
+ message = body.strip()[:500]
90
+
91
+ insufficient = bool(error_code and error_code in INSUFFICIENT_CREDITS_CODES)
92
+ # Some backends only flag credits via 402 Payment Required.
93
+ if status == 402:
94
+ insufficient = True
95
+
96
+ if message is None:
97
+ message = _default_message_for_status(status)
98
+
99
+ return GenApiError(
100
+ message,
101
+ error_code=error_code,
102
+ status=status,
103
+ insufficient_credits=insufficient,
104
+ )
105
+
106
+
107
+ def _default_message_for_status(status: int) -> str:
108
+ return {
109
+ 400: "The request was invalid.",
110
+ 401: "Authentication failed — check your GEN_API_KEY.",
111
+ 403: "You don't have permission to do that.",
112
+ 404: "Not found.",
113
+ 422: "The request could not be processed.",
114
+ 429: "Rate limited — please slow down and retry.",
115
+ 500: "The GEN service hit an internal error.",
116
+ 502: "The GEN service is temporarily unavailable.",
117
+ 503: "The GEN service is temporarily unavailable.",
118
+ }.get(status, f"Request failed (HTTP {status}).")
@@ -0,0 +1,142 @@
1
+ """MCP Prompts — the GEN home-screen Plays.
2
+
3
+ These are the 9 published default Plays shown on the per-agent home screen
4
+ (``src/gen/plays/registry.py::DEFAULT_PLAYS``). Exposing them as MCP prompts
5
+ gives MCP clients the same vetted, high-value starting points users get in the
6
+ product. Each prompt returns the Play's seed instruction; the assistant runs it
7
+ (via gen_do delegation or the deterministic tools).
8
+
9
+ This module currently mirrors the registry statically. The follow-on phase
10
+ derives these from the live ``shortcut_registry`` so new/edited Plays appear as
11
+ MCP prompts automatically (and only gate-passed Plays are surfaced).
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ from typing import Any
17
+
18
+ # Mirror of the 9 published default Plays (registry.py DEFAULT_PLAYS),
19
+ # grouped: make_content / spot_trends / know_audience.
20
+ DEFAULT_PLAYS: list[dict[str, str]] = [
21
+ {
22
+ "name": "monitor_and_create_daily",
23
+ "group": "make_content",
24
+ "title": "Monitor a topic/account and create videos every day",
25
+ "prompt": (
26
+ "I want to automatically monitor a topic or account and have videos "
27
+ "created for me in my formats every day. Help me set this up: ask me "
28
+ "what to monitor, which video formats, and how often, explain what the "
29
+ "daily automation will do, and walk me through turning it into a "
30
+ "recurring Task. Use multi-step orchestration so it can monitor then "
31
+ "create then schedule in one run once it's set up. Before creating the "
32
+ "Task, summarize the exact details — what's monitored, formats, cadence, "
33
+ "delivery — and ask me to confirm; only create it after I confirm."
34
+ ),
35
+ },
36
+ {
37
+ "name": "watchlist_and_weekly_report",
38
+ "group": "spot_trends",
39
+ "title": "Create a watchlist and send me a weekly report",
40
+ "prompt": (
41
+ "I want a watchlist of the topics or accounts I care about and a weekly "
42
+ "report emailed to me. Help me set this up: ask me what to track, confirm "
43
+ "the watchlist contents and the weekly report details, and only create "
44
+ "the watchlist and the recurring weekly Task after I confirm."
45
+ ),
46
+ },
47
+ {
48
+ "name": "top_videos_in_my_niche",
49
+ "group": "spot_trends",
50
+ "title": "Top-performing videos in my niche, ranked by views last month",
51
+ "prompt": (
52
+ "Find the top-performing videos in my niche over the last month, ranked "
53
+ "by view count. Return the top ~20 with creator, views, hook, and format; "
54
+ "group them into the 3-4 themes that dominate; and tell me which theme I "
55
+ "should make a video about first. If you can only pull N, say so — no "
56
+ "silent caps."
57
+ ),
58
+ },
59
+ {
60
+ "name": "competitor_sentiment",
61
+ "group": "know_audience",
62
+ "title": "Positive and negative sentiment about my competitors",
63
+ "prompt": (
64
+ "Pull recent comments across my competitors and classify sentiment "
65
+ "positive / negative / neutral. Summarize what people praise vs criticize "
66
+ "for each, with representative quotes, and flag the biggest opening for "
67
+ "me. Disclose how many comments you analyzed."
68
+ ),
69
+ },
70
+ {
71
+ "name": "my_account_hooks_and_views",
72
+ "group": "make_content",
73
+ "title": "Analyze my account's top videos by hooks and views",
74
+ "prompt": (
75
+ "Look at my account's best-performing recent videos by views. Break down "
76
+ "the hooks and formats that overperform my own average, what they have in "
77
+ "common, and 3 concrete things to repeat. If I haven't connected an "
78
+ "account, ask for my handle first."
79
+ ),
80
+ },
81
+ {
82
+ "name": "five_content_ideas",
83
+ "group": "make_content",
84
+ "title": "Give me 5 content ideas for my niche",
85
+ "prompt": (
86
+ "Give me 5 content ideas for my niche tuned to what's working right now — "
87
+ "each with a hook, format, and why it'll land. If you don't know my niche "
88
+ "yet, ask me first, then generate."
89
+ ),
90
+ },
91
+ {
92
+ "name": "ideas_from_a_video",
93
+ "group": "make_content",
94
+ "title": "Content ideas based on a specific video",
95
+ "prompt": (
96
+ "I want content ideas based on a specific video. Ask me for the link, "
97
+ "analyze its hook, format, and structure, then give me 5 ideas that adapt "
98
+ "what works to my brand."
99
+ ),
100
+ },
101
+ {
102
+ "name": "topic_comment_sentiment",
103
+ "group": "know_audience",
104
+ "title": "Analyze positive and negative comments for a topic",
105
+ "prompt": (
106
+ "Analyze positive and negative comments for a topic. Ask me for the topic "
107
+ "if I haven't given one, then pull recent comments, classify sentiment, "
108
+ "cluster the themes, and surface the strongest content angle. Disclose the "
109
+ "sample size."
110
+ ),
111
+ },
112
+ {
113
+ "name": "video_templates",
114
+ "group": "make_content",
115
+ "title": "Show me templates for creating videos",
116
+ "prompt": (
117
+ "Show me video templates matched to the formats I make. List the available "
118
+ "templates with what each is good for, and offer to clone one into a new "
119
+ "vidsheet so I can go from idea to finished video fast."
120
+ ),
121
+ },
122
+ ]
123
+
124
+
125
+ def register_all(mcp: Any) -> None:
126
+ def _make(play: dict[str, str]):
127
+ seed = play["prompt"]
128
+
129
+ def _prompt(agent_id: str) -> str:
130
+ return (
131
+ f"[GEN Play — {play['title']}] (agent {agent_id})\n\n{seed}\n\n"
132
+ "Use gen_do to run this end-to-end, or the deterministic gen_* tools "
133
+ "for exact steps. If a paid step reports insufficient_credits, tell me "
134
+ "I'm out of credits and offer gen_buy_credits."
135
+ )
136
+
137
+ _prompt.__name__ = play["name"]
138
+ _prompt.__doc__ = f"GEN Play ({play['group']}): {play['title']}"
139
+ return _prompt
140
+
141
+ for play in DEFAULT_PLAYS:
142
+ mcp.prompt()(_make(play))
@@ -0,0 +1,5 @@
1
+ from . import guidance
2
+
3
+
4
+ def register_all(mcp) -> None:
5
+ guidance.register(mcp)
@@ -0,0 +1,135 @@
1
+ """MCP Resources — the guidance layer (mental model + how-to-combine).
2
+
3
+ These teach the assistant HOW GEN works and how to combine tools into outcomes
4
+ (the knowledge a flat tool list lacks). The mental model spans the FULL breadth
5
+ of GEN; recipes show how to combine capabilities; the credits/errors note covers
6
+ failure handling. The daily guidance Task can regenerate richer versions later.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from typing import Any
12
+
13
+ MENTAL_MODEL = """\
14
+ # GEN — the full mental model
15
+
16
+ GEN is an end-to-end platform for autonomous social video. It turns a brand or
17
+ idea into finished, on-brand short-form (and stitched long-form) video, and runs
18
+ the whole loop — research → ideate → produce → publish → monitor — on autopilot.
19
+
20
+ ## The core objects
21
+ - **Workspace / Organization** — billing container; holds agents and credits.
22
+ - **Agent (an "AI human")** — a persistent identity: brand, persona, voice, look,
23
+ avatars, linked social accounts, monitored topics. Everything is scoped to an
24
+ agent_id.
25
+ - **Vidsheet (Auto Content Engine)** — a spreadsheet-as-video-editor: rows are
26
+ scenes/variants, columns are ingredients, cells hold content, and layers stack
27
+ (video / image / audio / captions / text overlays) into a final render.
28
+ - **Generation** — any AI job: text, image, video, speech, lipsync, captions.
29
+ - **Content idea / Play / Task** — the planning + automation layer.
30
+
31
+ ## What GEN can do (breadth)
32
+
33
+ **1. Research & trends**
34
+ - Trending videos / hashtags / sounds by niche, region, timeframe.
35
+ - Creator discovery; analyze a creator's or your own hooks & formats.
36
+ - Cross-platform web research (Reddit, X, YouTube, TikTok, IG, HN, etc.).
37
+ - Comment mining: audience sentiment on a topic or competitors.
38
+ - Watchlists: saved topics/accounts monitored over time + weekly reports.
39
+
40
+ **2. Ideation**
41
+ - Data-driven content ideas tuned to what's working now in your niche.
42
+ - Ideas adapted from a specific reference video (analyze → adapt to brand).
43
+ - Refine ideas conversationally; set persistent creative preferences.
44
+
45
+ **3. Production (the vidsheet engine)**
46
+ - Clone a template (fastest path) or build a vidsheet from scratch.
47
+ - Generate images — Gemini "Nano Banana" family incl. **nano-banana-pro**
48
+ (Gemini 3 Pro Image), 2K, aspect 1:1/9:16/16:9.
49
+ - Generate video — Seedance (1.0/1.5/2.0), Veo, Kling, Sora, Pika; short clips
50
+ (Seedance 2.0 up to ~15s) with ratios incl. 21:9.
51
+ - Voice — list/create/design/clone voices; text-to-speech.
52
+ - Avatars & talking avatars — create, train custom avatars, talking-head video,
53
+ lipsync.
54
+ - Captions, text overlays, music selection, B-roll import (any length, from a
55
+ URL), background removal, upscaling, image variants.
56
+ - **Render** — composite all layers/rows into ONE deliverable. This is how you
57
+ assemble multi-scene and long-form video (combine many clips + B-roll → render).
58
+
59
+ **4. Publishing & scheduling**
60
+ - Publish or schedule posts to **tiktok / instagram / youtube / x**.
61
+ - schedule_type: now | specific_time (calendar) | next slot. Full post calendar
62
+ CRUD (add / list / update / delete).
63
+ - Connect social accounts via an OAuth URL the user opens (no credentials handled
64
+ by the MCP).
65
+
66
+ **5. Automation (Tasks)**
67
+ - Recurring jobs: run any prompt on a schedule (daily/weekly/monthly). A fired
68
+ Task runs the SAME composer as chat, so a daily Task can generate + render +
69
+ (with confirmation) auto-publish video. Pause/resume/run-now/delete.
70
+
71
+ **6. Billing / self-service**
72
+ - Read credit balance + usage history (analyze your spend).
73
+ - Buy credits / upgrade workspace (confirm price with the user first — real money).
74
+
75
+ ## Two ways to drive GEN via this MCP
76
+ - **Deterministic tools** (gen_create_row, gen_create_video, gen_render_video,
77
+ gen_schedule_post, ...) — for EXACT single actions you know you want.
78
+ - **gen_do(goal)** — delegate a natural-language OUTCOME to the GEN composer,
79
+ which classifies intent and orchestrates multi-step (e.g. "make a 5-scene 16:9
80
+ video about X and schedule it for tomorrow 9am"). Use this for composed goals.
81
+
82
+ ## Knowing what's possible vs how to combine
83
+ Most real outcomes are COMBINATIONS (research → idea → produce → publish → repeat
84
+ daily). A single clip is short; long/multi-scene video comes from combining clips
85
+ + B-roll then rendering. When in doubt, describe the OUTCOME to gen_do and let the
86
+ composer sequence the steps.
87
+ """
88
+
89
+ LONGFORM_RECIPE = """\
90
+ # Recipe: build a long / multi-scene video
91
+
92
+ A single generation is one short clip (~5-15s). To make a long or multi-scene
93
+ video, COMBINE clips + imported B-roll, then render:
94
+
95
+ 1. gen_create_engine (or gen_clone_template) → a vidsheet.
96
+ 2. For each scene: gen_create_row, then gen_create_video (per-scene prompt).
97
+ For images use gen_create_image with version='nano-banana-pro' (Gemini 3 Pro).
98
+ 3. Import long B-roll with gen_import_asset_from_url (YouTube/TikTok/direct file —
99
+ no length limit) and place as layers.
100
+ 4. gen_render_video on the final_video cell → ONE combined video.
101
+
102
+ Or just: gen_do("create a 5-scene 16:9 video about <topic>") and let the
103
+ composer do all of the above.
104
+
105
+ To do it every day: gen_create_recurring_job(prompt="create a video about ...",
106
+ cadence="daily", auto_publish=true) — confirm the details first.
107
+ """
108
+
109
+ CREDITS_NOTE = """\
110
+ # Credits & errors
111
+
112
+ Paid operations (generation, voice, research) cost credits. If a tool returns
113
+ insufficient_credits=true, the user is OUT OF CREDITS — tell them plainly and
114
+ offer gen_buy_credits (confirm the plan/price first) or gen_upgrade_workspace.
115
+ Check gen_get_credit_balance before large jobs; estimate with gen_estimate_job;
116
+ analyze spend with gen_get_credit_usage.
117
+
118
+ All backend errors are surfaced as {ok:false, error, error_code} — present the
119
+ message to the user; never swallow it. Purchases and publishing are real-world
120
+ actions — confirm with the user before executing.
121
+ """
122
+
123
+
124
+ def register(mcp: Any) -> None:
125
+ @mcp.resource("gen://mental-model")
126
+ def mental_model() -> str:
127
+ return MENTAL_MODEL
128
+
129
+ @mcp.resource("gen://recipes/long-form-video")
130
+ def longform() -> str:
131
+ return LONGFORM_RECIPE
132
+
133
+ @mcp.resource("gen://credits-and-errors")
134
+ def credits() -> str:
135
+ return CREDITS_NOTE
@@ -0,0 +1,27 @@
1
+ """GEN MCP server entry point (FastMCP).
2
+
3
+ Exposes the GEN platform to MCP clients. Tools mirror what a user can do through
4
+ the GEN front end; gen_do delegates natural-language goals to the GEN composer.
5
+ Backend errors — especially out-of-credits — are surfaced to the user cleanly.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from fastmcp import FastMCP
11
+
12
+ from . import prompts, resources, tools
13
+
14
+ mcp = FastMCP("gen")
15
+
16
+ tools.register_all(mcp)
17
+ resources.register_all(mcp)
18
+ prompts.register_all(mcp)
19
+
20
+
21
+ def main() -> None:
22
+ """Run over stdio (the transport MCP clients use)."""
23
+ mcp.run()
24
+
25
+
26
+ if __name__ == "__main__":
27
+ main()