# Retained-obligation local MCP probe

Executed 2026-10-03. This is a **scripted transport and retrieval probe**, not a
fresh-agent experiment, customer outcome or time-saving measurement.

## Result

The current local CLI successfully returned the fixture's draft retry
obligation through MCP without the query supplying a requirement ID. The
script used the ID returned by that query to read the complete requirement,
including the reason for the 24-hour promise. The server exited 0 after stdin
closed. No tracked fixture file changed.

The negative results are part of the evidence:

| Actual request | Actual result |
| --- | --- |
| `initialize`, protocol `2024-11-05` | Negotiated `2024-11-05`; server name `reqproof`, serverInfo version `0.1.0`. |
| `notifications/initialized` | Server emitted an uncorrelated JSON-RPC error: `-32601`, `method not found: notifications/initialized`. The scripted client continued to read subsequent responses. |
| `tools/list` | 22 advertised tools, including requirement query and trace traversal. |
| `reqproof_query_requirements`, `{"search":"retry"}` | One record: `SW-REQ-241`, component `reservation_store`, status `draft`, assurance E, with its 24-hour description. No ID or component was supplied in this query. |
| Query `retry` with `status: approved` | Zero records. The fixture is a draft, not approved intent. |
| Query `Reduce storage used by the reservation cache` | Zero records. This probe does not establish semantic retrieval from the later task's wording. |
| `reqproof_trace_analysis` on the discovered ID, both directions, depth2 | Root returned with `entries: null`. No dependency links were returned. |
| `resources/list`, then `resources/read` of the advertised Requirement Detail template instantiated with the discovered ID | Full requirement returned: description, rationale, draft status and `_computed.file_hash`. Review/approval fields remain empty. |

The retrieved description says:

> A retry using the same key before 24 elapsed hours shall return the original reservation and shall not create another reservation.

The resource's rationale says:

> A client can lose the first response and retry later.

These are author-supplied fixture fields. The transport did not infer them
from implementation or authorize them. The returned default
`review.ai_generated: false` is not authenticated evidence of human authorship;
the fixture YAML did not supply that field. The draft state and empty review
fields must remain visible when presenting the result.

## Exact setup and artifacts

The probe used a disposable clone of the **existing, unchanged**
[`results/fixture.bundle`](../fixture/results/fixture.bundle),
checked out at tag C:

```text
08721dd7cda04dc5a52519d2c18ae5e8f45f0c26
```

Clone used a local file path. Its automatically created local-origin entry was
removed before starting MCP; `git remote` was empty. No remote was contacted,
no check or decision was posted, and no commit was created. The script strips
inherited Proof/agent/CI identity variables and sets `PROOF_NO_DOWNLOAD=1`.
It invokes only read operations; the server's advertised tool list also
contains mutators, so this is not a claim that the whole local MCP server is a
read-only security boundary.

Server command in the temporary fixture checkout:

```sh
/tmp/proof-retained-obligation mcp --transport stdio
```

Exact CLI build identity, separate from MCP's generic serverInfo version:

```text
proof 0.1.0-teaching-b845ff313bac
commit: b845ff313bacb887c4e9fb78145c681a15f6b3f0
binary SHA-256:
939db50a2227aae1506c27648bf01866222fdda78ec978ee0d78ae19ae4690c2
bundle SHA-256:
fc5a726684e6ee88a13c4f323eafed6835e6dccf1461b7592d6815a9cf32500f
```

Canonical complete session, from `2026-10-03T09:57:00.084805+00:00` to
`2026-10-03T09:57:00.635726+00:00`:

- [Actual requests, in order](./requests.jsonl)
- [Actual server responses, in order](./responses.jsonl)
- [Actual server stderr](./stderr.txt)
- [Execution metadata, parsed observations and transcript hashes](./summary.json)
- [Replay client with guarded error finalization](./mcp-probe.py)
- [Exact client used for the canonical capture](./mcp-probe-captured.py)

There are eight ID-correlated request/response exchanges, one initialized notification and one additional error response to that notification. The overall probe outcome is `retrieval_completed_with_protocol_errors`; the client exits 1 to preserve that qualification, although the server exits 0.
The requirement ID first appears in server response3. The client then reads
that returned ID for trace traversal and the requirement-detail URI; it is
not hard-coded into the client's query. The client name identifies a scripted
probe, not a person or AI agent.

The earlier `mcp-discovery-*` files retain the initial initialization/tool
discovery session. `mcp-results/` retains a shorter probe, and `mcp-results-complete/` retains the first full resource read. Both earlier summaries called the run completed without classifying the uncorrelated notification error; their raw response logs preserve it. `mcp-results-final/` is the canonical session with the corrected client and explicit protocol-error classification.

Reproduce from the Proof source root with a new output directory:

```sh
python3 examples/retained-obligation/mcp-probe.py \
  --proof /absolute/path/to/proof \
  --output /tmp/retained-mcp-replay
```

