NLWeb Specification v0.55

1. Overview

NLWeb defines a standardized interface for natural language interactions with agents. It abstracts the complexity of agentic interactions—such as tool use, long-running tasks, and rich structured data—into a unified protocol.

The primary API/tool/skill provided by an NLWeb agent is ask, using which a caller can ask the agent for some information or to perform a task. Await is a helper API that enables asynchronous answers, which is useful for long-running requests.

2. Underlying Concepts

2.1 Transport Neutrality

NLWeb is designed to be transport-protocol agnostic. While this specification uses HTTP for its primary examples, the core JSON structures are almost identical whether transmitted via HTTP, WebSockets, JSON-RPC, or within agentic protocols like the Model Context Protocol (MCP). We describe the core JSON structures in the main document and provide examples with HTTP and MCP in the appendices.

2.2 Extensibility

Arguments passed to 'ask', responses, etc. all involve structured objects with schemas. Indeed much of specs like this one is to define these schemas. However, we would like extensibility and for that we need to be able to introduce new schemas without changing the core spec. The linked data community has solved this problem with the use of the '@context' attribute in JSON-LD. This is in wide use on tens of billions of web pages. Since NLWeb uses JSON for pretty much everything, '@context' is easily incorporated.

2.3 Context

A defining feature of LLMs is their ability to understand and use extended context. We expect many tools will themselves be AI powered. Tools should be able to send and receive context. Context also covers a very wide range of temporal granularities, from tokens identifying sessions to the last few queries to conversation histories to memory. We introduce contexts as first-class objects. We represent contexts as JSON objects with an extensible set of attributes whose definitions can be referenced using the @context attribute. Context objects may appear as values of attributes, both in the request and in the response.

2.4 Authentication and Authorization

Authentication and authorization are handled at the transport layer and are outside the scope of this specification. For HTTP transport, standard mechanisms such as OAuth 2.0 bearer tokens, API keys in headers, or mutual TLS may be used. For MCP transport, authentication is handled by the MCP framework. NLWeb agents SHOULD document their authentication requirements separately.

2.5 Rate Limiting

Rate limiting is a transport-layer concern and is outside the scope of this specification. Agents implementing NLWeb over HTTP SHOULD use standard HTTP rate limiting mechanisms (e.g., 429 status codes with Retry-After headers). Rate limiting policies SHOULD be documented separately by each agent.

3. Ask Query Structure

The request object consists of four sections: query, context, prefer, and meta.

3.1 Query (Required)

Specifies the user's current request and associated query parameters.

Attributes:

  • text (string, required): The natural language query string from the user.
  • site (string, optional): An agent may have 'sub corpora' and allow a request to specify which corpora must be searched.
  • Additional filter attributes (optional): Any number of domain-specific filters such as:
    • itemType: The type of the item requested (e.g., Movie, Recipe, etc.)
    • location: Geographic constraint
    • price: Price range or constraint

These attributes, and their values, should use schema.org vocabulary or comparable schemas where possible.

Example:

{
  "query": {
    "text": "something protein rich that has cinnamon in it",
    "site": "pumpkins-r-us.com",
    "location": "Idaho",
    "price": "less than $20"
  }
}

3.2 Context (Optional)

Provides contextual information about the query to help the agent better understand and respond to the request. Context can be communicated using one or more attributes, as specified by the schema referenced in the @context attribute.

Attributes:

  • @type (string, optional): The type of Context, which determines the available attributes and their semantics. The default is "ConversationalContext". When omitted, ConversationalContext is assumed. Custom context types can be defined using the @context mechanism to reference external schemas, enabling domain-specific context structures without modifying the core protocol.

The following attributes are defined by ConversationalContext:

  • prev (array of strings, optional): Array of previous queries in the conversation.
  • text (string, optional): Free-form text paragraph describing the broader context.
  • memory (string, optional): Persistent information about the user's preferences, constraints, or characteristics.

Example (default ConversationalContext):

{
  "context": {
    "prev": ["breakfast muffins", "high fiber snacks"],
    "text": "User has been looking at different options in the context of planning a party",
    "memory": "vegetarian, has a sweet tooth"
  }
}

Example (custom context type):

{
  "context": {
    "@type": "UserDiet",
    "@context": "https://example.com/schemas/diet",
    "restrictions": ["vegan"],
    "allergies": ["peanuts"]
  }
}

The ability to reference external schemas via the @context mechanism enables future extensibility. For instance, in a more advanced setting, documents could contain context shared by multiple agents, and a reference to that document could be passed within the context.

3.3 Prefer (Optional)

Specifies expectations and requirements for how the response should be formatted and delivered. The design pattern we try to follow is that of HTTP content negotiation.

Attributes (all optional):

  • streaming (boolean): Whether a streaming response is desired (true or false).
  • response_format (string): Indicates the preferred response format (see 3.3.1).
  • mode (string): Response mode (see 3.3.2).
  • accept-language (string): Language code for all textual content in the response (e.g., "en"), aligning with the Accept-Language HTTP header. This governs both agent-generated text (summaries, elicitation messages) and item descriptions in the results.
  • user-agent (string): Type of client making the request (e.g., "mobile", "desktop"), aligning with a conceptual User-Agent HTTP header.

Example:

{
  "prefer": {
    "streaming": false,
    "response_format": "chatgpt_app",
    "mode": "list, summarize",
    "accept-language": "en",
    "user-agent": "Copilot/1.0.0"
  }
}

3.3.1 response_format

We expect a wide range of clients to call NLWeb agents — from chatbots to site search interfaces to data analytics tools. Different output structures may be suitable for different clients. The set of possible response_format values is open-ended and extensible. This specification defines two formats:

  • conversational_search (default): Returns results in the Conversational Search result structure (see 4.1.1).
  • chatgpt_app: Returns results in the ChatGPT App result structure (see 4.1.1), conforming to the ChatGPT Apps SDK.

NLWeb agents may support additional formats. A client may specify the formats it can accept, and the NLWeb agent chooses the best match.

3.3.2 mode

The mode parameter specifies the preferred level of AI processing on the results. This specification defines the following modes:

  • list: Provides a list of result items.
  • summarize: Adds an agent-generated summary of the results.

Multiple comma-separated values (e.g., "list, summarize") can be specified. New mode types can be introduced through the extensibility mechanism (@context) without changing the core specification.

3.4 Meta (Optional)

Contains metadata about the request itself, including the requested version number of the protocol, tracking information, etc.

Attributes (all optional):

  • version (string): API version number being used (e.g., "0.55").
  • session_context (object): Context object to capture state about the session (loosely the analog of HTTP cookies).
  • user (string or object): A user identifier. This can be either a simple string identifier or a richer object with structured user information. When using an object, schema.org vocabulary (e.g., the Person type) is recommended where applicable.
  • remember (boolean): Whether to remember this interaction.

Example (simple user identifier):

{
  "meta": {
    "version": "0.55",
    "user": "user_12345",
    "session_context": {
      "conversation_id": "conv_98765",
      "state_token": "encrypted_blob_xyz"
    }
  }
}

Example (structured user object):

{
  "meta": {
    "version": "0.55",
    "user": {
      "@type": "Person",
      "@context": "https://schema.org",
      "identifier": "user_12345",
      "name": "Jane Smith"
    }
  }
}

4. Response Structure

NLWeb responses are always JSON objects with a required metadata field (_meta) and one or more content fields whose structure depends on the response type.

Convention: Request metadata uses the attribute name meta. Response metadata uses _meta (with a leading underscore) to clearly distinguish request metadata from response metadata.

_meta (Required)

