@unboundai/tb-ppt-mgagent 0.3.0 → 0.5.0

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 (3) hide show
  1. package/README.md +62 -45
  2. package/build/index.js +64 -5
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,12 +1,14 @@
1
1
  # Traffic Builders PowerPoint MCP Server
2
2
 
3
- A Model Context Protocol (MCP) server that hands a presentation outline to Anthropic's hosted **Managed Agent** for building Traffic Builders-branded PowerPoints, then retrieves the finished file once it's done. Brand assets (logos, Outfit font) and the design brief are already provisioned in that agent's environment — this server does not upload anything, it just starts the run and later collects the result.
3
+ A Model Context Protocol (MCP) server that hands a presentation outline to Anthropic's hosted **Managed Agent** for building Traffic Builders-branded PowerPoints, then retrieves the finished file once it's done.
4
+
5
+ Brand assets (the design brief, logos, Outfit font) are **not** assumed to already exist in the agent's environment. A Managed Agents "deployment" (scheduled/cron runs) was investigated as a way to pin a session to a specific pre-configured setup, but it only re-sends a fixed baked-in message on a schedule — it offers no extra asset-targeting capability over a plain session. So instead, this server uploads each brand asset once via the Files API (a one-time step, see [Setup](#setup)) and attaches them explicitly to **every** session it creates via the `resources` array, mounted into the sandbox for the agent to read.
4
6
 
5
7
  Built against the official Managed Agents docs (session creation, session operations, events & streaming, files, event/type reference) using the official `@anthropic-ai/sdk` client, which sets the `managed-agents-2026-04-01` beta header automatically for session endpoints.
6
8
 
7
9
  ## Available tools
8
10
 
9
- - **`generate_tb_powerpoint(outline, deckType?, clientName?, filename?)`** — creates a session against the configured agent + environment, sends the outline as the first message, returns `{ success, sessionId, message }`. Does not wait for the deck to finish.
11
+ - **`generate_tb_powerpoint(outline, deckType?, clientName?, filename?)`** — creates a session against the configured agent + environment, attaches whichever brand asset `resources` are configured (see Setup), sends the outline as the first message, returns `{ success, sessionId, message }`. Does not wait for the deck to finish.
10
12
 
11
13
  - **`get_tb_powerpoint_result(sessionId)`** — checks on a generation started above:
12
14
  1. Retrieves the session. If its `status` isn't `idle`, returns `{ ready: false, status }` — still running, try again later.
