---
title: An agent at work
summary: The Model Context Protocol exchange behind an agent task — "characterise this aerofoil and tell me how far to trust the drag" — shown as the raw tool calls and results.
section: examples
order: 10
level: 2
audience: [AI agents, agent builders]
keywords: [MCP, agent, tools, transcript, example]
---
<!-- gyre docs: expanded Markdown of examples/agent-session.md (generated tables, verification numbers and chart data are written out). Base level of this page: L2 Practice; passages at another level are bracketed by 'begin level N' / 'end level N' comments and start with [LN Name]. Built from revision ceb1f4b0be. -->

The requests below are JSON-RPC messages posted to `/mcp`; any MCP client produces them. The
replies were recorded from a service running revision `5ee1cdc` on the CPU (a scratch
instance, not a public deployment); numbers are shortened to the digits shown and `…` marks
omitted keys and values. Nothing on this page was typed in from memory.

> **Note: What stands behind the recorded replies**
>
> The exchange was recorded once and the recording itself is not kept in the repository. The
> force coefficients, gradients and error estimate it contains were reproduced afterwards by
> an independent run of the same case through the command line (`gyre run naca0012_euler`
> with the same gradients and error estimate); the lift and drag at 2.5° were reproduced by a
> cold run at that angle. The parts that belong to the exchange itself — the job
> still `running` after the first 120 seconds, the nonlinear iteration counts 16 and 6, the
> `l2_norm` of the shape-sensitivity field, the digests, and the number, order and scores of
> the search hits — have not been reproduced; take them as an illustration of the shape of
> the replies, not as reference values.

## 1. Orient

```json
{"jsonrpc": "2.0", "id": 1, "method": "tools/call",
 "params": {"name": "validate_case",
            "arguments": {"case": "naca0012_euler", "overrides": {"discretization.order": 3}}}}
```

```json
{"valid": true, "digest": "e81f2ad4bcafe5b9",
 "estimate": {"elements": 256, "dim": 2, "block_size": 64, "degrees_of_freedom": 16384, "viscous": false},
 "device": "cpu", "spec": {"…": "…"}, "warnings": []}
```

A wrong name is answered with a way forward rather than a dead end:

```json
{"ok": false, "status": 404,
 "error": {"type": "UnknownPreset", "message": "unknown preset 'naca0013'",
           "hint": "available presets: ['bump_euler', 'cylinder_re40', 'naca0012_euler', 'naca0012_euler_3d', …]"}}
```

## 2. Analyse with an error estimate

```json
{"name": "submit_job",
 "arguments": {"case": "naca0012_euler", "gradients_of": ["cl", "cd"],
               "gradients_wrt": ["alpha", "mach"], "error_estimate": ["cd"], "wait_seconds": 120}}
```

```json
{"id": "job-…", "state": "running", "device": "cpu", "digest": "e4180d2af8d6dd7e",
 "estimate": {"elements": 256, "degrees_of_freedom": 9216, "…": "…"}, "…": "…"}
```

The job had not finished within the 120 seconds of the call (the kernels of this case had
never been compiled on that service, and the machine was busy), so the agent waits again:

```json
{"name": "get_job", "arguments": {"job_id": "job-…", "wait_seconds": 120}}
```

```json
{"name": "get_job_result", "arguments": {"job_id": "job-…"}}
```

```json
{"converged": true, "reason": "residual tolerance reached", "residual_norm": 7.06e-13,
 "outputs": {"cl": 0.278767, "cd": 0.000949, "cm": -0.002021, "…": "…"},
 "gradients": {"derivatives": {"cl": {"alpha": 7.7383, "mach": 0.23041},
                               "cd": {"alpha": 0.011770, "mach": 7.908e-05}},
               "info": {"mode": "adjoint", "linear_solves": [
                   {"output": "cl", "iterations": 51, "reduction": 7.09e-11, "converged": true},
                   {"output": "cd", "iterations": 50, "reduction": 7.18e-11, "converged": true}], "…": "…"}},
 "error_estimate": {"cd": {"value": 0.000949, "estimate": -0.000771, "corrected": 0.000264, "error": 0.000684,
                            "indicators": {"_array": true, "shape": [256], "max": 1.19e-04, "…": "…"}, "…": "…"}},
 "provenance": {"version": "0.1.0", "device": {"platform": "cpu", "…": "…"}, "…": "…"}}
```

The agent can now state: lift coefficient 0.279; drag coefficient 0.00095, of which about
0.0007 is estimated to be discretization error on this mesh (the exact inviscid drag is zero)
— and cite the revision that produced it. The derivatives with respect to `alpha` are per
radian.

## 3. Ground the claim in the documentation

```json
{"name": "search_docs", "arguments": {"query": "adjoint-weighted residual effectivity"}}
```

```json
{"query": "adjoint-weighted residual effectivity",
 "results": [{"title": "…", "section": "…", "level": 2, "summary": "…", "path": "….md", "score": 32}, "…"]}
```

Each hit carries `title`, `section`, `level`, `summary`, `path` and `score`, best first. The
titles are elided here on purpose: the ranking is computed from the pages of the deployed
revision and changes whenever the documentation does. In the recorded exchange six pages were
returned and `verification/output-error.md`, the page that defines the effectivity, was the
sixth; an agent should read down the list rather than take the first hit.

```json
{"name": "read_doc", "arguments": {"path": "verification/output-error.md"}}
```

## 4. A sweep in a session

```json
{"name": "open_session", "arguments": {"case": "naca0012_euler"}}
{"name": "session_evaluate", "arguments": {"session_id": "ses-…", "inputs": {"alpha_deg": 2.0}}}
{"name": "session_gradients", "arguments": {"session_id": "ses-…", "of": ["cl"], "wrt": ["alpha_deg", "x_surface"]}}
{"name": "session_evaluate", "arguments": {"session_id": "ses-…", "inputs": {"alpha_deg": 2.5}}}
{"name": "close_session", "arguments": {"session_id": "ses-…"}}
```

In the recorded exchange the evaluation at 2° converged in 16 nonlinear iterations to
`cl` = 0.278767, the gradient call returned `alpha_deg`: 0.135059 (per degree) and a
`[128, 2]` shape-sensitivity field summarised as `{"_array": true, "shape": [128, 2],
"l2_norm": 61.73, …}`, and an evaluation at 2.5° warm-started from the previous flow needed
6 iterations (`cl` = 0.345916).

<!-- begin level 3 (Mechanics) -->
**[L3 Mechanics] Why the interface looks like this**

See the design rules in the [agent guide](../guide/agents.md): one code path with the REST API,
structured results with summarised arrays, errors that carry hints, bounded waits.

<!-- end level 3 -->

<!-- begin level 3 (Mechanics) -->
**[L3 Mechanics] What is tested**

The validate → submit → result path and the hinted error are asserted end-to-end through MCP
in `tests/test_service.py::test_mcp_agent_workflow`; the session calls are asserted through the
REST API (which the MCP tools call) in `test_session_evaluate_gradients_and_coupling`; the
deployment smoke test checks that the search index and `llms.txt`, which the documentation
tools read, are served. The documentation tools themselves and the session tools through MCP
are not covered by an automated test.

<!-- end level 3 -->
