Skip to content
mcpd
no daemon

Prompts

Change a prompt without a deploy, and see which version wrote each answer.

Versions and labels

A prompt is a name and a list of versions. A version is a text template or a list of chat messages, with {{variable}} placeholders and the model settings you want stored beside it. A version never changes once stored; a new body is a new version, numbered by the daemon. Posting a body identical to the latest version stores nothing, so a deploy that posts its prompts on every start is a no-op when nothing changed.

A label points at one version. Your code fetches by label, usually production, so releasing a prompt is moving the label to the new version and rolling it back is moving it to the old one. Neither needs a deploy. latest is reserved and always means the newest version.

support/reply PUT labels/production {version: 2}, a roll back
v1 v2 v3 production staging fetch support/reply → v2
Each step is a request. The fetch with no label asks for production, and gets the latest version while no version carries it. The last step moves production back to v2 and no code is deployed.

store a version, then release it

curl -X POST localhost:4317/v1/api/prompts \ -H 'content-type: application/json' \ -d '{"name": "support/reply", "messages": [{"role": "system", "content": "Answer {{customer}} briefly."}]}' curl -X PUT localhost:4317/v1/api/prompts/support%2Freply/labels/production \ -H 'content-type: application/json' -d '{"version": 1}'

Fetching and rendering

Each SDK fetches a prompt by name and label and renders it with your variables in the process; the daemon never renders one. With no label and no version the SDK asks for production, and falls back to the latest version when no version carries it. A variable the prompt names and you did not pass is an error naming it.

Fetched prompts are cached for 60 seconds by default. After that the SDK fetches again, and if the daemon does not answer it keeps serving the copy it has, so an outage does not stop an agent that fetched once. Pass a fallback template for the first start, before anything was fetched.

fetch, render, link

/**
 * A model generation. Its prompt is stored in mcpd, so a new version ships by
 * moving the `production` label, with no deploy.
 */
async function draftAnswer(
  ticket: Ticket,
  order: { status: string; eta: string },
): Promise<string> {
  // Cached for a minute. When the daemon cannot answer, the last copy is
  // used, and with no copy the fallback, so an outage never stops an answer.
  const prompt = await mcpd.getPrompt('support-answer', {
    label: 'production',
    fallback: ANSWER_MESSAGES,
  })
  const messages = renderPrompt(prompt, {
    question: ticket.question,
    order: JSON.stringify(order),
  })

  return await mcpd.withSpan(
    'draft_answer',
    async (generation) => {
      // Links the call to its prompt version, so spans can be read per version.
      generation.setPrompt(prompt)
      generation.setInput(messages)
      const response = await callModel(generation, order)
      const answer = response.content[0]?.text ?? ''
      generation.setOutput(answer)
      // The model, the token counts mcpd prices, the response id and the
      // finish reason, read from the response in one call.
      generation.recordResponse(response)
      return answer
    },
    { kind: 'model_generation', entityKind: 'model', entityName: 'answer_writer' },
  )
}

Linking a step to its prompt

Link the model span to the prompt it ran and the span carries mcpd.prompt.name and mcpd.prompt.version. GET /v1/api/spans?prompt=support/reply&prompt_version=2 lists every step that ran version 2, which is how a regression after a release is traced back to the change that caused it.

In the app

The Prompts screen lists every prompt at its latest version. Open one to read each version, what changed from the one before, the labels on it and the steps that ran it, to move a label, and to store a new version.

Endpoints

  • GET /v1/api/prompts: every prompt at its latest version.
  • POST /v1/api/prompts: store a version.
  • GET /v1/api/prompts/{name}: one version, by label or version.
  • GET /v1/api/prompts/{name}/versions: every version, newest first.
  • PUT and DELETE /v1/api/prompts/{name}/labels/{label}: move or remove a label.