@@ -15,7 +17,7 @@ Built against the official Managed Agents docs (session creation, session operat
15
17
 
16
18
  ## What's still an assumption
17
19
 
18
- Every SDK call in `src/index.ts` (`sessions.create`, `sessions.events.send`, `sessions.retrieve`, `sessions.events.list`, `files.list`, `files.download`) is checked against `@anthropic-ai/sdk`'s own `.d.ts`/source (installed version, not just the docs prose) — that's how a real bug was caught in 0.1.0: the docs' TypeScript sample for downloading a file shows `content.writeToFile(path)`, but that method doesn't exist on the installed SDK. `files.download()` actually resolves to a plain `Response`; 0.1.1 fixes this by reading it with `.arrayBuffer()` and writing the bytes directly.
20
+ Every SDK call in `src/index.ts` (`sessions.create`, `sessions.events.send`, `sessions.retrieve`, `sessions.events.list`, `files.list`, `files.download`) is checked against `@anthropic-ai/sdk`'s own `.d.ts`/source (installed version, not just the docs prose) — that's how a real bug was caught in 0.1.0: the docs' TypeScript sample for downloading a file shows `content.writeToFile(path)`, but that method doesn't exist on the installed SDK. `files.download()` actually resolves to a plain `Response`; 0.1.1 fixes this by reading it with `.arrayBuffer()` and writing the bytes directly. The `resources` shape (`{ type: "file", file_id, mount_path }`) is likewise checked against the SDK source, not just the docs.
19
21
 
20
22
  The one thing still **not** confirmed against a real response is the exact `filename`/path convention the Files API returns for a file the agent wrote to its outputs directory — the code guesses by matching `/outputs?[\/]/i` against the filename and falling back to any `.pptx` file on the session if nothing matches that pattern. If a real run's file list looks different, adjust the filter in `get_tb_powerpoint_result` in `src/index.ts`.
21
23
 
@@ -31,7 +33,13 @@ The one thing still **not** confirmed against a real response is the exact `file
31
33
  npm run build
32
34
  ```
33
35
 
34
- 3. **Configure environment variables**:
36
+ 3. **Upload the brand assets** (one time, or again whenever an asset changes):
37
+ ```
38
+ .\uploadAssets.ps1 -ApiKey "sk-ant-..."
39
+ ```
40
+ Uploads `TrafficBuilders-PPT-Handoff.md`, all five `logos/*.png`, and `fonts/Outfit-VariableFont_wght.ttf` to the Files API, and prints a `file_id` per asset along with the matching env var name. These are just config, not code — plug them into step 5 below and there's nothing else to change or republish.
41
+
42
+ 4. **Configure environment variables**:
35
43
  - `ANTHROPIC_API_KEY` — Anthropic API key with Managed Agents access.
36
44
  - `ANTHROPIC_AGENT_ID` — e.g. `agent_01H8osDSMeEtGcEHT1ajzuin`.
37
45
  - `ANTHROPIC_ENVIRONMENT_ID` — e.g. `env_01VHzZmqBababsghFjQoAGFx`.
@@ -39,40 +47,9 @@ The one thing still **not** confirmed against a real response is the exact `file
39
47
  - `TB_PPT_OUTPUT_DIR` — required for `get_tb_powerpoint_result`. Local folder that's synced to GCS by something outside this server; finished `.pptx` files are written here.
40
48
  - `TB_PPT_PUBLIC_URL_BASE` — required for `get_tb_powerpoint_result`. Base URL the synced folder is served from (e.g. `https://storage.googleapis.com/bucket/prefix`), used to build the returned download link.
41
49
  - `TB_PPT_LOG_FILE` — optional. Path to the task log file. Defaults to `logs/tasks.log` next to this package.
50
+ - `TB_DESIGN_BRIEF_FILE_ID`, `TB_LOGO_HORIZONTAL_FILE_ID`, `TB_LOGO_HORIZONTAL_WHITE_FILE_ID`, `TB_LOGO_ICON_FILE_ID`, `TB_LOGO_ICON_WHITE_FILE_ID`, `TB_LOGO_ICON_TAGLINE_FILE_ID`, `TB_FONT_FILE_ID` — all optional but strongly recommended, from step 3. Any left unset are just skipped (with a warning in the log) rather than failing the call — the deck still gets built, just without that asset available to the agent.
42
51
 
43
- ## Task logging
44
-
45
- Every tool call writes one JSON-lines entry to `TB_PPT_LOG_FILE` (default `logs/tasks.log`) and mirrors it to stderr (which the MCP host's own log viewer already shows, as seen in the `[powerpoint-creator]` logs). Each line has a `timestamp`, `tool`, and `status`, plus whatever's relevant to that outcome:
46
-
47
- | status | tool | meaning |
48
- |---|---|---|
49
- | `started` | either | call received, with its key arguments (outline preview/length, or sessionId) |
50
- | `success` | `generate_tb_powerpoint` | session created; includes `sessionId` |
51
- | `not_ready` | `get_tb_powerpoint_result` | session isn't `idle` yet; includes `sessionStatus` |
52
- | `agent_message` | `get_tb_powerpoint_result` | the agent's own most recent `agent.message` text, up to 500 chars, in `agentMessagePreview` — this is what the agent actually said, not our derived status. Logged once the session is idle, before the stop-reason check, so it's there even on `not_end_turn` |
53
- | `not_end_turn` | `get_tb_powerpoint_result` | idle, but `stop_reason` wasn't `end_turn`; includes `stopReason` |
54
- | `listing_files` | `get_tb_powerpoint_result` | about to call Files API `list` for this session |
55
- | `files_listed` | `get_tb_powerpoint_result` | includes `fileCount`, every `.pptx` candidate found (`pptxCandidates`, each with `id`/`filename`/`sizeBytes`), and which one was `chosenFileId` |
56
- | `no_output_file` | `get_tb_powerpoint_result` | finished cleanly but no `.pptx` found; includes `fileCount` |
57
- | `download_started` | `get_tb_powerpoint_result` | about to call Files API `download`; includes `fileId`, `filename`, `expectedSizeBytes` |
58
- | `download_completed` | `get_tb_powerpoint_result` | bytes received; includes `downloadedBytes` |
59
- | `saving_file` | `get_tb_powerpoint_result` | about to write to `destPath` inside `outputDir` |
60
- | `file_saved` | `get_tb_powerpoint_result` | write confirmed via `fs.statSync`; includes `savedBytes` and `bytesMatch` (should be `true`) |
61
- | `success` | `get_tb_powerpoint_result` | fully done; includes `filename`, `destPath`, `downloadUrl` |
62
- | `invalid_arguments` | either | zod validation failed; includes `details` |
63
- | `error` | either | anything else threw; includes `message` |
64
-
65
- The agent's actual final message is also returned to the caller as `agentMessage` on every `get_tb_powerpoint_result` response (not just logged), so a not-quite-right run can be diagnosed from the tool's own output, not just the log file.
66
-
67
- All entries include `durationMs` except the intermediate progress lines (`agent_message`, `listing_files`, `files_listed`, `download_started`, `download_completed`, `saving_file`) — those are pure checkpoints, timed by their surrounding `started`/`success`/`error` lines instead. To see what's been run:
68
-
69
- ```bash
70
- tail -f logs/tasks.log
71
- # or, for just failures:
72
- grep -E '"status":"(error|not_end_turn|no_output_file)"' logs/tasks.log
73
- ```
74
-
75
- 4. **Register with your MCP client** (Claude Desktop / TypingMind's local MCP connector — same pattern as this repo's siblings, e.g. `tb-gcs-assembly-mcp`). Published to npm as [`@unboundai/tb-ppt-mgagent`](https://www.npmjs.com/package/@unboundai/tb-ppt-mgagent), so `npx` can run it without a local checkout:
52
+ 5. **Register with your MCP client** (Claude Desktop / TypingMind's local MCP connector — same pattern as this repo's siblings, e.g. `tb-gcs-assembly-mcp`). Published to npm as [`@unboundai/tb-ppt-mgagent`](https://www.npmjs.com/package/@unboundai/tb-ppt-mgagent), so `npx` can run it without a local checkout:
76
53
 
77
54
  ```json
78
55
  "tb-ppt-mgagent": {
@@ -86,7 +63,14 @@ grep -E '"status":"(error|not_end_turn|no_output_file)"' logs/tasks.log
86
63
  "ANTHROPIC_AGENT_ID": "agent_...",
87
64
  "ANTHROPIC_ENVIRONMENT_ID": "env_...",
88
65
  "TB_PPT_OUTPUT_DIR": "/path/to/gcs-synced-folder",
89
- "TB_PPT_PUBLIC_URL_BASE": "https://storage.googleapis.com/your-bucket/your-prefix"
66
+ "TB_PPT_PUBLIC_URL_BASE": "https://storage.googleapis.com/your-bucket/your-prefix",
67
+ "TB_DESIGN_BRIEF_FILE_ID": "file_...",
68
+ "TB_LOGO_HORIZONTAL_FILE_ID": "file_...",
69
+ "TB_LOGO_HORIZONTAL_WHITE_FILE_ID": "file_...",
70
+ "TB_LOGO_ICON_FILE_ID": "file_...",
71
+ "TB_LOGO_ICON_WHITE_FILE_ID": "file_...",
72
+ "TB_LOGO_ICON_TAGLINE_FILE_ID": "file_...",
73
+ "TB_FONT_FILE_ID": "file_..."
90
74
  }
91
75
  }
92
76
  ```
@@ -103,12 +87,45 @@ grep -E '"status":"(error|not_end_turn|no_output_file)"' logs/tasks.log
103
87
  }
104
88
  ```
105
89
 
106
- ### Publishing a new version
90
+ ### Publishing a new version
107
91
 
108
- ```bash
109
- npm version patch # or minor/major
110
- npm publish # prepublishOnly rebuilds automatically; will prompt for a 2FA OTP
111
- ```
92
+ ```bash
93
+ npm version patch # or minor/major
94
+ npm publish # prepublishOnly rebuilds automatically; will prompt for a 2FA OTP
95
+ ```
96
+
97
+ ## Task logging
98
+
99
+ Every tool call writes one JSON-lines entry to `TB_PPT_LOG_FILE` (default `logs/tasks.log`) and mirrors it to stderr (which the MCP host's own log viewer already shows, as seen in the `[powerpoint-creator]` logs). Each line has a `timestamp`, `tool`, and `status`, plus whatever's relevant to that outcome:
100
+
101
+ | status | tool | meaning |
102
+ |---|---|---|
103
+ | `started` | either | call received, with its key arguments (outline preview/length, or sessionId) |
104
+ | `attaching_assets` | `generate_tb_powerpoint` | which brand asset `resources` are being attached (`attached`, a list of mount paths) and which env vars are unset (`missing`) |
105
+ | `success` | `generate_tb_powerpoint` | session created; includes `sessionId` and `assetsAttached` count |
106
+ | `not_ready` | `get_tb_powerpoint_result` | session isn't `idle` yet; includes `sessionStatus` |
107
+ | `agent_message` | `get_tb_powerpoint_result` | the agent's own most recent `agent.message` text, up to 500 chars, in `agentMessagePreview` — this is what the agent actually said, not our derived status. Logged once the session is idle, before the stop-reason check, so it's there even on `not_end_turn` |
108
+ | `not_end_turn` | `get_tb_powerpoint_result` | idle, but `stop_reason` wasn't `end_turn`; includes `stopReason` |
109
+ | `listing_files` | `get_tb_powerpoint_result` | about to call Files API `list` for this session |
110
+ | `files_listed` | `get_tb_powerpoint_result` | includes `fileCount`, every `.pptx` candidate found (`pptxCandidates`, each with `id`/`filename`/`sizeBytes`), and which one was `chosenFileId` |
111
+ | `no_output_file` | `get_tb_powerpoint_result` | finished cleanly but no `.pptx` found; includes `fileCount` |
112
+ | `download_started` | `get_tb_powerpoint_result` | about to call Files API `download`; includes `fileId`, `filename`, `expectedSizeBytes` |
113
+ | `download_completed` | `get_tb_powerpoint_result` | bytes received; includes `downloadedBytes` |
114
+ | `saving_file` | `get_tb_powerpoint_result` | about to write to `destPath` inside `outputDir` |
115
+ | `file_saved` | `get_tb_powerpoint_result` | write confirmed via `fs.statSync`; includes `savedBytes` and `bytesMatch` (should be `true`) |
116
+ | `success` | `get_tb_powerpoint_result` | fully done; includes `filename`, `destPath`, `downloadUrl` |
117
+ | `invalid_arguments` | either | zod validation failed; includes `details` |
118
+ | `error` | either | anything else threw; includes `message` |
119
+
120
+ The agent's actual final message is also returned to the caller as `agentMessage` on every `get_tb_powerpoint_result` response (not just logged), so a not-quite-right run can be diagnosed from the tool's own output, not just the log file.
121
+
122
+ All entries include `durationMs` except the intermediate progress lines (`attaching_assets`, `agent_message`, `listing_files`, `files_listed`, `download_started`, `download_completed`, `saving_file`) — those are pure checkpoints, timed by their surrounding `started`/`success`/`error` lines instead. To see what's been run:
123
+
124
+ ```bash
125
+ tail -f logs/tasks.log
126
+ # or, for just failures:
127
+ grep -E '"status":"(error|not_end_turn|no_output_file)"' logs/tasks.log
128
+ ```
112
129
 
113
130
  ## Development
114
131
 
@@ -117,8 +134,8 @@ grep -E '"status":"(error|not_end_turn|no_output_file)"' logs/tasks.log
117
134
  npm run dev
118
135
  ```
119
136
 
120
- Both tools were smoke-tested end-to-end over the real MCP protocol (`tools/list`, and calling each with a dummy API key to confirm the SDK calls actually reach `api.anthropic.com` and get a real `401 authentication_error` back rather than failing on a wrong method/shape before the network call).
137
+ Both tools were smoke-tested end-to-end over the real MCP protocol (`tools/list`, and calling each with a dummy API key to confirm the SDK calls actually reach `api.anthropic.com` and get a real `401 authentication_error` back rather than failing on a wrong method/shape before the network call) — including with asset env vars set, to confirm the `resources` array builds correctly.
121
138
 
122
139
  ## Design brief reference
123
140
 
124
- `TrafficBuilders-PPT-Handoff.md`, `logos/`, and `fonts/` in this repo are the source material that was provisioned into the Managed Agent's environment (colors, type scale, the six slide archetypes, brand logo PNGs, Outfit variable font). Kept here as the local record of what the environment should contain — not read or uploaded by this server at runtime.
141
+ `TrafficBuilders-PPT-Handoff.md`, `logos/`, and `fonts/` in this repo are the source material — pulled from the "Traffic Builders Design System" Claude Design project (colors, type scale, the 19 slide archetypes, brand logo PNGs, Outfit variable font) — that `uploadAssets.ps1` uploads and every session attaches via `resources`. Update the files here first if the design system changes, then re-run `uploadAssets.ps1` and update the env vars with the new file_ids. No slide-image assets are attached separately — the handoff brief embeds a literal HTML/CSS reference snippet per archetype, which is enough on its own (see its closing section for when a visual PNG reference would be worth adding).
package/build/index.js CHANGED
@@ -3,11 +3,17 @@
3
3
  * Traffic Builders PowerPoint MCP Server
4
4
  *
5
5
  * Hands a presentation outline to Anthropic's hosted Managed Agent that
6
- * builds Traffic Builders-branded PowerPoints (brand assets and design
7
- * brief are already provisioned in that agent's environment - this server
8
- * does not upload any brand files itself), then later retrieves the
6
+ * builds Traffic Builders-branded PowerPoints, then later retrieves the
9
7
  * finished .pptx once the agent's turn has ended.
10
8
  *
9
+ * Brand assets (design brief, logos, font) are NOT assumed to already exist
10
+ * in the agent's environment - a "deployment" in the Managed Agents API is
11
+ * only a fixed/scheduled way to re-run the same baked-in message and offers
12
+ * no extra asset-targeting capability over a plain session, so instead this
13
+ * server attaches each asset to every session explicitly via the `resources`
14
+ * array (mounted through the Files API - see uploadAssets.ps1 for the
15
+ * one-time upload step that produces the file_ids below).
16
+ *
11
17
  * Built against the documented Managed Agents API:
12
18
  * https://platform.claude.com/docs/en/managed-agents/sessions
13
19
  * https://platform.claude.com/docs/en/managed-agents/session-operations
@@ -42,6 +48,15 @@
42
48
  * next to this package. Every entry is also mirrored to stderr, which the
43
49
  * MCP host's own log viewer already picks up - the file exists so history
44
50
  * survives a host restart and can be grepped/tailed directly.
51
+ * - TB_DESIGN_BRIEF_FILE_ID, TB_LOGO_HORIZONTAL_FILE_ID,
52
+ * TB_LOGO_HORIZONTAL_WHITE_FILE_ID, TB_LOGO_ICON_FILE_ID,
53
+ * TB_LOGO_ICON_WHITE_FILE_ID, TB_LOGO_ICON_TAGLINE_FILE_ID,
54
+ * TB_FONT_FILE_ID: all optional but strongly recommended. Files API
55
+ * file_ids (from uploadAssets.ps1) for the design brief, each logo
56
+ * variant, and the Outfit font. Any that are set get mounted into every
57
+ * session via `resources`; any left unset are just skipped (with a
58
+ * warning), so the agent falls back to approximating the brand from the
59
+ * prompt text alone.
45
60
  */
46
61
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
47
62
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
@@ -87,6 +102,26 @@ if (!OUTPUT_DIR)
87
102
  console.error("Warning: TB_PPT_OUTPUT_DIR environment variable is not set (needed for get_tb_powerpoint_result)");
88
103
  if (!PUBLIC_URL_BASE)
89
104
  console.error("Warning: TB_PPT_PUBLIC_URL_BASE environment variable is not set (needed for get_tb_powerpoint_result)");
105
+ /**
106
+ * Brand assets mounted into every session via `resources`. `mountPath` is
107
+ * relative to the session's uploads root - see file header - so the actual
108
+ * sandbox path is `/mnt/session/uploads${mountPath}`. Any entry whose env
109
+ * var isn't set is skipped (not an error): the deck still gets built, just
110
+ * without that asset available to the agent.
111
+ */
112
+ const ASSET_RESOURCES = [
113
+ { envVar: "TB_DESIGN_BRIEF_FILE_ID", mountPath: "/design/TrafficBuilders-PPT-Handoff.md", label: "design brief" },
114
+ { envVar: "TB_LOGO_HORIZONTAL_FILE_ID", mountPath: "/design/logos/logo-horizontal.png", label: "logo-horizontal.png (full-color, light backgrounds)" },
115
+ { envVar: "TB_LOGO_HORIZONTAL_WHITE_FILE_ID", mountPath: "/design/logos/logo-horizontal-white.png", label: "logo-horizontal-white.png (reversed, brand-blue backgrounds)" },
116
+ { envVar: "TB_LOGO_ICON_FILE_ID", mountPath: "/design/logos/logo-icon.png", label: "logo-icon.png (full-color square mark)" },
117
+ { envVar: "TB_LOGO_ICON_WHITE_FILE_ID", mountPath: "/design/logos/logo-icon-white.png", label: "logo-icon-white.png (reversed square mark)" },
118
+ { envVar: "TB_LOGO_ICON_TAGLINE_FILE_ID", mountPath: "/design/logos/logo-icon-tagline.png", label: "logo-icon-tagline.png (icon + tagline lockup)" },
119
+ { envVar: "TB_FONT_FILE_ID", mountPath: "/design/fonts/Outfit-VariableFont_wght.ttf", label: "Outfit variable font (weights 300-900)" }
120
+ ];
121
+ const missingAssetEnvVars = ASSET_RESOURCES.filter((a) => !(process.env[a.envVar] || "").trim());
122
+ if (missingAssetEnvVars.length > 0) {
123
+ console.error(`Warning: brand asset file_ids not configured, decks will be built without them: ${missingAssetEnvVars.map((a) => a.envVar).join(", ")}`);
124
+ }
90
125
  function requireSessionConfig() {
91
126
  if (!API_KEY)
92
127
  throw new Error("ANTHROPIC_API_KEY is not configured on this MCP server.");
@@ -208,9 +243,27 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
208
243
  });
209
244
  const { apiKey, agentId, environmentId } = requireSessionConfig();
210
245
  const client = getClient(apiKey);
246
+ const attachedAssets = ASSET_RESOURCES
247
+ .map((a) => ({ ...a, fileId: (process.env[a.envVar] || "").trim() }))
248
+ .filter((a) => a.fileId);
249
+ logTask({
250
+ tool: name,
251
+ status: "attaching_assets",
252
+ attached: attachedAssets.map((a) => a.mountPath),
253
+ missing: missingAssetEnvVars.map((a) => a.envVar)
254
+ });
211
255
  const session = await client.beta.sessions.create({
212
256
  agent: agentId,
213
- environment_id: environmentId
257
+ environment_id: environmentId,
258
+ ...(attachedAssets.length > 0
259
+ ? {
260
+ resources: attachedAssets.map((a) => ({
261
+ type: "file",
262
+ file_id: a.fileId,
263
+ mount_path: a.mountPath
264
+ }))
265
+ }
266
+ : {})
214
267
  });
215
268
  const lines = [];
216
269
  if (deckType)
@@ -220,7 +273,12 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
220
273
  if (filename)
221
274
  lines.push(`Save the resulting file as "${filename}.pptx".`);
222
275
  const meta = lines.length ? `${lines.join("\n")}\n\n` : "";
223
- const messageText = `Build a Traffic Builders PowerPoint from the following outline.\n\n${meta}## Outline\n${outline}`;
276
+ const assetsNote = attachedAssets.length > 0
277
+ ? `## Attached brand assets\nThese files are mounted in your sandbox:\n${attachedAssets
278
+ .map((a) => `- /mnt/session/uploads${a.mountPath} - ${a.label}`)
279
+ .join("\n")}\n\nRead the design brief first and follow it exactly: brand colors, type scale, and the 19 slide archetypes it defines. Follow its logo lockup rule precisely - it is not a simple per-background swap: the wordmark logo appears ONLY on Title and Section-divider slides (top-left), while a small icon mark appears bottom-right on EVERY slide regardless of archetype; use the white logo variants on brand-blue backgrounds and the full-color variants on white backgrounds. Embed/register the attached font file and use it for all text - ExtraBold (800) for headings, Regular (400) for body - instead of a fallback typeface.\n\n---\n\n`
280
+ : "";
281
+ const messageText = `Build a Traffic Builders PowerPoint from the following outline.\n\n${assetsNote}${meta}## Outline\n${outline}`;
224
282
  await client.beta.sessions.events.send(session.id, {
225
283
  events: [
226
284
  { type: "user.message", content: [{ type: "text", text: messageText }] }
@@ -230,6 +288,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
230
288
  tool: name,
231
289
  status: "success",
232
290
  sessionId: session.id,
291
+ assetsAttached: attachedAssets.length,
233
292
  durationMs: Date.now() - startedAt
234
293
  });
235
294
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unboundai/tb-ppt-mgagent",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "MCP server that hands a presentation outline to the Traffic Builders PowerPoint Managed Agent, then retrieves the finished .pptx",
5
5
  "main": "build/index.js",
6
6
  "bin": {