Skip to main content

Structured invocation logging for BridgeMCP

Project description

bridgemcp-logging

Structured invocation logging for BridgeMCP.

Every tool call, resource read, and prompt render is recorded with timing, exception details, and a structured log record. Zero configuration required.


Installation

pip install bridgemcp-logging

Requires bridgemcp-py >= 0.2.1 and Python 3.11+.


Quickstart

from bridgemcp import BridgeMCP
from bridgemcp_logging import LoggingPlugin

app = BridgeMCP(name="my-server")
app.register_plugin(LoggingPlugin())

@app.tool
def greet(name: str) -> str:
    return f"Hello, {name}!"

app.run()

Console output for each call:

[2026-06-30 12:00:00Z] INFO  tool:greet           2.1ms  OK

Configuration

from bridgemcp_logging import LoggingPlugin, LoggingConfig, ConsoleHandler

plugin = LoggingPlugin(
    config=LoggingConfig(
        success_level="DEBUG",   # level for successful calls (default: "INFO")
        error_level="ERROR",     # level for failed calls (default: "ERROR")
        log_kwargs=True,         # include call arguments in the record (default: False)
        log_result=False,        # include return values in the record (default: False)
    ),
    handler=ConsoleHandler(stream=sys.stdout),
)
app.register_plugin(plugin)

log_kwargs and log_result are False by default because arguments and return values may contain secrets or large payloads. Enable them explicitly when needed.


Public API

LoggingPlugin

class LoggingPlugin(Plugin):
    name = "bridgemcp-logging"
    version: str          # from installed package metadata
    description: str

    def __init__(
        self,
        config: LoggingConfig = LoggingConfig(),
        handler: ConsoleHandler = ConsoleHandler(),
    ) -> None: ...

    def setup(self, app: BridgeMCP) -> None: ...
    async def on_startup(self, app: BridgeMCP) -> None: ...
    async def on_shutdown(self, app: BridgeMCP) -> None: ...

LoggingConfig

class LoggingConfig(BaseModel, frozen=True):
    success_level: str = "INFO"
    error_level: str = "ERROR"
    log_kwargs: bool = False
    log_result: bool = False

InvocationRecord

@dataclass(frozen=True)
class InvocationRecord:
    invocation_id: str
    app_name: str
    framework_version: str
    plugin_version: str
    primitive: str              # "tool" | "resource" | "prompt"
    name: str
    kwargs: dict[str, Any] | None
    result: Any
    exception: Exception | None
    exception_type: str | None
    exception_chain: list[str]
    succeeded: bool
    duration_ms: float
    started_at: datetime
    finished_at: datetime
    level: str

TextFormatter

class TextFormatter:
    def format(self, record: InvocationRecord) -> str: ...

Produces one-line human-readable output:

[2026-06-30 12:00:00Z] INFO  tool:greet           12.3ms  OK
[2026-06-30 12:00:01Z] ERROR tool:send_email        3.2ms  FAILED  SMTPAuthenticationError: ...

ConsoleHandler

class ConsoleHandler:
    def __init__(
        self,
        stream: TextIO = sys.stderr,
        formatter: TextFormatter = TextFormatter(),
    ) -> None: ...

    def emit(self, record: InvocationRecord) -> None: ...
    def flush(self) -> None: ...

Exception handling

If a tool, resource, or prompt handler raises, the exception is captured in the InvocationRecord, the record is emitted, and the exception is re-raised. The logging plugin is transparent — it never swallows exceptions.

asyncio.CancelledError and KeyboardInterrupt are not captured (they are not Exception subclasses and should propagate without interference).


Middleware ordering

bridgemcp-logging should be the first plugin registered so its timing measurement covers the full middleware chain:

app.register_plugin(LoggingPlugin())   # outermost — measures total wall time
app.register_plugin(AuthPlugin())
app.register_plugin(RateLimitPlugin())

Versioning

bridgemcp-logging is versioned independently from bridgemcp-py. Compatible versions:

bridgemcp-logging bridgemcp-py
0.1.x >= 0.2.1

License

MIT — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

bridgemcp_logging-0.1.0.tar.gz (11.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

bridgemcp_logging-0.1.0-py3-none-any.whl (10.6 kB view details)

Uploaded Python 3

File details

Details for the file bridgemcp_logging-0.1.0.tar.gz.

File metadata

  • Download URL: bridgemcp_logging-0.1.0.tar.gz
  • Upload date:
  • Size: 11.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.6

File hashes

Hashes for bridgemcp_logging-0.1.0.tar.gz
Algorithm Hash digest
SHA256 e1916d6d126516d459c834a2c6203b61c8bb87e97c29dc81f44b2a8051870992
MD5 81a57cbe15ec57148bbd7b384b2c7158
BLAKE2b-256 b711a713ee55f5529baffccea317ab4598f8204ce9259f421e6bc89ea48bf750

See more details on using hashes here.

File details

Details for the file bridgemcp_logging-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for bridgemcp_logging-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7fa24ae7745eab714ca7df413dc11f12943839593e0f163409ab049aa5c7f436
MD5 f476ddbcd8277a1aa01bd72d08e50ef3
BLAKE2b-256 0195e7d67be3538211f2f77a2d6868b13406656377e939044a1026bf2eecf525

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page