pomera-ai-commander 1.1.1 → 1.2.2
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.
- package/LICENSE +21 -21
- package/README.md +105 -680
- package/bin/pomera-ai-commander.js +62 -62
- package/core/__init__.py +65 -65
- package/core/app_context.py +482 -482
- package/core/async_text_processor.py +421 -421
- package/core/backup_manager.py +655 -655
- package/core/backup_recovery_manager.py +1199 -1033
- package/core/content_hash_cache.py +508 -508
- package/core/context_menu.py +313 -313
- package/core/data_directory.py +549 -0
- package/core/data_validator.py +1066 -1066
- package/core/database_connection_manager.py +744 -744
- package/core/database_curl_settings_manager.py +608 -608
- package/core/database_promera_ai_settings_manager.py +446 -446
- package/core/database_schema.py +411 -411
- package/core/database_schema_manager.py +395 -395
- package/core/database_settings_manager.py +1507 -1507
- package/core/database_settings_manager_interface.py +456 -456
- package/core/dialog_manager.py +734 -734
- package/core/diff_utils.py +239 -0
- package/core/efficient_line_numbers.py +540 -510
- package/core/error_handler.py +746 -746
- package/core/error_service.py +431 -431
- package/core/event_consolidator.py +511 -511
- package/core/mcp/__init__.py +43 -43
- package/core/mcp/find_replace_diff.py +334 -0
- package/core/mcp/protocol.py +288 -288
- package/core/mcp/schema.py +251 -251
- package/core/mcp/server_stdio.py +299 -299
- package/core/mcp/tool_registry.py +2699 -2345
- package/core/memento.py +275 -0
- package/core/memory_efficient_text_widget.py +711 -711
- package/core/migration_manager.py +914 -914
- package/core/migration_test_suite.py +1085 -1085
- package/core/migration_validator.py +1143 -1143
- package/core/optimized_find_replace.py +714 -714
- package/core/optimized_pattern_engine.py +424 -424
- package/core/optimized_search_highlighter.py +552 -552
- package/core/performance_monitor.py +674 -674
- package/core/persistence_manager.py +712 -712
- package/core/progressive_stats_calculator.py +632 -632
- package/core/regex_pattern_cache.py +529 -529
- package/core/regex_pattern_library.py +350 -350
- package/core/search_operation_manager.py +434 -434
- package/core/settings_defaults_registry.py +1087 -1087
- package/core/settings_integrity_validator.py +1111 -1111
- package/core/settings_serializer.py +557 -557
- package/core/settings_validator.py +1823 -1823
- package/core/smart_stats_calculator.py +709 -709
- package/core/statistics_update_manager.py +619 -619
- package/core/stats_config_manager.py +858 -858
- package/core/streaming_text_handler.py +723 -723
- package/core/task_scheduler.py +596 -596
- package/core/update_pattern_library.py +168 -168
- package/core/visibility_monitor.py +596 -596
- package/core/widget_cache.py +498 -498
- package/mcp.json +51 -61
- package/migrate_data.py +127 -0
- package/package.json +64 -57
- package/pomera.py +7883 -7482
- package/pomera_mcp_server.py +183 -144
- package/requirements.txt +33 -0
- package/scripts/Dockerfile.alpine +43 -0
- package/scripts/Dockerfile.gui-test +54 -0
- package/scripts/Dockerfile.linux +43 -0
- package/scripts/Dockerfile.test-linux +80 -0
- package/scripts/Dockerfile.ubuntu +39 -0
- package/scripts/README.md +53 -0
- package/scripts/build-all.bat +113 -0
- package/scripts/build-docker.bat +53 -0
- package/scripts/build-docker.sh +55 -0
- package/scripts/build-optimized.bat +101 -0
- package/scripts/build.sh +78 -0
- package/scripts/docker-compose.test.yml +27 -0
- package/scripts/docker-compose.yml +32 -0
- package/scripts/postinstall.js +62 -0
- package/scripts/requirements-minimal.txt +33 -0
- package/scripts/test-linux-simple.bat +28 -0
- package/scripts/validate-release-workflow.py +450 -0
- package/tools/__init__.py +4 -4
- package/tools/ai_tools.py +2891 -2891
- package/tools/ascii_art_generator.py +352 -352
- package/tools/base64_tools.py +183 -183
- package/tools/base_tool.py +511 -511
- package/tools/case_tool.py +308 -308
- package/tools/column_tools.py +395 -395
- package/tools/cron_tool.py +884 -884
- package/tools/curl_history.py +600 -600
- package/tools/curl_processor.py +1207 -1207
- package/tools/curl_settings.py +502 -502
- package/tools/curl_tool.py +5467 -5467
- package/tools/diff_viewer.py +1817 -1072
- package/tools/email_extraction_tool.py +248 -248
- package/tools/email_header_analyzer.py +425 -425
- package/tools/extraction_tools.py +250 -250
- package/tools/find_replace.py +2289 -1750
- package/tools/folder_file_reporter.py +1463 -1463
- package/tools/folder_file_reporter_adapter.py +480 -480
- package/tools/generator_tools.py +1216 -1216
- package/tools/hash_generator.py +255 -255
- package/tools/html_tool.py +656 -656
- package/tools/jsonxml_tool.py +729 -729
- package/tools/line_tools.py +419 -419
- package/tools/markdown_tools.py +561 -561
- package/tools/mcp_widget.py +1417 -1417
- package/tools/notes_widget.py +978 -973
- package/tools/number_base_converter.py +372 -372
- package/tools/regex_extractor.py +571 -571
- package/tools/slug_generator.py +310 -310
- package/tools/sorter_tools.py +458 -458
- package/tools/string_escape_tool.py +392 -392
- package/tools/text_statistics_tool.py +365 -365
- package/tools/text_wrapper.py +430 -430
- package/tools/timestamp_converter.py +421 -421
- package/tools/tool_loader.py +710 -710
- package/tools/translator_tools.py +522 -522
- package/tools/url_link_extractor.py +261 -261
- package/tools/url_parser.py +204 -204
- package/tools/whitespace_tools.py +355 -355
- package/tools/word_frequency_counter.py +146 -146
- package/core/__pycache__/__init__.cpython-313.pyc +0 -0
- package/core/__pycache__/app_context.cpython-313.pyc +0 -0
- package/core/__pycache__/async_text_processor.cpython-313.pyc +0 -0
- package/core/__pycache__/backup_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/backup_recovery_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/content_hash_cache.cpython-313.pyc +0 -0
- package/core/__pycache__/context_menu.cpython-313.pyc +0 -0
- package/core/__pycache__/data_validator.cpython-313.pyc +0 -0
- package/core/__pycache__/database_connection_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/database_curl_settings_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/database_promera_ai_settings_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/database_schema.cpython-313.pyc +0 -0
- package/core/__pycache__/database_schema_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/database_settings_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/database_settings_manager_interface.cpython-313.pyc +0 -0
- package/core/__pycache__/dialog_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/efficient_line_numbers.cpython-313.pyc +0 -0
- package/core/__pycache__/error_handler.cpython-313.pyc +0 -0
- package/core/__pycache__/error_service.cpython-313.pyc +0 -0
- package/core/__pycache__/event_consolidator.cpython-313.pyc +0 -0
- package/core/__pycache__/memory_efficient_text_widget.cpython-313.pyc +0 -0
- package/core/__pycache__/migration_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/migration_test_suite.cpython-313.pyc +0 -0
- package/core/__pycache__/migration_validator.cpython-313.pyc +0 -0
- package/core/__pycache__/optimized_find_replace.cpython-313.pyc +0 -0
- package/core/__pycache__/optimized_pattern_engine.cpython-313.pyc +0 -0
- package/core/__pycache__/optimized_search_highlighter.cpython-313.pyc +0 -0
- package/core/__pycache__/performance_monitor.cpython-313.pyc +0 -0
- package/core/__pycache__/persistence_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/progressive_stats_calculator.cpython-313.pyc +0 -0
- package/core/__pycache__/regex_pattern_cache.cpython-313.pyc +0 -0
- package/core/__pycache__/regex_pattern_library.cpython-313.pyc +0 -0
- package/core/__pycache__/search_operation_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/settings_defaults_registry.cpython-313.pyc +0 -0
- package/core/__pycache__/settings_integrity_validator.cpython-313.pyc +0 -0
- package/core/__pycache__/settings_serializer.cpython-313.pyc +0 -0
- package/core/__pycache__/settings_validator.cpython-313.pyc +0 -0
- package/core/__pycache__/smart_stats_calculator.cpython-313.pyc +0 -0
- package/core/__pycache__/statistics_update_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/stats_config_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/streaming_text_handler.cpython-313.pyc +0 -0
- package/core/__pycache__/task_scheduler.cpython-313.pyc +0 -0
- package/core/__pycache__/visibility_monitor.cpython-313.pyc +0 -0
- package/core/__pycache__/widget_cache.cpython-313.pyc +0 -0
- package/core/mcp/__pycache__/__init__.cpython-313.pyc +0 -0
- package/core/mcp/__pycache__/protocol.cpython-313.pyc +0 -0
- package/core/mcp/__pycache__/schema.cpython-313.pyc +0 -0
- package/core/mcp/__pycache__/server_stdio.cpython-313.pyc +0 -0
- package/core/mcp/__pycache__/tool_registry.cpython-313.pyc +0 -0
- package/tools/__pycache__/__init__.cpython-313.pyc +0 -0
- package/tools/__pycache__/ai_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/ascii_art_generator.cpython-313.pyc +0 -0
- package/tools/__pycache__/base64_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/base_tool.cpython-313.pyc +0 -0
- package/tools/__pycache__/case_tool.cpython-313.pyc +0 -0
- package/tools/__pycache__/column_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/cron_tool.cpython-313.pyc +0 -0
- package/tools/__pycache__/curl_history.cpython-313.pyc +0 -0
- package/tools/__pycache__/curl_processor.cpython-313.pyc +0 -0
- package/tools/__pycache__/curl_settings.cpython-313.pyc +0 -0
- package/tools/__pycache__/curl_tool.cpython-313.pyc +0 -0
- package/tools/__pycache__/diff_viewer.cpython-313.pyc +0 -0
- package/tools/__pycache__/email_extraction_tool.cpython-313.pyc +0 -0
- package/tools/__pycache__/email_header_analyzer.cpython-313.pyc +0 -0
- package/tools/__pycache__/extraction_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/find_replace.cpython-313.pyc +0 -0
- package/tools/__pycache__/folder_file_reporter.cpython-313.pyc +0 -0
- package/tools/__pycache__/folder_file_reporter_adapter.cpython-313.pyc +0 -0
- package/tools/__pycache__/generator_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/hash_generator.cpython-313.pyc +0 -0
- package/tools/__pycache__/html_tool.cpython-313.pyc +0 -0
- package/tools/__pycache__/huggingface_helper.cpython-313.pyc +0 -0
- package/tools/__pycache__/jsonxml_tool.cpython-313.pyc +0 -0
- package/tools/__pycache__/line_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/list_comparator.cpython-313.pyc +0 -0
- package/tools/__pycache__/markdown_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/mcp_widget.cpython-313.pyc +0 -0
- package/tools/__pycache__/notes_widget.cpython-313.pyc +0 -0
- package/tools/__pycache__/number_base_converter.cpython-313.pyc +0 -0
- package/tools/__pycache__/regex_extractor.cpython-313.pyc +0 -0
- package/tools/__pycache__/slug_generator.cpython-313.pyc +0 -0
- package/tools/__pycache__/sorter_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/string_escape_tool.cpython-313.pyc +0 -0
- package/tools/__pycache__/text_statistics_tool.cpython-313.pyc +0 -0
- package/tools/__pycache__/text_wrapper.cpython-313.pyc +0 -0
- package/tools/__pycache__/timestamp_converter.cpython-313.pyc +0 -0
- package/tools/__pycache__/tool_loader.cpython-313.pyc +0 -0
- package/tools/__pycache__/translator_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/url_link_extractor.cpython-313.pyc +0 -0
- package/tools/__pycache__/url_parser.cpython-313.pyc +0 -0
- package/tools/__pycache__/whitespace_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/word_frequency_counter.cpython-313.pyc +0 -0
package/core/mcp/schema.py
CHANGED
|
@@ -1,251 +1,251 @@
|
|
|
1
|
-
"""
|
|
2
|
-
MCP Schema Module - Data classes for Model Context Protocol types
|
|
3
|
-
|
|
4
|
-
This module defines the core data structures used in MCP communication:
|
|
5
|
-
- MCPMessage: JSON-RPC 2.0 message format
|
|
6
|
-
- MCPTool: Tool definition with input schema
|
|
7
|
-
- MCPResource: Resource definition with URI and metadata
|
|
8
|
-
- MCPError: Error response structure
|
|
9
|
-
|
|
10
|
-
Based on MCP specification: https://modelcontextprotocol.io/
|
|
11
|
-
"""
|
|
12
|
-
|
|
13
|
-
from dataclasses import dataclass, field, asdict
|
|
14
|
-
from typing import Optional, Dict, Any, List
|
|
15
|
-
from enum import IntEnum
|
|
16
|
-
import json
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class MCPErrorCode(IntEnum):
|
|
20
|
-
"""Standard JSON-RPC 2.0 and MCP error codes."""
|
|
21
|
-
# JSON-RPC 2.0 standard errors
|
|
22
|
-
PARSE_ERROR = -32700
|
|
23
|
-
INVALID_REQUEST = -32600
|
|
24
|
-
METHOD_NOT_FOUND = -32601
|
|
25
|
-
INVALID_PARAMS = -32602
|
|
26
|
-
INTERNAL_ERROR = -32603
|
|
27
|
-
|
|
28
|
-
# MCP-specific errors
|
|
29
|
-
RESOURCE_NOT_FOUND = -32001
|
|
30
|
-
TOOL_NOT_FOUND = -32002
|
|
31
|
-
TOOL_EXECUTION_ERROR = -32003
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
@dataclass
|
|
35
|
-
class MCPError:
|
|
36
|
-
"""JSON-RPC 2.0 error object."""
|
|
37
|
-
code: int
|
|
38
|
-
message: str
|
|
39
|
-
data: Optional[Any] = None
|
|
40
|
-
|
|
41
|
-
def to_dict(self) -> Dict[str, Any]:
|
|
42
|
-
"""Convert to dictionary for JSON serialization."""
|
|
43
|
-
result = {"code": self.code, "message": self.message}
|
|
44
|
-
if self.data is not None:
|
|
45
|
-
result["data"] = self.data
|
|
46
|
-
return result
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
@dataclass
|
|
50
|
-
class MCPMessage:
|
|
51
|
-
"""
|
|
52
|
-
JSON-RPC 2.0 message structure for MCP communication.
|
|
53
|
-
|
|
54
|
-
Can represent:
|
|
55
|
-
- Request: has method and optionally params
|
|
56
|
-
- Response: has result or error
|
|
57
|
-
- Notification: has method but no id
|
|
58
|
-
"""
|
|
59
|
-
jsonrpc: str = "2.0"
|
|
60
|
-
id: Optional[int] = None
|
|
61
|
-
method: Optional[str] = None
|
|
62
|
-
params: Optional[Dict[str, Any]] = None
|
|
63
|
-
result: Optional[Any] = None
|
|
64
|
-
error: Optional[MCPError] = None
|
|
65
|
-
|
|
66
|
-
def to_dict(self) -> Dict[str, Any]:
|
|
67
|
-
"""Convert to dictionary, excluding None values."""
|
|
68
|
-
result = {"jsonrpc": self.jsonrpc}
|
|
69
|
-
|
|
70
|
-
if self.id is not None:
|
|
71
|
-
result["id"] = self.id
|
|
72
|
-
if self.method is not None:
|
|
73
|
-
result["method"] = self.method
|
|
74
|
-
if self.params is not None:
|
|
75
|
-
result["params"] = self.params
|
|
76
|
-
if self.result is not None:
|
|
77
|
-
result["result"] = self.result
|
|
78
|
-
if self.error is not None:
|
|
79
|
-
result["error"] = self.error.to_dict()
|
|
80
|
-
|
|
81
|
-
return result
|
|
82
|
-
|
|
83
|
-
def to_json(self) -> str:
|
|
84
|
-
"""Serialize to JSON string."""
|
|
85
|
-
return json.dumps(self.to_dict())
|
|
86
|
-
|
|
87
|
-
@classmethod
|
|
88
|
-
def from_dict(cls, data: Dict[str, Any]) -> "MCPMessage":
|
|
89
|
-
"""Create MCPMessage from dictionary."""
|
|
90
|
-
error = None
|
|
91
|
-
if "error" in data and data["error"] is not None:
|
|
92
|
-
err_data = data["error"]
|
|
93
|
-
error = MCPError(
|
|
94
|
-
code=err_data.get("code", MCPErrorCode.INTERNAL_ERROR),
|
|
95
|
-
message=err_data.get("message", "Unknown error"),
|
|
96
|
-
data=err_data.get("data")
|
|
97
|
-
)
|
|
98
|
-
|
|
99
|
-
return cls(
|
|
100
|
-
jsonrpc=data.get("jsonrpc", "2.0"),
|
|
101
|
-
id=data.get("id"),
|
|
102
|
-
method=data.get("method"),
|
|
103
|
-
params=data.get("params"),
|
|
104
|
-
result=data.get("result"),
|
|
105
|
-
error=error
|
|
106
|
-
)
|
|
107
|
-
|
|
108
|
-
@classmethod
|
|
109
|
-
def from_json(cls, json_str: str) -> "MCPMessage":
|
|
110
|
-
"""Parse MCPMessage from JSON string."""
|
|
111
|
-
return cls.from_dict(json.loads(json_str))
|
|
112
|
-
|
|
113
|
-
def is_request(self) -> bool:
|
|
114
|
-
"""Check if this is a request message."""
|
|
115
|
-
return self.method is not None and self.id is not None
|
|
116
|
-
|
|
117
|
-
def is_notification(self) -> bool:
|
|
118
|
-
"""Check if this is a notification (request without id)."""
|
|
119
|
-
return self.method is not None and self.id is None
|
|
120
|
-
|
|
121
|
-
def is_response(self) -> bool:
|
|
122
|
-
"""Check if this is a response message."""
|
|
123
|
-
return self.method is None and (self.result is not None or self.error is not None)
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
@dataclass
|
|
127
|
-
class MCPTool:
|
|
128
|
-
"""
|
|
129
|
-
MCP Tool definition.
|
|
130
|
-
|
|
131
|
-
Represents a callable tool with its metadata and input schema.
|
|
132
|
-
"""
|
|
133
|
-
name: str
|
|
134
|
-
description: str
|
|
135
|
-
inputSchema: Dict[str, Any] = field(default_factory=lambda: {
|
|
136
|
-
"type": "object",
|
|
137
|
-
"properties": {},
|
|
138
|
-
"required": []
|
|
139
|
-
})
|
|
140
|
-
|
|
141
|
-
def to_dict(self) -> Dict[str, Any]:
|
|
142
|
-
"""Convert to MCP tool definition format."""
|
|
143
|
-
return {
|
|
144
|
-
"name": self.name,
|
|
145
|
-
"description": self.description,
|
|
146
|
-
"inputSchema": self.inputSchema
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
@dataclass
|
|
151
|
-
class MCPResource:
|
|
152
|
-
"""
|
|
153
|
-
MCP Resource definition.
|
|
154
|
-
|
|
155
|
-
Represents a readable resource with URI and metadata.
|
|
156
|
-
"""
|
|
157
|
-
uri: str
|
|
158
|
-
name: str
|
|
159
|
-
description: str = ""
|
|
160
|
-
mimeType: str = "text/plain"
|
|
161
|
-
|
|
162
|
-
def to_dict(self) -> Dict[str, Any]:
|
|
163
|
-
"""Convert to MCP resource definition format."""
|
|
164
|
-
return {
|
|
165
|
-
"uri": self.uri,
|
|
166
|
-
"name": self.name,
|
|
167
|
-
"description": self.description,
|
|
168
|
-
"mimeType": self.mimeType
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
@dataclass
|
|
173
|
-
class MCPResourceContent:
|
|
174
|
-
"""Content of a resource when read."""
|
|
175
|
-
uri: str
|
|
176
|
-
mimeType: str = "text/plain"
|
|
177
|
-
text: Optional[str] = None
|
|
178
|
-
blob: Optional[str] = None # Base64-encoded binary data
|
|
179
|
-
|
|
180
|
-
def to_dict(self) -> Dict[str, Any]:
|
|
181
|
-
"""Convert to MCP resource content format."""
|
|
182
|
-
result = {"uri": self.uri, "mimeType": self.mimeType}
|
|
183
|
-
if self.text is not None:
|
|
184
|
-
result["text"] = self.text
|
|
185
|
-
if self.blob is not None:
|
|
186
|
-
result["blob"] = self.blob
|
|
187
|
-
return result
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
@dataclass
|
|
191
|
-
class MCPToolResult:
|
|
192
|
-
"""Result of a tool execution."""
|
|
193
|
-
content: List[Dict[str, Any]] = field(default_factory=list)
|
|
194
|
-
isError: bool = False
|
|
195
|
-
|
|
196
|
-
@classmethod
|
|
197
|
-
def text(cls, text: str, is_error: bool = False) -> "MCPToolResult":
|
|
198
|
-
"""Create a text result."""
|
|
199
|
-
return cls(
|
|
200
|
-
content=[{"type": "text", "text": text}],
|
|
201
|
-
isError=is_error
|
|
202
|
-
)
|
|
203
|
-
|
|
204
|
-
@classmethod
|
|
205
|
-
def error(cls, message: str) -> "MCPToolResult":
|
|
206
|
-
"""Create an error result."""
|
|
207
|
-
return cls.text(message, is_error=True)
|
|
208
|
-
|
|
209
|
-
def to_dict(self) -> Dict[str, Any]:
|
|
210
|
-
"""Convert to MCP tool result format."""
|
|
211
|
-
return {
|
|
212
|
-
"content": self.content,
|
|
213
|
-
"isError": self.isError
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
@dataclass
|
|
218
|
-
class MCPServerCapabilities:
|
|
219
|
-
"""Server capabilities advertised during initialization."""
|
|
220
|
-
tools: bool = True
|
|
221
|
-
resources: bool = True
|
|
222
|
-
prompts: bool = False
|
|
223
|
-
logging: bool = False
|
|
224
|
-
|
|
225
|
-
def to_dict(self) -> Dict[str, Any]:
|
|
226
|
-
"""Convert to MCP capabilities format."""
|
|
227
|
-
caps = {}
|
|
228
|
-
if self.tools:
|
|
229
|
-
caps["tools"] = {}
|
|
230
|
-
if self.resources:
|
|
231
|
-
caps["resources"] = {}
|
|
232
|
-
if self.prompts:
|
|
233
|
-
caps["prompts"] = {}
|
|
234
|
-
if self.logging:
|
|
235
|
-
caps["logging"] = {}
|
|
236
|
-
return caps
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
@dataclass
|
|
240
|
-
class MCPServerInfo:
|
|
241
|
-
"""Server information returned during initialization."""
|
|
242
|
-
name: str = "pomera-mcp-server"
|
|
243
|
-
version: str = "0.1.0"
|
|
244
|
-
|
|
245
|
-
def to_dict(self) -> Dict[str, Any]:
|
|
246
|
-
"""Convert to MCP server info format."""
|
|
247
|
-
return {
|
|
248
|
-
"name": self.name,
|
|
249
|
-
"version": self.version
|
|
250
|
-
}
|
|
251
|
-
|
|
1
|
+
"""
|
|
2
|
+
MCP Schema Module - Data classes for Model Context Protocol types
|
|
3
|
+
|
|
4
|
+
This module defines the core data structures used in MCP communication:
|
|
5
|
+
- MCPMessage: JSON-RPC 2.0 message format
|
|
6
|
+
- MCPTool: Tool definition with input schema
|
|
7
|
+
- MCPResource: Resource definition with URI and metadata
|
|
8
|
+
- MCPError: Error response structure
|
|
9
|
+
|
|
10
|
+
Based on MCP specification: https://modelcontextprotocol.io/
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from dataclasses import dataclass, field, asdict
|
|
14
|
+
from typing import Optional, Dict, Any, List
|
|
15
|
+
from enum import IntEnum
|
|
16
|
+
import json
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class MCPErrorCode(IntEnum):
|
|
20
|
+
"""Standard JSON-RPC 2.0 and MCP error codes."""
|
|
21
|
+
# JSON-RPC 2.0 standard errors
|
|
22
|
+
PARSE_ERROR = -32700
|
|
23
|
+
INVALID_REQUEST = -32600
|
|
24
|
+
METHOD_NOT_FOUND = -32601
|
|
25
|
+
INVALID_PARAMS = -32602
|
|
26
|
+
INTERNAL_ERROR = -32603
|
|
27
|
+
|
|
28
|
+
# MCP-specific errors
|
|
29
|
+
RESOURCE_NOT_FOUND = -32001
|
|
30
|
+
TOOL_NOT_FOUND = -32002
|
|
31
|
+
TOOL_EXECUTION_ERROR = -32003
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@dataclass
|
|
35
|
+
class MCPError:
|
|
36
|
+
"""JSON-RPC 2.0 error object."""
|
|
37
|
+
code: int
|
|
38
|
+
message: str
|
|
39
|
+
data: Optional[Any] = None
|
|
40
|
+
|
|
41
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
42
|
+
"""Convert to dictionary for JSON serialization."""
|
|
43
|
+
result = {"code": self.code, "message": self.message}
|
|
44
|
+
if self.data is not None:
|
|
45
|
+
result["data"] = self.data
|
|
46
|
+
return result
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@dataclass
|
|
50
|
+
class MCPMessage:
|
|
51
|
+
"""
|
|
52
|
+
JSON-RPC 2.0 message structure for MCP communication.
|
|
53
|
+
|
|
54
|
+
Can represent:
|
|
55
|
+
- Request: has method and optionally params
|
|
56
|
+
- Response: has result or error
|
|
57
|
+
- Notification: has method but no id
|
|
58
|
+
"""
|
|
59
|
+
jsonrpc: str = "2.0"
|
|
60
|
+
id: Optional[int] = None
|
|
61
|
+
method: Optional[str] = None
|
|
62
|
+
params: Optional[Dict[str, Any]] = None
|
|
63
|
+
result: Optional[Any] = None
|
|
64
|
+
error: Optional[MCPError] = None
|
|
65
|
+
|
|
66
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
67
|
+
"""Convert to dictionary, excluding None values."""
|
|
68
|
+
result = {"jsonrpc": self.jsonrpc}
|
|
69
|
+
|
|
70
|
+
if self.id is not None:
|
|
71
|
+
result["id"] = self.id
|
|
72
|
+
if self.method is not None:
|
|
73
|
+
result["method"] = self.method
|
|
74
|
+
if self.params is not None:
|
|
75
|
+
result["params"] = self.params
|
|
76
|
+
if self.result is not None:
|
|
77
|
+
result["result"] = self.result
|
|
78
|
+
if self.error is not None:
|
|
79
|
+
result["error"] = self.error.to_dict()
|
|
80
|
+
|
|
81
|
+
return result
|
|
82
|
+
|
|
83
|
+
def to_json(self) -> str:
|
|
84
|
+
"""Serialize to JSON string."""
|
|
85
|
+
return json.dumps(self.to_dict())
|
|
86
|
+
|
|
87
|
+
@classmethod
|
|
88
|
+
def from_dict(cls, data: Dict[str, Any]) -> "MCPMessage":
|
|
89
|
+
"""Create MCPMessage from dictionary."""
|
|
90
|
+
error = None
|
|
91
|
+
if "error" in data and data["error"] is not None:
|
|
92
|
+
err_data = data["error"]
|
|
93
|
+
error = MCPError(
|
|
94
|
+
code=err_data.get("code", MCPErrorCode.INTERNAL_ERROR),
|
|
95
|
+
message=err_data.get("message", "Unknown error"),
|
|
96
|
+
data=err_data.get("data")
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
return cls(
|
|
100
|
+
jsonrpc=data.get("jsonrpc", "2.0"),
|
|
101
|
+
id=data.get("id"),
|
|
102
|
+
method=data.get("method"),
|
|
103
|
+
params=data.get("params"),
|
|
104
|
+
result=data.get("result"),
|
|
105
|
+
error=error
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
@classmethod
|
|
109
|
+
def from_json(cls, json_str: str) -> "MCPMessage":
|
|
110
|
+
"""Parse MCPMessage from JSON string."""
|
|
111
|
+
return cls.from_dict(json.loads(json_str))
|
|
112
|
+
|
|
113
|
+
def is_request(self) -> bool:
|
|
114
|
+
"""Check if this is a request message."""
|
|
115
|
+
return self.method is not None and self.id is not None
|
|
116
|
+
|
|
117
|
+
def is_notification(self) -> bool:
|
|
118
|
+
"""Check if this is a notification (request without id)."""
|
|
119
|
+
return self.method is not None and self.id is None
|
|
120
|
+
|
|
121
|
+
def is_response(self) -> bool:
|
|
122
|
+
"""Check if this is a response message."""
|
|
123
|
+
return self.method is None and (self.result is not None or self.error is not None)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
@dataclass
|
|
127
|
+
class MCPTool:
|
|
128
|
+
"""
|
|
129
|
+
MCP Tool definition.
|
|
130
|
+
|
|
131
|
+
Represents a callable tool with its metadata and input schema.
|
|
132
|
+
"""
|
|
133
|
+
name: str
|
|
134
|
+
description: str
|
|
135
|
+
inputSchema: Dict[str, Any] = field(default_factory=lambda: {
|
|
136
|
+
"type": "object",
|
|
137
|
+
"properties": {},
|
|
138
|
+
"required": []
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
142
|
+
"""Convert to MCP tool definition format."""
|
|
143
|
+
return {
|
|
144
|
+
"name": self.name,
|
|
145
|
+
"description": self.description,
|
|
146
|
+
"inputSchema": self.inputSchema
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
@dataclass
|
|
151
|
+
class MCPResource:
|
|
152
|
+
"""
|
|
153
|
+
MCP Resource definition.
|
|
154
|
+
|
|
155
|
+
Represents a readable resource with URI and metadata.
|
|
156
|
+
"""
|
|
157
|
+
uri: str
|
|
158
|
+
name: str
|
|
159
|
+
description: str = ""
|
|
160
|
+
mimeType: str = "text/plain"
|
|
161
|
+
|
|
162
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
163
|
+
"""Convert to MCP resource definition format."""
|
|
164
|
+
return {
|
|
165
|
+
"uri": self.uri,
|
|
166
|
+
"name": self.name,
|
|
167
|
+
"description": self.description,
|
|
168
|
+
"mimeType": self.mimeType
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
@dataclass
|
|
173
|
+
class MCPResourceContent:
|
|
174
|
+
"""Content of a resource when read."""
|
|
175
|
+
uri: str
|
|
176
|
+
mimeType: str = "text/plain"
|
|
177
|
+
text: Optional[str] = None
|
|
178
|
+
blob: Optional[str] = None # Base64-encoded binary data
|
|
179
|
+
|
|
180
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
181
|
+
"""Convert to MCP resource content format."""
|
|
182
|
+
result = {"uri": self.uri, "mimeType": self.mimeType}
|
|
183
|
+
if self.text is not None:
|
|
184
|
+
result["text"] = self.text
|
|
185
|
+
if self.blob is not None:
|
|
186
|
+
result["blob"] = self.blob
|
|
187
|
+
return result
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
@dataclass
|
|
191
|
+
class MCPToolResult:
|
|
192
|
+
"""Result of a tool execution."""
|
|
193
|
+
content: List[Dict[str, Any]] = field(default_factory=list)
|
|
194
|
+
isError: bool = False
|
|
195
|
+
|
|
196
|
+
@classmethod
|
|
197
|
+
def text(cls, text: str, is_error: bool = False) -> "MCPToolResult":
|
|
198
|
+
"""Create a text result."""
|
|
199
|
+
return cls(
|
|
200
|
+
content=[{"type": "text", "text": text}],
|
|
201
|
+
isError=is_error
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
@classmethod
|
|
205
|
+
def error(cls, message: str) -> "MCPToolResult":
|
|
206
|
+
"""Create an error result."""
|
|
207
|
+
return cls.text(message, is_error=True)
|
|
208
|
+
|
|
209
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
210
|
+
"""Convert to MCP tool result format."""
|
|
211
|
+
return {
|
|
212
|
+
"content": self.content,
|
|
213
|
+
"isError": self.isError
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
@dataclass
|
|
218
|
+
class MCPServerCapabilities:
|
|
219
|
+
"""Server capabilities advertised during initialization."""
|
|
220
|
+
tools: bool = True
|
|
221
|
+
resources: bool = True
|
|
222
|
+
prompts: bool = False
|
|
223
|
+
logging: bool = False
|
|
224
|
+
|
|
225
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
226
|
+
"""Convert to MCP capabilities format."""
|
|
227
|
+
caps = {}
|
|
228
|
+
if self.tools:
|
|
229
|
+
caps["tools"] = {}
|
|
230
|
+
if self.resources:
|
|
231
|
+
caps["resources"] = {}
|
|
232
|
+
if self.prompts:
|
|
233
|
+
caps["prompts"] = {}
|
|
234
|
+
if self.logging:
|
|
235
|
+
caps["logging"] = {}
|
|
236
|
+
return caps
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
@dataclass
|
|
240
|
+
class MCPServerInfo:
|
|
241
|
+
"""Server information returned during initialization."""
|
|
242
|
+
name: str = "pomera-mcp-server"
|
|
243
|
+
version: str = "0.1.0"
|
|
244
|
+
|
|
245
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
246
|
+
"""Convert to MCP server info format."""
|
|
247
|
+
return {
|
|
248
|
+
"name": self.name,
|
|
249
|
+
"version": self.version
|
|
250
|
+
}
|
|
251
|
+
|