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

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):

PrimitiveWho drives itRole
ToolsModel (with approval)Actions
ResourcesApplication / hostContext to read
PromptsUserTemplates / 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),
        },
      ],
    };
  },
);
PieceJob
Name (bookmarks-catalog)Stable id for the registration
URI (bookmarks://list)How clients address the resource
MetadataTitle, description, mimeType for hosts/Inspector
Read callbackReturns 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'),
          },
        },
      ],
    };
  },
);
PieceJob
argsSchemaOptional Zod args (like tool inputs)
messagesRole + content the host inserts into a conversation
Live dataPrompt 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:

  1. Tools — the original three still work.
  2. Resources — bookmarks://list (or the catalog entry); read it and get JSON.
  3. Prompts — summarize-bookmarks; invoke with or without focus and 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.

Next optional step in the series Discovery, capability negotiation, and transports. How MCP Talks