Metadata about the response.

  • response_type (string, required): One of "answer", "elicitation", "promise", or "failure".
  • response_format (string, optional): The response format of the answer (e.g., "conversational_search", "chatgpt_app").
  • version (string, required): API version number.
  • session_context (object, optional): Context object which can include attribute-value pairs that need to be included in future calls to the NLWeb agent.
  • Response format-specific fields such as:
    • openai/outputTemplate (string): For ChatGPT Apps SDK — URI of the widget template.
    • openai/widgetAccessible (boolean): For ChatGPT Apps SDK — whether the widget can make tool calls.
    • Other protocol-specific metadata as needed.

4.1 Response Content

The result structure is a function of the response_type. The following subsections define the result structures for answer, elicitation, promise, and failure.

4.1.1 Answer

Though we expect to allow different structures for the content, as specified by the response_format in the request, we expect most answers to be an array of JSON objects, each encoding some semi-structured information. In some cases, as with ChatGPT apps, the structured and unstructured portions may be broken out into separate sections.

This specification defines two result structures.

Conversational Search Result Structure

Conversational search (for websites, applications, etc.) is a primary use case for NLWeb. In this case, the attribute results contains an array of typed semi-structured JSON objects. Each object contains:

  • @type (string, recommended): Specifies the object's type (e.g., "Restaurant", "Movie", "Product", "Recipe"). The use of schema.org types is recommended where applicable, although any defined schema is permissible.
  • Type-specific fields: Includes attributes such as url, name, title, description, image, price, ingredients, and other fields relevant to the object's type.
  • grounding (object, optional): Contains data establishing provenance, such as source URLs, citations, or references to schema objects.
  • actions (array, optional): Lists the executable actions associated with the item (see Section 5).

When the mode includes "summarize", the agent includes a summary in the results stream. A summary item SHOULD use @type of "SearchSummary" (or a domain-appropriate type) and include a text attribute with the summary content. In streaming responses, the summary may appear at any position in the stream — before, after, or interspersed with result items.

Example:

{
  "_meta": {
    "response_type": "answer",
    "response_format": "conversational_search",
    "version": "0.55"
  },
  "results": [
    {
      "@type": "SearchSummary",
      "text": "Here are protein-rich recipes featuring cinnamon, ranging from breakfast items to snacks."
    },
    {
      "@type": "Recipe",
      "name": "Pumpkin spice with coconut",
      "description": "....",
      "recipeIngredient": ["..."],
      "cookTime": "PT30M",
      "actions": [{"...": "..."}]
    },
    {
      "@type": "Restaurant",
      "name": "Idaho Pumpkin Place",
      "address": "..."
    }
  ]
}

ChatGPT App Result Structure

This structure conforms to the structure specified for ChatGPT apps. The main differences from Conversational Search are:

  1. content (array, required): Used for natural language descriptions of the result, meant for consumption by the chatbot's LLM. An array of JSON objects, each with:

    • type (string): The value "text".
    • text (string): A natural language description of the results.
  2. structuredData (array, required): An array of typed semi-structured JSON objects, following the same item schema as results in the Conversational Search structure.

Example:

{
  "_meta": {
    "response_type": "answer",
    "response_format": "chatgpt_app",
    "version": "0.55",
    "openai/outputTemplate": "https://example.com/recipe-widget",
    "openai/widgetAccessible": true
  },
  "content": [
    {
      "type": "text",
      "text": "Here are protein-rich pumpkin recipes with cinnamon..."
    }
  ],
  "structuredData": [
    {
      "@type": "Recipe",
      "name": "Pumpkin spice with coconut",
      "description": "....",
      "recipeIngredient": ["..."],
      "cookTime": "PT30M"
    }
  ]
}

4.1.2 Promise

If the NLWeb agent is unable to immediately respond with an answer, it may return a promise (which is loosely modeled after the promise in JavaScript or async in Python).

Attributes:

  • token (string, required): An opaque identifier for the promise, used with the await API.
  • estimated_time (integer, optional): Estimated time in seconds until the result is ready.
  • message (string, optional): A human-readable status message.
  • progress (number, optional): A progress indicator between 0 and 1.

