Skip to content

Events API

dcc_mcp_core.EventBus

EventBus

Thread-safe publish/subscribe event bus backed by DashMap.

Constructor

python
from dcc_mcp_core import EventBus
bus = EventBus()

Methods

MethodReturnsDescription
subscribe(event_name, callback)intSubscribe a callable. Returns subscriber ID
unsubscribe(event_name, subscriber_id)boolUnsubscribe by ID. Returns True if found
publish(event_name, **kwargs)Call all subscribers with kwargs

Dunder Methods

MethodDescription
__repr__EventBus(subscriptions=N)

Behavior

  • Subscribers receive keyword arguments from publish(event_name, **kwargs)
  • Exceptions in subscribers are logged via tracing but do not propagate
  • Callbacks are collected before invocation to avoid DashMap deadlocks
  • Multiple subscribers per event are supported
  • Subscriber IDs are monotonically increasing (starting at 1)

Example

python
bus = EventBus()

def on_action(action_name=None, **kwargs):
    print(f"Action: {action_name}")

sid = bus.subscribe("action.executed", on_action)
bus.publish("action.executed", action_name="create_sphere")
bus.unsubscribe("action.executed", sid)

ToolRecorder

Records per-tool execution time and success/failure counters. Use this to collect performance telemetry for any tools your code executes.

Constructor

python
from dcc_mcp_core import ToolRecorder

recorder = ToolRecorder("my-service")
ParameterTypeDescription
scopestrLogical name for this recorder instance (e.g. service or module name)

Methods

MethodReturnsDescription
start(action_name, dcc_name)RecordingGuardStart timing a tool; returns a RAII guard
metrics(action_name)ToolMetrics | NoneAggregated metrics for a specific action; None if no data
all_metrics()list[ToolMetrics]Aggregated metrics for all recorded actions
reset()NoneClear all in-memory statistics

Example

python
from dcc_mcp_core import ToolRecorder

recorder = ToolRecorder("maya-skill-server")

# Manual guard usage
guard = recorder.start("create_sphere", "maya")
try:
    # ... do work ...
    guard.finish(success=True)
except Exception:
    guard.finish(success=False)
    raise

# Context manager usage (success=True if no exception)
with recorder.start("delete_mesh", "maya"):
    pass  # work here

# Query metrics
m = recorder.metrics("create_sphere")
if m:
    print(f"calls={m.invocation_count}, success_rate={m.success_rate():.2%}")
    print(f"avg={m.avg_duration_ms:.1f}ms  p95={m.p95_duration_ms:.1f}ms")

RecordingGuard

RAII guard returned by ToolRecorder.start(). Automatically records the duration and outcome.

Methods

MethodReturnsDescription
finish(success)NoneCommit the recording with the given success flag
__enter__RecordingGuardContext manager entry
__exit__NoneContext manager exit (success=True when no exception was raised)

ToolMetrics

Read-only snapshot of per-tool performance metrics. Obtained from ToolRecorder.metrics() or ToolRecorder.all_metrics().

Properties

PropertyTypeDescription
action_namestrAction this metric belongs to
invocation_countintTotal number of calls recorded
success_countintNumber of successful calls
failure_countintNumber of failed calls
avg_duration_msfloatMean execution time in milliseconds
p95_duration_msfloat95th-percentile execution time in milliseconds
p99_duration_msfloat99th-percentile execution time in milliseconds

Methods

MethodReturnsDescription
success_rate()floatSuccess ratio in [0.0, 1.0]

Example

python
recorder = ToolRecorder("server")

for _ in range(10):
    with recorder.start("ping", "maya"):
        pass

all_m = recorder.all_metrics()
for m in all_m:
    print(
        f"{m.action_name}: "
        f"{m.invocation_count} calls, "
        f"{m.success_rate():.0%} success, "
        f"avg {m.avg_duration_ms:.1f}ms"
    )

Released under the MIT License.