Wix — MCP Resources: all you need to know¶
Summary¶
Wix Engineering's 2026-01-08 Medium post by an unnamed author is a
tutorial-shape retrospective on the MCP Resources primitive —
the read-only, addressable, client-cacheable, optionally-
subscribable content shape in the
Model Context Protocol
specification. Where MCP tools are widely documented and
understood as the action/mutation surface of MCP, MCP resources
are the lesser-known data-return surface — and the post's thesis
is that resources are "often overlooked" despite being the
correct shape for documentation, config files, filesystem content,
live logs, metrics feeds, and any other read-only content. The
post canonicalises the tools-vs-resources decision rule, the
static / template / updating three-shape taxonomy of MCP
resources, the resource-link vs embedded-resource trade-off
when returning resources from tools, and six code walkthroughs
against the @modelcontextprotocol/sdk TypeScript SDK (version
^1.8.0).
The post is a protocol-design tutorial rather than a
production-scale retrospective: there are no operational numbers,
no scale disclosures, no latency or throughput measurements, no
incident narratives. What it delivers is vocabulary and
decision-rule canonicalisation for a protocol feature that — per
the post — most MCP-server implementers skip. Three specific
production gotchas are called out: (1) the JavaScript URL
constructor's custom handling of known schemes (file:// gets a
trailing slash appended, breaking file://example.txt resource
resolution — the fix is to use a custom scheme like doc://);
(2) the SDK's subscribe method is not implemented in
v1.8.0, so servers either implement it themselves or accept the
limitation that "Server doesn't track subscribers, so it sends
ALL resource updates to ALL clients"; (3) not all MCP clients
discover resources directly — the recommended workaround is
to expose resources as tools via the resource_link /
resource tool content types, since "all agents understand
tools" but resource-discovery support is fragmented.
Scope disposition. This is the first on-scope Wix ingest on the sysdesign-wiki. Wix is Tier-3 (stricter content filter), and the raw file had been pre-classified "batch-skip — zero architecture signals in 18089-char body (pure marketing)" — which on re-read is a severe classifier error. The body is a protocol-design tutorial with six code walkthroughs, three documented SDK gotchas, one decision taxonomy (tool-vs-resource), one resource-shape taxonomy (static / template / updating), one integration-pattern taxonomy (resource-link-tool vs embedded- resource-tool), and two canonical URI-scheme design recommendations. The post passes scope on vocabulary- canonicalisation grounds: it is the only source in the current wiki corpus that walks the MCP-resources API surface end-to-end at the implementer level, complementing the existing systems/model-context-protocol page's heavy bias toward MCP-tools-as-context-budget disclosures (sources/2025-11-17-dropbox-how-dash-uses-context-engineering-for-smarter-ai, sources/2026-03-04-datadog-mcp-server-agent-tools, sources/2026-04-20-cloudflare-internal-ai-engineering-stack). The post is explicitly invoked by the user via "Full ingest… No shortcuts" override — same precedent as the 2026-03-12 Stripe agentic-commerce ingest.
Key takeaways¶
-
Resources and tools are separate surfaces in MCP with distinct decision rules. Tools are for actions, mutations, side effects, calculations. Resources are for returning read-only data: docs, configs, logs. Verbatim decision rule for resources: "Use resources when: Content is read-only (no side effects); Content can be cached; Content might be updated — client can subscribe to updates; Both user and AI agent might need to access content." Canonicalised as concepts/mcp-tool-vs-resource.
-
MCP resources come in three shapes: static, template, updating. Static resources return identical content for all callers (documentation, config, enums, lookup tables). Template resources parameterise the URI with
{placeholder}syntax per RFC 6570 (concepts/uri-template-rfc6570) — e.g.resource://user-profile/{userId}— and extract variables in the handler. Updating resources declare asubscribe: truecapability and emitnotifications/resources/updatedevents when content changes (concepts/resource-subscribe-capability). -
Every resource registration carries six pieces of metadata: name, URI, description, MIME type, annotations, handler. The MIME type field is canonical: "Always specify MIME type to help clients render resource content correctly" — canonicalised as concepts/mime-type-as-first-class-metadata. Annotations (optional) allow clients to filter by
audience(['user', 'assistant']), sort bypriority, or displaylastModified— canonicalised as concepts/resource-annotations. -
RFC 3986 URI scheme choice interacts with the JavaScript
URLconstructor in ways that break obvious picks. The post verbatim: "forfile://it adds trailing slash, which causes URI change fromfile://example.txttofile://example.txt/, so your client always receivesResource not founderror. To fix this, either use custom scheme or adjust your URI and handler." The recommended fix is a custom scheme (doc://,log://,git://) that bypasses the JavaScript URL constructor's built-in handlers. Gotcha specifically applies to@modelcontextprotocol/sdkwhich uses the JavaScript URL constructor internally. -
Template resources expose either path or query parameters, but clients handle path parameters more reliably. Verbatim pro tip: "According to URI template specification you can use both path parameters like
resource://user-profile/{userId}and query parameter likeresource://user-profile?userId={userId}. However, not all clients understand query parameters so try to avoid them." Canonical form: path params. -
Resources can notify clients of updates, but the
@modelcontextprotocol/sdkv1.8.0 does not implement thesubscribemethod. Three verbatim consequences: "Clients callingsubscribewill get 'method not found' error; Clients will receivenotifications/resources/updatedif you setcapabilities.resources.subscribe: true; Server doesn't track subscribers, so it sends ALL resource updates to ALL clients." Production implications: fan-out cost is O(clients) per update; subscriber targeting must be implemented by the server author if needed. -
Not all agents discover resources directly — expose them as tools for universal discoverability. Verbatim load-bearing claim: "Not all AI agents know how to discover and use resources directly. However, all agents understand tools. By exposing resource link as a tool, you: Make resources discoverable in all AI agent flows through tool listing; Provide explicit resource access patterns; Allow parameter validation before resource access." Canonicalised as patterns/expose-resource-as-tool-for-agent-discoverability.
-
Resource-link vs embedded-resource is a token-budget trade-off, not a correctness one. When a tool returns a resource, two tool-content-type options exist:
resource_link(URI only — client fetches on demand) vsresource(URI + full content inlined in the tool response). Decision rule verbatim: "avoid embedded resource if content is large or frequently reused. In such cases, by returning a link instead of content, you allow the client to avoid reloading full content repeatedly after it has already been fetched." Canonicalised as concepts/resource-link-vs-embedded-resource. This is a retrieval-cost / context-budget trade-off analogous to the Dropbox Dash "store tool results locally rather than inline them into the context window" lever for MCP tool results — same underlying economics (don't inline what the client can cache), different direction (outbound-from-tool rather than inbound-to-LLM). -
MCP-server capability declaration is a three-line boilerplate on the
McpServerconstructor. The server must advertise{ capabilities: { tools: {}, resources: {} } }for resource discovery to work at all; addresources: { subscribe: true }to opt into the updating-resource shape; the SDK will permit resource registration but emit no update notifications if thesubscribecapability isn't declared.
Systems and concepts extracted¶
Systems¶
- Model Context Protocol
(MCP) — extended with new MCP Resources implementer-
altitude axis: three-shape taxonomy (static / template /
updating), six-field metadata shape per resource (name / URI /
description / MIME type / annotations / handler), the
resource-link-vs-embedded-resource integration trade-off, the
JavaScript URL constructor gotcha for
file://schemes, the SDK v1.8.0subscribegap. @modelcontextprotocol/sdk— new TypeScript SDK page (stub). Canonical package name is@modelcontextprotocol/sdk; version^1.8.0at post time. ExportsMcpServer,ResourceTemplate. Does not implement thesubscribemethod; tracks no per-subscriber targeting — update notifications fan out to all connected clients.
Concepts¶
- concepts/mcp-resource — the MCP-resource primitive: read-only, addressable, optionally-subscribable content exposed by an MCP server. Three shapes: static, template, updating.
- concepts/mcp-tool-vs-resource — the decision rule for when to expose behaviour as an MCP tool vs an MCP resource. Tools = actions/mutations/side-effects/calculations; resources = read-only cacheable data that users and AI agents might both need to view.
- concepts/uri-template-rfc6570 — URI templates per
RFC 6570.
{placeholder}syntax allows a single resource registration to return different content based on extracted variables. Production rule: prefer path params to query params for client compatibility. - concepts/resource-link-vs-embedded-resource — the
token-budget trade-off when returning resources from MCP
tools.
resource_linkreturns a URI only (client fetches on demand, can cache, receives update notifications);resource(embedded) inlines the full content in the tool response (one fewer roundtrip, but repeated tool calls = repeated full-content transmission). - concepts/mime-type-as-first-class-metadata — the principle that read-only addressable content should always declare a MIME type on the wire so clients can render correctly. Applies beyond MCP — general API-design discipline.
- concepts/resource-subscribe-capability — MCP's
update-notification primitive. Servers declare
capabilities: { resources: { subscribe: true } }; clients receivenotifications/resources/updatedevents that cue a re-read. Implementation caveat: SDK v1.8.0 ships with no per-subscriber targeting — every update fans out to every client. - concepts/resource-annotations — optional metadata on
each MCP resource:
audience(['user', 'assistant']),priority(numeric),lastModified(ISO 8601 timestamp). Clients use annotations to filter and sort resources in discovery UIs.
Patterns¶
- patterns/expose-resource-as-tool-for-agent-discoverability
— for MCP clients whose agent flow doesn't discover resources
natively, register a companion tool that returns a
resource_link- orresource-typed content. Makes resources discoverable through tool listing in every MCP-aware agent flow; enables parameter validation before resource access; converts resource discovery from a client-capability-gated feature into a universally-available one. - patterns/subscribe-notify-for-updatable-resource —
structure live content (logs, metrics, notifications, live
feeds) as an MCP resource with
subscribe: true. Server pushesnotifications/resources/updatedon every change; clients re-read the resource on notification. Equivalent to server-sent events over the MCP protocol, cached in the client's resource layer.
Operational details disclosed¶
- SDK version at post time:
@modelcontextprotocol/sdkv^1.8.0. - Handler signature for static resources:
async () => { ... }returning{ contents: [ { type: 'text', mimeType, uri, text } ] }. - Handler signature for template resources:
async (uri, variables) => { ... }— variables extracted from the URI via RFC 6570 template matching. - URI variable extraction quirk: per URI template
specification a variable can have multiple values; handler
code must handle both
stringandstring[]. - Update cadence example: the working logs example
simulates new entries every 20 seconds via
setInterval. - Subscribe-capability default: off. Must be explicitly
enabled in
capabilities.resources.subscribe: true. resource_linkcontent type (tool return):{ type: 'resource_link', name, uri, mimeType }.resource(embedded) content type (tool return):{ type: 'resource', resource: { uri, mimeType, text } }.- Supported URI schemes (per RFC 3986): any scheme valid
per RFC 3986 —
https://,file://,doc://,log://,git://. Avoidfile://due to JS URL constructor trailing-slash bug; prefer custom schemes for non-HTTP content.
Caveats¶
- Tutorial shape, not production retrospective. No operational numbers, no scale, no latency, no incident narratives. The post canonicalises vocabulary and decision rules, not measured outcomes.
- Single-SDK disclosure scope. All code examples are
against
@modelcontextprotocol/sdk(TypeScript). The protocol is language-agnostic but the three documented gotchas (JS URL constructorfile://bug, SDK v1.8.0 missingsubscribe, no subscriber targeting) are TypeScript-SDK-specific implementation artefacts, not protocol-specification constraints. Implementers on other language SDKs (Python, Go, Rust) may hit different or no gotchas. - Unsigned post. No named author at the top of the article. Wix Engineering's Medium publication is the byline. Accountability for the claims is at organisation level, not individual.
- Single-server scope. The post assumes you are writing an MCP server against the SDK directly. No coverage of MCP-server aggregation (Cloudflare's MCP Server Portal), MCP-over-CLI wrappers (patterns/wrap-cli-as-mcp-server), or enterprise-SSO / auth layering (Databricks' Unity AI Gateway) — those are adjacent concerns not addressed.
- No discussion of MCP tool-inventory context-budget cost. The post treats MCP resources as the primitive for read-only data but does not engage with the agent-context-window cost of resource registrations. Resources "sit in context" the same way tools do; the Dropbox / Datadog / Cloudflare corpus on this wiki has established that tool-inventory growth degrades tool-selection accuracy, and a parallel analysis is likely needed for resources at scale. The post does not cover this.
- No multi-tenancy / auth guidance. Resource handlers are written as if all callers are trusted. One pro tip says "always validate and sanitize parameters received from user to prevent unauthorized data access" but there is no deeper guidance on per-user auth, row-level security, or tenant isolation for resource handlers. Aligns with the general MCP-spec limitation noted on the MCP system page: "No built-in multi-tenancy / auth pattern. Enterprises layer their own."
- Wix product context absent. The post is not about Wix's production MCP deployment (if any exists) — it is a general-purpose protocol tutorial that happens to be published on Wix Engineering's Medium blog. No claim is made about which Wix systems use MCP resources, at what scale, or for what workloads.
Source¶
- Original: https://medium.com/wix-engineering/mcp-resources-all-you-need-to-know-34435249a451?source=rss----e239c562f907---4
- Raw markdown:
raw/wix/2026-01-08-mcp-resources-all-you-need-to-know-aea23e21.md
Related¶
- companies/wix
- systems/model-context-protocol
- systems/mcp-typescript-sdk
- concepts/mcp-resource · concepts/mcp-tool-vs-resource · concepts/uri-template-rfc6570 · concepts/resource-link-vs-embedded-resource · concepts/mime-type-as-first-class-metadata · concepts/resource-subscribe-capability · concepts/resource-annotations
- patterns/expose-resource-as-tool-for-agent-discoverability · patterns/subscribe-notify-for-updatable-resource
- Adjacent MCP implementer corpus: sources/2025-11-17-dropbox-how-dash-uses-context-engineering-for-smarter-ai, sources/2026-03-04-datadog-mcp-server-agent-tools, sources/2026-04-20-cloudflare-internal-ai-engineering-stack, sources/2026-01-28-dropbox-knowledge-graphs-mcp-dspy-dash, sources/2026-04-16-cloudflare-email-service-public-beta-ready-for-agents.