Example:

{
  "_meta": {
    "response_type": "promise",
    "version": "0.55"
  },
  "promise": {
    "token": "promise_xyz",
    "estimated_time": 120,
    "message": "Analyzing your meal history and preferences...",
    "progress": 0.1
  }
}

The await API/tool can be used to check on a promise (see Section 4.2).

4.1.3 Elicitation

Sometimes, the agent requires more information before answering. In such cases, the response_type is "elicitation". The elicitation attribute of the response contains the information being requested.

Elicitation Attributes:

  • text (string, optional): A natural language message explaining what information is needed.
  • questions (array, optional): An array of structured questions. Each question has:
    • id (string, required): Unique identifier for the question.
    • text (string, required): The question text.
    • type (string, required): The question type. Defined types are:
      • "single_select": Choose exactly one option from a list.
      • "multi_select": Choose one or more options from a list.
      • "free_text": Open-ended text input.
      • "number": Numeric input.
      • "boolean": Yes/no input.
    • options (array of strings, optional): Available choices (required for single_select and multi_select).
    • default (any, optional): Default value for the question.

Additional question types can be introduced through the extensibility mechanism.

Example: User makes a vague request for dinner.

Request:

{
  "query": {
    "text": "I need something for dinner"
  },
  "meta": {
    "version": "0.55"
  }
}

Response:

{
  "_meta": {
    "response_type": "elicitation",
    "version": "0.55"
  },
  "elicitation": {
    "text": "I'd love to help you find a great dinner recipe! To provide the best recommendations, could you tell me:",
    "questions": [
      {
        "id": "dietary_restrictions",
        "text": "Do you have any dietary restrictions or preferences?",
        "type": "multi_select",
        "options": ["vegetarian", "vegan", "gluten-free", "dairy-free", "none"]
      },
      {
        "id": "protein_type",
        "text": "What type of protein would you like?",
        "type": "single_select",
        "options": ["chicken", "beef", "fish", "pork", "tofu", "beans", "no preference"]
      },
      {
        "id": "cooking_time",
        "text": "How much time do you have for cooking?",
        "type": "single_select",
        "options": ["under 20 minutes", "20-40 minutes", "40-60 minutes", "over an hour"]
      }
    ]
  }
}

4.1.4 Failure

When the agent cannot fulfill the request, it returns a failure response.

Attributes:

  • code (string, required): A machine-readable error code. Standard error codes defined by this specification:
    • "NO_RESULTS": The query returned no matching results.
    • "INVALID_QUERY": The query could not be parsed or is malformed.
    • "UNSUPPORTED_FORMAT": The requested response_format is not supported by this agent.
    • "UNSUPPORTED_MODE": The requested mode is not supported by this agent.
    • "RATE_LIMITED": The request was rejected due to rate limiting.
    • "INTERNAL_ERROR": An internal error occurred within the agent.
    • "TIMEOUT": The request timed out before a result could be produced.
    • "TOKEN_LIMIT": The request exceeded token or processing limits.
  • message (string, optional): A human-readable error message.

Additional error codes can be introduced through the extensibility mechanism.

Example:

{
  "_meta": {
    "response_type": "failure",
    "version": "0.55"
  },
  "error": {
    "code": "TOKEN_LIMIT",
    "message": "Ran out of tokens."
  }
}

4.2 Await

Check the status of or cancel a task using a promise token.

Attributes:

  • promise_token (string, required): The token returned in the promise response.
  • action (string, required): Either "checkin" (check status) or "cancel" (cancel the task).
  • meta (object, optional): Standard meta object.

Example:

{
  "promise_token": "promise_xyz789",
  "action": "checkin",
  "meta": {
    "version": "0.55",
    "request_id": "req_def456"
  }
}

Response: Returns a standard NLWeb response. If the task is still running, it returns another promise (with an updated progress value if available). If complete, it returns an answer. If the task was cancelled, it returns a failure with code "CANCELLED".

