Skip to content

AI agent conversations: MCP endpoints, and adopt AI Sessionizer 130601c - #14108

Merged
wu-sheng merged 1 commit into
masterfrom
ai-agent-mcp-endpoints
Sep 27, 2026
Merged

wu-sheng merged 1 commit into
masterfrom
ai-agent-mcp-endpoints

Conversation

@wu-sheng

@wu-sheng wu-sheng commented Sep 26, 2026 •

Copy link
Copy Markdown
Member

AI agent conversations: MCP endpoints, and adopt AI Sessionizer 130601c

  • If this is non-trivial feature, paste the links/URLs to the design doc.
  • Update the documentation to include this new feature.
  • Tests(including UT, IT, E2E) are added to verify the new feature.
  • If it's UI related, attach the screenshots below.

MCP endpoints

  • New otel-rules/ai-agent/mcp_endpoint.yaml: one endpoint per MCP server and tool, <server>/<tool>, under the agent's service in the AI_AGENT layer, with meter_ai_agent_mcp_calls, meter_ai_agent_mcp_calls_by_outcome and meter_ai_agent_mcp_duration, from the Sessionizer's agent.mcp.calls and agent.mcp.duration.
  • The token rules read agent.token.usage, the Sessionizer's name for the metric.

The conversation document follows AI Sessionizer 130601c

