> ## Documentation Index
> Fetch the complete documentation index at: https://docs.agentcat.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Event Tags & Properties

> Attach structured tags and flexible metadata to every event AgentCat captures.

AgentCat's SDKs automatically capture rich telemetry on every tool call and major event in your MCP server. But sometimes, you need additional information to query or debug events. Event tags and properties let you attach that context:

* **Tags**: string key-value pairs designed for filtering and grouping in the dashboard and exported data
* **Properties**: flexible JSON for arbitrary context like feature flags, device info, or build metadata

Both are callback options on `agentcat.track()` that attach metadata to every auto-captured event - tool calls, tool lists, and session initialization. You set them up once and every event gets enriched automatically, without modifying individual tool handlers.

Both callbacks receive the same `(request, extra)` arguments as [`identify`](/sdk/identifying-users), and if they throw or return null, the event is still sent without metadata.

## Event Tags

Use `eventTags` to attach structured, filterable metadata to every event. Tags are ideal for values you'll want to filter or group by in the dashboard, such as environments, regions, trace IDs, or deployment versions.

<CodeGroup>
  ```typescript TypeScript theme={null}
  agentcat.track(mcpServer, "proj_abc123xyz", {
    eventTags: async (request, extra) => ({
      env: process.env.NODE_ENV ?? "development",
      region: "us-east-1",
      trace_id: extra?.requestContext?.traceId ?? "none",
    }),
  });
  ```

  ```python Python theme={null}
  import os
  import agentcat

  def get_event_tags(request, context):
      return {
          "env": os.environ.get("APP_ENV", "development"),
          "region": "us-east-1",
          "trace_id": getattr(context, "trace_id", "none"),
      }

  agentcat.track(server, "proj_abc123xyz",
               agentcat.AgentCatOptions(event_tags=get_event_tags))
  ```

  ```go Go theme={null}
  import (
      "os"
      "github.com/modelcontextprotocol/go-sdk/mcp"
      mcpcat "github.com/mcpcat/mcpcat-go-sdk/officialsdk"
  )

  mcpcat.Track(s, "proj_abc123xyz", &mcpcat.Options{
      EventTags: func(ctx context.Context, req *mcp.CallToolRequest) map[string]string {
          env := os.Getenv("APP_ENV")
          if env == "" {
              env = "development"
          }
          return map[string]string{
              "env":    env,
              "region": "us-east-1",
          }
      },
  })
  ```
</CodeGroup>

## Event Properties

Use `eventProperties` to attach flexible JSON metadata. Properties have no client-side validation constraints beyond being valid JSON.

<CodeGroup>
  ```typescript TypeScript theme={null}
  agentcat.track(mcpServer, "proj_abc123xyz", {
    eventProperties: async (request, extra) => ({
      device: "desktop",
      app_version: "2.1.0",
      feature_flags: ["dark_mode", "beta_ui"],
      build: {
        commit: "abc123",
        branch: "main",
      },
    }),
  });
  ```

  ```python Python theme={null}
  import agentcat

  def get_event_properties(request, context):
      return {
          "device": "desktop",
          "app_version": "2.1.0",
          "feature_flags": ["dark_mode", "beta_ui"],
          "build": {
              "commit": "abc123",
              "branch": "main",
          },
      }

  agentcat.track(server, "proj_abc123xyz",
               agentcat.AgentCatOptions(event_properties=get_event_properties))
  ```

  ```go Go theme={null}
  mcpcat.Track(s, "proj_abc123xyz", &mcpcat.Options{
      EventProperties: func(ctx context.Context, req *mcp.CallToolRequest) map[string]any {
          return map[string]any{
              "device":      "desktop",
              "app_version": "2.1.0",
              "feature_flags": []string{"dark_mode", "beta_ui"},
              "build": map[string]any{
                  "commit": "abc123",
                  "branch": "main",
              },
          }
      },
  })
  ```
</CodeGroup>

## Using Both Together

Use tags for the values you'd filter by in a dashboard and properties for the detail you'd want when clicking into a specific event.

<CodeGroup>
  ```typescript TypeScript theme={null}
  agentcat.track(mcpServer, "proj_abc123xyz", {
    identify: async (request, extra) => {
      const userId = request.params?.arguments?.userId;
      if (!userId) return null;
      return { userId };
    },
    eventTags: async (request, extra) => ({
      env: process.env.NODE_ENV ?? "development",
      region: process.env.AWS_REGION ?? "unknown",
    }),
    eventProperties: async (request, extra) => ({
      tool_name: request.params?.name,
      server_version: process.env.npm_package_version,
    }),
  });
  ```

  ```python Python theme={null}
  import os
  import agentcat
  from agentcat import UserIdentity

  def identify_user(request, context):
      user_id = request.params.arguments.get("userId")
      if not user_id:
          return None
      return UserIdentity(user_id=user_id)

  def get_event_tags(request, context):
      return {
          "env": os.environ.get("APP_ENV", "development"),
          "region": os.environ.get("AWS_REGION", "unknown"),
      }

  def get_event_properties(request, context):
      return {
          "tool_name": getattr(request.params, "name", None),
          "server_version": os.environ.get("APP_VERSION"),
      }

  agentcat.track(server, "proj_abc123xyz", agentcat.AgentCatOptions(
      identify=identify_user,
      event_tags=get_event_tags,
      event_properties=get_event_properties,
  ))
  ```

  ```go Go theme={null}
  import (
      "os"
      "github.com/modelcontextprotocol/go-sdk/mcp"
      mcpcat "github.com/mcpcat/mcpcat-go-sdk/officialsdk"
  )

  mcpcat.Track(s, "proj_abc123xyz", &mcpcat.Options{
      Identify: func(ctx context.Context, req *mcp.CallToolRequest) *mcpcat.UserIdentity {
          args := req.GetArguments()
          userID, _ := args["userId"].(string)
          if userID == "" {
              return nil
          }
          return &mcpcat.UserIdentity{UserID: userID}
      },
      EventTags: func(ctx context.Context, req *mcp.CallToolRequest) map[string]string {
          env := os.Getenv("APP_ENV")
          if env == "" {
              env = "development"
          }
          return map[string]string{
              "env":    env,
              "region": os.Getenv("AWS_REGION"),
          }
      },
      EventProperties: func(ctx context.Context, req *mcp.CallToolRequest) map[string]any {
          return map[string]any{
              "tool_name":      req.Params.Name,
              "server_version": os.Getenv("APP_VERSION"),
          }
      },
  })
  ```
</CodeGroup>

## Examples

### Tagging by Environment

Tag events with your deployment environment and region to compare error rates and tool usage patterns across production, staging, and development.

<CodeGroup>
  ```typescript TypeScript theme={null}
  agentcat.track(mcpServer, "proj_abc123xyz", {
    eventTags: async (request, extra) => ({
      env: process.env.NODE_ENV ?? "development",
      region: process.env.AWS_REGION ?? "unknown",
      version: process.env.npm_package_version ?? "0.0.0",
    }),
  });
  ```

  ```python Python theme={null}
  import os
  import agentcat

  agentcat.track(server, "proj_abc123xyz", agentcat.AgentCatOptions(
      event_tags=lambda request, context: {
          "env": os.environ.get("APP_ENV", "development"),
          "region": os.environ.get("AWS_REGION", "unknown"),
          "version": os.environ.get("APP_VERSION", "0.0.0"),
      }
  ))
  ```

  ```go Go theme={null}
  mcpcat.Track(s, "proj_abc123xyz", &mcpcat.Options{
      EventTags: func(ctx context.Context, req *mcp.CallToolRequest) map[string]string {
          return map[string]string{
              "env":     os.Getenv("APP_ENV"),
              "region":  os.Getenv("AWS_REGION"),
              "version": os.Getenv("APP_VERSION"),
          }
      },
  })
  ```