5. Actions

Each result object can include a set of actions relevant to the item. Actions describe executable operations and align with standard tool definition formats.

Action Attributes:

  • @context (string, optional): Schema reference (e.g., "http://schema.org/").
  • @type (string, optional): The action type (e.g., "AddToCartAction"). Use of schema.org action types is recommended where applicable.
  • name (string, required): A machine-readable identifier for the action.
  • description (string, required): A human-readable description of what the action does.
  • protocol (string, required): The protocol used to invoke the action. Defined values:
    • "HTTP": The action is invoked via an HTTP request.
    • "MCP": The action is invoked as an MCP tool call.
    • "A2A": The action is invoked via the Agent2Agent protocol.
  • Protocol-specific attributes:

For "HTTP" actions:

  • method (string, required): HTTP method (e.g., "POST", "GET").
  • endpoint (string, required): The URL to invoke.
  • params (object, optional): Parameters to include in the request.
  • headers (object, optional): HTTP headers to include.

For "MCP" actions:

  • server (string, required): The MCP server identifier.
  • tool (string, required): The MCP tool name to invoke.
  • arguments (object, optional): Arguments to pass to the tool.

For "A2A" actions:

  • agent_url (string, required): The A2A agent endpoint.
  • skill (string, required): The skill to invoke.
  • message (object, optional): The message to send to the agent.

Example (HTTP action):

{
  "actions": [
    {
      "@context": "http://schema.org/",
      "@type": "AddToCartAction",
      "name": "add_ingredients",
      "description": "Add recipe ingredients for XYZ to your shopping cart",
      "protocol": "HTTP",
      "method": "POST",
      "endpoint": "https://api.recipes.example.com/cart/add",
      "params": {
        "items": ["4 large eggs", "1/2 cup diced bell peppers", "1/4 cup chopped spinach"]
      }
    }
  ]
}

Example (MCP action):

{
  "actions": [
    {
      "name": "add_to_cart",
      "description": "Add recipe ingredients to your shopping cart",
      "protocol": "MCP",
      "server": "grocery-store-mcp",
      "tool": "cart_add",
      "arguments": {
        "items": ["4 large eggs", "1/2 cup diced bell peppers"]
      }
    }
  ]
}

6. Streaming

NLWeb supports streaming responses via Server-Sent Events (SSE) over HTTP transport. Streaming is requested by setting prefer.streaming to true.

6.1 Event Types

The following SSE event types are defined:

  • start: Sent once at the beginning of the stream. Contains the _meta block with "streaming": true. Clients SHOULD use this event to initialize their response handling.
  • result: Delivers a single result item from the results array. The data payload contains:
    • index (integer): The position of this item in the final results array.
    • item (object): The result object (same schema as items in the results array). Results may arrive out of order (i.e., index values are not guaranteed to be sequential).
  • error: Signals an error that occurred during streaming. The data payload follows the failure response structure (see 4.1.4). After an error event, the stream may continue (for recoverable errors) or terminate.
  • complete: Sent once to signal the end of the stream. Contains the final _meta block, including session_context if applicable. Clients MUST process this event to capture session state for subsequent requests.

6.2 Streaming Example

Request:

POST /ask HTTP/1.1
Host: api.recipes.example.com
Content-Type: application/json
Accept: text/event-stream

{
  "query": {
    "text": "give me a detailed tutorial on making homemade pasta"
  },
  "prefer": {
    "streaming": true
  }
}

Response:

HTTP/1.1 200 OK
Content-Type: text/event-stream
Cache-Control: no-cache

event: start
data: {"_meta": {"response_type": "answer", "version": "0.55", "streaming": true}}

event: result
data: {"index": 0, "item": {"@type": "SearchSummary", "text": "Here is a step-by-step guide to making fresh pasta from scratch."}}

event: result
data: {"index": 1, "item": {"@type": "Recipe", "name": "Classic Homemade Pasta Dough", "description": "...", "cookTime": "PT45M"}}

