How does an MCP prompt declare its arguments, and what does required mean?
answer
- four small fields, no schema
- the model is not filling these in
- everything arrives as text
- missing one is an invalid-params error
basics
~20 sEach entry in a prompt's arguments array is a PromptArgument with a name, an optional title and description, and an optional required boolean. Callers pass values as a flat name-to-string map on prompts/get; omitting a required argument earns a -32602 invalid-params error.
solid answer
~50 sA prompt declares its inputs in the `arguments` array returned by `prompts/list`. Each element is a `PromptArgument`: a `name`, an optional `title` and `description` for display, and an optional `required` boolean. That is deliberately a *thin* declaration — unlike a tool, a prompt has no JSON Schema, no types, no enums and no nested objects. On `prompts/get`, the caller supplies an `arguments` object mapping those names to **string** values. Anything richer — a number, a list, a date — is passed as its string form and parsed by the server. `required: true` means the server cannot produce sensible messages without it, so the client must collect it before calling. A server that receives a call missing a required argument answers with `-32602` invalid params, the same code it uses for an unknown prompt name. Validation is the server's job; the client should still gate the call in its UI.
code
json · 9 lines{
"name": "summarize_log",
"title": "Summarize a log file",
"description": "Condenses a log file into an incident summary",
"arguments": [
{ "name": "path", "description": "Log file path", "required": true },
{ "name": "since", "description": "ISO timestamp lower bound" }
]
}go deeper
Know that a prompt lists its arguments by name with an optional required flag, and that you pass values by name when calling prompts/get. Recall that the values you send are plain strings.
Explain the full PromptArgument shape and contrast it with a tool's JSON Schema: no types, no enums, no defaults. Say that a missing required argument comes back as -32602 invalid params.
Demonstrate defensive server design: validate every required argument yourself, parse string values rather than assuming types, and never carry argument values over from an earlier request, because the protocol is stateless.
Frame the tradeoff the thin declaration encodes — human-filled inputs validated by prose and server-side parsing versus machine-filled inputs validated by schema — and set a house rule for when a workflow deserves the schema-checked tool surface instead.
## The declaration When a client calls `prompts/list`, each `Prompt` in the result may carry an `arguments` array. Every element is a `PromptArgument` object with a small, fixed shape: - `name` — the key the caller will use in the `arguments` map on `prompts/get`. This is the programmatic identifier. - `title` — an optional human-friendly label for a form field or menu entry. - `description` — optional prose telling the user what to put here. - `required` — an optional boolean; when absent, treat the argument as optional. That is the whole vocabulary. There is no type field, no format, no default, no enumeration of allowed values, and no nesting. This is the single most surprising thing about prompt arguments for someone who has only worked with the tool primitive, where a tool's inputs are described by a full JSON Schema. ## Why the declaration is deliberately thin A prompt is filled in by a human, usually through a text box or a small form the host renders from these three or four fields. The design leans on the user rather than on a validator: the description tells the person what to type, and the server interprets what arrives. A tool, by contrast, is filled in by a language model that has no interface to ask clarifying questions, so it needs a machine-checkable schema. The consequence at the wire level is that **prompt argument values are strings**. The `arguments` field on `prompts/get` is a flat map from argument name to a string value. If a prompt conceptually takes a line count, a boolean flag or a comma-separated list, the client still sends text and the server parses it. A server that assumes it will receive a JSON number will break the first time a real client calls it. ## What required actually obliges `required: true` is a contract in both directions. For the client, it means the value must be collected before the call is worth making. A host that renders a prompt as a form should mark the field mandatory; a host that renders it as a slash command should refuse to send until the user has supplied it. Guessing or substituting an empty string is worse than not calling, because the server may happily template an empty value into the messages and produce a plausible-looking but useless prompt. For the server, it means validation is mandatory rather than optional. A `prompts/get` that omits a required argument is answered with the standard JSON-RPC `-32602` invalid-params error. The same `-32602` covers an unknown prompt name. Servers should not silently substitute defaults for required arguments — if a sensible default exists, the argument was not required in the first place. ## Argument completion Because the declaration carries no enum, a server that wants to offer the user a list of legal values does so at a different endpoint: `completion/complete` with a `ref` of type `ref/prompt`, which returns candidate values for one named argument given what the user has typed so far. That is an entirely separate opt-in capability, not part of the `PromptArgument` shape, and a client that does not implement it simply presents a free-text field. ## Statelessness and argument handling Under revision 2026-07-28 MCP is stateless: every request is self-contained and a server MUST NOT rely on prior requests over the same connection to establish context. That has a direct consequence for arguments. A server cannot remember values a user supplied on an earlier `prompts/get` and fill them in implicitly; every call must carry every argument it needs. If the server wants continuity across calls, it has to mint an explicit handle and take it as another ordinary argument, exactly as tools do now that protocol sessions have been removed. Separately, `prompts/get` is one of the three methods permitted to answer with `resultType: "input_required"` rather than `"complete"`, which gives a server a protocol-level way to ask for something it still needs. That is the multi-round-trip mechanism, and a client must branch on `resultType` rather than assuming `messages` is present. ## Common mistakes Claiming prompt arguments are described by a JSON Schema is the standard wrong answer — that is tools. Claiming values may be arbitrary JSON is the second. Assuming an absent `required` means required is the third: absent means optional.
- Why don't prompt arguments use a JSON Schema the way tool inputs do?Because the filler is different. A tool's arguments are produced by a language model that cannot be asked to clarify, so it needs a machine-checkable schema. A prompt's arguments are typed by a human into a host-rendered field, so a name, a description and a required flag are enough, and the server parses whatever text arrives.
- If a prompt needs a value the client did not send, must the server always answer -32602?No. -32602 is the right answer for a missing required argument or an unknown prompt name. But prompts/get is also allowed to return resultType "input_required" instead of "complete", which lets the server ask the client to gather the missing input and retry the request. Which one to use depends on whether the omission is a client error or a legitimate ask.
saying these in an interview costs you the question
- Saying prompt arguments are validated by a JSON Schema
- Sending numbers or objects as argument values instead of strings
- Treating an absent required flag as meaning required
- Expecting the server to remember arguments from an earlier call
- Answering a missing required argument with a successful empty result