Coverage for mcpgateway/types.py: 99%

211 statements  

« prev     ^ index     » next       coverage.py v7.9.1, created at 2025-06-22 12:53 +0100

1# -*- coding: utf-8 -*- 

2"""MCP Protocol Type Definitions. 

3 

4Copyright 2025 

5SPDX-License-Identifier: Apache-2.0 

6Authors: Mihai Criveti 

7 

8This module defines all core MCP protocol types according to the specification. 

9It includes: 

10 - Message content types (text, image, resource) 

11 - Tool definitions and schemas 

12 - Resource types and templates 

13 - Prompt structures 

14 - Protocol initialization types 

15 - Sampling message types 

16 - Capability definitions 

17""" 

18 

19from datetime import datetime 

20from enum import Enum 

21from typing import Any, Dict, List, Literal, Optional, Union 

22 

23from pydantic import AnyHttpUrl, AnyUrl, BaseModel, Field 

24 

25 

26class Role(str, Enum): 

27 """Message role in conversations. 

28 

29 Attributes: 

30 ASSISTANT (str): Indicates the assistant's role. 

31 USER (str): Indicates the user's role. 

32 """ 

33 

34 ASSISTANT = "assistant" 

35 USER = "user" 

36 

37 

38class LogLevel(str, Enum): 

39 """Standard syslog severity levels as defined in RFC 5424. 

40 

41 Attributes: 

42 DEBUG (str): Debug level. 

43 INFO (str): Informational level. 

44 NOTICE (str): Notice level. 

45 WARNING (str): Warning level. 

46 ERROR (str): Error level. 

47 CRITICAL (str): Critical level. 

48 ALERT (str): Alert level. 

49 EMERGENCY (str): Emergency level. 

50 """ 

51 

52 DEBUG = "debug" 

53 INFO = "info" 

54 NOTICE = "notice" 

55 WARNING = "warning" 

56 ERROR = "error" 

57 CRITICAL = "critical" 

58 ALERT = "alert" 

59 EMERGENCY = "emergency" 

60 

61 

62# Base content types 

63class TextContent(BaseModel): 

64 """Text content for messages. 

65 

66 Attributes: 

67 type (Literal["text"]): The fixed content type identifier for text. 

68 text (str): The actual text message. 

69 """ 

70 

71 type: Literal["text"] 

72 text: str 

73 

74 

75class JSONContent(BaseModel): 

76 """JSON content for messages. 

77 Attributes: 

78 type (Literal["text"]): The fixed content type identifier for text. 

79 json (dict): The actual text message. 

80 """ 

81 

82 type: Literal["text"] 

83 text: dict 

84 

85 

86class ImageContent(BaseModel): 

87 """Image content for messages. 

88 

89 Attributes: 

90 type (Literal["image"]): The fixed content type identifier for images. 

91 data (bytes): The binary data of the image. 

92 mime_type (str): The MIME type (e.g. "image/png") of the image. 

93 """ 

94 

95 type: Literal["image"] 

96 data: bytes 

97 mime_type: str 

98 

99 

100class ResourceContent(BaseModel): 

101 """Resource content that can be embedded. 

102 

103 Attributes: 

104 type (Literal["resource"]): The fixed content type identifier for resources. 

105 uri (str): The URI identifying the resource. 

106 mime_type (Optional[str]): The MIME type of the resource, if known. 

107 text (Optional[str]): A textual representation of the resource, if applicable. 

108 blob (Optional[bytes]): Binary data of the resource, if applicable. 

109 """ 

110 

111 type: Literal["resource"] 

112 uri: str 

113 mime_type: Optional[str] = None 

114 text: Optional[str] = None 

115 blob: Optional[bytes] = None 

116 

117 

118ContentType = Union[TextContent, JSONContent, ImageContent, ResourceContent] 

119 

120 

121# Reference types - needed early for completion 

122class PromptReference(BaseModel): 

123 """Reference to a prompt or prompt template. 

124 

125 Attributes: 

126 type (Literal["ref/prompt"]): The fixed reference type identifier for prompts. 

127 name (str): The unique name of the prompt. 

128 """ 

129 

130 type: Literal["ref/prompt"] 

131 name: str 

132 

133 

134class ResourceReference(BaseModel): 

