- Keep the low-level
ServerAPI (noMcpServerregistry). - Preserve current resource behavior (Skyfire readme + OpenAI widgets).
- Make the implementation easy to extend without extra abstractions.
- Keep changes minimal and localized.
- Do not add new resources or templates in this phase.
- Resource handlers are thin and delegate to
createResourceService. - Resource service lives in
src/resources/resource_service.ts. - Widget registry lives in
src/resources/widgets.ts. - Supported resources:
file://readme.md(Skyfire usage guide, gated byskyfireMode)ui://widget/*(OpenAI UI widgets, gated byuiMode === "openai")
- Templates are not exposed (
ListResourceTemplatesRequestSchemareturns empty list).
Create a single service module that owns list/read/templates logic and keeps handlers thin.
Location:
src/resources/resource_service.ts
API:
listResources(): Promise<ListResourcesResult>readResource(uri: string): Promise<ReadResourceResult>(extended to includehtmlfor widgets)listResourceTemplates(): Promise<ListResourceTemplatesResult>(empty for now)
ActorsMcpServer.setupResourceHandlers delegates directly:
ListResourcesRequestSchema→resourceService.listResources()ReadResourceRequestSchema→resourceService.readResource(uri)ListResourceTemplatesRequestSchema→resourceService.listResourceTemplates()
- Skyfire readme only when
skyfireModeis true. - Widgets only when
uiMode === "openai"and the widget file exists. - Read failures return plain-text content (no throw).
- Add new resource types by extending
resource_service.ts. - Add resource templates by returning non-empty
resourceTemplates. - Add subscriptions/notifications by layering a small subscription manager in the service.
- No new resource types or templates.
- No change to low-level
Serverusage. - No behavior changes for current clients.
- Use MCP SDK types (
Resource,ListResourcesResult,ReadResourceResult) for clarity. - Keep widget metadata in
_metawith OpenAI keys as-is. - Keep service synchronous where possible and avoid extra indirection.
The official SDK’s conformance server (/home/jirka/github/typescript-sdk/src/conformance/everything-server.ts) uses McpServer.registerResource and ResourceTemplate. The SDK’s high-level server owns:
- Resource registry (static and template resources)
resources/list,resources/read, andresources/templates/listhandlers- Template matching and completion
This is a different abstraction layer than the low-level Server we use here, so the registry and handlers are not available to reuse.
FastMCP is also built on the low-level Server but provides its own registry layer:
- Maintains internal maps:
#resourcesand#resourceTemplates - Registers low-level handlers:
ListResourcesRequestSchemareturns the cached list from the mapReadResourceRequestSchemaloads a direct resource or resolves a templateListResourceTemplatesRequestSchemareturns templates (if present)
- Exposes convenience methods:
addResource,addResources,addResourceTemplate,removeResource, etc. - Handles template matching via
parseURITemplate
There is no ResourceProvider abstraction. FastMCP centralizes list/read logic in one place and uses an internal registry to keep handlers simple.
No. A provider interface is optional and not part of MCP or the official SDK. Given the current scope, a single minimal resource service (like a small registry) keeps the code shortest and easiest to follow. Add a provider interface only if the number of resource types grows enough to justify the extra indirection.
- Servers that support resources must declare
capabilities.resources. - Optional flags:
subscribe: server supportsresources/subscribeand update notifications.listChanged: server emitsnotifications/resources/list_changed.
resources/listsupports pagination and returnsresourcesplus optionalnextCursor.resources/readreturnscontentscontaining text or binary resource blocks.resources/templates/listreturns URI templates for parameterized resources.
notifications/resources/list_changedwhen the list changes.notifications/resources/updatedfor subscribed resources.
Resourcefields:uri,name, optionaltitle,description,icons,mimeType,size.ResourceContentcontains eithertextorblob(base64), plusuriandmimeType.- Optional
annotations:audience,priority,lastModified.
https://: only when client can fetch directly.file://: filesystem-like resources (virtual or real).git://: version control resources.- Custom schemes must follow RFC 3986.
- Resource not found:
-32002 - Internal error:
-32603
- Official MCP TypeScript SDK:
/home/jirka/github/typescript-sdk - Example server implementing full MCP specs:
/home/jirka/github/servers/src/everything - FastMCP:
/home/jirka/github/fastmcp