Skip to content

Conversation

@vova-jb
Copy link

@vova-jb vova-jb commented Jan 27, 2026

Motivation and Context

Mcp support for opentelemetry metrics

Breaking Changes

none


Type of the changes

  • [* ] New feature (non-breaking change which adds functionality)

@vova-jb
Copy link
Author

vova-jb commented Jan 27, 2026

Uploading Screenshot 2026-01-27 at 15.17.25.png…

@vova-jb vova-jb force-pushed the vm/otel-mcp-3 branch 3 times, most recently from 1d40250 to 1633b4a Compare January 28, 2026 10:55
@vova-jb vova-jb requested a review from tiginamaria January 28, 2026 10:56
@vova-jb vova-jb marked this pull request as ready for review January 28, 2026 10:56
@vova-jb vova-jb force-pushed the vm/otel-mcp-3 branch 2 times, most recently from cdddf62 to 32ca582 Compare January 28, 2026 12:13
Copy link
Collaborator

@tiginamaria tiginamaria left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! Looks good to me, but I need @sdubov's second independent opinion here

public val argsSerializer: KSerializer<TArgs>,
public val resultSerializer: KSerializer<TResult>,
public val descriptor: ToolDescriptor,
private val meta: Map<KClass<*>, Any> = emptyMap(),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For me it's fine like that (better then string or storage key), but need @sdubov oppinion here

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also not sure how it will work with java api

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have couple notes here:

  1. I would name it metaInfo to match the naming with Message class that we use.
  2. I'm not sure how this approach should be extended if we would like to pass this meta info through network. I would assume that this should be serrializable class. Otherwise, this data is only for for internal usage.
  3. How would that work with Java API?
  4. What is the problem with key-value approach here?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For key-value you mean string-string? It bas another option, but It's not type-safe and if I want MCP+ACP tool (for example) and it could cause key clashing. On the other hand it's easy to serialize and it's for sure java-friendly


/**
* A constant representing an empty registry with no tools.
* TODO: ToolRegistry is mutable but stored as an immutable object.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe put deprecation with empty() replacement?

* @property sessionId Unique identifier for the current MCP session, if session management is enabled.
*/
@InternalAgentsApi
public class McpServerMeta(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For @sdubov: this was added to the core intentionally, as we don't wnat Otel dependend on MCP

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Folks, as I see the metadata is used not for features, but for tool registry. I have a proposal to discuss here: What do you think if we add a general metadata key-value property (not directly referring MCP parameters) for our internal tools in the core module. MCP adds special MCP-related attributes to this metadata. We add this metadata to tool events, OTel will read this metadata and add necessary attributes to spans converting all or filtered MCP data into spans. WDYT?

@tiginamaria tiginamaria requested a review from sdubov January 28, 2026 15:11
Copy link
Contributor

@sdubov sdubov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vova-jb, thank you for your implementation. I looked through general approach and through details. Please see my comments in review. I would like to discuss two general questions that was raised in my mind:

  1. How do we compose / wrap spans for MCP vs regular tool call spans?
  2. How do we present meta information for tools?

I would also add someone from the team to discuss this together if you do not mind.

agentConfig: AIAgentConfig,
strategy: AIAgentGraphStrategy<Input, Output>,
toolRegistry: ToolRegistry = ToolRegistry.EMPTY,
toolRegistry: ToolRegistry = ToolRegistry.empty(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vova-jb, good point. I think it worth creating a separate ticket and separate update though

* @property sessionId Unique identifier for the current MCP session, if session management is enabled.
*/
@InternalAgentsApi
public class McpServerMeta(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Folks, as I see the metadata is used not for features, but for tool registry. I have a proposal to discuss here: What do you think if we add a general metadata key-value property (not directly referring MCP parameters) for our internal tools in the core module. MCP adds special MCP-related attributes to this metadata. We add this metadata to tool events, OTel will read this metadata and add necessary attributes to spans converting all or filtered MCP data into spans. WDYT?

public val instructions: String?,
public val mcpProtocolVersion: String,
public val mcpTransportType: McpTransportType,
public val sessionId: String?,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have session Id inside the framework. Maybe name it mcpSessionId to not mess with Koog session id?

public class McpServerMeta(
public val serverUrl: String?,
public val serverPort: Int?,
public val siteUrl: String?,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, could you please clarify the difference between serverUrl and siteUrl? I've read the properties KDoc, but I feel that I not exactly got it.

* This transport is typically used for local MCP servers running as separate
* processes that communicate via stdio. Suitable for development and local tools.
*/
Pipe("pipe"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vova-jb, is not it called "stdio" mcp transport type by MCP providers?

import kotlin.test.assertTrue
import kotlin.time.Duration.Companion.seconds

@InternalAgentsApi
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please clarify why did you mark a test class as InternalAgentToolsApi. This annotation is used for internal methods that we explicitly mark for a users to show that it is not a public API.

import kotlin.time.Duration.Companion.seconds

@Execution(ExecutionMode.SAME_THREAD)
@InternalAgentsApi
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as above for tests.

public val argsSerializer: KSerializer<TArgs>,
public val resultSerializer: KSerializer<TResult>,
public val descriptor: ToolDescriptor,
private val meta: Map<KClass<*>, Any> = emptyMap(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have couple notes here:

  1. I would name it metaInfo to match the naming with Message class that we use.
  2. I'm not sure how this approach should be extended if we would like to pass this meta info through network. I would assume that this should be serrializable class. Otherwise, this data is only for for internal usage.
  3. How would that work with Java API?
  4. What is the problem with key-value approach here?

* 1. Set up a Langfuse project and credentials as described [here](https://langfuse.com/docs/get-started#create-new-project-in-langfuse)
* 2. Get Langfuse credentials as described [here](https://langfuse.com/faq/all/where-are-langfuse-api-keys)
* 3. Set `LANGFUSE_HOST`, `LANGFUSE_PUBLIC_KEY`, and `LANGFUSE_SECRET_KEY` environment variables
* 4. Set `OPENAI_API_KEY` from [here](https://platform.openai.com/account/api-keys)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes in this file seem unrelated to the code from the PR. Maybe we can do it separately if needed?

#
LANGFUSE_SECRET_KEY=sk-lf-...
LANGFUSE_PUBLIC_KEY=pk-lf-...
LANGFUSE_HOST=http://localhost:3000
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please skip the value part as it is defined for other env vars to keep it consistent?

@sdubov sdubov requested review from EugeneTheDev and sdubov January 29, 2026 20:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants