feat(devframe): add MCP resource providers, templates, and subscriptions - #292
feat(devframe): add MCP resource providers, templates, and subscriptions#292dvcolomban wants to merge 5 commits into
Conversation
|
@dvcolomban is attempting to deploy a commit to the NuxtLabs Team on Vercel. A member of the Team first needs to authorize it. |
There was a problem hiding this comment.
Pull request overview
Adds first-class MCP resource capabilities to Devframe’s agent surface by introducing resource templates, lazy resource providers, and per-connection resource subscriptions. This extends the existing “tools vs readable context” model so adapters (notably MCP) can advertise URI families, list concrete instances, and push invalidation updates to subscribed clients without polling.
Changes:
- Extend the agent API/types to support concrete resources, URI templates, resource providers, and subscription lifecycle hooks (read/list/subscribe/unsubscribe + updated notifications).
- Implement MCP server support for
resources/templates/list, template-backedresources/list,resources/subscribe/resources/unsubscribe, and filteredresources/updatednotifications with async disposal. - Add/expand tests (in-memory + stdio + HTTP) and update docs to describe the new resource model and events.
Reviewed changes
Copilot reviewed 12 out of 16 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/snapshots/tsnapi/devframe/types.snapshot.d.ts | Snapshot updates for newly exported agent resource/provider/template types. |
| tests/snapshots/tsnapi/devframe/internal.snapshot.d.ts | Snapshot updates for DevframeAgentHost’s updated private fields and new resource APIs. |
| tests/snapshots/tsnapi/devframe/index.snapshot.d.ts | Snapshot updates for public agent interfaces (templates/providers/subscriptions). |
| tests/snapshots/tsnapi/devframe/constants.snapshot.d.ts | Snapshot update for the new agent:resource:updated event constant. |
| skills/devframe/SKILL.md | Update skill docs/examples to include templates/providers/subscriptions usage. |
| packages/devframe/src/types/agent.ts | Core type additions for templates, providers, variables, handles, and new agent host methods/events. |
| packages/devframe/src/node/host-agent.ts | Agent host implementation for registering templates/providers and forwarding reads/subscriptions + update notifications. |
| packages/devframe/src/node/tests/host-agent.test.ts | Unit tests covering custom URIs, templates, variables, subscriptions, handles, and providers. |
| packages/devframe/src/events.ts | Add the agent:resource:updated event name to the central event map. |
| packages/devframe/src/adapters/mcp/fetch.ts | Ensure MCP session disposal awaits async resource cleanup. |
| packages/devframe/src/adapters/mcp/build-server.ts | MCP resources: list/read/templates + subscribe/unsubscribe + subscription reconciliation/disposal. |
| packages/devframe/src/adapters/mcp/tests/mcp-server.test.ts | In-memory MCP tests for explicit URIs, templates, subscription behavior, provider churn, and stdio coverage. |
| packages/devframe/src/adapters/mcp/tests/mcp-http.test.ts | HTTP transport test verifying session-local subscriptions and cleanup on disconnect. |
| packages/devframe/src/adapters/mcp/tests/fixtures/resource-stdio-server.ts | Stdio fixture server wiring resources + template and emitting updates. |
| docs/content/1.guide/20.events.md | Document agent:resource:updated and clarify registered payload types. |
| docs/content/1.guide/14.agent-native.md | Document resource URIs, templates, subscriptions, and providers for native agent usage. |
Suppressed comments (1)
packages/devframe/src/adapters/mcp/build-server.ts:430
- During manifest reconciliation, the code removes each subscription from the
subscriptionsmap before awaiting its cleanup. If a cleanup throws/rejects, the outer.catch()swallows the error and the subscription is permanently lost (not tracked for later disposal/retry), causing leaks and inconsistent subscription state. Keep the subscription tracked until cleanup succeeds, and handle cleanup errors per-URI so one failure doesn’t abort the entire reconciliation pass.
for (const [uri, cleanup] of [...subscriptions]) {
subscriptions.delete(uri)
await cleanup()
const resource = resolveAgentResource(ctx, uri)
if (!resource)
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Why
Devframe already distinguishes agent actions from readable context. Actions are exposed as tools through
ctx.agent.registerTool, while snapshots are exposed as resources throughctx.agent.registerResource.The resource side currently supports one concrete URI and pull-based reads. MCP has two useful resource features that Devframe cannot express yet:
logs://{process}without registering every possible URI up front. A template may still list the concrete resources that currently exist.resources/updated; the client then reads the latest snapshot. This keeps values current without polling or pushing resource contents through a separate event format.Resource providers mirror tool providers. They let an existing catalog remain the source of truth while Devframe projects its current resources on demand.
How it fits Devframe
The existing agent host remains the seam between a devtool and protocol adapters:
The agent host owns registration order, duplicate handling, provider precedence, reads, and lifecycle callbacks. The MCP adapter owns URI-template matching and connection-local subscriptions because those are MCP concerns.
Tools and resources keep separate roles. Tools invoke behavior. Resources expose current context through stable URIs.
Interface
registerResourceaccepts either anAgentResourceInputor anAgentResourceTemplateInput.URL. Existing zero-argument readers remain valid.notifyUpdated(). Template handles identify the concrete URI that changed.registerResourceProvideradds lazy discovery withnotifyChanged()andnotifyUpdated(uri).MCP behavior
urikeeps the generateddevframe://resource/<encoded-id>URI.resources/templates/listadvertises templates. Templatelist()results also appear inresources/list.resources.subscribebecause it implementsresources/subscribeandresources/unsubscribe. MCP clients use this capability to decide whether subscriptions are supported.resources/updatedis sent only to connections subscribed to that URI.devframe://state/...resources use their SharedState update event to notify subscribed clients.resources/list_changed. Content changes emitresources/updated.exposeSharedState: falseor a key predicate. The default remainstrue.Compatibility
This change keeps the existing defaults and behavior for:
devframe://state/...resources and theexposeSharedStatedefaultdevframe_state_readtoolExisting resource registrations retain their generated URI and default JSON MIME type.