Tools are the everyday MCP win. Resources and prompts sit beside them on the same server: contextual data to read, and reusable templates the user can invoke. This page teaches both end-to-end on the bookmarks lab.
Before you start
- Terms: resource, prompt, tool in MCP Without the Hype.
- Working tools-only server: Build Your First MCP Server in TypeScript or clone tag
part-3:
git clone https://github.com/SRVivek1/geekmonks-mcp-bookmarks.git
cd geekmonks-mcp-bookmarks
git checkout part-3
npm install
npm run build
You will end on tag part-4 (same repo): geekmonks-mcp-bookmarks.
Why resources and prompts
Quick control reminder from Part 1 (no second glossary):
| Primitive | Who drives it | Role |
|---|---|---|
| Tools | Model (with approval) | Actions |
| Resources | Application / host | Context to read |
| Prompts | User | Templates / workflows |
Add a resource when the host should be able to pull a catalog without inventing a one-off tool. Add a prompt when you want a repeatable starter message wired to live data.
Register a resource
In src/index.ts (same createServer as Part 3), register a static URI that returns the JSON catalog:
server.registerResource(
'bookmarks-catalog',
'bookmarks://list',
{
title: 'Bookmarks catalog',
description: 'Full local bookmarks JSON catalog',
mimeType: 'application/json',
},
async (uri) => {
const bookmarks = await loadBookmarks();
return {
contents: [
{
uri: uri.href,
mimeType: 'application/json',
text: JSON.stringify({ bookmarks }, null, 2),
},
],
};
},
);
| Piece | Job |
|---|---|
Name (bookmarks-catalog) | Stable id for the registration |
URI (bookmarks://list) | How clients address the resource |
| Metadata | Title, description, mimeType for hosts/Inspector |
| Read callback | Returns contents with uri, mimeType, and text (or binary) |
Rebuild after editing:
npm run build
Register a prompt
A prompt returns messages the host can feed into a chat — here, a user message that embeds the current catalog:
server.registerPrompt(
'summarize-bookmarks',
{
title: 'Summarize bookmarks',
description: 'Ask the model to summarize saved bookmarks and suggest what to read next.',
argsSchema: z.object({
focus: z
.string()
.optional()
.describe('Optional topic to emphasize (e.g. TypeScript, MCP)'),
}),
},
async ({ focus }) => {
const bookmarks = await loadBookmarks();
const catalog = JSON.stringify(bookmarks, null, 2);
const focusLine = focus?.trim()
? `Emphasize anything related to: ${focus.trim()}.`
: 'Cover the whole list evenly.';
return {
messages: [
{
role: 'user' as const,
content: {
type: 'text' as const,
text: [
'Here is my local bookmarks catalog as JSON:',
catalog,
'',
'Summarize what I have saved in a few bullets, then suggest one bookmark to open next and why.',
focusLine,
].join('\n'),
},
},
],
};
},
);
| Piece | Job |
|---|---|
argsSchema | Optional Zod args (like tool inputs) |
messages | Role + content the host inserts into a conversation |
| Live data | Prompt handler can call the same store as tools |
Keep logging on stderr only — same stdio rule as Part 3.
Verify in MCP Inspector
Do not trust the host UI alone for resources and prompts.
npx @modelcontextprotocol/inspector node dist/index.js
You should see:
- Tools — the original three still work.
- Resources —
bookmarks://list(or the catalog entry); read it and get JSON. - Prompts —
summarize-bookmarks; invoke with or withoutfocusand inspect the returned messages.
Companion checkpoint after these changes: tag part-4.
Host caveat
Hosts expose tools most reliably. Cursor may show your tools clearly while resources or prompts are harder to find (or missing) in the UI. That does not mean the server is wrong — prove them in Inspector, then treat host support as a product detail that improves over time.
Cursor re-check
Your Part 3 mcp.json entry still works — same node + dist/index.js path. Reload MCP after rebuild. Confirm tools stay Connected. If resources/prompts do not appear in Cursor, lean on Inspector for this lab’s success criteria.
Wrap-up
You kept the bookmarks tools and added one resource plus one prompt on the same stdio server. Series hub: MCP Without the Hype. Tools-only baseline: Part 3. Code: tags part-3 → part-4 on geekmonks-mcp-bookmarks.