Repository navigation
Record every MCP tool call's duration into the read-latency histograms (#4442) - #4453
Merged
Merged
Conversation
…ome classifier, and record web and compose reads (#4442)
…in (#4442) ReadLatencyPercentilesTests' field-shaped fixture asserted p99 strictly above 5,000 ms, but with the fixture's exact 90/9/1 split the 990th sample lands exactly on the slow tier's own upper bound -- fixed to assert the honest answer, 5,000 ms. Added ReadLatencyWebRecordingTests: drives a real /api/read/<name> request through the actual web pipeline and asserts the read-latency accumulator received the sample the dispatch loop is supposed to record, plus a second case for the 57014 timeout shape.
…n a constructor-shape pin (#4442)
…ency # Conflicts: # Darling/Darling.Tests/ReadLatencyWebRecordingTests.cs
Adds McpToolLatencyRecordingTests: a real tools/call through DarlingMcpHostService.ConfigureMcpServices + ConfigurePipeline, with the test's own ReadLatencyAccumulator, proving a cheap tool call records one Ok sample, a 57014-shaped error envelope records one Timeout sample, a /core call is recorded too, and run_custom_view_panel records nothing.
erikdarlingdata
marked this pull request as ready for review
September 26, 2026 23:28
This was referenced Sep 27, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Refs #4442 (scope 2).
Why
The web
/api/read/*dispatch loop and the composed-panel runner already record every read'sduration and outcome into
ReadLatencyAccumulator. MCP tool calls (the third way a read reachesDarling) recorded nothing, so a read tool that answers slowly, or times out, from an MCP client
was invisible to that histogram.
What changes
McpToolLatencyFilter, registered inDarlingMcpHostService.ConfigureMcpServicesalongside the two existing filters (
McpUnknownArgumentGuard,GcfCallToolFilter). It times everytools/call(on both/and/core, since a call outside/core's narrowed tool set never reachesdispatch or any filter — there is nothing to time) and records one sample per call.
run_custom_view_panelis skipped by name: its body already records oneComposesample through theshared panel runner, so recording it here too would double-count every MCP custom-view call.
uses; a normal return whose result is an explicit error, or carries the tool's own caught-error
envelope, classifies the envelope's sentence the same way (so a 57014 statement-timeout sentence
counts as a timeout, not a generic error); anything else counts as Ok.
posture the web and compose recorders already take.
ConfigureMcpServicesandDarlingMcpHostService's constructor both gained an optionalReadLatencyAccumulatorparameter, defaulted so every existing call site keeps building unchanged;production resolves the one process-wide singleton Program.cs already registers for the web host and
worker flush.
Test plan
New class
McpToolLatencyRecordingTestsdrives realtools/callrequests through the actualConfigureMcpServices+ConfigurePipelinepipeline (the same pattern the existing MCP host gate testsuse), with the test's own accumulator:
(Mcp, tool, Ok)sample;(Mcp, tool, Timeout)sample;/corefor a tool in its pinned set (list_servers) is recorded too;run_custom_view_panelrecords no sample.Mutation test: commented out the filter's
Recordcall on the success/error-return path (the exceptionpath's
Recordcall was left in place, since removing either one alone proves the point) and reran thenew class:
RED (before restoring):
(3 of 4 facts failed — the "run_custom_view_panel records nothing" fact still passed, correctly, since it
asserts absence.)
GREEN (after restoring):
Also run, all green:
Both
Darling.TestsandLite.Testsbuild 0 errors / 0 warnings withEnableWindowsTargeting=true.The full suite was not run here (tests-only scope, targeted classes above cover the touched
surface); the product code itself was written and merged in an earlier PR and is unchanged here.
CHANGELOG entry
SECTION: None
ENTRY: None: MCP tool durations are recorded into the store's latency histograms; nothing surfaces them until the read tool lands (a later change).