The OAP answers with the same asz.view document that asz conversation -json prints for the same files.

  • Tool executions: the execution file kind is stored like any other. The document lists every execution/1 record under tool_executions, and a tool step names its records under executions.
  • Provider bodies: the round carries the join. The OAP no longer joins bodies itself, and a round whose bodies do not read is refused.
  • Order: a stream's opened_by, the relations and a step's edges are in the order they happened. That is position inside one stream or workflow run, and time across them, never an id.
  • Reading follows the format pages, not an implementation. The formats are language-neutral JSON, and the OAP follows the rules the pages state (see State the rules a reader follows on the format pages skywalking-ai-sessionizer#47):
    • every line is read by JsonText, a reader of JSON as RFC 8259 defines it, in one loop; a line holding more than 256 objects and lists open at once is refused the same way on every run, and a number keeps its written text;
    • a record is read by the types the page gives its fields, parts, dropped entries and usage included, and a data part of another shape is not a record;
    • a Session Flow frame is checked against the types of its fields, and a round with a frame field of another type, or a negative sequence, row or round number, does not read;
    • record times compare as the instants they name, and ties go by code point order;
    • a call's usage and a step's dropped entries are written by their listed fields, and attrs keep the round's order and number text.
  • Each record's shape is declared once, in Schema, which replaces the hand-written shape checks.
  • A talk's tree is walked in one loop that visits each node once, siblings sort in a total order, and only the files that landed in a round's range are visited, so a malformed round cannot keep a request busy.
  • The comments no longer describe Go or name the Sessionizer's Go functions; they state the format's rule or the reason.

Existing tests changed (approved by the maintainer)

  • ConversationViewBuilderTest: three assertions now use long values (1L, 14L, 4L), since the format's integers are 64-bit.
  • aSessionWithoutItsProviderBodiesListsNone is now aSessionMissingItsBodyFileStillNamesWhatTheRoundJoined, as the round carries the join.
  • Removed noRequestJoinsInAStreamWithAGap, aManifestTheSessionizerDoesNotDecodeIsNoBody and ordsAreReadAsTheSessionizerReadsThem. They tested the OAP's own provider-body join, which is gone.
  • The fixture documents are regenerated from Sessionizer 130601c and are byte-identical to its output. The provider-body round and body fixtures are regenerated too.
  • e2e expected files: one more conversation, for the new mcp-calls case.
  • MAL test data: the input metric is renamed to agent_token_usage.
  • MALExpressionExecutionTest and its Envoy test data: the Envoy CA expiration rules subtract time() from a certificate's expiry, and the data held the result recorded on 2026-03-06. The 1% tolerance for large values ran out on 2026-09-27, so the test failed on every build from then, master included. An expected value taken from time() is now written as value_minus_now and checked against the current second, within a minute.
  • Comment-only edits in ChangesRecordTest, SessionFormatsTest and ConversationViewBuilderTest, which described Go's behavior. Every other changed assertion is in a test this pull request adds.

Verified

  • The module's 99 tests pass, and so do the MAL script tests, 1,427 expressions. A wrong expiry in the Envoy data fails them.

  • Checkstyle, the full build with javadoc, and the license check pass.

  • The BanyanDB e2e passes, 20 of 20, including the new MCP case.

  • 94 real conversations (65 Claude Code, 8 MCP, 21 LangChain) give the same document as Sessionizer 130601c. Five differ only in LangChain file names landed before a Sessionizer fix.

  • Every guard the change adds was broken on purpose, and a test caught it.

  • If this pull request closes/resolves/fixes an existing issue, replace the issue number. Closes #.

  • Update the CHANGES log.

Add otel-rules/ai-agent/mcp_endpoint.yaml: one endpoint per MCP server and
tool under the agent's service, `<server>/<tool>`, with calls, calls by
outcome and duration, from the Sessionizer's agent.mcp.calls and
agent.mcp.duration. The token rules read agent.token.usage.

The conversation document follows AI Sessionizer 130601c, so the OAP
answers with the document asz conversation -json prints for the same files:
- execution records under tool_executions, each kept once by its id, and
  each tool step's executions; a call to an MCP server names its server
  and tool in its attrs;
- provider bodies taken from the join the round carries;
- a stream's origins, the relations and a step's edges in the order they
  happened, by position inside one stream or workflow run and by time
  across them, never by id.

The formats are read as the Sessionizer's format pages define them, not
as Go's libraries read them:
- Every line is read by JsonText, a reader of JSON as RFC 8259 defines
  it, in one loop. A line holding more than 256 objects and lists open at
  once is refused the same way on every run. A number keeps its text.
- A Session Data record is read by the types its page gives each field,
  inside its parts, dropped entries and usage too. A record of another
  shape is skipped. Integers fit in 64 bits with their sign.
- A Session Flow frame is checked against the types of its fields. A
  frame with a field of another type does not decode, so its round does
  not read, and neither does one with a negative sequence, row or round.
- Record times are RFC 3339 and compare as instants. Ties and map keys
  sort in code point order.
- A talk's tree is walked in one loop, siblings sort in a total order,
  and a call's usage and a step's dropped entries are written by their
  listed fields.

The documents of the 94 real conversations measured are unchanged by the
reading rules. The e2e adds an mcp-calls case and pins the Sessionizer
commit.

MALExpressionExecutionTest failed on every build from 2026-09-27. The
Envoy CA expiration rules subtract time() from a certificate's expiry,
and their test data held the result recorded on 2026-03-06. The 1%
tolerance for large values ran out about 205 days later. An expected
value taken from time() is now written as value_minus_now and checked
against the current second, within a minute.
@wu-sheng
wu-sheng force-pushed the ai-agent-mcp-endpoints branch from af01307 to cd9b63b Compare September 27, 2026 13:15
@wu-sheng
wu-sheng merged commit d9e895f into master Sep 27, 2026
475 of 481 checks passed
@wu-sheng
wu-sheng deleted the ai-agent-mcp-endpoints branch September 27, 2026 14:20
wu-sheng added a commit to apache/skywalking-horizon-ui that referenced this pull request Sep 27, 2026
…rries for each position

The Evidence tab listed a step's landed positions as chips, but below
them it always drew the step's own text and flags, whichever chip was
picked.

- A call's request and result chips showed the same thing, the request.
  A call's first position is its request and the others name what came
  back, as the asz.view format page defines. A result position now
  shows the call's result, under a heading that names it the call's,
  since the document carries one result per call.
- Each change and execution record of the step is now a chip after the
  step's own positions, however the tab is opened. It used to join only
  when the reader came from the record's link.
- A picked record is drawn as the document carries it, every string
  whole, instead of the step's text.

Positions from the document are written as escaped text. Two new
strings are in all 8 locales, and the operate page and the 1.1.0
changelog say what the tab lists and shows.

The ai-agent e2e case covers calls to MCP servers. It pins OAP d9e895f560
(apache/skywalking#14108), whose document lists each call's execution
records, and AI Sessionizer fc04fa1. The Sessionizer builds the mcp-calls
scenario beside provider-bodies, a readiness check waits for the four
execution records, and the browser suite checks the call on the MCP lane,
its card's outcome and time, the Execution tab, and each Evidence chip.
wu-sheng added a commit to apache/skywalking-horizon-ui that referenced this pull request Sep 27, 2026
…rries for each position

The Evidence tab listed a step's landed positions as chips, but below
them it always drew the step's own text and flags, whichever chip was
picked.

- A call's request and result chips showed the same thing, the request.
  A call's first position is its request and the others name what came
  back, as the asz.view format page defines. A result position now
  shows the call's result, under a heading that names it the call's,
  since the document carries one result per call.
- Each change and execution record of the step is now a chip after the
  step's own positions, however the tab is opened. It used to join only
  when the reader came from the record's link.
- A picked record is drawn as the document carries it, every string
  whole, instead of the step's text.

Positions from the document are written as escaped text. Two new
strings are in all 8 locales, and the operate page and the 1.1.0
changelog say what the tab lists and shows.

The ai-agent e2e case covers calls to MCP servers. It pins OAP d9e895f560
(apache/skywalking#14108), whose document lists each call's execution
records, and AI Sessionizer fc04fa1. The Sessionizer builds the mcp-calls
scenario beside provider-bodies, a readiness check waits for the four
execution records, and the browser suite checks the call on the MCP lane,
its card's outcome and time, the Execution tab, and each Evidence chip.

OAP 11.1.0 stores OpenTelemetry spans natively by default and no longer
converts them into Zipkin form. The five bundled templates that named
Zipkin (mesh, mesh_cp, mesh_dp, k8s, k8s_service) now list TraceQL - OTLP
beside Zipkin, since a deployment can send its spans either way. Only
mesh has its Traces tab on, so only mesh shows the new row. The Zipkin
store's description no longer says it always carries OpenTelemetry spans.
wu-sheng added a commit to apache/skywalking-horizon-ui that referenced this pull request Sep 27, 2026
…rries for each position

The Evidence tab listed a step's landed positions as chips, but below
them it always drew the step's own text and flags, whichever chip was
picked.

- A call's request and result chips showed the same thing, the request.
  A call's first position is its request and the others name what came
  back, as the asz.view format page defines. A result position now
  shows the call's result, under a heading that names it the call's,
  since the document carries one result per call.
- Each change and execution record of the step is now a chip after the
  step's own positions, however the tab is opened. It used to join only
  when the reader came from the record's link.
- A picked record is drawn as the document carries it, every string
  whole, instead of the step's text.

Positions from the document are written as escaped text. Two new
strings are in all 8 locales, and the operate page and the 1.1.0
changelog say what the tab lists and shows.

The ai-agent e2e case covers calls to MCP servers. It pins OAP d9e895f560
(apache/skywalking#14108), whose document lists each call's execution
records, and AI Sessionizer fc04fa1. The Sessionizer builds the mcp-calls
scenario beside provider-bodies, a readiness check waits for the four
execution records, and the browser suite checks the call on the MCP lane,
its card's outcome and time, the Execution tab, and each Evidence chip.

OAP 11.1.0 stores OpenTelemetry spans natively by default and no longer
converts them into Zipkin form. The five bundled templates that named
Zipkin (mesh, mesh_cp, mesh_dp, k8s, k8s_service) now list TraceQL - OTLP
beside Zipkin, since a deployment can send its spans either way. Only
mesh has its Traces tab on, so only mesh shows the new row. The Zipkin
store's description no longer says it always carries OpenTelemetry spans.

oap.traceql.url defaults to http://127.0.0.1:3200, like the other OAP
hosts, so the TraceQL - OTLP row works once OAP enables its TraceQL
module. `url: ''` in the configuration file turns TraceQL off; an empty
environment variable falls back to the default. The e2e Horizon points
at the fixture's OAP.

The VIRTUAL_GENAI layer has no Traces tab, and on OAP 11.1.0's default an
OTLP-linked evaluation record's trace is not in the Zipkin store. The
genai e2e no longer checks that it opens through Zipkin, and drops the
Zipkin settings kept only for that. The native trace link checks stay.
The GenAI docs say an OTLP record's trace opens only when OAP converts
OTLP spans into Zipkin form.
wu-sheng added a commit to apache/skywalking-horizon-ui that referenced this pull request Sep 28, 2026
… e2e and Evidence per position

The e2e pins OAP d9e895f560 (apache/skywalking#14108) and AI Sessionizer
fc04fa1, and Horizon follows what changed.

Traces. OAP 11.1.0 stores OpenTelemetry spans natively by default and no
longer converts them into Zipkin form. A deployment can send its spans
either way, so the five templates that named Zipkin (mesh, mesh_cp,
mesh_dp, k8s, k8s_service) list TraceQL - OTLP beside Zipkin. Only mesh
has its Traces tab on. oap.traceql.url defaults to http://127.0.0.1:3200,
like the other OAP hosts; url: '' in the configuration file turns TraceQL
off. The Zipkin store's description no longer says it always carries
OpenTelemetry spans.

GenAI. The VIRTUAL_GENAI layer has no Traces tab, and on OAP's default an
OTLP-linked evaluation record's trace is not in the Zipkin store. The
genai e2e no longer checks that it opens through Zipkin, and drops the
Zipkin settings kept only for that; the native trace link checks stay.
The docs say an OTLP record's trace opens only when OAP converts OTLP
spans into Zipkin form.

Evidence. The Evidence tab drew the step's own text under every chip. A
call's first position is its request and the others name what came
back, so a result position now shows the call's result. Each change and
execution record of the step is listed after the step's own positions,
however the tab is opened, and a picked record is shown as the document
carries it, every string whole. Positions are written as escaped text.

MCP. The ai-agent e2e builds the mcp-calls scenario beside
provider-bodies, waits until the document lists its four execution
records, and checks the MCP lane, the card's outcome and time, the
Execution tab and each Evidence chip.
wu-sheng added a commit to apache/skywalking-horizon-ui that referenced this pull request Sep 28, 2026
… e2e and Evidence per position

The e2e pins OAP d9e895f560 (apache/skywalking#14108) and AI Sessionizer
fc04fa1, and Horizon follows what changed.

Traces. OAP 11.1.0 stores OpenTelemetry spans natively by default and no
longer converts them into Zipkin form. A deployment can send its spans
either way, so the five templates that named Zipkin (mesh, mesh_cp,
mesh_dp, k8s, k8s_service) list the OTLP store beside Zipkin. Only mesh
has its Traces tab on. The OTLP store's row is named OTLP Traces, as the
Zipkin store's is Zipkin Traces: TraceQL is the only way to read it, so a
TraceQL prefix told nothing apart. oap.traceql.url defaults to http://127.0.0.1:3200,
like the other OAP hosts; url: '' in the configuration file turns TraceQL
off. The Zipkin store's description no longer says it always carries
OpenTelemetry spans.

GenAI. The VIRTUAL_GENAI layer has no Traces tab, and on OAP's default an
OTLP-linked evaluation record's trace is not in the Zipkin store. The
genai e2e no longer checks that it opens through Zipkin, and drops the
Zipkin settings kept only for that; the native trace link checks stay.
The docs say an OTLP record's trace opens only when OAP converts OTLP
spans into Zipkin form.

Evidence. The Evidence tab drew the step's own text under every chip. A
call's first position is its request and the others name what came
back, so a result position now shows the call's result. Each change and
execution record of the step is listed after the step's own positions,
however the tab is opened, and a picked record is shown as the document
carries it, every string whole. Positions are written as escaped text.

MCP. The ai-agent e2e builds the mcp-calls scenario beside
provider-bodies, waits until the document lists its four execution
records, and checks the MCP lane, the card's outcome and time, the
Execution tab and each Evidence chip.
wu-sheng added a commit to apache/skywalking-horizon-ui that referenced this pull request Sep 28, 2026
… e2e and Evidence per position (#176)

The e2e pins OAP d9e895f560 (apache/skywalking#14108) and AI Sessionizer
fc04fa1, and Horizon follows what changed.

Traces. OAP 11.1.0 stores OpenTelemetry spans natively by default and no
longer converts them into Zipkin form. A deployment can send its spans
either way, so the five templates that named Zipkin (mesh, mesh_cp,
mesh_dp, k8s, k8s_service) list the OTLP store beside Zipkin. Only mesh
has its Traces tab on. The OTLP store's row is named OTLP Traces, as the
Zipkin store's is Zipkin Traces: TraceQL is the only way to read it, so a
TraceQL prefix told nothing apart. oap.traceql.url defaults to http://127.0.0.1:3200,
like the other OAP hosts; url: '' in the configuration file turns TraceQL
off. The Zipkin store's description no longer says it always carries
OpenTelemetry spans.

GenAI. The VIRTUAL_GENAI layer has no Traces tab, and on OAP's default an
OTLP-linked evaluation record's trace is not in the Zipkin store. The
genai e2e no longer checks that it opens through Zipkin, and drops the
Zipkin settings kept only for that; the native trace link checks stay.
The docs say an OTLP record's trace opens only when OAP converts OTLP
spans into Zipkin form.

Evidence. The Evidence tab drew the step's own text under every chip. A
call's first position is its request and the others name what came
back, so a result position now shows the call's result. Each change and
execution record of the step is listed after the step's own positions,
however the tab is opened, and a picked record is shown as the document
carries it, every string whole. Positions are written as escaped text.

MCP. The ai-agent e2e builds the mcp-calls scenario beside
provider-bodies, waits until the document lists its four execution
records, and checks the MCP lane, the card's outcome and time, the
Execution tab and each Evidence chip.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend OAP backend related. feature New feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants