mirror of
https://github.com/modelcontextprotocol/servers.git
synced 2026-04-17 15:43:24 +02:00
feat(everything): add resource collection example
This adds a resource collection example demonstrating the pattern where a single resources/read request returns multiple ResourceContents with different URIs. This is useful for modeling collections, indexes, or composite resources. The example includes: - A summer specials collection that returns all items - Category-filtered collections for accessories, footwear, and skincare - Individual item resources for direct access Based on the gist provided by @olaservo: https://gist.github.com/olaservo/585b1ad042723a824b6a0e0e02ae60a8 Fixes #3130 Co-authored-by: Ola Hungerford <olaservo@users.noreply.github.com>
This commit is contained in:
104
src/everything/resources/collections.ts
Normal file
104
src/everything/resources/collections.ts
Normal file
@@ -0,0 +1,104 @@
|
||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
|
||||
/**
|
||||
* Sample collection items
|
||||
* - These items represent a simple product catalog for demonstration purposes
|
||||
*/
|
||||
const collectionItems = [
|
||||
{ id: 1, name: "Summer Hat", price: 29.99, category: "accessories" },
|
||||
{ id: 2, name: "Beach Towel", price: 19.99, category: "accessories" },
|
||||
{ id: 3, name: "Sunglasses", price: 49.99, category: "accessories" },
|
||||
{ id: 4, name: "Flip Flops", price: 14.99, category: "footwear" },
|
||||
{ id: 5, name: "Sunscreen SPF50", price: 12.99, category: "skincare" },
|
||||
];
|
||||
|
||||
const collectionUriBase = "demo://collection";
|
||||
const itemUriBase = "demo://collection/item";
|
||||
|
||||
/**
|
||||
* Helper to generate an item URI
|
||||
* @param id
|
||||
*/
|
||||
const itemUri = (id: number) => `${itemUriBase}/${id}`;
|
||||
|
||||
/**
|
||||
* Register collection resources with the MCP server.
|
||||
*
|
||||
* This demonstrates the pattern where a single resources/read request returns
|
||||
* multiple ResourceContents with different URIs - useful for modeling collections,
|
||||
* indexes, or composite resources.
|
||||
*
|
||||
* Resources:
|
||||
* - `demo://collection/summer-specials`: Returns all items as separate resources
|
||||
* - `demo://collection/by-category/{category}`: Returns items filtered by category
|
||||
* - `demo://collection/item/{id}`: Returns a single item (for individual access)
|
||||
*
|
||||
* @param server
|
||||
*/
|
||||
export const registerCollectionResources = (server: McpServer) => {
|
||||
// Main collection resource returning all items
|
||||
server.registerResource(
|
||||
"Summer Specials Collection",
|
||||
`${collectionUriBase}/summer-specials`,
|
||||
{
|
||||
mimeType: "application/json",
|
||||
description:
|
||||
"A collection resource that returns multiple items, each with its own URI.",
|
||||
},
|
||||
async () => {
|
||||
return {
|
||||
contents: collectionItems.map((item) => ({
|
||||
uri: itemUri(item.id),
|
||||
mimeType: "application/json",
|
||||
text: JSON.stringify(item, null, 2),
|
||||
})),
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
// Category-filtered collections
|
||||
const categories = [...new Set(collectionItems.map((i) => i.category))];
|
||||
for (const category of categories) {
|
||||
server.registerResource(
|
||||
`Collection: ${category}`,
|
||||
`${collectionUriBase}/by-category/${category}`,
|
||||
{
|
||||
mimeType: "application/json",
|
||||
description: `Items in the "${category}" category.`,
|
||||
},
|
||||
async () => {
|
||||
const filtered = collectionItems.filter((i) => i.category === category);
|
||||
return {
|
||||
contents: filtered.map((item) => ({
|
||||
uri: itemUri(item.id),
|
||||
mimeType: "application/json",
|
||||
text: JSON.stringify(item, null, 2),
|
||||
})),
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Individual item resources
|
||||
for (const item of collectionItems) {
|
||||
server.registerResource(
|
||||
`Item: ${item.name}`,
|
||||
itemUri(item.id),
|
||||
{
|
||||
mimeType: "application/json",
|
||||
description: `Individual item: ${item.name} ($${item.price})`,
|
||||
},
|
||||
async (uri) => {
|
||||
return {
|
||||
contents: [
|
||||
{
|
||||
uri: uri.toString(),
|
||||
mimeType: "application/json",
|
||||
text: JSON.stringify(item, null, 2),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -1,6 +1,7 @@
|
||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import { registerResourceTemplates } from "./templates.js";
|
||||
import { registerFileResources } from "./files.js";
|
||||
import { registerCollectionResources } from "./collections.js";
|
||||
import { fileURLToPath } from "url";
|
||||
import { dirname, join } from "path";
|
||||
import { readFileSync } from "fs";
|
||||
@@ -12,6 +13,7 @@ import { readFileSync } from "fs";
|
||||
export const registerResources = (server: McpServer) => {
|
||||
registerResourceTemplates(server);
|
||||
registerFileResources(server);
|
||||
registerCollectionResources(server);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user