Module: PostHog::MCP::EventBuilder Private

Defined in:
lib/posthog/mcp/event_builder.rb

Overview

This module is part of a private API. You should avoid using this module if possible, as it may be removed or be changed in the future.

Translates a processed internal event (string keys) into one or two PostHog payloads: the main $mcp_* event plus an optional $exception sibling.

Class Method Summary collapse

Class Method Details

.add_common_properties(event, properties) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/posthog/mcp/event_builder.rb', line 69

def add_common_properties(event, properties)
  if present(event['resource_name'])
    properties[Property::RESOURCE_NAME] = event['resource_name']
    properties[Property::TOOL_NAME] = event['resource_name'] if tool_call?(event)
  end
  if present(event['tool_description']) && tool_call?(event)
    properties[Property::TOOL_DESCRIPTION] =
      event['tool_description']
  end
  if present(event['tool_category']) && tool_call?(event)
    properties[Property::TOOL_CATEGORY] = event['tool_category']
  end
  listed = event['listed_tool_names']
  if listed.is_a?(Array) && !listed.empty? && event['event_type'] == EventType::MCP_TOOLS_LIST
    properties[Property::LISTED_TOOL_NAMES] = listed
  end
  properties[Property::DURATION_MS] = event['duration'] unless event['duration'].nil?
  properties[Property::SERVER_NAME] = event['server_name'] if present(event['server_name'])
  properties[Property::SERVER_VERSION] = event['server_version'] if present(event['server_version'])
  properties[Property::CLIENT_NAME] = event['client_name'] if present(event['client_name'])
  properties[Property::CLIENT_VERSION] = event['client_version'] if present(event['client_version'])
  properties[Property::CLIENT_USER_AGENT] = event['client_user_agent'] if present(event['client_user_agent'])
  properties[Property::VENDOR_CLIENT] = event['vendor_client'] if present(event['vendor_client'])
  properties[Property::PROTOCOL_VERSION] = event['protocol_version'] if present(event['protocol_version'])
  properties[Property::INTENT] = event['user_intent'] if present(event['user_intent'])
  properties[Property::INTENT_SOURCE] = event['user_intent_source'] if present(event['user_intent_source'])
  properties[Property::LLM_MODEL] = event['llm_model'] if present(event['llm_model'])
  properties[Property::LLM_MODEL_SOURCE] = event['llm_model_source'] if present(event['llm_model_source'])
  properties[Property::IS_ERROR] = event['is_error'] unless event['is_error'].nil?
  add_error_details(event, properties) if event['is_error']
  properties[Property::PARAMETERS] = event['parameters'] unless event['parameters'].nil?
  properties[Property::RESPONSE] = event['response'] unless event['response'].nil?
  actor_data = event['identify_actor_data']
  properties['$set'] = actor_data.dup if actor_data.is_a?(Hash) && !actor_data.empty?
end

.add_conversation_id(event, properties) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



49
50
51
52
# File 'lib/posthog/mcp/event_builder.rb', line 49

def add_conversation_id(event, properties)
  conversation_id = event['conversation_id']
  properties[Property::CONVERSATION_ID] = conversation_id unless conversation_id.nil? || conversation_id == ''
end

.add_custom_properties(event, properties) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



115
116
117
118
119
120
# File 'lib/posthog/mcp/event_builder.rb', line 115

def add_custom_properties(event, properties)
  custom = event['properties']
  return unless custom.is_a?(Hash)

  custom.each { |key, value| properties[key.to_s] = value }
end

.add_error_details(event, properties) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Surface the failure reason on the primary event itself, so dashboards need not join to the $exception sibling (which can be switched off).



107
108
109
110
111
112
113
# File 'lib/posthog/mcp/event_builder.rb', line 107

def add_error_details(event, properties)
  first = Exceptions.primary_exception(event['error'])
  error_type = present(event['error_type']) || present(first['type'])
  properties[Property::ERROR_TYPE] = error_type if error_type
  message = first['value']
  properties[Property::ERROR_MESSAGE] = message if present(message)
end

.add_groups(event, properties) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



54
55
56
57
# File 'lib/posthog/mcp/event_builder.rb', line 54

def add_groups(event, properties)
  groups = event['groups']
  properties['$groups'] = groups if truthy?(groups)
end

.add_person_processing(event, properties) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Without a resolved identity the distinct id is just the session id, so processing a person profile would mint one anonymous person per session.