event: result
data: {"index": 2, "item": {"@type": "Recipe", "name": "Semolina Pasta Variation", "description": "..."}}

event: complete
data: {"_meta": {"response_type": "answer", "version": "0.55", "session_context": {"conversation_id": "conv_pasta_456"}}}

7. Binding: HTTP Transport

This section defines how NLWeb maps to standard HTTP 1.1/2.0.

7.1 Endpoints

  • POST /ask — Submit a natural language query.
  • POST /await — Check on or cancel a promised result.

7.2 Headers

The prefer argument to ask is used to specify preferences for streaming, structure of output, etc. (as opposed to HTTP headers). Standard HTTP headers (Content-Type, Accept, Authorization, etc.) are used at the transport level as appropriate.

7.3 Streaming

Server-Sent Events (SSE) are supported via Accept: text/event-stream (see Section 6).

7.4 HTTP Status Codes

NLWeb agents SHOULD use appropriate HTTP status codes:

  • 200 OK: Successful response (answer, elicitation, or failure at the application level).
  • 202 Accepted: Promise response for long-running tasks.
  • 400 Bad Request: Malformed request structure.
  • 401 Unauthorized: Authentication required.
  • 429 Too Many Requests: Rate limited.
  • 500 Internal Server Error: Server-side failure.

Note that an NLWeb failure response (Section 4.1.4) is an application-level response and is typically returned with HTTP 200, since the HTTP request itself was processed successfully.

Appendix A: Binding: Model Context Protocol (MCP)

NLWeb operations can be exposed as Tools within the Model Context Protocol (MCP) or other JSON-RPC-based agentic standards.

A.1 Tool Definition: ask

{
  "name": "ask",
  "description": "Natural Language interface to recipes involving pumpkins.",
  "inputSchema": {
    "type": "object",
    "properties": {
      "query": {
        "type": "object",
        "description": "The query object containing text and filters",
        "properties": {
          "text": {"type": "string"},
          "site": {"type": "string"},
          "itemType": {"type": "string"}
        },
        "required": ["text"]
      },
      "context": {
        "type": "object",
        "description": "Semantic context including conversation history"
      },
      "prefer": {
        "type": "object",
        "description": "Response preferences (streaming, formatting, mode)"
      },
      "meta": {
        "type": "object",
        "description": "Protocol metadata, version, and session context"
      }
    },
    "required": ["query"]
  }
}

A.2 Tool Definition: await

{
  "name": "await",
  "description": "Check status or cancel a long-running promise.",
  "inputSchema": {
    "type": "object",
    "properties": {
      "promise_token": {"type": "string"},
      "action": {
        "type": "string",
        "enum": ["checkin", "cancel"]
      },
      "meta": {"type": "object"}
    },
    "required": ["promise_token", "action"]
  }
}

A.3 JSON-RPC Interaction Example

Request:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "ask",
    "arguments": {
      "query": { "text": "Find high protein recipes" },
      "context": { "@type": "UserDiet", "restrictions": ["vegan"] }
    }
  }
}

Response:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "Here are 5 vegan high-protein recipes..."
      }
    ],
    "_meta": {
      "response_type": "answer",
      "version": "0.55",
      "session_context": { "conversation_id": "conv_123" }
    }
  }
}

Appendix B: HTTP Examples — Cooking Recipes

This appendix provides comprehensive examples using cooking recipes as the domain to illustrate all aspects of NLWeb with standard HTTP transport.

Request:

POST /ask HTTP/1.1
Host: api.recipes.example.com
Content-Type: application/json
Accept: application/json

{
  "query": {
    "text": "healthy breakfast recipes with eggs",
    "site": "breakfast-central.com"
  },
  "meta": {
    "version": "0.55"
  }
}

Response:

HTTP/1.1 200 OK
Content-Type: application/json

