compono-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.
@@ -0,0 +1,44 @@
1
+ Metadata-Version: 2.4
2
+ Name: compono-mcp
3
+ Version: 0.1.0
4
+ Summary: MCP server exposing compono's render_deck/validate as MCP tools.
5
+ Author: Shaik-Hamzah123
6
+ Author-email: Shaik-Hamzah123 <hamzah.shaik2003@gmail.com>
7
+ License-Expression: MIT
8
+ Requires-Dist: compono>=0.1.0
9
+ Requires-Dist: fastmcp>=4.0.3
10
+ Requires-Python: >=3.13
11
+ Description-Content-Type: text/markdown
12
+
13
+ # compono-mcp
14
+
15
+ MCP server wrapper exposing [`compono`](https://pypi.org/project/compono/)'s
16
+ `render_deck`/`validate` as MCP tools, for any MCP-compatible client (not just
17
+ Claude Code).
18
+
19
+ ## Install
20
+
21
+ ```bash
22
+ pip install compono-mcp
23
+ # or
24
+ uv add compono-mcp
25
+ ```
26
+
27
+ ## Usage
28
+
29
+ Add to your MCP client config (Claude Desktop / Claude Code style):
30
+
31
+ ```json
32
+ { "mcpServers": { "compono": { "command": "compono-mcp" } } }
33
+ ```
34
+
35
+ Exposes:
36
+ - **`validate(spec)`** — schema + layout + overflow checks, no file write.
37
+ - **`render_deck(spec, output_path)`** — writes a real `.pptx` file.
38
+ - **resource `compono://reference`** — the full agent-facing reference doc
39
+ (quickstart, primitive catalog, worked examples, error shape), for MCP
40
+ clients that don't have Claude Code's skill system.
41
+
42
+ See the [main compono README](https://github.com/Shaik-Hamzah123/compono) for
43
+ the primitive schema and worked examples — `spec` here is the identical JSON
44
+ shape `compono.render_deck`/`validate` accept directly.
@@ -0,0 +1,32 @@
1
+ # compono-mcp
2
+
3
+ MCP server wrapper exposing [`compono`](https://pypi.org/project/compono/)'s
4
+ `render_deck`/`validate` as MCP tools, for any MCP-compatible client (not just
5
+ Claude Code).
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ pip install compono-mcp
11
+ # or
12
+ uv add compono-mcp
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ Add to your MCP client config (Claude Desktop / Claude Code style):
18
+
19
+ ```json
20
+ { "mcpServers": { "compono": { "command": "compono-mcp" } } }
21
+ ```
22
+
23
+ Exposes:
24
+ - **`validate(spec)`** — schema + layout + overflow checks, no file write.
25
+ - **`render_deck(spec, output_path)`** — writes a real `.pptx` file.
26
+ - **resource `compono://reference`** — the full agent-facing reference doc
27
+ (quickstart, primitive catalog, worked examples, error shape), for MCP
28
+ clients that don't have Claude Code's skill system.
29
+
30
+ See the [main compono README](https://github.com/Shaik-Hamzah123/compono) for
31
+ the primitive schema and worked examples — `spec` here is the identical JSON
32
+ shape `compono.render_deck`/`validate` accept directly.
@@ -0,0 +1,24 @@
1
+ [project]
2
+ name = "compono-mcp"
3
+ version = "0.1.0"
4
+ description = "MCP server exposing compono's render_deck/validate as MCP tools."
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ authors = [
8
+ { name = "Shaik-Hamzah123", email = "hamzah.shaik2003@gmail.com" }
9
+ ]
10
+ requires-python = ">=3.13"
11
+ dependencies = [
12
+ "compono>=0.1.0",
13
+ "fastmcp>=4.0.3",
14
+ ]
15
+
16
+ [project.scripts]
17
+ compono-mcp = "compono_mcp.server:main"
18
+
19
+ [build-system]
20
+ requires = ["uv_build>=0.11.17,<0.12.0"]
21
+ build-backend = "uv_build"
22
+
23
+ [tool.uv.sources]
24
+ compono = { workspace = true }
@@ -0,0 +1 @@
1
+ """compono-mcp — MCP server exposing compono's render_deck/validate as MCP tools."""
@@ -0,0 +1,212 @@
1
+ <!--
2
+ Served verbatim as the `compono://reference` MCP resource (see server.py).
3
+ Kept in sync with the repo root skills/compono/SKILL.md and README.md —
4
+ same convention already used between those two files. Update all three
5
+ together when the API surface changes.
6
+ -->
7
+
8
+ # compono
9
+
10
+ **Agent-oriented, code-based PPTX generation — "Manim, but for PowerPoint."**
11
+
12
+ compono lets you describe a slide deck as data — headers, bullet text,
13
+ stats, tables, charts, images, process sequences, shapes — and get back a
14
+ real, editable `.pptx` file. You never write raw `x`/`y`/`w`/`h`
15
+ coordinates: a constraint-based layout resolver computes every position
16
+ from a small set of typed primitives.
17
+
18
+ Every rendered element is a genuine, editable native shape (`p:sp`, `p:pic`,
19
+ `p:graphicFrame`) — never a flattened image or embedded video. Opening the
20
+ result in PowerPoint and dragging a box around works; it's a real object,
21
+ not a picture of one.
22
+
23
+ You are receiving this document through the `compono-mcp` MCP server's
24
+ `compono://reference` resource — use its `validate`/`render_deck` tools as
25
+ described below.
26
+
27
+ ## Quickstart
28
+
29
+ ```python
30
+ from compono import render_deck
31
+
32
+ spec = {
33
+ "slides": [
34
+ {
35
+ "header": {"title": "Q3 Results", "subtitle": "Engineering team"},
36
+ "body": [
37
+ {
38
+ "primitive": "text",
39
+ "mode": "bullets",
40
+ "content": [
41
+ "Shipped the new layout resolver",
42
+ "Cut render time by 40%",
43
+ "Zero overflow bugs in production",
44
+ ],
45
+ "emphasis_indices": [1],
46
+ }
47
+ ],
48
+ }
49
+ ]
50
+ }
51
+
52
+ report = render_deck(spec, "deck.pptx")
53
+ print(report.pptx_path, report.warnings)
54
+ ```
55
+
56
+ Through this MCP server, call the `validate` and `render_deck` tools with
57
+ the identical `spec` shape instead of importing Python directly.
58
+
59
+ ## Core concepts
60
+
61
+ - **One entry point, two verbs.** `render_deck(spec, output_path)` and
62
+ `validate(spec)` are the only two functions you need. `validate` is cheap
63
+ — no pptx write, millisecond-scale — so iterate on a spec before paying
64
+ render cost.
65
+ - **A spec is plain data.** A raw `dict`/JSON (what tool-calling naturally
66
+ produces) is all you need — pass it straight to `render_deck`/`validate`.
67
+ - **You never write coordinates.** Every primitive claims space in a slide;
68
+ the resolver (a CSS-flexbox-style directional box model) computes real
69
+ EMU positions. `grid` is the one primitive that does true 2D
70
+ row/column math.
71
+ - **Errors are fixes, not diagnoses.** Every validation/render failure is
72
+ `{slide, primitive, field, error, detail, fix}` — see
73
+ [Error shape](#error-shape) below. Act on `fix`, don't just retry blindly.
74
+ - **render_deck returns a report, not just a file** —
75
+ `{pptx_path, manifest, warnings, actual_layout}` — reason about what
76
+ happened without reopening the file.
77
+
78
+ ## Tools (via this MCP server)
79
+
80
+ | Tool | Input | Output | Notes |
81
+ |---|---|---|---|
82
+ | `validate` | `spec: object` | `{valid, errors, warnings}` | No file write. Never errors out on malformed input — `valid: false` with structured errors instead. |
83
+ | `render_deck` | `spec: object, output_path: string` | `{pptx_path, manifest, warnings}` on success, or `{valid: false, errors}` on failure | Writes a real `.pptx` at `output_path` on the machine running this server. |
84
+
85
+ A `spec` (a `Deck`) is `{template?: str, slides: [Slide, ...]}`. A `Slide` is
86
+ `{header?: Header, body: [primitive, ...], notes?: str}`. `body` (and
87
+ `grid.items`) accept any primitive, keyed by its `"primitive"` field.
88
+
89
+ **Prefer `validate` before `render_deck` when iterating** — it's cheap and
90
+ gives you the same structured errors without writing a file.
91
+
92
+ ### Error shape
93
+
94
+ ```json
95
+ {
96
+ "slide": 3,
97
+ "primitive": "grid.items[1]",
98
+ "field": "content",
99
+ "error": "overflow",
100
+ "detail": "Text is ~14pt too tall for the box at font size 18pt (6 lines).",
101
+ "fix": "Shorten the text, reduce bullet/line count, or split into two slides."
102
+ }
103
+ ```
104
+
105
+ ## Primitive catalog
106
+
107
+ Every primitive accepts an optional `id` (needed if another primitive
108
+ references it, e.g. a connector) and an optional `notes` (speaker notes).
109
+ There is no separate "title slide" / "content slide" / "thank-you slide"
110
+ taxonomy — a slide is just `{header?, body: [...]}`, and genre/density/tone
111
+ decisions (what kind of slide this is, how much goes on it) are yours to
112
+ make by composing primitives, not a schema type to pick.
113
+
114
+ | Primitive | Key fields | Purpose |
115
+ |---|---|---|
116
+ | `header` | `title`, `subtitle?`, `eyebrow?`, `align` | Slide title region. |
117
+ | `text` | `mode` (paragraph/bullets), `content`, `columns?`, `emphasis_indices?` | Prose or bullet list. |
118
+ | `image` | `src?`, `placeholder`, `caption?`, `fit` (cover/contain) | A real picture, or a first-class placeholder — see below. |
119
+ | `stat` | `value`, `label`, `trend?` | A headline number with a label. |
120
+ | `grid` | `items`, `columns`, `direction`, `align`, `justify` | The one primitive with true 2D layout. Items can be any primitive, including nested grids. |
121
+ | `table` | `headers`, `rows`, `emphasis_row?`, `emphasis_col?` | Renders as a real OOXML table (`p:graphicFrame`), not an image. |
122
+ | `sequence` | `steps` (`{label, description?}`), `orientation` | A row/column of connected step boxes — process/timeline diagrams. |
123
+ | `chart` | `chart_type` (bar/line/pie), `categories`, `series` | A real, editable native chart with live data — not a picture of a chart. |
124
+ | `shape` | `kind` (rect/rounded_rect/oval/line/arrow/connector), `fill`, `border`, `connects?`, `text?` | Freeform shape, optionally with text inside, or a connector between two other primitives by `id`. |
125
+
126
+ ### Image placeholders
127
+
128
+ Set `"placeholder": true` (with an optional `caption`) instead of `src` when
129
+ you don't have a real image yet. It renders as an intentional design
130
+ element — dashed border, centered caption — and `render_deck`'s response
131
+ gets one manifest entry per placeholder:
132
+ `{slide, primitive, rect: {x, y, w, h}, caption}`. A later pass (image
133
+ search/generation/human upload) can fill each reserved rect directly from
134
+ the manifest EMU rect — no re-layout needed, and you don't need
135
+ image-generation capability just to build the deck.
136
+
137
+ ## Worked examples
138
+
139
+ ### 1. Title slide
140
+
141
+ ```json
142
+ {
143
+ "slides": [
144
+ { "header": { "title": "2026 Roadmap", "subtitle": "Platform team", "eyebrow": "Q1 Kickoff" } }
145
+ ]
146
+ }
147
+ ```
148
+
149
+ ### 2. Two-column comparison with a connector
150
+
151
+ ```json
152
+ {
153
+ "slides": [{
154
+ "header": { "title": "Before vs. After" },
155
+ "body": [
156
+ {
157
+ "primitive": "grid",
158
+ "columns": 2,
159
+ "items": [
160
+ { "id": "before", "primitive": "shape", "kind": "rounded_rect", "fill": "#EF4444",
161
+ "text": { "content": "Manual layout" } },
162
+ { "id": "after", "primitive": "shape", "kind": "rounded_rect", "fill": "#10B981",
163
+ "text": { "content": "Resolver-computed layout" } }
164
+ ]
165
+ },
166
+ { "primitive": "shape", "kind": "connector", "connects": { "from_id": "before", "to_id": "after" } }
167
+ ]
168
+ }]
169
+ }
170
+ ```
171
+
172
+ ### 3. Stat + table + chart dashboard
173
+
174
+ ```json
175
+ {
176
+ "slides": [{
177
+ "header": { "title": "Q3 Metrics" },
178
+ "body": [
179
+ { "primitive": "stat", "value": "42%", "label": "YoY growth", "trend": "+12% vs Q2" },
180
+ { "primitive": "table", "headers": ["Quarter", "Revenue"], "rows": [["Q1", "10"], ["Q2", "14"]] },
181
+ { "primitive": "chart", "chart_type": "bar", "categories": ["Q1", "Q2"],
182
+ "series": [{ "name": "Revenue", "values": [10, 14] }] }
183
+ ]
184
+ }]
185
+ }
186
+ ```
187
+
188
+ ### 4. Process sequence
189
+
190
+ ```json
191
+ {
192
+ "slides": [{
193
+ "header": { "title": "Our Process" },
194
+ "body": [{
195
+ "primitive": "sequence",
196
+ "orientation": "horizontal",
197
+ "steps": [
198
+ { "label": "Discover", "description": "Understand the problem" },
199
+ { "label": "Design", "description": "Sketch options" },
200
+ { "label": "Ship", "description": "Release to users" }
201
+ ]
202
+ }]
203
+ }]
204
+ }
205
+ ```
206
+
207
+ ## Fonts and overflow validation
208
+
209
+ Overflow checking reads real glyph advance widths via `fonttools` — no
210
+ rendering required. As of this release, no font is bundled yet; validation
211
+ falls back to a system font if one is found, and is skipped — not faked —
212
+ with a warning if none is available.
@@ -0,0 +1,72 @@
1
+ """MCP server exposing compono's render_deck/validate as MCP tools.
2
+
3
+ Every tool here is a thin proxy — no reimplemented logic. `spec` parameters
4
+ are typed as plain `dict`, not the `Deck` pydantic model, so malformed input
5
+ reaches compono.validate/render_deck itself and comes back as compono's own
6
+ structured {slide, primitive, field, error, detail, fix} shape, never MCP's
7
+ generic schema-rejection error (this is deliberate — see the project plan).
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import importlib.resources
13
+ from typing import Any
14
+
15
+ from fastmcp import FastMCP
16
+
17
+ from compono import DeckValidationError, render_deck, validate
18
+
19
+ mcp = FastMCP("compono")
20
+
21
+
22
+ @mcp.tool()
23
+ def validate_deck(spec: dict[str, Any]) -> dict[str, Any]:
24
+ """Validate a compono deck spec: schema + layout + text-overflow checks, no file write.
25
+
26
+ Cheap (millisecond-scale) — prefer this before render_deck when iterating.
27
+ Never raises: malformed input comes back as {valid: false, errors: [...]},
28
+ each error shaped {slide, primitive, field, error, detail, fix}.
29
+ """
30
+ report = validate(spec)
31
+ return {"valid": report.valid, "errors": report.errors, "warnings": report.warnings}
32
+
33
+
34
+ @mcp.tool()
35
+ def render_deck_tool(spec: dict[str, Any], output_path: str) -> dict[str, Any]:
36
+ """Render a compono deck spec to a real, editable .pptx file at output_path.
37
+
38
+ On success: {pptx_path, manifest, warnings}. On any validation/layout/
39
+ overflow error: {valid: false, errors: [...]} in the same shape as
40
+ validate_deck — nothing is written to output_path in that case.
41
+ """
42
+ try:
43
+ report = render_deck(spec, output_path)
44
+ except DeckValidationError as exc:
45
+ return {"valid": False, "errors": exc.errors}
46
+
47
+ return {
48
+ "pptx_path": str(report.pptx_path),
49
+ "manifest": report.manifest,
50
+ "warnings": report.warnings,
51
+ }
52
+
53
+
54
+ @mcp.resource("compono://reference")
55
+ def reference() -> str:
56
+ """The full agent-facing compono reference: quickstart, primitive catalog,
57
+ worked examples, and error shape — for MCP clients without Claude Code's
58
+ skill system.
59
+ """
60
+ return (
61
+ importlib.resources.files("compono_mcp")
62
+ .joinpath("reference.md")
63
+ .read_text(encoding="utf-8")
64
+ )
65
+
66
+
67
+ def main() -> None:
68
+ mcp.run(transport="stdio")
69
+
70
+
71
+ if __name__ == "__main__":
72
+ main()