MCP Search Interface Specification¶
This document specifies the desired behavior for Moraine's MCP retrieval tools:
search_sessionsopenlist_sessions
The scope of this document is the external interface contract: accepted inputs, output shapes, response behavior, errors, performance targets, and success criteria. It intentionally does not specify storage layout, indexing strategy, query planning, or implementation internals.
Status¶
This is a product and interface specification for the next Moraine MCP search surface. It should be treated as the behavioral target for implementation.
Terminology¶
The interface exposes session history as a hierarchy:
Definitions:
- A session is one agent conversation or trace file.
- A turn is one user-driven interaction within a session.
- An event is one recorded item inside a turn, such as user input, assistant output, reasoning, tool call, tool response, compaction, or runtime status.
- A terminal event is an event that ends a turn and requires new external input before the session can continue.
- A searchable document is one event eligible for retrieval by
search_sessions.
Design Principles¶
- Search returns lookup handles, not full conversations.
openis the only expansion primitive.- Every returned ID should be usable in a later
opencall. - Full payloads should appear only when opening an event.
- Session and turn responses should summarize and provide traversal IDs.
- Defaults should favor useful content over noisy internal events.
- Error responses should be explicit and machine-readable.
Common Interface Rules¶
ID Format¶
MCP IDs are opaque strings. Callers must not parse them for meaning.
The specification examples use typed illustrative IDs:
session:ses_01J9Q3N7W6F9A8K2M4V5R6T7Y8
turn:turn_01J9Q3P4V8BN7XM9G2K6Q1W3E4
event:evt_01J9Q3Q2C4TD9K7F8M1N5R6P2A
Implementations must return stable IDs for the lifetime of the indexed session
data. An ID returned by search_sessions, list_sessions, or open must be
accepted by open unless the underlying session data has been deleted or the
index has been rebuilt with incompatible IDs.
Time Format¶
All timestamps must be RFC 3339 strings in UTC.
Example:
Event Types¶
The MCP interface should expose a normalized event type vocabulary:
Rules:
- Event type names are lowercase snake_case.
- Provider-specific event names should be normalized into this vocabulary.
- Events that cannot be confidently classified should use
unknown. unknownevents may be opened, but are not searched by default.
Completion Status¶
Completion must be reported at session and turn levels.
Session completion:
completed: truemeans the latest known turn has reached a terminal event.completed: falsemeans the latest known turn has not reached a terminal event, or Moraine cannot prove that it has.
Turn completion:
completed: truemeans the turn has a terminal event.completed: falsemeans no terminal event is known.
Terminal event types include:
- final assistant response
- cancellation
- user interrupt
- crash
- runtime exit
- other stop condition
Response Envelope¶
Successful tool responses must use a top-level JSON object with this common shape:
{
"schema_version": "moraine.mcp.<tool>.v1",
"tool": "<tool>",
"request": {},
"data": {},
"warnings": [],
"performance": {
"elapsed_ms": 42,
"sla_target_ms": 750,
"met_sla": true
}
}
Field rules:
schema_versionidentifies the response schema.toolis the MCP tool name.requestcontains the canonicalized request after defaults are applied.datacontains the tool-specific payload.warningsis always present and is an array.performance.elapsed_msis the measured end-to-end tool handling time.performance.sla_target_msis the target that applied to this request.performance.met_slaindicates whether the request met its target.
Error Envelope¶
Rejected requests and failed lookups must return a machine-readable error.
These are in-band tool results, not MCP/JSON-RPC transport failures; the MCP
tool result wrapper should therefore be returned cleanly with the error object
in structuredContent.
{
"schema_version": "moraine.mcp.error.v1",
"tool": "<tool>",
"request": {},
"error": {
"code": "invalid_request",
"message": "query must be a non-empty string",
"details": {
"field": "query"
}
},
"warnings": [],
"performance": {
"elapsed_ms": 3,
"sla_target_ms": 750,
"met_sla": true
}
}
Required error codes:
Error behavior:
- Invalid inputs must not be silently coerced, except where this specification explicitly defines normalization.
- Missing IDs must return
not_found. - Malformed IDs must return
invalid_id. - Unknown event type filters must return
unsupported_event_type. - Runtime failures must return
internal_errorwith a concise message.
Tool: search_sessions¶
Purpose¶
search_sessions finds relevant events across Moraine history and returns
compact handles into the session graph.
It answers:
It does not return full event payloads, full turns, or full sessions.
Request Schema¶
search_sessions({
query: string,
within_id?: string | null,
event_types?: string[] | null,
n_hits?: number | null
})
Accepted Inputs¶
query:
- Required.
- Must be a string.
- Must contain at least one non-whitespace character after trimming.
- Maximum length: 4096 characters.
- The original query text should be preserved in the canonical request except for trimming leading and trailing whitespace.
within_id:
- Optional.
- May be omitted or
null. - When omitted or
null, search covers all indexed sessions visible to the Moraine configuration. - May be a session ID returned by Moraine.
- May be a turn ID returned by Moraine.
- Must not be an event ID in v1.
event_types:
- Optional.
- May be omitted or
null. - When omitted or
null, defaults to:
- May contain any supported event type except
unknown. - Must contain at least one event type after normalization.
- Duplicate event types should be de-duplicated in the canonical request.
- Event type order in the canonical request should follow Moraine's normalized event type order, not caller order.
n_hits:
- Optional.
- May be omitted or
null. - Default:
10. - Minimum:
1. - Maximum:
50. - Must be an integer.
Search Scope Behavior¶
When within_id is omitted:
- Search all indexed sessions.
- Return hits from any matching session.
When within_id is a session ID:
- Search only events whose
session.idmatches that session. - If the session exists but has no matching events, return an empty result set.
- If the session ID does not exist, return
not_found.
When within_id is a turn ID:
- Search only events whose
turn.idmatches that turn. - If the turn exists but has no matching events, return an empty result set.
- If the turn ID does not exist, return
not_found.
When within_id is an event ID:
- Return
invalid_request. - Message:
within_id accepts session and turn IDs, not event IDs.
Event Type Filter Behavior¶
Default behavior searches:
This default intentionally omits:
Callers may explicitly include supported omitted types when they need them.
Examples:
{
"query": "sandbox monitor health endpoint",
"within_id": "session:ses_01J9Q3N7W6F9A8K2M4V5R6T7Y8"
}
Ranking Behavior¶
Results must be ordered by:
- Relevance score descending.
- Event timestamp descending for ties.
- Event ID ascending for remaining ties.
The score must be a number between 0.0 and 1.0.
Scores are only required to be comparable within a single response. Callers should not compare scores across different queries.
Successful Response Shape¶
{
"schema_version": "moraine.mcp.search_sessions.v1",
"tool": "search_sessions",
"request": {
"query": "clickhouse schema migration failure",
"within_id": null,
"event_types": ["user_input", "assistant_response", "tool_response"],
"n_hits": 10
},
"data": {
"result_count": 2,
"limit": 10,
"truncated": false,
"results": []
},
"warnings": [],
"performance": {
"elapsed_ms": 64,
"sla_target_ms": 750,
"met_sla": true
}
}
data.result_count:
- Number of hits returned.
- Must be less than or equal to
data.limit.
data.limit:
- The canonical
n_hitsvalue.
data.truncated:
truewhen more matches may exist beyonddata.limit.falsewhen the response includes all matches known to the query execution.
data.results:
- Ordered array of search hits.
Search Hit Shape¶
Each hit must have this shape:
{
"rank": 1,
"score": 0.82,
"id": "event:evt_01J9Q3Q2C4TD9K7F8M1N5R6P2A",
"event": {
"id": "event:evt_01J9Q3Q2C4TD9K7F8M1N5R6P2A",
"type": "user_input",
"timestamp": "2026-04-29T18:42:31.125Z",
"ordinal": 1,
"terminal": false
},
"turn": {
"id": "turn:turn_01J9Q3P4V8BN7XM9G2K6Q1W3E4",
"ordinal": 7,
"completed": true,
"event_count": 12
},
"session": {
"id": "session:ses_01J9Q3N7W6F9A8K2M4V5R6T7Y8",
"title": "Fix ClickHouse schema migration failure",
"source": "codex",
"started_at": "2026-04-29T18:41:55.000Z",
"updated_at": "2026-04-29T19:03:12.442Z",
"completed": true
},
"snippet": {
"text": "The ClickHouse schema migration is failing after adding the event ordinal column...",
"truncated": true
},
"open": {
"event_id": "event:evt_01J9Q3Q2C4TD9K7F8M1N5R6P2A",
"turn_id": "turn:turn_01J9Q3P4V8BN7XM9G2K6Q1W3E4",
"session_id": "session:ses_01J9Q3N7W6F9A8K2M4V5R6T7Y8"
}
}
Field rules:
rankis one-based.idis the same asevent.id.event.ordinalis one-based within the parent turn.turn.ordinalis one-based within the parent session.snippet.textshould be short enough to scan and must not contain a full payload when the event content is large.openrepeats the IDs callers are expected to use next.
Example: Default Global Search¶
Request:
Response:
{
"schema_version": "moraine.mcp.search_sessions.v1",
"tool": "search_sessions",
"request": {
"query": "ClickHouse schema migration failure",
"within_id": null,
"event_types": ["user_input", "assistant_response", "tool_response"],
"n_hits": 10
},
"data": {
"result_count": 2,
"limit": 10,
"truncated": false,
"results": [
{
"rank": 1,
"score": 0.91,
"id": "event:evt_01J9Q3Q2C4TD9K7F8M1N5R6P2A",
"event": {
"id": "event:evt_01J9Q3Q2C4TD9K7F8M1N5R6P2A",
"type": "user_input",
"timestamp": "2026-04-29T18:42:31.125Z",
"ordinal": 1,
"terminal": false
},
"turn": {
"id": "turn:turn_01J9Q3P4V8BN7XM9G2K6Q1W3E4",
"ordinal": 7,
"completed": true,
"event_count": 12
},
"session": {
"id": "session:ses_01J9Q3N7W6F9A8K2M4V5R6T7Y8",
"title": "Fix ClickHouse schema migration failure",
"source": "codex",
"started_at": "2026-04-29T18:41:55.000Z",
"updated_at": "2026-04-29T19:03:12.442Z",
"completed": true
},
"snippet": {
"text": "The ClickHouse schema migration is failing after adding the event ordinal column...",
"truncated": true
},
"open": {
"event_id": "event:evt_01J9Q3Q2C4TD9K7F8M1N5R6P2A",
"turn_id": "turn:turn_01J9Q3P4V8BN7XM9G2K6Q1W3E4",
"session_id": "session:ses_01J9Q3N7W6F9A8K2M4V5R6T7Y8"
}
},
{
"rank": 2,
"score": 0.78,
"id": "event:evt_01J9Q4A91M7S4V3BK2Y5N6X8D9",
"event": {
"id": "event:evt_01J9Q4A91M7S4V3BK2Y5N6X8D9",
"type": "assistant_response",
"timestamp": "2026-04-29T19:02:48.030Z",
"ordinal": 12,
"terminal": true
},
"turn": {
"id": "turn:turn_01J9Q3P4V8BN7XM9G2K6Q1W3E4",
"ordinal": 7,
"completed": true,
"event_count": 12
},
"session": {
"id": "session:ses_01J9Q3N7W6F9A8K2M4V5R6T7Y8",
"title": "Fix ClickHouse schema migration failure",
"source": "codex",
"started_at": "2026-04-29T18:41:55.000Z",
"updated_at": "2026-04-29T19:03:12.442Z",
"completed": true
},
"snippet": {
"text": "Updated the migration ordering and verified the ClickHouse schema applies cleanly...",
"truncated": true
},
"open": {
"event_id": "event:evt_01J9Q4A91M7S4V3BK2Y5N6X8D9",
"turn_id": "turn:turn_01J9Q3P4V8BN7XM9G2K6Q1W3E4",
"session_id": "session:ses_01J9Q3N7W6F9A8K2M4V5R6T7Y8"
}
}
]
},
"warnings": [],
"performance": {
"elapsed_ms": 64,
"sla_target_ms": 750,
"met_sla": true
}
}
Example: Search Within A Turn¶
Request:
{
"query": "cargo test failure",
"within_id": "turn:turn_01J9Q3P4V8BN7XM9G2K6Q1W3E4",
"event_types": ["tool_response"],
"n_hits": 3
}
Response:
{
"schema_version": "moraine.mcp.search_sessions.v1",
"tool": "search_sessions",
"request": {
"query": "cargo test failure",
"within_id": "turn:turn_01J9Q3P4V8BN7XM9G2K6Q1W3E4",
"event_types": ["tool_response"],
"n_hits": 3
},
"data": {
"result_count": 1,
"limit": 3,
"truncated": false,
"results": [
{
"rank": 1,
"score": 0.86,
"id": "event:evt_01J9Q45J7G6KN92PV4RB8M2N0H",
"event": {
"id": "event:evt_01J9Q45J7G6KN92PV4RB8M2N0H",
"type": "tool_response",
"timestamp": "2026-04-29T18:56:02.810Z",
"ordinal": 9,
"terminal": false
},
"turn": {
"id": "turn:turn_01J9Q3P4V8BN7XM9G2K6Q1W3E4",
"ordinal": 7,
"completed": true,
"event_count": 12
},
"session": {
"id": "session:ses_01J9Q3N7W6F9A8K2M4V5R6T7Y8",
"title": "Fix ClickHouse schema migration failure",
"source": "codex",
"started_at": "2026-04-29T18:41:55.000Z",
"updated_at": "2026-04-29T19:03:12.442Z",
"completed": true
},
"snippet": {
"text": "cargo test --workspace --locked failed in moraine-clickhouse-client...",
"truncated": true
},
"open": {
"event_id": "event:evt_01J9Q45J7G6KN92PV4RB8M2N0H",
"turn_id": "turn:turn_01J9Q3P4V8BN7XM9G2K6Q1W3E4",
"session_id": "session:ses_01J9Q3N7W6F9A8K2M4V5R6T7Y8"
}
}
]
},
"warnings": [],
"performance": {
"elapsed_ms": 18,
"sla_target_ms": 300,
"met_sla": true
}
}
Example: No Hits¶
Request:
Response:
{
"schema_version": "moraine.mcp.search_sessions.v1",
"tool": "search_sessions",
"request": {
"query": "nonexistent exact phrase for this index",
"within_id": null,
"event_types": ["user_input", "assistant_response", "tool_response"],
"n_hits": 5
},
"data": {
"result_count": 0,
"limit": 5,
"truncated": false,
"results": []
},
"warnings": [],
"performance": {
"elapsed_ms": 21,
"sla_target_ms": 750,
"met_sla": true
}
}
Search Error Examples¶
Blank query:
{
"schema_version": "moraine.mcp.error.v1",
"tool": "search_sessions",
"request": {
"query": " "
},
"error": {
"code": "invalid_request",
"message": "query must be a non-empty string",
"details": {
"field": "query"
}
},
"warnings": [],
"performance": {
"elapsed_ms": 2,
"sla_target_ms": 750,
"met_sla": true
}
}
Unsupported event type:
{
"schema_version": "moraine.mcp.error.v1",
"tool": "search_sessions",
"request": {
"query": "migration",
"event_types": ["user_input", "debug_trace"]
},
"error": {
"code": "unsupported_event_type",
"message": "unsupported event type: debug_trace",
"details": {
"field": "event_types",
"supported": [
"user_input",
"assistant_response",
"reasoning",
"tool_call",
"tool_response",
"compaction",
"system",
"runtime"
]
}
},
"warnings": [],
"performance": {
"elapsed_ms": 2,
"sla_target_ms": 750,
"met_sla": true
}
}
Tool: list_sessions¶
Purpose¶
list_sessions lists sessions that overlap a caller-supplied datetime range.
Use it for metadata browsing by time; use search_sessions for content search
and open to inspect a selected session.
Request Schema¶
{
"start_datetime": "2026-04-30T09:00:00-04:00",
"end_datetime": "2026-04-30T13:00:00-04:00",
"limit": 20,
"cursor": null,
"mode": null,
"sort": "desc"
}
Rules:
start_datetimeis inclusive andend_datetimeis exclusive.- Datetimes must be RFC 3339 / ISO 8601 strings with an explicit timezone
offset or
Z. - Sessions match when
updated_at >= start_datetimeandstarted_at < end_datetime. mode, when present, is one ofweb_search,mcp_internal,tool_calling, orchat.sortisdescorasc, ordered by sessionupdated_atand session ID.
Response Shape¶
Successful responses use moraine.mcp.list_sessions.v1 and return compact
session metadata only:
{
"schema_version": "moraine.mcp.list_sessions.v1",
"tool": "list_sessions",
"request": {},
"data": {
"result_count": 1,
"limit": 20,
"truncated": false,
"sessions": [
{
"rank": 1,
"id": "session:c2Vzcy0x",
"session": {
"id": "session:c2Vzcy0x",
"title": "Build failure triage",
"source": "codex",
"started_at": "2026-04-30T13:00:00.000Z",
"updated_at": "2026-04-30T13:10:00.000Z",
"completed": true,
"turn_count": 3,
"event_count": 17,
"mode": "tool_calling",
"session_slug": "build-failure",
"session_summary": "Build failure triage."
},
"open": {
"session_id": "session:c2Vzcy0x"
}
}
],
"next_cursor": null
},
"warnings": [],
"performance": {
"elapsed_ms": 42,
"sla_target_ms": 300,
"met_sla": true
}
}
list_sessions must not return event snippets, transcript text, or event
payloads. To inspect a listed session, pass open.session_id to open.
Tool: open¶
Purpose¶
open expands a stable Moraine ID into structured context.
It answers:
The same tool opens sessions, turns, and events. The response type depends on the ID kind.
Request Schema¶
Accepted Inputs¶
id:
- Required.
- Must be a string.
- Must be a valid Moraine MCP ID returned by
search_sessions,list_sessions, oropen. - May refer to a session, turn, or event.
Invalid inputs:
- Missing
idreturnsinvalid_request. - Empty or whitespace-only
idreturnsinvalid_request. - Malformed IDs return
invalid_id. - Well-formed but unknown IDs return
not_found.
Successful Response Shape¶
All successful open responses use this envelope:
{
"schema_version": "moraine.mcp.open.v1",
"tool": "open",
"request": {
"id": "session:ses_01J9Q3N7W6F9A8K2M4V5R6T7Y8"
},
"data": {
"kind": "session"
},
"warnings": [],
"performance": {
"elapsed_ms": 32,
"sla_target_ms": 500,
"met_sla": true
}
}
data.kind must be one of:
Opening A Session¶
Opening a session returns session metadata plus a compact list of turns.
It must not return full event payloads.
Session response shape:
{
"kind": "session",
"session": {
"id": "session:ses_01J9Q3N7W6F9A8K2M4V5R6T7Y8",
"title": "Fix ClickHouse schema migration failure",
"source": "codex",
"started_at": "2026-04-29T18:41:55.000Z",
"updated_at": "2026-04-29T19:03:12.442Z",
"completed": true,
"turn_count": 2,
"event_count": 18
},
"turns": [],
"traversal": {
"previous_session_id": null,
"next_session_id": null
}
}
Turn summary shape:
{
"id": "turn:turn_01J9Q3P4V8BN7XM9G2K6Q1W3E4",
"ordinal": 1,
"completed": true,
"terminal_event_id": "event:evt_01J9Q4A91M7S4V3BK2Y5N6X8D9",
"event_count": 12,
"started_at": "2026-04-29T18:42:31.125Z",
"updated_at": "2026-04-29T19:02:48.030Z",
"user_input": {
"event_id": "event:evt_01J9Q3Q2C4TD9K7F8M1N5R6P2A",
"text": "The ClickHouse schema migration is failing after adding the event ordinal column...",
"truncated": true
},
"final_response": {
"event_id": "event:evt_01J9Q4A91M7S4V3BK2Y5N6X8D9",
"text": "Updated the migration ordering and verified the ClickHouse schema applies cleanly...",
"truncated": true
},
"tools_called": ["exec_command", "apply_patch"],
"event_types": ["user_input", "tool_call", "tool_response", "assistant_response"],
"open": {
"turn_id": "turn:turn_01J9Q3P4V8BN7XM9G2K6Q1W3E4",
"terminal_event_id": "event:evt_01J9Q4A91M7S4V3BK2Y5N6X8D9"
}
}
Rules:
turnsare ordered byordinalascending.turnsmust include every known turn in the session.user_inputmay benullif no user input event is known.final_responsemay benullif the turn is incomplete or ended without a final assistant response.tools_calledmust contain unique tool names in first-seen order.event_typesmust contain unique event types in first-seen order.terminal_event_idmay benullwhencompletedisfalse.
Example:
{
"schema_version": "moraine.mcp.open.v1",
"tool": "open",
"request": {
"id": "session:ses_01J9Q3N7W6F9A8K2M4V5R6T7Y8"
},
"data": {
"kind": "session",
"session": {
"id": "session:ses_01J9Q3N7W6F9A8K2M4V5R6T7Y8",
"title": "Fix ClickHouse schema migration failure",
"source": "codex",
"started_at": "2026-04-29T18:41:55.000Z",
"updated_at": "2026-04-29T19:03:12.442Z",
"completed": true,
"turn_count": 2,
"event_count": 18
},
"turns": [
{
"id": "turn:turn_01J9Q3P4V8BN7XM9G2K6Q1W3E4",
"ordinal": 1,
"completed": true,
"terminal_event_id": "event:evt_01J9Q4A91M7S4V3BK2Y5N6X8D9",
"event_count": 12,
"started_at": "2026-04-29T18:42:31.125Z",
"updated_at": "2026-04-29T19:02:48.030Z",
"user_input": {
"event_id": "event:evt_01J9Q3Q2C4TD9K7F8M1N5R6P2A",
"text": "The ClickHouse schema migration is failing after adding the event ordinal column...",
"truncated": true
},
"final_response": {
"event_id": "event:evt_01J9Q4A91M7S4V3BK2Y5N6X8D9",
"text": "Updated the migration ordering and verified the ClickHouse schema applies cleanly...",
"truncated": true
},
"tools_called": ["exec_command", "apply_patch"],
"event_types": ["user_input", "tool_call", "tool_response", "assistant_response"],
"open": {
"turn_id": "turn:turn_01J9Q3P4V8BN7XM9G2K6Q1W3E4",
"terminal_event_id": "event:evt_01J9Q4A91M7S4V3BK2Y5N6X8D9"
}
},
{
"id": "turn:turn_01J9Q4P93SP6B2D5M8K7V1H4NC",
"ordinal": 2,
"completed": true,
"terminal_event_id": "event:evt_01J9Q4T0N8D6W3F2HK5P7M9VX1",
"event_count": 6,
"started_at": "2026-04-29T19:02:59.510Z",
"updated_at": "2026-04-29T19:03:12.442Z",
"user_input": {
"event_id": "event:evt_01J9Q4P93SP6B2D5M8K7V1H4NC",
"text": "Can you summarize the validation?",
"truncated": false
},
"final_response": {
"event_id": "event:evt_01J9Q4T0N8D6W3F2HK5P7M9VX1",
"text": "Validation passed with make docs-build and cargo test for the affected crate.",
"truncated": false
},
"tools_called": [],
"event_types": ["user_input", "assistant_response"],
"open": {
"turn_id": "turn:turn_01J9Q4P93SP6B2D5M8K7V1H4NC",
"terminal_event_id": "event:evt_01J9Q4T0N8D6W3F2HK5P7M9VX1"
}
}
],
"traversal": {
"previous_session_id": null,
"next_session_id": null
}
},
"warnings": [],
"performance": {
"elapsed_ms": 32,
"sla_target_ms": 500,
"met_sla": true
}
}
Opening A Turn¶
Opening a turn returns a compact view of that turn plus ordered event handles.
It must not return full payloads for every event.
Turn response shape:
{
"kind": "turn",
"turn": {
"id": "turn:turn_01J9Q3P4V8BN7XM9G2K6Q1W3E4",
"session_id": "session:ses_01J9Q3N7W6F9A8K2M4V5R6T7Y8",
"ordinal": 1,
"completed": true,
"terminal_event_id": "event:evt_01J9Q4A91M7S4V3BK2Y5N6X8D9",
"event_count": 12,
"started_at": "2026-04-29T18:42:31.125Z",
"updated_at": "2026-04-29T19:02:48.030Z"
},
"session": {
"id": "session:ses_01J9Q3N7W6F9A8K2M4V5R6T7Y8",
"title": "Fix ClickHouse schema migration failure",
"source": "codex"
},
"summary": {
"user_input": {},
"final_response": {},
"tools_called": [],
"event_types": []
},
"events": [],
"traversal": {}
}
Event summary shape inside events:
{
"id": "event:evt_01J9Q45J7G6KN92PV4RB8M2N0H",
"ordinal": 9,
"type": "tool_response",
"timestamp": "2026-04-29T18:56:02.810Z",
"terminal": false,
"tool_name": "exec_command",
"model": null,
"summary": "cargo test --workspace --locked failed in moraine-clickhouse-client...",
"truncated": true
}
Rules:
eventsare ordered byordinalascending.eventsmust include every known event in the turn.- Event summaries are compact. Full event content is available through
open(event_id). summary.user_inputmay benull.summary.final_responsemay benull.summary.tools_calledmust contain unique tool names in first-seen order.summary.event_typesmust contain unique event types in first-seen order.
Complete turn example:
{
"schema_version": "moraine.mcp.open.v1",
"tool": "open",
"request": {
"id": "turn:turn_01J9Q3P4V8BN7XM9G2K6Q1W3E4"
},
"data": {
"kind": "turn",
"turn": {
"id": "turn:turn_01J9Q3P4V8BN7XM9G2K6Q1W3E4",
"session_id": "session:ses_01J9Q3N7W6F9A8K2M4V5R6T7Y8",
"ordinal": 1,
"completed": true,
"terminal_event_id": "event:evt_01J9Q4A91M7S4V3BK2Y5N6X8D9",
"event_count": 4,
"started_at": "2026-04-29T18:42:31.125Z",
"updated_at": "2026-04-29T19:02:48.030Z"
},
"session": {
"id": "session:ses_01J9Q3N7W6F9A8K2M4V5R6T7Y8",
"title": "Fix ClickHouse schema migration failure",
"source": "codex"
},
"summary": {
"user_input": {
"event_id": "event:evt_01J9Q3Q2C4TD9K7F8M1N5R6P2A",
"text": "The ClickHouse schema migration is failing after adding the event ordinal column...",
"truncated": true
},
"final_response": {
"event_id": "event:evt_01J9Q4A91M7S4V3BK2Y5N6X8D9",
"text": "Updated the migration ordering and verified the ClickHouse schema applies cleanly...",
"truncated": true
},
"tools_called": ["exec_command"],
"event_types": ["user_input", "tool_call", "tool_response", "assistant_response"]
},
"events": [
{
"id": "event:evt_01J9Q3Q2C4TD9K7F8M1N5R6P2A",
"ordinal": 1,
"type": "user_input",
"timestamp": "2026-04-29T18:42:31.125Z",
"terminal": false,
"tool_name": null,
"model": null,
"summary": "The ClickHouse schema migration is failing after adding the event ordinal column...",
"truncated": true
},
{
"id": "event:evt_01J9Q43T4HB1W7V69N2CM8K5D0",
"ordinal": 2,
"type": "tool_call",
"timestamp": "2026-04-29T18:55:59.001Z",
"terminal": false,
"tool_name": "exec_command",
"model": null,
"summary": "cargo test --workspace --locked",
"truncated": false
},
{
"id": "event:evt_01J9Q45J7G6KN92PV4RB8M2N0H",
"ordinal": 3,
"type": "tool_response",
"timestamp": "2026-04-29T18:56:02.810Z",
"terminal": false,
"tool_name": "exec_command",
"model": null,
"summary": "cargo test --workspace --locked failed in moraine-clickhouse-client...",
"truncated": true
},
{
"id": "event:evt_01J9Q4A91M7S4V3BK2Y5N6X8D9",
"ordinal": 4,
"type": "assistant_response",
"timestamp": "2026-04-29T19:02:48.030Z",
"terminal": true,
"tool_name": null,
"model": "gpt-5",
"summary": "Updated the migration ordering and verified the ClickHouse schema applies cleanly...",
"truncated": true
}
],
"traversal": {
"session_id": "session:ses_01J9Q3N7W6F9A8K2M4V5R6T7Y8",
"previous_turn_id": null,
"next_turn_id": "turn:turn_01J9Q4P93SP6B2D5M8K7V1H4NC",
"first_event_id": "event:evt_01J9Q3Q2C4TD9K7F8M1N5R6P2A",
"last_event_id": "event:evt_01J9Q4A91M7S4V3BK2Y5N6X8D9"
}
},
"warnings": [],
"performance": {
"elapsed_ms": 19,
"sla_target_ms": 300,
"met_sla": true
}
}
Incomplete turn example:
{
"schema_version": "moraine.mcp.open.v1",
"tool": "open",
"request": {
"id": "turn:turn_01J9R1A7X2C6D5E4F3G2H1J9K8"
},
"data": {
"kind": "turn",
"turn": {
"id": "turn:turn_01J9R1A7X2C6D5E4F3G2H1J9K8",
"session_id": "session:ses_01J9R19PV0A2B3C4D5E6F7G8H9",
"ordinal": 4,
"completed": false,
"terminal_event_id": null,
"event_count": 2,
"started_at": "2026-04-29T20:12:00.000Z",
"updated_at": "2026-04-29T20:12:08.000Z"
},
"session": {
"id": "session:ses_01J9R19PV0A2B3C4D5E6F7G8H9",
"title": "Investigate monitor startup",
"source": "codex"
},
"summary": {
"user_input": {
"event_id": "event:evt_01J9R1B1CZ0K6P9Q8R7S6T5V4W",
"text": "Check whether the monitor starts after the latest config change.",
"truncated": false
},
"final_response": null,
"tools_called": ["exec_command"],
"event_types": ["user_input", "tool_call"]
},
"events": [
{
"id": "event:evt_01J9R1B1CZ0K6P9Q8R7S6T5V4W",
"ordinal": 1,
"type": "user_input",
"timestamp": "2026-04-29T20:12:00.000Z",
"terminal": false,
"tool_name": null,
"model": null,
"summary": "Check whether the monitor starts after the latest config change.",
"truncated": false
},
{
"id": "event:evt_01J9R1B9N8M7L6K5J4H3G2F1E0",
"ordinal": 2,
"type": "tool_call",
"timestamp": "2026-04-29T20:12:08.000Z",
"terminal": false,
"tool_name": "exec_command",
"model": null,
"summary": "bin/moraine status",
"truncated": false
}
],
"traversal": {
"session_id": "session:ses_01J9R19PV0A2B3C4D5E6F7G8H9",
"previous_turn_id": "turn:turn_01J9R18Y8W7V6T5S4R3Q2P1N0M",
"next_turn_id": null,
"first_event_id": "event:evt_01J9R1B1CZ0K6P9Q8R7S6T5V4W",
"last_event_id": "event:evt_01J9R1B9N8M7L6K5J4H3G2F1E0"
}
},
"warnings": [],
"performance": {
"elapsed_ms": 16,
"sla_target_ms": 300,
"met_sla": true
}
}
Opening An Event¶
Opening an event returns full event metadata and full event content.
Event response shape:
{
"kind": "event",
"event": {
"id": "event:evt_01J9Q45J7G6KN92PV4RB8M2N0H",
"session_id": "session:ses_01J9Q3N7W6F9A8K2M4V5R6T7Y8",
"turn_id": "turn:turn_01J9Q3P4V8BN7XM9G2K6Q1W3E4",
"ordinal": 3,
"type": "tool_response",
"timestamp": "2026-04-29T18:56:02.810Z",
"terminal": false,
"model": null,
"originating_model": "gpt-5",
"tool_name": "exec_command"
},
"content": {},
"session": {},
"turn": {},
"traversal": {}
}
Common content fields:
Rules:
content.truncatedmust befalsefor normal event opens.content.textmust contain the full available event text for text-like events.- Structured event payloads may include additional fields, but
content.textshould provide a human-readable representation when available. - Tool calls should include tool name and arguments.
- Tool responses should include tool name, exit status when available, and full output when available.
- Reasoning events should be openable when captured and permitted by the local data source.
User input event example:
{
"schema_version": "moraine.mcp.open.v1",
"tool": "open",
"request": {
"id": "event:evt_01J9Q3Q2C4TD9K7F8M1N5R6P2A"
},
"data": {
"kind": "event",
"event": {
"id": "event:evt_01J9Q3Q2C4TD9K7F8M1N5R6P2A",
"session_id": "session:ses_01J9Q3N7W6F9A8K2M4V5R6T7Y8",
"turn_id": "turn:turn_01J9Q3P4V8BN7XM9G2K6Q1W3E4",
"ordinal": 1,
"type": "user_input",
"timestamp": "2026-04-29T18:42:31.125Z",
"terminal": false,
"model": null,
"originating_model": null,
"tool_name": null
},
"content": {
"format": "text",
"text": "The ClickHouse schema migration is failing after adding the event ordinal column. Please find the issue and fix it.",
"truncated": false
},
"session": {
"id": "session:ses_01J9Q3N7W6F9A8K2M4V5R6T7Y8",
"title": "Fix ClickHouse schema migration failure",
"source": "codex"
},
"turn": {
"id": "turn:turn_01J9Q3P4V8BN7XM9G2K6Q1W3E4",
"ordinal": 1,
"completed": true
},
"traversal": {
"session_id": "session:ses_01J9Q3N7W6F9A8K2M4V5R6T7Y8",
"turn_id": "turn:turn_01J9Q3P4V8BN7XM9G2K6Q1W3E4",
"previous_event_id": null,
"next_event_id": "event:evt_01J9Q43T4HB1W7V69N2CM8K5D0",
"previous_turn_id": null,
"next_turn_id": "turn:turn_01J9Q4P93SP6B2D5M8K7V1H4NC"
}
},
"warnings": [],
"performance": {
"elapsed_ms": 9,
"sla_target_ms": 200,
"met_sla": true
}
}
Tool call event example:
{
"schema_version": "moraine.mcp.open.v1",
"tool": "open",
"request": {
"id": "event:evt_01J9Q43T4HB1W7V69N2CM8K5D0"
},
"data": {
"kind": "event",
"event": {
"id": "event:evt_01J9Q43T4HB1W7V69N2CM8K5D0",
"session_id": "session:ses_01J9Q3N7W6F9A8K2M4V5R6T7Y8",
"turn_id": "turn:turn_01J9Q3P4V8BN7XM9G2K6Q1W3E4",
"ordinal": 2,
"type": "tool_call",
"timestamp": "2026-04-29T18:55:59.001Z",
"terminal": false,
"model": null,
"originating_model": "gpt-5",
"tool_name": "exec_command"
},
"content": {
"format": "tool_call",
"tool_name": "exec_command",
"arguments": {
"cmd": "cargo test --workspace --locked",
"workdir": "/Users/eric/src/moraine"
},
"text": "exec_command(cmd=\"cargo test --workspace --locked\", workdir=\"/Users/eric/src/moraine\")",
"truncated": false
},
"session": {
"id": "session:ses_01J9Q3N7W6F9A8K2M4V5R6T7Y8",
"title": "Fix ClickHouse schema migration failure",
"source": "codex"
},
"turn": {
"id": "turn:turn_01J9Q3P4V8BN7XM9G2K6Q1W3E4",
"ordinal": 1,
"completed": true
},
"traversal": {
"session_id": "session:ses_01J9Q3N7W6F9A8K2M4V5R6T7Y8",
"turn_id": "turn:turn_01J9Q3P4V8BN7XM9G2K6Q1W3E4",
"previous_event_id": "event:evt_01J9Q3Q2C4TD9K7F8M1N5R6P2A",
"next_event_id": "event:evt_01J9Q45J7G6KN92PV4RB8M2N0H",
"previous_turn_id": null,
"next_turn_id": "turn:turn_01J9Q4P93SP6B2D5M8K7V1H4NC"
}
},
"warnings": [],
"performance": {
"elapsed_ms": 8,
"sla_target_ms": 200,
"met_sla": true
}
}
Tool response event example:
{
"schema_version": "moraine.mcp.open.v1",
"tool": "open",
"request": {
"id": "event:evt_01J9Q45J7G6KN92PV4RB8M2N0H"
},
"data": {
"kind": "event",
"event": {
"id": "event:evt_01J9Q45J7G6KN92PV4RB8M2N0H",
"session_id": "session:ses_01J9Q3N7W6F9A8K2M4V5R6T7Y8",
"turn_id": "turn:turn_01J9Q3P4V8BN7XM9G2K6Q1W3E4",
"ordinal": 3,
"type": "tool_response",
"timestamp": "2026-04-29T18:56:02.810Z",
"terminal": false,
"model": null,
"originating_model": "gpt-5",
"tool_name": "exec_command"
},
"content": {
"format": "tool_response",
"tool_name": "exec_command",
"exit_code": 101,
"text": "cargo test --workspace --locked failed in moraine-clickhouse-client\n\nfailures:\n migrations_apply_in_order\n",
"truncated": false
},
"session": {
"id": "session:ses_01J9Q3N7W6F9A8K2M4V5R6T7Y8",
"title": "Fix ClickHouse schema migration failure",
"source": "codex"
},
"turn": {
"id": "turn:turn_01J9Q3P4V8BN7XM9G2K6Q1W3E4",
"ordinal": 1,
"completed": true
},
"traversal": {
"session_id": "session:ses_01J9Q3N7W6F9A8K2M4V5R6T7Y8",
"turn_id": "turn:turn_01J9Q3P4V8BN7XM9G2K6Q1W3E4",
"previous_event_id": "event:evt_01J9Q43T4HB1W7V69N2CM8K5D0",
"next_event_id": "event:evt_01J9Q4A91M7S4V3BK2Y5N6X8D9",
"previous_turn_id": null,
"next_turn_id": "turn:turn_01J9Q4P93SP6B2D5M8K7V1H4NC"
}
},
"warnings": [],
"performance": {
"elapsed_ms": 10,
"sla_target_ms": 200,
"met_sla": true
}
}
Assistant response event example:
{
"schema_version": "moraine.mcp.open.v1",
"tool": "open",
"request": {
"id": "event:evt_01J9Q4A91M7S4V3BK2Y5N6X8D9"
},
"data": {
"kind": "event",
"event": {
"id": "event:evt_01J9Q4A91M7S4V3BK2Y5N6X8D9",
"session_id": "session:ses_01J9Q3N7W6F9A8K2M4V5R6T7Y8",
"turn_id": "turn:turn_01J9Q3P4V8BN7XM9G2K6Q1W3E4",
"ordinal": 4,
"type": "assistant_response",
"timestamp": "2026-04-29T19:02:48.030Z",
"terminal": true,
"model": "gpt-5",
"originating_model": "gpt-5",
"tool_name": null
},
"content": {
"format": "text",
"text": "Updated the migration ordering and verified the ClickHouse schema applies cleanly. Validation: cargo test --workspace --locked passed.",
"truncated": false
},
"session": {
"id": "session:ses_01J9Q3N7W6F9A8K2M4V5R6T7Y8",
"title": "Fix ClickHouse schema migration failure",
"source": "codex"
},
"turn": {
"id": "turn:turn_01J9Q3P4V8BN7XM9G2K6Q1W3E4",
"ordinal": 1,
"completed": true
},
"traversal": {
"session_id": "session:ses_01J9Q3N7W6F9A8K2M4V5R6T7Y8",
"turn_id": "turn:turn_01J9Q3P4V8BN7XM9G2K6Q1W3E4",
"previous_event_id": "event:evt_01J9Q45J7G6KN92PV4RB8M2N0H",
"next_event_id": null,
"previous_turn_id": null,
"next_turn_id": "turn:turn_01J9Q4P93SP6B2D5M8K7V1H4NC"
}
},
"warnings": [],
"performance": {
"elapsed_ms": 9,
"sla_target_ms": 200,
"met_sla": true
}
}
Open Error Examples¶
Malformed ID:
{
"schema_version": "moraine.mcp.error.v1",
"tool": "open",
"request": {
"id": "not-a-valid-id"
},
"error": {
"code": "invalid_id",
"message": "id is not a valid Moraine MCP ID",
"details": {
"field": "id"
}
},
"warnings": [],
"performance": {
"elapsed_ms": 1,
"sla_target_ms": 200,
"met_sla": true
}
}
Missing object:
{
"schema_version": "moraine.mcp.error.v1",
"tool": "open",
"request": {
"id": "event:evt_01J9DOESNOTEXIST000000000000"
},
"error": {
"code": "not_found",
"message": "event not found",
"details": {
"id": "event:evt_01J9DOESNOTEXIST000000000000"
}
},
"warnings": [],
"performance": {
"elapsed_ms": 4,
"sla_target_ms": 200,
"met_sla": true
}
}
Input Permutation Matrix¶
search_sessions¶
| Input combination | Expected behavior |
|---|---|
query only |
Search all sessions with default event types and default n_hits. |
query + n_hits |
Search all sessions with default event types and requested hit count. |
query + event_types |
Search all sessions limited to those event types. |
query + within_id=session |
Search only that session with default event types. |
query + within_id=turn |
Search only that turn with default event types. |
query + within_id=session + event_types |
Search only that session and only those event types. |
query + within_id=turn + event_types |
Search only that turn and only those event types. |
query + within_id=event |
Return invalid_request. |
blank query |
Return invalid_request. |
unknown within_id |
Return not_found if ID is well-formed. |
malformed within_id |
Return invalid_id. |
empty event_types |
Return invalid_request. |
unsupported event_types value |
Return unsupported_event_type. |
n_hits < 1 |
Return invalid_request. |
n_hits > 50 |
Return invalid_request. |
non-integer n_hits |
Return invalid_request. |
list_sessions¶
| Input combination | Expected behavior |
|---|---|
start_datetime + end_datetime |
List sessions overlapping the datetime range with defaults. |
range + limit |
Return at most limit sessions. |
range + cursor |
Return the next deterministic page for the same filter and sort. |
range + mode |
Return only sessions with that mode. |
range + sort=asc |
Return oldest matching sessions first by updated_at, then ID. |
| missing datetime | Return invalid_request. |
| datetime without timezone | Return invalid_request. |
end_datetime <= start_datetime |
Return invalid_request. |
| unknown field | Return invalid_request. |
invalid mode or sort |
Return invalid_request. |
| cursor with changed filter or sort | Return invalid_request. |
open¶
| Input combination | Expected behavior |
|---|---|
id=session |
Return session metadata and compact turn list. |
id=turn |
Return turn metadata, compact event list, and traversal references. |
id=event |
Return event metadata, full content, and traversal references. |
missing id |
Return invalid_request. |
blank id |
Return invalid_request. |
malformed id |
Return invalid_id. |
well-formed unknown id |
Return not_found. |
Traversal Contract¶
The interface succeeds only if callers can move through history without inventing IDs or issuing unrelated searches.
Required traversal paths:
- Search hit to event:
search_sessions(...).data.results[].open.event_id - Search hit to turn:
search_sessions(...).data.results[].open.turn_id - Search hit to session:
search_sessions(...).data.results[].open.session_id - Listed session to session:
list_sessions(...).data.sessions[].open.session_id - Event to parent turn:
open(event).data.traversal.turn_id - Event to parent session:
open(event).data.traversal.session_id - Event to adjacent event:
open(event).data.traversal.previous_event_idandnext_event_id - Event to adjacent turn:
open(event).data.traversal.previous_turn_idandnext_turn_id - Turn to parent session:
open(turn).data.traversal.session_id - Turn to adjacent turn:
open(turn).data.traversal.previous_turn_idandnext_turn_id - Turn to first and last event:
open(turn).data.traversal.first_event_idandlast_event_id - Session to contained turns:
open(session).data.turns[].id
Null traversal references are valid at boundaries.
Performance SLA¶
These targets define what success looks like for local MCP use. They are measured from MCP tool invocation receipt to completed tool response serialization.
Definitions¶
Nis the number of searchable documents visible to the request.- One searchable document is one event eligible for
search_sessions. - Warm path means Moraine is already running and the relevant data has been ingested.
- Cold process startup is outside this SLA.
- Extremely large event payload serialization is measured separately for
open(event).
search_sessions Targets¶
For default event types and n_hits <= 10:
| Searchable documents | P50 | P95 | P99 |
|---|---|---|---|
| 100k | <= 250 ms | <= 750 ms | <= 1500 ms |
| 500k | <= 500 ms | <= 1500 ms | <= 3000 ms |
| 1M | <= 800 ms | <= 2500 ms | <= 5000 ms |
For constrained search with within_id=turn:
| Scope | P50 | P95 | P99 |
|---|---|---|---|
| Any single turn with <= 500 events | <= 50 ms | <= 300 ms | <= 750 ms |
For constrained search with within_id=session:
| Scope | P50 | P95 | P99 |
|---|---|---|---|
| Any single session with <= 250 turns | <= 100 ms | <= 500 ms | <= 1000 ms |
Deadline:
search_sessionsshould return a response ordeadline_exceededwithin 5 seconds for warm-path requests up to 1M searchable documents.
list_sessions Targets¶
For metadata-only requests with limit <= 50:
| Scenario | P50 | P95 | P99 | Deadline |
|---|---|---|---|---|
| Typical window, <= 5k matching sessions | <= 50 ms | <= 300 ms | <= 750 ms | 2 s |
| Broad window, <= 100k matching sessions | <= 200 ms | <= 1000 ms | <= 2000 ms | 3 s |
| Single-mode filtered window, <= 100k matching sessions | <= 250 ms | <= 1200 ms | <= 2500 ms | 3 s |
list_sessions should use session metadata or summary tables, avoid event text
search, always enforce limit, and return a normal response or
deadline_exceeded by the applicable deadline.
The response performance.sla_target_ms advertises the applicable target:
300 ms for typical metadata browse requests, 1000 ms for broad unfiltered
windows, and 1200 ms for broad single-mode filtered windows.
open Targets¶
| Request | P50 | P95 | P99 |
|---|---|---|---|
open(event) with payload <= 64 KiB |
<= 25 ms | <= 200 ms | <= 500 ms |
open(turn) with <= 100 events |
<= 50 ms | <= 300 ms | <= 750 ms |
open(session) with <= 100 turns |
<= 100 ms | <= 500 ms | <= 1000 ms |
open(session) with <= 1000 turns |
<= 250 ms | <= 1500 ms | <= 3000 ms |
Large payload note:
open(event)must return full event content.- For event payloads over 64 KiB, latency may scale with serialized payload size.
- Large payload responses should still report
performance.elapsed_msandperformance.met_slaagainst the applicable target.
Success Criteria¶
search_sessions¶
An implementation is successful when:
- Valid requests return the specified response envelope.
- Invalid requests return the specified error envelope.
- Default search covers
user_input,assistant_response, andtool_response. - Reasoning, tool calls, compactions, system events, and runtime events are excluded by default.
- Explicit event type filters are honored exactly.
- Session and turn scoped search never returns hits outside the requested scope.
n_hitsis honored exactly up to the maximum.- Results are ranked, stable, and include normalized scores.
- Every hit includes event, turn, and session IDs that can be opened.
- Snippets are compact and never substitute for full event content.
- Empty result sets return success with
results: []. - Performance meets the
search_sessionsSLA for the target corpus sizes.
list_sessions¶
An implementation is successful when:
- Valid requests return sessions overlapping the requested datetime range.
- Boundary behavior is inclusive at
start_datetimeand exclusive atend_datetime. - Results are sorted deterministically and cursor-paginated.
- Each session includes a typed session ID accepted by
open. - The response contains compact metadata and no event snippets, event payloads, or transcript text.
- Invalid ranges, unknown fields, bad cursors, invalid modes, and invalid sort values produce the specified errors.
- Performance meets the
list_sessionsSLA for target corpus sizes.
open¶
An implementation is successful when:
openaccepts every ID returned bysearch_sessionsandlist_sessions.- Session IDs return session metadata and all known turn summaries.
- Turn IDs return turn metadata, compact summaries, all known event summaries, and traversal references.
- Event IDs return full event metadata and full event content.
- Completion and terminal status are correct at session and turn levels.
- Parent references are correct for every opened object.
- Previous and next traversal references are correct or
nullat boundaries. - Tool names are surfaced for tool call and tool response events.
- Incomplete turns are represented without inventing final responses.
- Missing or malformed IDs produce the specified errors.
- Performance meets the
openSLA for the target object sizes.
End-To-End Discovery¶
The combined interface is successful when an agent can reliably perform this workflow:
- Call
search_sessionswith a vague natural-language query. - Select a hit and call
openon its event ID. - Call
openon the parent turn ID to inspect surrounding events. - Call
openon the parent session ID to inspect the broader session. - Traverse adjacent events or turns using IDs returned by
open.
For time-window discovery, the agent can call list_sessions, select a
returned open.session_id, and then call open.
Explicit Non-Goals¶
This specification does not define:
- database schema
- index format
- query algorithm
- ranking algorithm
- caching strategy
- migration plan from existing MCP tools
- monitor UI behavior
- authorization or multi-user access control