microbootstrap 1.3.0__tar.gz → 1.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {microbootstrap-1.3.0 → microbootstrap-1.4.0}/PKG-INFO +28 -1
- {microbootstrap-1.3.0 → microbootstrap-1.4.0}/README.md +24 -0
- {microbootstrap-1.3.0 → microbootstrap-1.4.0}/microbootstrap/__init__.py +4 -0
- microbootstrap-1.4.0/microbootstrap/bootstrappers/fastmcp.py +101 -0
- {microbootstrap-1.3.0 → microbootstrap-1.4.0}/microbootstrap/bootstrappers/litestar.py +2 -2
- microbootstrap-1.4.0/microbootstrap/config/fastmcp.py +42 -0
- {microbootstrap-1.3.0 → microbootstrap-1.4.0}/microbootstrap/instruments/prometheus_instrument.py +5 -0
- microbootstrap-1.4.0/microbootstrap/middlewares/fastmcp.py +46 -0
- {microbootstrap-1.3.0 → microbootstrap-1.4.0}/microbootstrap/settings.py +13 -0
- {microbootstrap-1.3.0 → microbootstrap-1.4.0}/pyproject.toml +2 -1
- {microbootstrap-1.3.0 → microbootstrap-1.4.0}/microbootstrap/bootstrappers/__init__.py +0 -0
- {microbootstrap-1.3.0 → microbootstrap-1.4.0}/microbootstrap/bootstrappers/base.py +0 -0
- {microbootstrap-1.3.0 → microbootstrap-1.4.0}/microbootstrap/bootstrappers/fastapi.py +0 -0
- {microbootstrap-1.3.0 → microbootstrap-1.4.0}/microbootstrap/bootstrappers/faststream.py +0 -0
- {microbootstrap-1.3.0 → microbootstrap-1.4.0}/microbootstrap/config/__init__.py +0 -0
- {microbootstrap-1.3.0 → microbootstrap-1.4.0}/microbootstrap/config/fastapi.py +0 -0
- {microbootstrap-1.3.0 → microbootstrap-1.4.0}/microbootstrap/config/faststream.py +0 -0
- {microbootstrap-1.3.0 → microbootstrap-1.4.0}/microbootstrap/config/litestar.py +0 -0
- {microbootstrap-1.3.0 → microbootstrap-1.4.0}/microbootstrap/console_writer.py +0 -0
- {microbootstrap-1.3.0 → microbootstrap-1.4.0}/microbootstrap/exceptions.py +0 -0
- {microbootstrap-1.3.0 → microbootstrap-1.4.0}/microbootstrap/granian_server.py +0 -0
- {microbootstrap-1.3.0 → microbootstrap-1.4.0}/microbootstrap/helpers.py +0 -0
- {microbootstrap-1.3.0 → microbootstrap-1.4.0}/microbootstrap/instruments/__init__.py +0 -0
- {microbootstrap-1.3.0 → microbootstrap-1.4.0}/microbootstrap/instruments/base.py +0 -0
- {microbootstrap-1.3.0 → microbootstrap-1.4.0}/microbootstrap/instruments/cors_instrument.py +0 -0
- {microbootstrap-1.3.0 → microbootstrap-1.4.0}/microbootstrap/instruments/health_checks_instrument.py +0 -0
- {microbootstrap-1.3.0 → microbootstrap-1.4.0}/microbootstrap/instruments/instrument_box.py +0 -0
- {microbootstrap-1.3.0 → microbootstrap-1.4.0}/microbootstrap/instruments/logging_instrument.py +0 -0
- {microbootstrap-1.3.0 → microbootstrap-1.4.0}/microbootstrap/instruments/opentelemetry_instrument.py +0 -0
- {microbootstrap-1.3.0 → microbootstrap-1.4.0}/microbootstrap/instruments/pyroscope_instrument.py +0 -0
- {microbootstrap-1.3.0 → microbootstrap-1.4.0}/microbootstrap/instruments/sentry_instrument.py +0 -0
- {microbootstrap-1.3.0 → microbootstrap-1.4.0}/microbootstrap/instruments/swagger_instrument.py +0 -0
- {microbootstrap-1.3.0 → microbootstrap-1.4.0}/microbootstrap/instruments_setupper.py +0 -0
- {microbootstrap-1.3.0 → microbootstrap-1.4.0}/microbootstrap/middlewares/__init__.py +0 -0
- {microbootstrap-1.3.0 → microbootstrap-1.4.0}/microbootstrap/middlewares/fastapi.py +0 -0
- {microbootstrap-1.3.0 → microbootstrap-1.4.0}/microbootstrap/middlewares/litestar.py +0 -0
- {microbootstrap-1.3.0 → microbootstrap-1.4.0}/microbootstrap/py.typed +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: microbootstrap
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.4.0
|
|
4
4
|
Summary: Package for bootstrapping new micro-services
|
|
5
5
|
Keywords: python,microservice,bootstrap,opentelemetry,logging,error-tracing,litestar,fastapi
|
|
6
6
|
Author: community-of-python
|
|
@@ -47,6 +47,8 @@ Requires-Dist: fastapi>=0.100 ; extra == 'fastapi'
|
|
|
47
47
|
Requires-Dist: fastapi-offline-docs>=1 ; extra == 'fastapi'
|
|
48
48
|
Requires-Dist: opentelemetry-instrumentation-fastapi>=0.46b0 ; extra == 'fastapi'
|
|
49
49
|
Requires-Dist: prometheus-fastapi-instrumentator>=6.1 ; extra == 'fastapi'
|
|
50
|
+
Requires-Dist: fastmcp>=2,<4 ; extra == 'fastmcp'
|
|
51
|
+
Requires-Dist: prometheus-client>=0.20 ; extra == 'fastmcp'
|
|
50
52
|
Requires-Dist: faststream~=0.6.2 ; extra == 'faststream'
|
|
51
53
|
Requires-Dist: prometheus-client>=0.20 ; extra == 'faststream'
|
|
52
54
|
Requires-Dist: granian[reload]>=1 ; extra == 'granian'
|
|
@@ -55,6 +57,7 @@ Requires-Dist: litestar-offline-docs>=1 ; extra == 'litestar'
|
|
|
55
57
|
Requires-Dist: prometheus-client>=0.20 ; extra == 'litestar'
|
|
56
58
|
Requires-Python: >=3.10, <4
|
|
57
59
|
Provides-Extra: fastapi
|
|
60
|
+
Provides-Extra: fastmcp
|
|
58
61
|
Provides-Extra: faststream
|
|
59
62
|
Provides-Extra: granian
|
|
60
63
|
Provides-Extra: litestar
|
|
@@ -110,6 +113,7 @@ Those instruments can be bootstrapped for:
|
|
|
110
113
|
- `fastapi`,
|
|
111
114
|
- `litestar`,
|
|
112
115
|
- or `faststream` service,
|
|
116
|
+
- or `fastmcp` service,
|
|
113
117
|
- or even a service that doesn't use one of these frameworks.
|
|
114
118
|
|
|
115
119
|
Interested? Let's dive right in ⚡
|
|
@@ -140,6 +144,7 @@ Also, you can specify extras during installation for concrete framework:
|
|
|
140
144
|
- `fastapi`
|
|
141
145
|
- `litestar`
|
|
142
146
|
- `faststream` (ASGI app)
|
|
147
|
+
- `fastmcp`
|
|
143
148
|
|
|
144
149
|
Also we have `granian` extra that is requires for `create_granian_server`.
|
|
145
150
|
|
|
@@ -260,6 +265,28 @@ settings = YourSettings()
|
|
|
260
265
|
application: AsgiFastStream = FastStreamBootstrapper(settings).bootstrap()
|
|
261
266
|
```
|
|
262
267
|
|
|
268
|
+
### FastMCP
|
|
269
|
+
|
|
270
|
+
```python
|
|
271
|
+
from fastmcp import FastMCP
|
|
272
|
+
|
|
273
|
+
from microbootstrap import FastMcpSettings
|
|
274
|
+
from microbootstrap.bootstrappers.fastmcp import FastMcpBootstrapper
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
class YourSettings(FastMcpSettings):
|
|
278
|
+
service_debug: bool = False
|
|
279
|
+
service_name: str = "my-awesome-mcp-service"
|
|
280
|
+
service_description: str = "MCP server for internal tools"
|
|
281
|
+
|
|
282
|
+
sentry_dsn: str = "your-sentry-dsn"
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
settings = YourSettings()
|
|
286
|
+
|
|
287
|
+
application: FastMCP = FastMcpBootstrapper(settings).bootstrap()
|
|
288
|
+
```
|
|
289
|
+
|
|
263
290
|
## Settings
|
|
264
291
|
|
|
265
292
|
The settings object is the core of microbootstrap.
|
|
@@ -48,6 +48,7 @@ Those instruments can be bootstrapped for:
|
|
|
48
48
|
- `fastapi`,
|
|
49
49
|
- `litestar`,
|
|
50
50
|
- or `faststream` service,
|
|
51
|
+
- or `fastmcp` service,
|
|
51
52
|
- or even a service that doesn't use one of these frameworks.
|
|
52
53
|
|
|
53
54
|
Interested? Let's dive right in ⚡
|
|
@@ -78,6 +79,7 @@ Also, you can specify extras during installation for concrete framework:
|
|
|
78
79
|
- `fastapi`
|
|
79
80
|
- `litestar`
|
|
80
81
|
- `faststream` (ASGI app)
|
|
82
|
+
- `fastmcp`
|
|
81
83
|
|
|
82
84
|
Also we have `granian` extra that is requires for `create_granian_server`.
|
|
83
85
|
|
|
@@ -198,6 +200,28 @@ settings = YourSettings()
|
|
|
198
200
|
application: AsgiFastStream = FastStreamBootstrapper(settings).bootstrap()
|
|
199
201
|
```
|
|
200
202
|
|
|
203
|
+
### FastMCP
|
|
204
|
+
|
|
205
|
+
```python
|
|
206
|
+
from fastmcp import FastMCP
|
|
207
|
+
|
|
208
|
+
from microbootstrap import FastMcpSettings
|
|
209
|
+
from microbootstrap.bootstrappers.fastmcp import FastMcpBootstrapper
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
class YourSettings(FastMcpSettings):
|
|
213
|
+
service_debug: bool = False
|
|
214
|
+
service_name: str = "my-awesome-mcp-service"
|
|
215
|
+
service_description: str = "MCP server for internal tools"
|
|
216
|
+
|
|
217
|
+
sentry_dsn: str = "your-sentry-dsn"
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
settings = YourSettings()
|
|
221
|
+
|
|
222
|
+
application: FastMCP = FastMcpBootstrapper(settings).bootstrap()
|
|
223
|
+
```
|
|
224
|
+
|
|
201
225
|
## Settings
|
|
202
226
|
|
|
203
227
|
The settings object is the core of microbootstrap.
|
|
@@ -8,6 +8,7 @@ from microbootstrap.instruments.opentelemetry_instrument import (
|
|
|
8
8
|
)
|
|
9
9
|
from microbootstrap.instruments.prometheus_instrument import (
|
|
10
10
|
FastApiPrometheusConfig,
|
|
11
|
+
FastMcpPrometheusConfig,
|
|
11
12
|
FastStreamPrometheusConfig,
|
|
12
13
|
FastStreamPrometheusMiddlewareProtocol,
|
|
13
14
|
LitestarPrometheusConfig,
|
|
@@ -17,6 +18,7 @@ from microbootstrap.instruments.sentry_instrument import SentryConfig
|
|
|
17
18
|
from microbootstrap.instruments.swagger_instrument import SwaggerConfig
|
|
18
19
|
from microbootstrap.settings import (
|
|
19
20
|
FastApiSettings,
|
|
21
|
+
FastMcpSettings,
|
|
20
22
|
FastStreamSettings,
|
|
21
23
|
InstrumentsSetupperSettings,
|
|
22
24
|
LitestarSettings,
|
|
@@ -27,6 +29,8 @@ __all__ = (
|
|
|
27
29
|
"CorsConfig",
|
|
28
30
|
"FastApiPrometheusConfig",
|
|
29
31
|
"FastApiSettings",
|
|
32
|
+
"FastMcpPrometheusConfig",
|
|
33
|
+
"FastMcpSettings",
|
|
30
34
|
"FastStreamOpentelemetryConfig",
|
|
31
35
|
"FastStreamPrometheusConfig",
|
|
32
36
|
"FastStreamPrometheusMiddlewareProtocol",
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import typing
|
|
3
|
+
|
|
4
|
+
import prometheus_client
|
|
5
|
+
import typing_extensions
|
|
6
|
+
from fastmcp import FastMCP
|
|
7
|
+
from starlette.responses import JSONResponse, Response
|
|
8
|
+
|
|
9
|
+
from microbootstrap.bootstrappers.base import ApplicationBootstrapper
|
|
10
|
+
from microbootstrap.config.fastmcp import FastMcpConfig
|
|
11
|
+
from microbootstrap.instruments.health_checks_instrument import HealthChecksInstrument, HealthCheckTypedDict
|
|
12
|
+
from microbootstrap.instruments.logging_instrument import LoggingInstrument
|
|
13
|
+
from microbootstrap.instruments.prometheus_instrument import FastMcpPrometheusConfig, PrometheusInstrument
|
|
14
|
+
from microbootstrap.instruments.pyroscope_instrument import PyroscopeInstrument
|
|
15
|
+
from microbootstrap.instruments.sentry_instrument import SentryInstrument
|
|
16
|
+
from microbootstrap.middlewares.fastmcp import FastMcpLoggingMiddleware
|
|
17
|
+
from microbootstrap.settings import FastMcpSettings
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
if typing.TYPE_CHECKING:
|
|
21
|
+
from starlette.requests import Request
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class KwargsFastMCP(FastMCP[typing.Any]):
|
|
25
|
+
def __init__(self, **kwargs: typing.Any) -> None: # noqa: ANN401
|
|
26
|
+
super().__init__(**kwargs)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class FastMcpBootstrapper(
|
|
30
|
+
ApplicationBootstrapper[FastMcpSettings, FastMCP[typing.Any], FastMcpConfig],
|
|
31
|
+
):
|
|
32
|
+
application_config = FastMcpConfig()
|
|
33
|
+
application_type = KwargsFastMCP
|
|
34
|
+
|
|
35
|
+
def bootstrap_before(self: typing_extensions.Self) -> dict[str, typing.Any]:
|
|
36
|
+
return {
|
|
37
|
+
"name": self.application_config.name or self.settings.service_name,
|
|
38
|
+
"instructions": self.application_config.instructions or self.settings.service_description,
|
|
39
|
+
"version": self.application_config.version or self.settings.service_version,
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
def bootstrap_before_instruments_after_app_created(
|
|
43
|
+
self,
|
|
44
|
+
application: FastMCP[typing.Any],
|
|
45
|
+
) -> FastMCP[typing.Any]:
|
|
46
|
+
self.console_writer.print_bootstrap_table()
|
|
47
|
+
return application
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
FastMcpBootstrapper.use_instrument()(SentryInstrument)
|
|
51
|
+
FastMcpBootstrapper.use_instrument()(PyroscopeInstrument)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@FastMcpBootstrapper.use_instrument()
|
|
55
|
+
class FastMcpLoggingInstrument(LoggingInstrument):
|
|
56
|
+
def bootstrap_after(self, application: FastMCP[typing.Any]) -> FastMCP[typing.Any]: # type: ignore[override]
|
|
57
|
+
if not self.instrument_config.logging_turn_off_middleware:
|
|
58
|
+
application.add_middleware(FastMcpLoggingMiddleware())
|
|
59
|
+
return application
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@FastMcpBootstrapper.use_instrument()
|
|
63
|
+
class FastMcpHealthChecksInstrument(HealthChecksInstrument):
|
|
64
|
+
def bootstrap_after(self, application: FastMCP[typing.Any]) -> FastMCP[typing.Any]: # type: ignore[override]
|
|
65
|
+
@application.custom_route(
|
|
66
|
+
self.instrument_config.health_checks_path,
|
|
67
|
+
methods=["GET"],
|
|
68
|
+
name="health_check",
|
|
69
|
+
include_in_schema=self.instrument_config.health_checks_include_in_schema,
|
|
70
|
+
)
|
|
71
|
+
async def health_check_handler(request: Request) -> JSONResponse: # noqa: ARG001
|
|
72
|
+
response_data: HealthCheckTypedDict = self.render_health_check_data()
|
|
73
|
+
return JSONResponse(response_data)
|
|
74
|
+
|
|
75
|
+
return application
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@FastMcpBootstrapper.use_instrument()
|
|
79
|
+
class FastMcpPrometheusInstrument(PrometheusInstrument[FastMcpPrometheusConfig]):
|
|
80
|
+
def bootstrap_after(self, application: FastMCP[typing.Any]) -> FastMCP[typing.Any]: # type: ignore[override]
|
|
81
|
+
if not self.instrument_config.prometheus_register_route:
|
|
82
|
+
return application
|
|
83
|
+
|
|
84
|
+
@application.custom_route(
|
|
85
|
+
self.instrument_config.prometheus_metrics_path,
|
|
86
|
+
methods=["GET"],
|
|
87
|
+
name="metrics",
|
|
88
|
+
include_in_schema=self.instrument_config.prometheus_metrics_include_in_schema,
|
|
89
|
+
)
|
|
90
|
+
async def metrics_handler(request: Request) -> Response: # noqa: ARG001
|
|
91
|
+
registry: typing.Final = self.instrument_config.prometheus_registry or prometheus_client.REGISTRY
|
|
92
|
+
return Response(
|
|
93
|
+
prometheus_client.generate_latest(registry),
|
|
94
|
+
headers={"content-type": prometheus_client.CONTENT_TYPE_LATEST},
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
return application
|
|
98
|
+
|
|
99
|
+
@classmethod
|
|
100
|
+
def get_config_type(cls) -> type[FastMcpPrometheusConfig]:
|
|
101
|
+
return FastMcpPrometheusConfig
|
|
@@ -160,8 +160,8 @@ class LitestarOpenTelemetryInstrumentationMiddleware(ASGIMiddleware):
|
|
|
160
160
|
def create_open_telemetry_middleware(self, app: ASGIApp) -> OpenTelemetryMiddleware:
|
|
161
161
|
return OpenTelemetryMiddleware(
|
|
162
162
|
app=app,
|
|
163
|
-
client_request_hook=self.config.client_request_hook_handler,
|
|
164
|
-
client_response_hook=self.config.client_response_hook_handler,
|
|
163
|
+
client_request_hook=self.config.client_request_hook_handler,
|
|
164
|
+
client_response_hook=self.config.client_response_hook_handler,
|
|
165
165
|
default_span_details=build_litestar_route_details_from_scope,
|
|
166
166
|
excluded_urls=get_excluded_urls(self.config.exclude_urls_env_key),
|
|
167
167
|
meter=self.config.meter,
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import dataclasses
|
|
3
|
+
import typing
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
if typing.TYPE_CHECKING:
|
|
7
|
+
import mcp.types
|
|
8
|
+
from fastmcp.client.sampling import SamplingHandler
|
|
9
|
+
from fastmcp.server.auth import AuthProvider
|
|
10
|
+
from fastmcp.server.lifespan import Lifespan
|
|
11
|
+
from fastmcp.server.middleware import Middleware as FastMcpMiddleware
|
|
12
|
+
from fastmcp.server.providers import Provider
|
|
13
|
+
from fastmcp.server.server import DuplicateBehavior, LifespanCallable
|
|
14
|
+
from fastmcp.server.transforms import Transform
|
|
15
|
+
from fastmcp.tools.base import Tool
|
|
16
|
+
from key_value.aio.protocols import AsyncKeyValue
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclasses.dataclass
|
|
20
|
+
class FastMcpConfig:
|
|
21
|
+
name: str | None = None
|
|
22
|
+
instructions: str | None = None
|
|
23
|
+
version: str | int | float | None = None
|
|
24
|
+
website_url: str | None = None
|
|
25
|
+
icons: list[mcp.types.Icon] | None = None
|
|
26
|
+
auth: AuthProvider | None = None
|
|
27
|
+
middleware: typing.Sequence[FastMcpMiddleware] | None = None
|
|
28
|
+
providers: typing.Sequence[Provider] | None = None
|
|
29
|
+
transforms: typing.Sequence[Transform] | None = None
|
|
30
|
+
lifespan: LifespanCallable | Lifespan | None = None
|
|
31
|
+
tools: typing.Sequence[Tool | typing.Callable[..., typing.Any]] | None = None
|
|
32
|
+
on_duplicate: DuplicateBehavior | None = None
|
|
33
|
+
mask_error_details: bool | None = None
|
|
34
|
+
dereference_schemas: bool = True
|
|
35
|
+
strict_input_validation: bool | None = None
|
|
36
|
+
list_page_size: int | None = None
|
|
37
|
+
tasks: bool | None = None
|
|
38
|
+
session_state_store: AsyncKeyValue | None = None
|
|
39
|
+
sampling_handler: SamplingHandler[typing.Any, typing.Any] | None = None
|
|
40
|
+
sampling_handler_behavior: typing.Literal["always", "fallback"] | None = None
|
|
41
|
+
client_log_level: mcp.types.LoggingLevel | None = None
|
|
42
|
+
experimental_capabilities: dict[str, dict[str, typing.Any]] | None = None
|
{microbootstrap-1.3.0 → microbootstrap-1.4.0}/microbootstrap/instruments/prometheus_instrument.py
RENAMED
|
@@ -32,6 +32,11 @@ class FastApiPrometheusConfig(BasePrometheusConfig):
|
|
|
32
32
|
prometheus_custom_labels: dict[str, typing.Any] = pydantic.Field(default_factory=dict)
|
|
33
33
|
|
|
34
34
|
|
|
35
|
+
class FastMcpPrometheusConfig(BasePrometheusConfig):
|
|
36
|
+
prometheus_registry: typing.Any | None = None
|
|
37
|
+
prometheus_register_route: bool = True
|
|
38
|
+
|
|
39
|
+
|
|
35
40
|
@typing.runtime_checkable
|
|
36
41
|
class FastStreamPrometheusMiddlewareProtocol(typing.Protocol):
|
|
37
42
|
def __init__(
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import time
|
|
3
|
+
import typing
|
|
4
|
+
|
|
5
|
+
import structlog
|
|
6
|
+
from fastmcp.server.middleware import Middleware, MiddlewareContext
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
if typing.TYPE_CHECKING:
|
|
10
|
+
from fastmcp.server.middleware import CallNext
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
fastmcp_access_logger: typing.Final = structlog.get_logger("mcp.access")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class FastMcpLoggingMiddleware(Middleware):
|
|
17
|
+
async def on_message(
|
|
18
|
+
self,
|
|
19
|
+
context: MiddlewareContext[typing.Any],
|
|
20
|
+
call_next: CallNext[typing.Any, typing.Any],
|
|
21
|
+
) -> typing.Any: # noqa: ANN401
|
|
22
|
+
start_time: typing.Final = time.perf_counter_ns()
|
|
23
|
+
try:
|
|
24
|
+
result: typing.Final = await call_next(context)
|
|
25
|
+
except Exception:
|
|
26
|
+
fastmcp_access_logger.exception(
|
|
27
|
+
context.method or "unknown",
|
|
28
|
+
mcp={
|
|
29
|
+
"method": context.method,
|
|
30
|
+
"source": context.source,
|
|
31
|
+
"type": context.type,
|
|
32
|
+
},
|
|
33
|
+
duration=time.perf_counter_ns() - start_time,
|
|
34
|
+
)
|
|
35
|
+
raise
|
|
36
|
+
|
|
37
|
+
fastmcp_access_logger.info(
|
|
38
|
+
context.method or "unknown",
|
|
39
|
+
mcp={
|
|
40
|
+
"method": context.method,
|
|
41
|
+
"source": context.source,
|
|
42
|
+
"type": context.type,
|
|
43
|
+
},
|
|
44
|
+
duration=time.perf_counter_ns() - start_time,
|
|
45
|
+
)
|
|
46
|
+
return result
|
|
@@ -8,6 +8,7 @@ import pydantic_settings
|
|
|
8
8
|
from microbootstrap import (
|
|
9
9
|
CorsConfig,
|
|
10
10
|
FastApiPrometheusConfig,
|
|
11
|
+
FastMcpPrometheusConfig,
|
|
11
12
|
FastStreamOpentelemetryConfig,
|
|
12
13
|
FastStreamPrometheusConfig,
|
|
13
14
|
HealthChecksConfig,
|
|
@@ -102,6 +103,18 @@ class FastStreamSettings( # type: ignore[misc]
|
|
|
102
103
|
asyncapi_path: str | None = "/asyncapi"
|
|
103
104
|
|
|
104
105
|
|
|
106
|
+
class FastMcpSettings( # type: ignore[misc]
|
|
107
|
+
BaseServiceSettings,
|
|
108
|
+
ServerConfig,
|
|
109
|
+
LoggingConfig,
|
|
110
|
+
SentryConfig,
|
|
111
|
+
FastMcpPrometheusConfig,
|
|
112
|
+
HealthChecksConfig,
|
|
113
|
+
PyroscopeConfig,
|
|
114
|
+
):
|
|
115
|
+
"""Settings for a fastmcp bootstrap."""
|
|
116
|
+
|
|
117
|
+
|
|
105
118
|
class InstrumentsSetupperSettings( # type: ignore[misc]
|
|
106
119
|
BaseServiceSettings,
|
|
107
120
|
LoggingConfig,
|
|
@@ -56,7 +56,7 @@ dependencies = [
|
|
|
56
56
|
"opentelemetry-instrumentation-asgi>=0.46b0",
|
|
57
57
|
"orjson>=3.10.18",
|
|
58
58
|
]
|
|
59
|
-
version = "1.
|
|
59
|
+
version = "1.4.0"
|
|
60
60
|
authors = [{ name = "community-of-python" }]
|
|
61
61
|
|
|
62
62
|
[project.optional-dependencies]
|
|
@@ -73,6 +73,7 @@ litestar = [
|
|
|
73
73
|
]
|
|
74
74
|
granian = ["granian[reload]>=1"]
|
|
75
75
|
faststream = ["faststream~=0.6.2", "prometheus-client>=0.20"]
|
|
76
|
+
fastmcp = ["fastmcp>=2,<4", "prometheus-client>=0.20"]
|
|
76
77
|
|
|
77
78
|
[dependency-groups]
|
|
78
79
|
dev = [
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{microbootstrap-1.3.0 → microbootstrap-1.4.0}/microbootstrap/instruments/health_checks_instrument.py
RENAMED
|
File without changes
|
|
File without changes
|
{microbootstrap-1.3.0 → microbootstrap-1.4.0}/microbootstrap/instruments/logging_instrument.py
RENAMED
|
File without changes
|
{microbootstrap-1.3.0 → microbootstrap-1.4.0}/microbootstrap/instruments/opentelemetry_instrument.py
RENAMED
|
File without changes
|
{microbootstrap-1.3.0 → microbootstrap-1.4.0}/microbootstrap/instruments/pyroscope_instrument.py
RENAMED
|
File without changes
|
{microbootstrap-1.3.0 → microbootstrap-1.4.0}/microbootstrap/instruments/sentry_instrument.py
RENAMED
|
File without changes
|
{microbootstrap-1.3.0 → microbootstrap-1.4.0}/microbootstrap/instruments/swagger_instrument.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|