61
62
63
# File 'lib/posthog/mcp/event_builder.rb', line 61

def add_person_processing(event, properties)
  properties['$process_person_profile'] = false unless present(event['identify_actor_given_id'])
end

.add_session_id(event, properties) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



44
45
46
47
# File 'lib/posthog/mcp/event_builder.rb', line 44

def add_session_id(event, properties)
  session_id = event['session_id']
  properties[Property::SESSION_ID] = session_id if session_id.is_a?(String) && !session_id.empty?
end

.build(event, enable_exception_autocapture: true) ⇒ Array<Hash>

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns payloads {'event', 'distinct_id', 'properties', 'timestamp'}.

Returns:

  • (Array<Hash>) —

    payloads {'event', 'distinct_id', 'properties', 'timestamp'}



14
15
16
17
18
19
20
# File 'lib/posthog/mcp/event_builder.rb', line 14

def build(event, enable_exception_autocapture: true)
  batch = [build_capture_event(event)]
  if event['is_error'] && truthy?(event['error']) && enable_exception_autocapture != false
    batch << build_exception_event(event)
  end
  batch
end

.build_capture_event(event) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/posthog/mcp/event_builder.rb', line 30

def build_capture_event(event)
  properties = { Property::SOURCE => SOURCE }
  add_session_id(event, properties)
  add_conversation_id(event, properties)
  add_person_processing(event, properties)
  add_groups(event, properties)
  add_common_properties(event, properties)
  add_custom_properties(event, properties)

  name = present(event['event_name']) || EventType::EVENT_NAME_BY_TYPE.fetch(event['event_type'], Event::CUSTOM)
  { 'event' => name, 'distinct_id' => distinct_id(event), 'properties' => properties,
    'timestamp' => timestamp(event) }
end

.build_exception_event(event) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/posthog/mcp/event_builder.rb', line 122

def build_exception_event(event)
  properties = {}
  add_session_id(event, properties)
  add_conversation_id(event, properties)
  add_person_processing(event, properties)
  add_groups(event, properties)

  error = event['error']
  properties.merge!(error) if error.is_a?(Hash)

  if present(event['resource_name'])
    properties[Property::RESOURCE_NAME] = event['resource_name']
    properties[Property::TOOL_NAME] = event['resource_name'] if tool_call?(event)
  end
  if present(event['tool_description']) && tool_call?(event)
    properties[Property::TOOL_DESCRIPTION] =
      event['tool_description']
  end
  if present(event['tool_category']) && tool_call?(event)
    properties[Property::TOOL_CATEGORY] = event['tool_category']
  end
  properties[Property::SERVER_NAME] = event['server_name'] if present(event['server_name'])
  properties[Property::SERVER_VERSION] = event['server_version'] if present(event['server_version'])
  properties[Property::CLIENT_NAME] = event['client_name'] if present(event['client_name'])
  properties[Property::CLIENT_VERSION] = event['client_version'] if present(event['client_version'])
  properties[Property::PROTOCOL_VERSION] = event['protocol_version'] if present(event['protocol_version'])

  add_custom_properties(event, properties)

  { 'event' => Event::EXCEPTION, 'distinct_id' => distinct_id(event), 'properties' => properties,
    'timestamp' => timestamp(event) }
end

.distinct_id(event) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



22
23
24
# File 'lib/posthog/mcp/event_builder.rb', line 22

def distinct_id(event)
  present(event['identify_actor_given_id']) || present(event['session_id']) || 'anonymous'
end

.present(value) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



155
156
157
158
159
160
161
# File 'lib/posthog/mcp/event_builder.rb', line 155

def present(value)
  return nil if value.nil?
  return nil if value.respond_to?(:empty?) && value.empty?
  return nil if value == false

  value
end

.timestamp(event) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



26
27
28
# File 'lib/posthog/mcp/event_builder.rb', line 26

def timestamp(event)
  event['timestamp'] || Time.now.utc
end

.tool_call?(event) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (Boolean)


65
66
67
# File 'lib/posthog/mcp/event_builder.rb', line 65

def tool_call?(event)
  event['event_type'] == EventType::MCP_TOOLS_CALL
end

.truthy?(value) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (Boolean)


163
164
165
# File 'lib/posthog/mcp/event_builder.rb', line 163

def truthy?(value)
  !present(value).nil?
end