</CodeGroup>

### Attaching Feature Flags

Attach feature flags and build metadata as properties so you can see exactly what configuration was active when a tool call happened — useful for debugging why a tool behaves differently for certain users.

<CodeGroup>
  ```typescript TypeScript theme={null}
  agentcat.track(mcpServer, "proj_abc123xyz", {
    eventProperties: async (request, extra) => ({
      feature_flags: getActiveFlags(),
      build: {
        commit: process.env.GIT_SHA,
        branch: process.env.GIT_BRANCH,
        ci: process.env.CI === "true",
      },
    }),
  });
  ```

  ```python Python theme={null}
  import os
  import agentcat

  agentcat.track(server, "proj_abc123xyz", agentcat.AgentCatOptions(
      event_properties=lambda request, context: {
          "feature_flags": get_active_flags(),
          "build": {
              "commit": os.environ.get("GIT_SHA"),
              "branch": os.environ.get("GIT_BRANCH"),
              "ci": os.environ.get("CI") == "true",
          },
      }
  ))
  ```

  ```go Go theme={null}
  mcpcat.Track(s, "proj_abc123xyz", &mcpcat.Options{
      EventProperties: func(ctx context.Context, req *mcp.CallToolRequest) map[string]any {
          return map[string]any{
              "feature_flags": getActiveFlags(),
              "build": map[string]any{
                  "commit": os.Getenv("GIT_SHA"),
                  "branch": os.Getenv("GIT_BRANCH"),
                  "ci":     os.Getenv("CI") == "true",
              },
          }
      },
  })
  ```
</CodeGroup>

### Correlating with External Observability

Tag events with trace and span IDs from your existing observability stack to link AgentCat events directly to traces in Datadog, Sentry, or any OpenTelemetry-compatible platform.

<CodeGroup>
  ```typescript TypeScript theme={null}
  agentcat.track(mcpServer, "proj_abc123xyz", {
    eventTags: async (request, extra) => ({
      trace_id: extra?.requestContext?.traceId ?? "none",
      span_id: extra?.requestContext?.spanId ?? "none",
      service: "my-mcp-server",
    }),
  });
  ```

  ```python Python theme={null}
  import agentcat

  def get_event_tags(request, context):
      return {
          "trace_id": getattr(context, "trace_id", "none"),
          "span_id": getattr(context, "span_id", "none"),
          "service": "my-mcp-server",
      }

  agentcat.track(server, "proj_abc123xyz",
               agentcat.AgentCatOptions(event_tags=get_event_tags))
  ```

  ```go Go theme={null}
  mcpcat.Track(s, "proj_abc123xyz", &mcpcat.Options{
      EventTags: func(ctx context.Context, req *mcp.CallToolRequest) map[string]string {
          traceID := "none"
          spanID := "none"
          if sc := trace.SpanContextFromContext(ctx); sc.IsValid() {
              traceID = sc.TraceID().String()
              spanID = sc.SpanID().String()
          }
          return map[string]string{
              "trace_id": traceID,
              "span_id":  spanID,
              "service":  "my-mcp-server",
          }
      },
  })
  ```
</CodeGroup>

## Tag Validation Rules

Tags are validated client-side before being attached to events. Invalid entries are silently dropped with a warning written to `~/agentcat.log`.

* **Keys**: Must be 32 characters or fewer and match `[a-zA-Z0-9_.:\- ]` (letters, digits, dots, underscores, colons, hyphens, spaces)
* **Values**: Must be strings, 200 characters or fewer, and cannot contain newline characters
* **Max entries**: 50 tags per event — entries beyond the limit are dropped

<Note>
  Event properties have no client-side validation constraints — any valid JSON
  is accepted. Only tags are validated.
</Note>

<Note>
  Tag validation applies to both `eventTags` callback results and inline `tags`
  on [custom events](/sdk/custom-events). Invalid entries are dropped, but the
  event is still sent.
</Note>