135 """Reference to a resource or resource template. 

136 

137 Attributes: 

138 type (Literal["ref/resource"]): The fixed reference type identifier for resources. 

139 uri (str): The URI of the resource. 

140 """ 

141 

142 type: Literal["ref/resource"] 

143 uri: str 

144 

145 

146# Completion types 

147class CompleteRequest(BaseModel): 

148 """Request for completion suggestions. 

149 

150 Attributes: 

151 ref (Union[PromptReference, ResourceReference]): A reference to a prompt or resource. 

152 argument (Dict[str, str]): A dictionary containing arguments for the completion. 

153 """ 

154 

155 ref: Union[PromptReference, ResourceReference] 

156 argument: Dict[str, str] 

157 

158 

159class CompleteResult(BaseModel): 

160 """Result for a completion request. 

161 

162 Attributes: 

163 completion (Dict[str, Any]): A dictionary containing the completion results. 

164 """ 

165 

166 completion: Dict[str, Any] = Field(..., description="Completion results") 

167 

168 

169# Implementation info 

170class Implementation(BaseModel): 

171 """MCP implementation information. 

172 

173 Attributes: 

174 name (str): The name of the implementation. 

175 version (str): The version of the implementation. 

176 """ 

177 

178 name: str 

179 version: str 

180 

181 

182# Model preferences 

183class ModelHint(BaseModel): 

184 """Hint for model selection. 

185 

186 Attributes: 

187 name (Optional[str]): An optional hint for the model name. 

188 """ 

189 

190 name: Optional[str] = None 

191 

192 

193class ModelPreferences(BaseModel): 

194 """Server preferences for model selection. 

195 

196 Attributes: 

197 cost_priority (float): Priority for cost efficiency (0 to 1). 

198 speed_priority (float): Priority for speed (0 to 1). 

199 intelligence_priority (float): Priority for intelligence (0 to 1). 

200 hints (List[ModelHint]): A list of model hints. 

201 """ 

202 

203 cost_priority: float = Field(ge=0, le=1) 

204 speed_priority: float = Field(ge=0, le=1) 

205 intelligence_priority: float = Field(ge=0, le=1) 

206 hints: List[ModelHint] = [] 

207 

208 

209# Capability types 

210class ClientCapabilities(BaseModel): 

211 """Capabilities that a client may support. 

212 

213 Attributes: 

214 roots (Optional[Dict[str, bool]]): Capabilities related to root management. 

215 sampling (Optional[Dict[str, Any]]): Capabilities related to LLM sampling. 

216 experimental (Optional[Dict[str, Dict[str, Any]]]): Experimental capabilities. 

217 """ 

218 

219 roots: Optional[Dict[str, bool]] = None 

220 sampling: Optional[Dict[str, Any]] = None 

221 experimental: Optional[Dict[str, Dict[str, Any]]] = None 

222 

223 

224class ServerCapabilities(BaseModel): 

225 """Capabilities that a server may support. 

226 

227 Attributes: 

228 prompts (Optional[Dict[str, bool]]): Capability for prompt support. 

229 resources (Optional[Dict[str, bool]]): Capability for resource support. 

230 tools (Optional[Dict[str, bool]]): Capability for tool support. 

231 logging (Optional[Dict[str, Any]]): Capability for logging support. 

232 experimental (Optional[Dict[str, Dict[str, Any]]]): Experimental capabilities. 

233 """ 

234 

235 prompts: Optional[Dict[str, bool]] = None 

236 resources: Optional[Dict[str, bool]] = None 

237 tools: Optional[Dict[str, bool]] = None 

238 logging: Optional[Dict[str, Any]] = None 

239 experimental: Optional[Dict[str, Dict[str, Any]]] = None 

240 

241 

242# Initialization types 

243class InitializeRequest(BaseModel): 

244 """Initial request sent from the client to the server. 

245 

246 Attributes: 

247 protocol_version (str): The protocol version (alias: protocolVersion). 

248 capabilities (ClientCapabilities): The client's capabilities. 

249 client_info (Implementation): The client's implementation information (alias: clientInfo). 

250 

251 Note: 

252 The alias settings allow backward compatibility with older Pydantic versions. 

253 """ 

254 

255 protocol_version: str = Field(..., alias="protocolVersion") 

256 capabilities: ClientCapabilities 

257 client_info: Implementation = Field(..., alias="clientInfo") 

258 

259 class Config: 

