A chat surface is not a smaller browser.
OpenAI now describes plugins as a package of reusable skills and connections to external services. Its current documentation tells builders to start with user goals, build tools before custom interface work, and make the workflow useful without a widget.[1]
That changes the design problem. A website can explain a product, support browsing, and provide a durable public address. A chat host may need one record, one action, or one result. Sending the whole homepage into that exchange adds presentation without defining authority.
Keep the public page. Build a separate contract for context and action.
Resources carry context, not permission.
The Model Context Protocol defines resources as application-driven context with unique URIs. A client can list, read, search, filter, or subscribe to resources. The protocol does not require one interface pattern.[2]
That makes a resource a good home for a document, schema, project summary, or other read target. Give each item a stable identifier and a useful media type. Do not turn every readable object into a callable action.
Tools need narrow verbs.
OpenAI's plugin guide recommends one tool for each distinct action. It calls for an action-oriented name, explicit input and output schemas, accurate safety annotations, and a handler that authorizes every request. It also says useful results should work without custom UI and should return stable identifiers for later calls.[1]
A tool named manage_project hides too much. Separate list_projects, get_project, and update_project. The first two can be read-only. The last one needs identity, scope, validation, confirmation when the change is costly, and a result that names the updated record.
The widget is still untrusted input.
OpenAI's security guide says plugin widgets run in an isolated iframe with a strict content security policy. It also tells servers to validate model-provided inputs, enforce scopes on every call, require confirmation for irreversible work, and keep secrets out of component properties and results.[3]
A polished card does not grant authority. Authorization belongs on the server. The visible control should tell the user what will happen, while the server checks whether it may happen.
Ship four tests, not one demo.
- Open the public page without chat and confirm that its explanation still works.
- List and read each resource by its stable URI.
- Call every tool with allowed, denied, stale, and malformed inputs.
- Check that each successful action returns a stable record ID, changed state, and correlation ID without secrets.
The transfer switch below drafts that contract. It does not create a plugin, connect an account, call a tool, or verify a deployment.