@womp/openai-plugin 0.0.0-stage → 0.1.1

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.
package/README.md CHANGED
@@ -1,3 +1,109 @@
1
- # Temporary Holding Version
1
+ # @womp/openai-plugin
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Womp in ChatGPT: the MCP tools, the model's workflow and the cards ChatGPT
4
+ shows. It is a library. swan-backend serves it over HTTP and implements its
5
+ backend; this package has no server, database or credentials of its own.
6
+
7
+ ```ts
8
+ import { createServer, BackendRefusal, type WompBackend } from "@womp/openai-plugin"
9
+
10
+ const server = createServer({ backend, subject, onError, instructions }) // one per request
11
+ ```
12
+
13
+ ## Architecture
14
+
15
+ ```
16
+ ChatGPT ──MCP──► swan-backend ── createServer({ backend, subject }) ──► this package
17
+ ▲ │
18
+ └──────────────── WompBackend ◄──────────────────────┘
19
+ ```
20
+
21
+ ```
22
+ src/
23
+ index.ts public API
24
+ server.ts createServer → registerResources (every card) + registerTools (every tool group)
25
+ backend.ts WompBackend: the contract the host implements
26
+ tools/ one file per tool group (scene.ts); tool.ts: shared helpers
27
+ cards/ one folder per card (design/); bridge.ts: shared host connection
28
+ text.ts what tools and cards say to the model
29
+ prompts/ the workflow the model follows
30
+ ```
31
+
32
+ ### Dependency rules
33
+
34
+ - `server` → `tools` → `backend`, `text`, `prompts`, `cards/<card>/data.ts`.
35
+ - `cards/<card>` → its own `data.ts` and `cards/bridge.ts`. A card never imports `tools`, `server` or `backend`.
36
+ - Nothing imports `server` except `index`. Nothing outside this package sees more than the public API.
37
+
38
+ ### Public API
39
+
40
+ | Export | Purpose |
41
+ |---|---|
42
+ | `createServer({ backend, subject?, onError?, instructions? })` | the MCP server for one request |
43
+ | `WompBackend` | the contract the host implements |
44
+ | `BackendRefusal` | an error whose message reaches the model as worded |
45
+
46
+ `subject` is the caller as the host established it. `onError` receives every
47
+ error that is not a `BackendRefusal`. `instructions` is appended to the
48
+ server instructions, for tools the host registers itself.
49
+
50
+ ## Contract
51
+
52
+ ### Host → plugin: `WompBackend`
53
+
54
+ | Method | Does |
55
+ |---|---|
56
+ | `openScene(subject, { designId?, title? })` | finds the caller's design, or makes one, and opens a **build** of it; returns `{ designId, buildId, title }` |
57
+ | `getSceneApi()` | the scene skill, script limits, view names, and `notes` about these designs |
58
+ | `runScript(subject, { designId, code, purpose })` | runs one script on the design; `purpose` becomes the current build's activity, its last screenshot or a fresh render its picture; a failed script returns `ok: false` |
59
+ | `renderScene(subject, { designId, view?, targetId? })` | renders the design; the image also becomes the current build's picture |
60
+ | `finishScene(subject, { designId, title })` | marks the current build done, with this version's title |
61
+ | `getBuild(subject, { designId, buildId })` | a build's status, activity, title and picture; a build that isn't the caller's reads as empty |
62
+
63
+ A build is one round of changes and has one card. Opening a new build never
64
+ changes an earlier one.
65
+
66
+ ### Plugin → model and cards
67
+
68
+ - **Identity.** Every tool acts as `subject`. Tool arguments and client `_meta` are never read for identity. Without a subject every tool call fails.
69
+ - **Errors.** A `BackendRefusal` message reaches the model as is. Any other error is one generic failure, reported to `onError`.
70
+ - **Tool metadata states facts.** Descriptions, input schemas and server instructions say what a tool does, never how the model should behave. Behaviour lives in `prompts/` and reaches the model in `load_scene_skill`'s result.
71
+ - **Every tool** declares `ui.visibility`, explicit annotation hints, and `securitySchemes: noauth`. Tools only a card calls are `ui.visibility: ["app"]`.
72
+ - **Card data** is the tool result's `structuredContent`, typed by the card's `data.ts`. Tools map backend types to it; a card never receives backend types.
73
+ - **Cards** are MCP Apps resources (`text/html;profile=mcp-app`): one self-contained HTML file each, loading nothing from outside, with a `ui://` URI that changes with its content.
74
+
75
+ ### Tools
76
+
77
+ | Tool | Called by | Card |
78
+ |---|---|---|
79
+ | `open_scene` | model | shows `design` |
80
+ | `load_scene_skill` | model | |
81
+ | `run_scene_script` | model | |
82
+ | `render_scene` | model | |
83
+ | `finish_scene` | model | |
84
+ | `get_scene_progress` | `design` card | |
85
+
86
+ ## Extending
87
+
88
+ **A card.** A folder in `src/cards/<name>/` with `index.html`, `main.ts` and
89
+ `data.ts`, and a description in `text.ts` (`CARD_DESCRIPTIONS`). The build
90
+ picks it up as `CARDS.<name>`; the tool that shows it sets `ui.resourceUri:
91
+ CARDS.<name>.uri` and returns its `data.ts` shape as `structuredContent`.
92
+
93
+ **A tool group.** `src/tools/<group>.ts` exporting `register<Group>Tools(server,
94
+ backend, run)`, called from `registerTools` in `server.ts`. Its text goes in
95
+ `text.ts`; new backend methods in `backend.ts`.
96
+
97
+ **A contract change** (anything in `backend.ts`) ships with the host's
98
+ implementation in the same release.
99
+
100
+ ## Development
101
+
102
+ ```bash
103
+ npm run dev # card preview at http://127.0.0.1:5188/preview/, live from source
104
+ npm test # build the cards, run the tests
105
+ npm run check # format, build, typecheck, tests (CI)
106
+ ```
107
+
108
+ Release: bump the version and tag `vX.Y.Z`; CI publishes to npm. Then bump the
109
+ dependency in swan-backend.
@@ -0,0 +1,83 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+
3
+ interface SceneApi {
4
+ skill: {
5
+ name: string;
6
+ version: string;
7
+ instructions: string;
8
+ declarations: string;
9
+ examples: string[];
10
+ };
11
+ limits: {
12
+ timeoutMs: number;
13
+ maxCodeLength: number;
14
+ maxImages: number;
15
+ };
16
+ views: string[];
17
+ notes: string[];
18
+ }
19
+ interface Image {
20
+ data: string;
21
+ mimeType: string;
22
+ }
23
+ interface ScriptResult {
24
+ ok: boolean;
25
+ value?: unknown;
26
+ logs: string[];
27
+ receipts: {
28
+ operation: string;
29
+ status: string;
30
+ }[];
31
+ images: Image[];
32
+ error?: string;
33
+ }
34
+ interface Picture extends Image {
35
+ at: string;
36
+ }
37
+ interface Build {
38
+ status: "building" | "done";
39
+ activity?: string;
40
+ title?: string;
41
+ picture: Picture | null;
42
+ }
43
+ interface WompBackend {
44
+ openScene(subject: string, input: {
45
+ designId?: string;
46
+ title?: string;
47
+ }): Promise<{
48
+ designId: string;
49
+ buildId: string;
50
+ title: string;
51
+ }>;
52
+ getSceneApi(): Promise<SceneApi>;
53
+ runScript(subject: string, input: {
54
+ designId: string;
55
+ code: string;
56
+ purpose: string;
57
+ }): Promise<ScriptResult>;
58
+ renderScene(subject: string, input: {
59
+ designId: string;
60
+ view?: string;
61
+ targetId?: number;
62
+ }): Promise<Image>;
63
+ finishScene(subject: string, input: {
64
+ designId: string;
65
+ title: string;
66
+ }): Promise<void>;
67
+ getBuild(subject: string, input: {
68
+ designId: string;
69
+ buildId: string;
70
+ }): Promise<Build>;
71
+ }
72
+ declare class BackendRefusal extends Error {
73
+ }
74
+
75
+ interface ServerOptions {
76
+ backend: WompBackend;
77
+ subject?: string;
78
+ onError?: (tool: string, error: unknown) => void;
79
+ instructions?: string;
80
+ }
81
+ declare function createServer({ backend, subject, onError, instructions }: ServerOptions): McpServer;
82
+
83
+ export { BackendRefusal, type WompBackend, createServer };