The script defaults to the adjacent original Git bundle. It refuses to
overwrite earlier probe results. All fixture work happens in a temporary
clone; the calling checkout and existing captured inputs/results remain
unchanged. A correlated MCP error, invalid response, timeout or failed behavior query is retained as an error outcome. The client also records all protocol error envelopes after the session and exits 1 when retrieval completed with a protocol error.

## Notification error: product follow-up

The tested source dispatches the bare method `initialized` at
`pkg/mcp/server.go:242`, while `notifications/initialized` reaches the default
method-not-found response at lines260–267. `handleRequest` writes every non-null
response at lines224–228. This probe does not change the engine.

Minimal reproduction inside any configured disposable fixture checkout:

```sh
printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"notification-probe","version":"1"}}}' '{"jsonrpc":"2.0","method":"notifications/initialized","params":{}}' | /absolute/path/to/proof mcp --transport stdio
```

The second stdout envelope in the captured session is exactly:

```json
{"jsonrpc":"2.0","error":{"code":-32601,"message":"method not found: notifications/initialized"}}
```

This is evidence of the tested server's handling of this notification, not a
claim about every external MCP client. The scripted client tolerated the
uncorrelated response and completed the reads. Compatibility with a fresh
agent's MCP client remains untested.

## Interpretation and product/vision limits

This establishes a narrow implemented capability: a real local MCP client can
discover the query tool, find a recorded draft obligation using a matching
behavior keyword and retrieve its full stored detail. The exact candidate
record and rationale survive independently of the previous conversation.

It does not establish that a fresh agent would choose that keyword, that it
would preserve the requirement while editing code, or that it would save
reviewer time. The source behind `reqproof_query_requirements` supports text
and field filtering, not a guarantee that an arbitrary task sentence yields
the relevant obligation. The full later-task phrase returned zero here.
An approved-only query also legitimately returned zero. Good agent workflows
must distinguish approved intent from draft conflicts and avoid equating an
empty filtered result with absence of relevant information.

The trace result did not establish the retention-config relationship or link
the execution artifacts. Those remain known limits from the earlier teaching
fixture. The probe does not erase the real EvidencePackages' `not_assessed`
and `blocked` outcomes. The resource returns a computed file hash, while the
checked-out Git revision is recorded by the probe; this is not a claim that
every MCP response carries a full, authenticated graph-version envelope.

Relevant implementation anchors:

- `cmd/proof/mcp.go`: local stdio command.
- `cmd/proof/mcp_subprocess_integration_test.go`: line-delimited JSON-RPC subprocess handshake.
- `pkg/mcp/tools.go`: requirement query filters and trace traversal.
- `pkg/mcp/resources.go`: requirement-detail resource template and reader.

## Validation and integration boundary

All canonical JSON/JSONL parses. Responses with IDs1–8 correspond to requests1–8 without correlated errors. An additional uncorrelated error records the notification problem above. Transcript SHA-256 values match the metadata. Query3 has only `search: retry`; the full resource remains a draft. Server exit is0, probe exit is1 because of the protocol error, remotes are empty and tracked Git status is clean before and after.

The original fixture inputs, captured test results and Git bundle remain unchanged. After quality review, the ZIP was repackaged with corrected source-pinning instructions in its README; every other archived file retains its original bytes. The public MCP download is a separate set of files. Website integration says **“scripted keyword retrieval executed, with a protocol warning”**, while keeping **“fresh-agent benefit experiment unrun.”**

## Reproduce from the public downloads

Download the [runnable ZIP](../retained-obligation.zip) and this probe's `mcp-probe.py`. Extract the ZIP, then pass its bundle explicitly because the downloaded client is outside the source tree:

```sh
unzip retained-obligation.zip
python3 mcp-probe.py \
  --proof /absolute/path/to/proof \
  --bundle retained-obligation/results/fixture.bundle \
  --output /tmp/retained-mcp-replay
```

Use a new output directory. With the recorded build, expect successful retrieval observations and probe exit1 because of the notification error. A different build can produce different observations; keep its recorded binary identity with the result. The original ZIP's README describes building the tested CLI from its source revision.

## Replay-client correction after capture

The canonical 09:57 session used `mcp-probe-captured.py`. The current replay
client has a guarded finalizer: malformed JSON or a non-object response now
retains the raw transcript and writes an error summary instead of crashing
while classifying response envelopes. The actual captured protocol messages
and summary have not been rewritten. The correction does not convert the
notification error into success.

Four regression tests exercise malformed JSON, non-object JSON, the actual
captured notification error and a valid response. Run them from the source
root with `python3 examples/retained-obligation/mcp-probe-test.py`. The public
download manifest hashes the current replay client, captured client, report,
transcripts, summary and revised fixture ZIP; these are distribution checksums,
not new behavioral evidence.

[Download integrity manifest](./download-sha256.json).
