Skip to content
Forward Deployed

Forward Deployed
Lessons and contents
MCP FoundationsLesson 6 of 8
8 lessons
Learn

Prompts and resources

Source
From the RAG & Agents Engineering course
By
Sourav Banerjee
Last updated
9 Nov 2026

Report an issue

Tools, resources, prompts

A Larkspur engineer may attach a handbook section, choose a reply template or let the model search. You will map those actions to resources, prompts and tools, then inspect what this host actually forwards to the model.

Step 1: Choose the primitive by who invokes it

A server can offer three kinds of thing. They differ in who decides to use them, and that decides which one a feature should be.

Tool Resource Prompt
FastMCP decorator @mcp.tool() @mcp.resource("papers://folders") @mcp.prompt()
Listed with tools/list resources/list, resources/templates/list prompts/list
Used with tools/call resources/read prompts/get
In the lesson 7 chatbot, chosen by the model the user, typing @topic the user, typing /prompt name arg=value
Returns content for the model data the app shows or adds to context messages to send to the model

Step 2: Read a named resource or URI template

are read-only data, like GET endpoints in a REST API: they return data and should not change anything. Each has a URI the server chooses. A static URI names one thing (papers://folders, the list of topic folders); a template names a family (papers://{topic}, the papers saved under one topic), and the client fills in the parameter at read time.

Step 3: Fetch a server-owned instruction template

are templates the server owns. generate_search_prompt(topic, num_papers=5) returns a long instruction to search for papers on the topic and summarise them; FastMCP takes the prompt's name from the function and its arguments from the signature, and prompts/get returns the filled-in text as messages.

The Larkspur server offers one of each kind of resource and a prompt. Recorded with SDK 1.30.0:

  • resources/list returned only the static resource, handbook://sections.
  • resources/templates/list returned the template, handbook://section/{chunk_id}.
  • resources/read on handbook://section/refund-timing returned that chunk as text/plain.
  • prompts/get for answer_with_citations with question = "How long does a refund take?" returned one message with role: "user" whose text asks the model to call search_handbook and cite chunk ids.

Step 4: Trace the host command before generation

The lesson 7 chatbot routes user input before the model sees it:

Diagram: User input; Starts with @?; read_resource papers://topic; Starts with /?; get_prompt /prompt name args; process_query model + toolsDiagram: User input; Starts with @?; read_resource papers://topic; Starts with /?; get_prompt /prompt name args; process_query model + tools

/prompts only prints the list. A prompt fetched with /prompt goes to process_query like a typed question. A resource is printed for the user and never reaches the model in this chatbot; another host could add it to the context instead. Two details in the chatbot's code are worth knowing before you copy it:

  • It lists only static resources. connect_to_server calls list_resources(), which does not return templates, so papers://{topic} never enters the routing table. get_resource works around it: for an unknown papers:// URI it uses any session that has a papers:// resource. With two servers using that scheme it picks the first.
  • One dict routes all three kinds. self.sessions maps tool names, prompt names and resource URIs to sessions, so a prompt named like another server's tool overwrites the route, the same collision the lab in lesson 4 of T12.1 shows for tools.

Step 5: Assign one concrete feature to each primitive

For Larkspur the split is: search_handbook is a tool, because the model needs it mid-answer with a query it writes; the sections are resources, for a support console that lets an engineer attach a section; and answer_with_citations is a prompt the engineer starts on purpose.

Try it yourself

List resources and resource templates separately, then read handbook://section/refund-timing. Check that listing static resources alone would not discover the template. Follow /prompt and a resource read through the host: identify which text enters process_query and which is only printed for the user.

Practice notebook

Run the complete implementation from the practice material after checking the trace or calculation above. Use its stated environment for live model or server calls; recorded model choices and timings are observations, not guaranteed outputs.

Continue learning

Run the notebooks

The code for this lesson is in these notebooks. Colab runs one in your browser: install the packages its first cell imports and set the API keys it reads. To run every notebook as written, clone the repository and use its uv environment.

Notebook GitHub Colab
Adding prompt and resource features Open on GitHub Open in Colab

Key Takeaways

  • Choose the kind by who decides to use it. The model picks tools mid-answer; the user picks resources (read-only data by URI) and prompts (server-owned message templates).
  • A static resource URI names one thing and a template such as papers://{topic} names a family. list_resources() does not return templates, so list them separately.
  • Routing tools, prompts and resource URIs through one dict lets a name on one server overwrite a route on another.

Check yourself

1. What decides whether a server feature should be a tool, a resource or a prompt?

Who decides to use it. The model chooses a tool mid-answer through tools/call. The user chooses a resource, read-only data fetched with resources/read, and a prompt, a server-owned template fetched with prompts/get; in the lesson 7 chatbot that means typing @topic or /prompt name arg=value.

2. Why is search_handbook a tool on the Larkspur server, while the handbook sections are resources and answer_with_citations is a prompt?

The model needs search_handbook mid-answer with a query it writes, so it is a tool. The sections are data a support console lets an engineer attach (handbook://sections and the template handbook://section/{chunk_id}), so they are resources. answer_with_citations is something the engineer starts on purpose, so it is a prompt.

3. The lesson 7 chatbot never puts the papers topic template in its routing table. Why, and how does reading a topic still work?

connect_to_server calls list_resources(), which returns static resources but not templates, so papers://{topic} never enters the table. get_resource works around it: for an unknown papers:// URI it uses any session that has a papers:// resource. With two servers using that scheme, it picks the first.

Rate your confidence and keep notes on the module page.