Add resources and prompts

Add a project review prompt

Register a reusable prompt that turns one validated topic into a clear review request without performing the review itself.

A prompt is a reusable conversation starter. The server writes the message, the client puts it in front of the model. The prompt itself doesn’t run anything.

Think of it as a saved request. Instead of typing “search the notes about deploy and tell me what’s missing” every time, the user picks review_project, fills in a topic, and gets a well-formed request.

Add the prompt below the resource, inside createServer():

  server.registerPrompt(
    'review_project',
    {
      title: 'Review project notes',
      description: 'Review project notes about one topic',
      argsSchema: z.object({
        topic: z.string().min(1).describe('Topic to review')
      })
    },
    ({ topic }) => ({
      messages: [{
        role: 'user' as const,
        content: {
          type: 'text' as const,
          text: `Search the project notes for "${topic}". Summarize the evidence, identify missing information, and suggest one next action.`
        }
      }]
    })
  )

The argsSchema rejects an empty topic before the callback runs, the same way tool schemas guard handlers. The callback returns one user message with the validated topic inside it.

The as const on role and type keeps TypeScript from widening those strings to string. Without it, npm run check complains that string is not assignable to the literal type the SDK expects.

What the prompt doesn’t do

Notice the boundary. This prompt does not call search_notes. It doesn’t read the catalog. It doesn’t perform the review. It produces text and stops.

The host decides everything after that: whether to render the prompt, which model receives it, and which tools that model may use to answer. Our server has no say. That’s the correct split. A prompt that quietly triggers tools would be a hidden workflow, and hidden workflows are hard to audit.

Prompts are public content

Everything in a prompt registration is discoverable. A client can list prompts and read their descriptions and rendered text. So never put secrets, hidden policy, or unreviewed text fetched from somewhere else into a prompt. It’s not a private control channel. It’s content.

Render it in the Inspector

Run npm run check, restart the Inspector, and open the Prompts tab. Render review_project with deploy as the topic. You get one user message:

Search the project notes for "deploy". Summarize the evidence, identify missing information, and suggest one next action.

Now try an empty topic. Validation rejects it before rendering. Then try a topic with quotes in it, like "release" day. It renders fine, and the quotes are just characters inside the message. The topic is ordinary text, not code.

One last thought for later. When the model follows this prompt and calls search_notes, the notes it gets back are still untrusted data. The prompt asks for a review. It doesn’t grant the notes any authority. We’ll come back to that in the security module.

Lesson completed