{
  "_meta": {
    "response_type": "answer",
    "response_format": "conversational_search",
    "version": "0.55",
    "processing_time_ms": 145
  },
  "results": [
    {
      "@type": "Recipe",
      "@context": "https://schema.org",
      "name": "Veggie-Packed Scrambled Eggs",
      "description": "Nutritious scrambled eggs loaded with colorful vegetables",
      "url": "https://recipes.example.com/veggie-scrambled-eggs",
      "image": "https://cdn.recipes.example.com/images/veggie-eggs-425.jpg",
      "cookTime": "PT15M",
      "prepTime": "PT10M",
      "recipeYield": "2 servings",
      "nutrition": {
        "@type": "NutritionInformation",
        "calories": "220 calories",
        "proteinContent": "18g"
      },
      "recipeIngredient": [
        "4 large eggs",
        "1/2 cup diced bell peppers",
        "1/4 cup chopped spinach",
        "2 tbsp milk",
        "Salt and pepper to taste"
      ]
    }
  ]
}

B.2 Elicitation Response

Request:

POST /ask HTTP/1.1
Host: api.recipes.example.com
Content-Type: application/json

{
  "query": {
    "text": "pasta recipe"
  },
  "meta": {
    "version": "0.55"
  }
}

Response:

HTTP/1.1 200 OK
Content-Type: application/json

{
  "_meta": {
    "response_type": "elicitation",
    "version": "0.55"
  },
  "elicitation": {
    "text": "I can help you find the perfect pasta recipe! To give you the best recommendations, could you tell me more about what you're looking for?",
    "questions": [
      {
        "id": "sauce_type",
        "text": "What type of sauce do you prefer?",
        "type": "single_select",
        "options": ["tomato", "cream", "pesto", "oil-based", "no preference"]
      },
      {
        "id": "dietary_restrictions",
        "text": "Do you have any dietary restrictions?",
        "type": "multi_select",
        "options": ["vegetarian", "vegan", "gluten-free", "dairy-free", "none"]
      },
      {
        "id": "cooking_time",
        "text": "How much time do you have for cooking?",
        "type": "single_select",
        "options": ["under 20 minutes", "20-40 minutes", "40-60 minutes", "over an hour"]
      }
    ]
  }
}

B.3 Promise for Long-Running Operations

Initial Request:

POST /ask HTTP/1.1
Host: api.recipes.example.com
Content-Type: application/json

{
  "query": {
    "text": "analyze my meal history and create a personalized weekly meal plan with shopping list",
    "personalized": true
  },
  "meta": {
    "version": "0.55",
    "session_context": {
      "conversation_id": "conv_meal_plan_789"
    }
  }
}

Promise Response:

HTTP/1.1 202 Accepted
Content-Type: application/json

{
  "_meta": {
    "response_type": "promise",
    "version": "0.55",
    "session_context": {
      "conversation_id": "conv_meal_plan_789"
    }
  },
  "promise": {
    "token": "promise_mealplan_xyz789",
    "estimated_time": 30,
    "message": "Analyzing your meal history and preferences...",
    "progress": 0.1
  }
}

Checking on the promise:

POST /await HTTP/1.1
Host: api.recipes.example.com
Content-Type: application/json

{
  "promise_token": "promise_mealplan_xyz789",
  "action": "checkin",
  "meta": {
    "version": "0.55"
  }
}

B.4 Streaming Response (SSE)

Request:

POST /ask HTTP/1.1
Host: api.recipes.example.com
Content-Type: application/json
Accept: text/event-stream

{
  "query": {
    "text": "give me a detailed tutorial on making homemade pasta"
  },
  "prefer": {
    "streaming": true,
    "mode": "list, summarize"
  }
}

Streaming Response:

HTTP/1.1 200 OK
Content-Type: text/event-stream
Cache-Control: no-cache

event: start
data: {"_meta": {"response_type": "answer", "version": "0.55", "streaming": true}}

event: result
data: {"index": 0, "item": {"@type": "SearchSummary", "text": "Here is a step-by-step guide to making fresh pasta, including a classic egg dough and a semolina variation."}}

