Immutable
release. Only release title and notes can be modified.
What’s Changed
Resources container ergonomics (breaking improvement)
From a user’s point of view the old resources API felt like working “inside the protocol” instead of just declaring some files. You had to:
- Build wire-shaped structs (MCP resource/content blocks) instead of plain Go values.
- Pass
context.Contextinto trivial in‑memory operations. - Replace whole slices to make small edits.
- Learn (and care about) subscription mechanics you didn’t ask for.
The redesigned container is intentionally boring—in a good way.
What you do now
rc := mcpservice.NewResourcesContainer()
rc.AddResource(mcpservice.TextResource(
"res://welcome",
"Welcome!",
mcpservice.WithName("Welcome"),
mcpservice.WithDescription("Landing copy"),
mcpservice.WithMimeType("text/plain"),
))
// Change or create (metadata + variants) with one call.
rc.UpsertResource(mcpservice.ResourceWithVariants(
"res://logo",
[]mcpservice.ContentVariant{
mcpservice.BlobVariant(logoPNGBytes, "image/png"),
},
mcpservice.WithName("Logo"),
))
// Force clients to refresh lists (even if structurally identical).
rc.ReplaceResources(rc.SnapshotResources())Key ergonomic wins
- Plain structs:
Resource,ContentVariant—no premature MCP wire coupling. - Obvious CRUD:
AddResource,UpsertResource,RemoveResource,ReplaceResources. - No contexts for synchronous, in‑memory ops.
- Helper constructors (
TextResource,BlobResource, variants helpers) remove boilerplate. UpsertResourcehandles create vs update; only emits “updated” if variants actually changed.- Always emits listChanged on
ReplaceResources—gives you a cheap “poke” to invalidate client caches. - Engine owns subscriptions now; you never juggle session IDs or goroutines.
Mental model now
“Declare resources, mutate them directly, and the system will push the right notifications.”
No subscription plumbing, no slice surgery, no protocol leakage.
That’s the whole point: lower cognitive load, fewer ways to misuse it, zero ceremony for the 90% case.