260 """Configuration for InitializeRequest. 

261 

262 Attributes: 

263 populate_by_name (bool): Enables population by field name. 

264 allow_population_by_field_name (bool): Allows backward compatibility with older Pydantic versions. 

265 """ 

266 

267 populate_by_name = True 

268 allow_population_by_field_name = True # Use this for backward compatibility with older Pydantic versions 

269 

270 

271class InitializeResult(BaseModel): 

272 """Server's response to the initialization request. 

273 

274 Attributes: 

275 protocol_version (str): The protocol version used. 

276 capabilities (ServerCapabilities): The server's capabilities. 

277 server_info (Implementation): The server's implementation information. 

278 instructions (Optional[str]): Optional instructions for the client. 

279 """ 

280 

281 protocol_version: str = Field(..., alias="protocolVersion") 

282 capabilities: ServerCapabilities = Field(..., alias="capabilities") 

283 server_info: Implementation = Field(..., alias="serverInfo") 

284 instructions: Optional[str] = Field(None, alias="instructions") 

285 

286 class Config: 

287 """ 

288 Configuration class for Pydantic models. 

289 

290 Enables population of model fields by name and by field name. 

291 """ 

292 

293 populate_by_name = True 

294 allow_population_by_field_name = True 

295 

296 

297# Message types 

298class Message(BaseModel): 

299 """A message in a conversation. 

300 

301 Attributes: 

302 role (Role): The role of the message sender. 

303 content (ContentType): The content of the message. 

304 """ 

305 

306 role: Role 

307 content: ContentType 

308 

309 

310class SamplingMessage(BaseModel): 

311 """A message used in LLM sampling requests. 

312 

313 Attributes: 

314 role (Role): The role of the sender. 

315 content (ContentType): The content of the sampling message. 

316 """ 

317 

318 role: Role 

319 content: ContentType 

320 

321 

322# Sampling types for the client features 

323class CreateMessageResult(BaseModel): 

324 """Result from a sampling/createMessage request. 

325 

326 Attributes: 

327 content (Union[TextContent, ImageContent]): The generated content. 

328 model (str): The model used for generating the content. 

329 role (Role): The role associated with the content. 

330 stop_reason (Optional[str]): An optional reason for why sampling stopped. 

331 """ 

332 

333 content: Union[TextContent, ImageContent] 

334 model: str 

335 role: Role 

336 stop_reason: Optional[str] = None 

337 

338 

339# Prompt types 

340class PromptArgument(BaseModel): 

341 """An argument that can be passed to a prompt. 

342 

343 Attributes: 

344 name (str): The name of the argument. 

345 description (Optional[str]): An optional description of the argument. 

346 required (bool): Whether the argument is required. Defaults to False. 

347 """ 

348 

349 name: str 

350 description: Optional[str] = None 

351 required: bool = False 

352 

353 

354class Prompt(BaseModel): 

355 """A prompt template offered by the server. 

356 

357 Attributes: 

358 name (str): The unique name of the prompt. 

359 description (Optional[str]): A description of the prompt. 

360 arguments (List[PromptArgument]): A list of expected prompt arguments. 

361 """ 

362 

363 name: str 

364 description: Optional[str] = None 

365 arguments: List[PromptArgument] = [] 

366 

367 

368class PromptResult(BaseModel): 

369 """Result of rendering a prompt template. 

370 

371 Attributes: 

372 messages (List[Message]): The list of messages produced by rendering the prompt. 

373 description (Optional[str]): An optional description of the rendered result. 

374 """ 

375 

376 messages: List[Message] 

377 description: Optional[str] = None 

378 

379 

380# Tool types 

381class Tool(BaseModel): 

382 """A tool that can be invoked. 

383 

384 Attributes: 

385 name (str): The unique name of the tool. 

386 url (AnyHttpUrl): The URL of the tool. 

387 description (Optional[str]): A description of the tool. 

388 integrationType (str): The integration type of the tool (e.g. MCP or REST). 

389 requestType (str): The HTTP method used to invoke the tool (GET, POST, PUT, DELETE, SSE, STDIO). 

390 headers (Dict[str, Any]): A JSON object representing HTTP headers. 

391 input_schema (Dict[str, Any]): A JSON Schema for validating the tool's input. 

392 auth_type (Optional[str]): The type of authentication used ("basic", "bearer", or None). 

393 auth_username (Optional[str]): The username for basic authentication. 

394 auth_password (Optional[str]): The password for basic authentication. 

395 auth_token (Optional[str]): The token for bearer authentication. 

396 """ 

397 

398 name: str 

399 url: AnyHttpUrl 

400 description: Optional[str] = None 

401 integrationType: str = "MCP" 

402 requestType: str = "SSE" 

403 headers: Dict[str, Any] = Field(default_factory=dict) 

404 input_schema: Dict[str, Any] = Field(default_factory=lambda: {"type": "object", "properties": {}}) 

405 auth_type: Optional[str] = None 

406 auth_username: Optional[str] = None 

407 auth_password: Optional[str] = None 

408 auth_token: Optional[str] = None 

409 

410 

411class ToolResult(BaseModel): 

412 """Result of a tool invocation. 

413 

414 Attributes: 

415 content (List[ContentType]): A list of content items returned by the tool. 

416 is_error (bool): Flag indicating if the tool call resulted in an error. 

417 """ 

418 

419 content: List[ContentType] 

420 is_error: bool = False 

421 

422 

423# Resource types 

424class Resource(BaseModel): 

425 """A resource available from the server. 

426 

427 Attributes: 

428 uri (str): The unique URI of the resource. 

429 name (str): The human-readable name of the resource. 

430 description (Optional[str]): A description of the resource. 

431 mime_type (Optional[str]): The MIME type of the resource. 

432 size (Optional[int]): The size of the resource. 

433 """ 

434 

435 uri: str 

436 name: str 

437 description: Optional[str] = None 

438 mime_type: Optional[str] = None 

439 size: Optional[int] = None 

440 

441 

442class ResourceTemplate(BaseModel): 

443 """A template for constructing resource URIs. 

444 

445 Attributes: 

446 uri_template (str): The URI template string. 

447 name (str): The unique name of the template. 

448 description (Optional[str]): A description of the template. 

449 mime_type (Optional[str]): The MIME type associated with the template. 

450 """ 

451 

452 uri_template: str 

453 name: str 

454 description: Optional[str] = None 

455 mime_type: Optional[str] = None 

456 

457 

458class ListResourceTemplatesResult(BaseModel): 

459 """The server's response to a resources/templates/list request from the client. 

460 

461 Attributes: 

462 meta (Optional[Dict[str, Any]]): Reserved property for metadata. 

463 next_cursor (Optional[str]): Pagination cursor for the next page of results. 

464 resource_templates (List[ResourceTemplate]): List of resource templates. 

465 """ 

466 

467 meta: Optional[Dict[str, Any]] = Field( 

468 None, alias="_meta", description="This result property is reserved by the protocol to allow clients and servers to attach additional metadata to their responses." 

469 ) 

470 next_cursor: Optional[str] = Field(None, description="An opaque token representing the pagination position after the last returned result.\nIf present, there may be more results available.") 

471 resource_templates: List[ResourceTemplate] = Field(default_factory=list, description="List of resource templates available on the server") 

472 

473 class Config: 

474 """Configuration for model serialization.""" 

475 

476 populate_by_name = True 

477 allow_population_by_field_name = True 

478 

479 

480# Root types 

481class FileUrl(AnyUrl): 

482 """A specialized URL type for local file-scheme resources. 

483 

484 Key characteristics 

485 ------------------- 

486 * Scheme restricted – only the "file" scheme is permitted 

487 (e.g. file:///path/to/file.txt). 

488 * No host required – "file" URLs typically omit a network host; 

489 therefore, the host component is not mandatory. 

490 * String-friendly equality – developers naturally expect 

491 FileUrl("file:///data") == "file:///data" to evaluate True. 

492 AnyUrl (Pydantic) does not implement that, so we override 

493 __eq__ to compare against plain strings transparently. 

494 Hash semantics are kept consistent by delegating to the parent class. 

495 

496 Examples 

497 -------- 

498 >>> url = FileUrl("file:///etc/hosts") 

499 >>> url.scheme 

500 'file' 

501 >>> url == "file:///etc/hosts" 

502 True 

503 >>> {"path": url} # hashable 

504 {'path': FileUrl('file:///etc/hosts')} 

505 

506 Notes 

507 ----- 

508 The override does not interfere with comparisons to other 

509 AnyUrl/FileUrl instances; those still use the superclass 

510 implementation. 

511 """ 

512 

513 # Restrict to the "file" scheme and omit host requirement 

514 allowed_schemes = {"file"} 

515 host_required = False 

516 

517 def __eq__(self, other): # type: ignore[override] 

518 """Return True when other is an equivalent URL or string. 

519 

520 If other is a str it is coerced with str(self) for comparison; 

521 otherwise defer to AnyUrl's comparison. 

522 

523 Args: 

524 other (Any): The object to compare against. May be a str, FileUrl, or AnyUrl. 

525 

526 Returns: 

527 bool: True if the other value is equal to this URL, either as a string 

528 or as another URL object. False otherwise. 

529 """ 

530 if isinstance(other, str): 530 ↛ 532line 530 didn't jump to line 532 because the condition on line 530 was always true

531 return str(self) == other 

532 return super().__eq__(other) 

533 

534 # Keep hashing behaviour aligned with equality 

535 __hash__ = AnyUrl.__hash__ 

536 

537 

538class Root(BaseModel): 

539 """A root directory or file. 

540 

541 Attributes: 

542 uri (Union[FileUrl, AnyUrl]): The unique identifier for the root. 

543 name (Optional[str]): An optional human-readable name. 

544 """ 

545 

546 uri: Union[FileUrl, AnyUrl] = Field(..., description="Unique identifier for the root") 

547 name: Optional[str] = Field(None, description="Optional human-readable name") 

548 

549 

550# Progress types 

551class ProgressToken(BaseModel): 

552 """Token for associating progress notifications. 

553 

554 Attributes: 

555 value (Union[str, int]): The token value. 

556 """ 

557 

558 value: Union[str, int] 

559 

560 

561class Progress(BaseModel): 

562 """Progress update for long-running operations. 

563 

564 Attributes: 

565 progress_token (ProgressToken): The token associated with the progress update. 

566 progress (float): The current progress value. 

567 total (Optional[float]): The total progress value, if known. 

568 """ 

569 

570 progress_token: ProgressToken 

571 progress: float 

572 total: Optional[float] = None 

573 

574 

575# JSON-RPC types 

576class JSONRPCRequest(BaseModel): 

577 """JSON-RPC 2.0 request. 

578 

579 Attributes: 

580 jsonrpc (Literal["2.0"]): The JSON-RPC version. 

581 id (Optional[Union[str, int]]): The request identifier. 

582 method (str): The method name. 

583 params (Optional[Dict[str, Any]]): The parameters for the request. 

584 """ 

585 

586 jsonrpc: Literal["2.0"] 

587 id: Optional[Union[str, int]] = None 

588 method: str 

589 params: Optional[Dict[str, Any]] = None 

590 

591 

592class JSONRPCResponse(BaseModel): 

593 """JSON-RPC 2.0 response. 

594 

595 Attributes: 

596 jsonrpc (Literal["2.0"]): The JSON-RPC version. 

597 id (Optional[Union[str, int]]): The request identifier. 

598 result (Optional[Any]): The result of the request. 

599 error (Optional[Dict[str, Any]]): The error object if an error occurred. 

600 """ 

601 

602 jsonrpc: Literal["2.0"] 

603 id: Optional[Union[str, int]] = None 

604 result: Optional[Any] = None 

605 error: Optional[Dict[str, Any]] = None 

606 

607 

608class JSONRPCError(BaseModel): 

609 """JSON-RPC 2.0 error. 

610 

611 Attributes: 

612 code (int): The error code. 

613 message (str): A short description of the error. 

614 data (Optional[Any]): Additional data about the error. 

615 """ 

616 

617 code: int 

618 message: str 

619 data: Optional[Any] = None 

620 

621 

622# Transport message types 

623class SSEEvent(BaseModel): 

624 """Server-Sent Events message. 

625 

626 Attributes: 

627 id (Optional[str]): The event identifier. 

628 event (Optional[str]): The event type. 

629 data (str): The event data. 

630 retry (Optional[int]): The retry timeout in milliseconds. 

631 """ 

632 

633 id: Optional[str] = None 

634 event: Optional[str] = None 

635 data: str 

636 retry: Optional[int] = None 

637 

638 

639class WebSocketMessage(BaseModel): 

640 """WebSocket protocol message. 

641 

642 Attributes: 

643 type (str): The type of the WebSocket message. 

644 data (Any): The message data. 

645 """ 

646 

647 type: str 

648 data: Any 

649 

650 

651# Notification types 

652class ResourceUpdateNotification(BaseModel): 

653 """Notification of resource changes. 

654 

655 Attributes: 

656 method (Literal["notifications/resources/updated"]): The notification method. 

657 uri (str): The URI of the updated resource. 

658 """ 

659 

660 method: Literal["notifications/resources/updated"] 

661 uri: str 

662 

663 

664class ResourceListChangedNotification(BaseModel): 

665 """Notification of resource list changes. 

666 

667 Attributes: 

668 method (Literal["notifications/resources/list_changed"]): The notification method. 

669 """ 

670 

671 method: Literal["notifications/resources/list_changed"] 

672 

673 

674class PromptListChangedNotification(BaseModel): 

675 """Notification of prompt list changes. 

676 

677 Attributes: 

678 method (Literal["notifications/prompts/list_changed"]): The notification method. 

679 """ 

680 

681 method: Literal["notifications/prompts/list_changed"] 

682 

683 

684class ToolListChangedNotification(BaseModel): 

685 """Notification of tool list changes. 

686 

687 Attributes: 

688 method (Literal["notifications/tools/list_changed"]): The notification method. 

689 """ 

690 

691 method: Literal["notifications/tools/list_changed"] 

692 

693 

694class CancelledNotification(BaseModel): 

695 """Notification of request cancellation. 

696 

697 Attributes: 

698 method (Literal["notifications/cancelled"]): The notification method. 

699 request_id (Union[str, int]): The ID of the cancelled request. 

700 reason (Optional[str]): An optional reason for cancellation. 

701 """ 

702 

703 method: Literal["notifications/cancelled"] 

704 request_id: Union[str, int] 

705 reason: Optional[str] = None 

706 

707 

708class ProgressNotification(BaseModel): 

709 """Notification of operation progress. 

710 

711 Attributes: 

712 method (Literal["notifications/progress"]): The notification method. 

713 progress_token (ProgressToken): The token associated with the progress. 

714 progress (float): The current progress value. 

715 total (Optional[float]): The total progress value, if known. 

716 """ 

717 

718 method: Literal["notifications/progress"] 

719 progress_token: ProgressToken 

720 progress: float 

721 total: Optional[float] = None 

722 

723 

724class LoggingNotification(BaseModel): 

725 """Notification of log messages. 

726 

727 Attributes: 

728 method (Literal["notifications/message"]): The notification method. 

729 level (LogLevel): The log level of the message. 

730 logger (Optional[str]): The logger name. 

731 data (Any): The log message data. 

732 """ 

733 

734 method: Literal["notifications/message"] 

735 level: LogLevel 

736 logger: Optional[str] = None 

737 data: Any 

738 

739 

740# Federation types 

741class FederatedTool(Tool): 

742 """A tool from a federated gateway. 

743 

744 Attributes: 

745 gateway_id (str): The identifier of the gateway. 

746 gateway_name (str): The name of the gateway. 

747 """ 

748 

749 gateway_id: str 

750 gateway_name: str 

751 

752 

753class FederatedResource(Resource): 

754 """A resource from a federated gateway. 

755 

756 Attributes: 

757 gateway_id (str): The identifier of the gateway. 

758 gateway_name (str): The name of the gateway. 

759 """ 

760 

761 gateway_id: str 

762 gateway_name: str 

763 

764 

765class FederatedPrompt(Prompt): 

766 """A prompt from a federated gateway. 

767 

768 Attributes: 

769 gateway_id (str): The identifier of the gateway. 

770 gateway_name (str): The name of the gateway. 

771 """ 

772 

773 gateway_id: str 

774 gateway_name: str 

775 

776 

777class Gateway(BaseModel): 

778 """A federated gateway peer. 

779 

780 Attributes: 

781 id (str): The unique identifier for the gateway. 

782 name (str): The name of the gateway. 

783 url (AnyHttpUrl): The URL of the gateway. 

784 capabilities (ServerCapabilities): The capabilities of the gateway. 

785 last_seen (Optional[datetime]): Timestamp when the gateway was last seen. 

786 """ 

787 

788 id: str 

789 name: str 

790 url: AnyHttpUrl 

791 capabilities: ServerCapabilities 

792 last_seen: Optional[datetime] = None