event: result
data: {"index": 1, "item": {"@type": "Recipe", "name": "Classic Homemade Pasta Dough", "description": "Traditional Italian egg pasta dough, perfect for fettuccine, ravioli, and more.", "cookTime": "PT45M"}}

event: result
data: {"index": 2, "item": {"@type": "Recipe", "name": "Semolina Pasta Variation", "description": "A heartier dough using semolina flour for shapes like orecchiette and cavatelli."}}

event: complete
data: {"_meta": {"response_type": "answer", "version": "0.55", "session_context": {"conversation_id": "conv_pasta_456"}}}

B.5 Failure Response

Request:

POST /ask HTTP/1.1
Host: api.recipes.example.com
Content-Type: application/json

{
  "query": {
    "text": "recipes from planet Mars"
  },
  "meta": {
    "version": "0.55"
  }
}

Response:

HTTP/1.1 200 OK
Content-Type: application/json

{
  "_meta": {
    "response_type": "failure",
    "version": "0.55"
  },
  "error": {
    "code": "NO_RESULTS",
    "message": "No recipes found matching your query."
  }
}

Appendix C: MCP Examples — Cooking Recipes

This appendix provides the same examples as the HTTP appendix but using the Model Context Protocol (MCP) transport with JSON-RPC.

Request:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "ask",
    "arguments": {
      "query": {
        "text": "healthy breakfast recipes with eggs",
        "site": "breakfast-central.com"
      },
      "meta": {
        "version": "0.55"
      }
    }
  }
}

Response:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "{\"_meta\":{\"response_type\":\"answer\",\"version\":\"0.55\"},\"results\":[{\"@type\":\"Recipe\",\"name\":\"Veggie-Packed Scrambled Eggs\",\"description\":\"Nutritious scrambled eggs loaded with colorful vegetables\",\"cookTime\":\"PT15M\",\"nutrition\":{\"@type\":\"NutritionInformation\",\"calories\":\"220 calories\",\"proteinContent\":\"18g\"}}]}"
      }
    ]
  }
}

C.2 Promise and Await via MCP

Initial ask call returns a promise:

{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "{\"_meta\":{\"response_type\":\"promise\",\"version\":\"0.55\"},\"promise\":{\"token\":\"promise_mealplan_xyz789\",\"estimated_time\":30}}"
      }
    ]
  }
}

Checking on the promise with await:

{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "tools/call",
  "params": {
    "name": "await",
    "arguments": {
      "promise_token": "promise_mealplan_xyz789",
      "action": "checkin"
    }
  }
}

Appendix D: Change Log

Changes from v0.54 to v0.55

  • Sections renumbered for continuity (no missing section numbers).
  • meta vs _meta convention explicitly documented: requests use meta, responses use _meta.
  • version attribute standardized to version throughout (previously api_version in some places).
  • Streaming promoted to its own section (Section 6) with formal SSE event type definitions (start, result, error, complete).
  • Actions formalized with full schema definitions for HTTP, MCP, and A2A protocol types (Section 5).
  • Elicitation question types enumerated: single_select, multi_select, free_text, number, boolean.
  • Error codes enumerated: NO_RESULTS, INVALID_QUERY, UNSUPPORTED_FORMAT, UNSUPPORTED_MODE, RATE_LIMITED, INTERNAL_ERROR, TIMEOUT, TOKEN_LIMIT.
  • Summary items in Conversational Search results given a recommended @type of SearchSummary.
  • response_format values documented: conversational_search (default) and chatgpt_app.
  • User object in meta clarified as accepting either a string or structured object.
  • Authentication, authorization, and rate limiting explicitly scoped as transport-layer concerns (Sections 2.4, 2.5).
  • HTTP status code guidance added (Section 7.4).
  • Failure example added to HTTP examples appendix (B.5).
  • Promise attributes (message, progress) formally documented.