pomera-ai-commander 0.1.0
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 -0
- package/README.md +680 -0
- package/bin/pomera-ai-commander.js +62 -0
- package/core/__init__.py +66 -0
- 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/app_context.py +482 -0
- package/core/async_text_processor.py +422 -0
- package/core/backup_manager.py +656 -0
- package/core/backup_recovery_manager.py +1034 -0
- package/core/content_hash_cache.py +509 -0
- package/core/context_menu.py +313 -0
- package/core/data_validator.py +1067 -0
- package/core/database_connection_manager.py +745 -0
- package/core/database_curl_settings_manager.py +609 -0
- package/core/database_promera_ai_settings_manager.py +447 -0
- package/core/database_schema.py +412 -0
- package/core/database_schema_manager.py +396 -0
- package/core/database_settings_manager.py +1508 -0
- package/core/database_settings_manager_interface.py +457 -0
- package/core/dialog_manager.py +735 -0
- package/core/efficient_line_numbers.py +511 -0
- package/core/error_handler.py +747 -0
- package/core/error_service.py +431 -0
- package/core/event_consolidator.py +512 -0
- package/core/mcp/__init__.py +43 -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/core/mcp/protocol.py +288 -0
- package/core/mcp/schema.py +251 -0
- package/core/mcp/server_stdio.py +299 -0
- package/core/mcp/tool_registry.py +2345 -0
- package/core/memory_efficient_text_widget.py +712 -0
- package/core/migration_manager.py +915 -0
- package/core/migration_test_suite.py +1086 -0
- package/core/migration_validator.py +1144 -0
- package/core/optimized_find_replace.py +715 -0
- package/core/optimized_pattern_engine.py +424 -0
- package/core/optimized_search_highlighter.py +553 -0
- package/core/performance_monitor.py +675 -0
- package/core/persistence_manager.py +713 -0
- package/core/progressive_stats_calculator.py +632 -0
- package/core/regex_pattern_cache.py +530 -0
- package/core/regex_pattern_library.py +351 -0
- package/core/search_operation_manager.py +435 -0
- package/core/settings_defaults_registry.py +1087 -0
- package/core/settings_integrity_validator.py +1112 -0
- package/core/settings_serializer.py +558 -0
- package/core/settings_validator.py +1824 -0
- package/core/smart_stats_calculator.py +710 -0
- package/core/statistics_update_manager.py +619 -0
- package/core/stats_config_manager.py +858 -0
- package/core/streaming_text_handler.py +723 -0
- package/core/task_scheduler.py +596 -0
- package/core/update_pattern_library.py +169 -0
- package/core/visibility_monitor.py +596 -0
- package/core/widget_cache.py +498 -0
- package/mcp.json +61 -0
- package/package.json +57 -0
- package/pomera.py +7483 -0
- package/pomera_mcp_server.py +144 -0
- package/tools/__init__.py +5 -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/tools/ai_tools.py +2892 -0
- package/tools/ascii_art_generator.py +353 -0
- package/tools/base64_tools.py +184 -0
- package/tools/base_tool.py +511 -0
- package/tools/case_tool.py +309 -0
- package/tools/column_tools.py +396 -0
- package/tools/cron_tool.py +885 -0
- package/tools/curl_history.py +601 -0
- package/tools/curl_processor.py +1208 -0
- package/tools/curl_settings.py +503 -0
- package/tools/curl_tool.py +5467 -0
- package/tools/diff_viewer.py +1072 -0
- package/tools/email_extraction_tool.py +249 -0
- package/tools/email_header_analyzer.py +426 -0
- package/tools/extraction_tools.py +250 -0
- package/tools/find_replace.py +1751 -0
- package/tools/folder_file_reporter.py +1463 -0
- package/tools/folder_file_reporter_adapter.py +480 -0
- package/tools/generator_tools.py +1217 -0
- package/tools/hash_generator.py +256 -0
- package/tools/html_tool.py +657 -0
- package/tools/huggingface_helper.py +449 -0
- package/tools/jsonxml_tool.py +730 -0
- package/tools/line_tools.py +419 -0
- package/tools/list_comparator.py +720 -0
- package/tools/markdown_tools.py +562 -0
- package/tools/mcp_widget.py +1417 -0
- package/tools/notes_widget.py +973 -0
- package/tools/number_base_converter.py +373 -0
- package/tools/regex_extractor.py +572 -0
- package/tools/slug_generator.py +311 -0
- package/tools/sorter_tools.py +459 -0
- package/tools/string_escape_tool.py +393 -0
- package/tools/text_statistics_tool.py +366 -0
- package/tools/text_wrapper.py +431 -0
- package/tools/timestamp_converter.py +422 -0
- package/tools/tool_loader.py +710 -0
- package/tools/translator_tools.py +523 -0
- package/tools/url_link_extractor.py +262 -0
- package/tools/url_parser.py +205 -0
- package/tools/whitespace_tools.py +356 -0
- package/tools/word_frequency_counter.py +147 -0
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
"""
|
|
2
|
+
MCP Protocol Module - JSON-RPC 2.0 message handling
|
|
3
|
+
|
|
4
|
+
This module provides utilities for parsing and creating MCP messages
|
|
5
|
+
following the JSON-RPC 2.0 specification.
|
|
6
|
+
|
|
7
|
+
Features:
|
|
8
|
+
- Parse incoming JSON-RPC messages
|
|
9
|
+
- Create response/error messages
|
|
10
|
+
- Validate message structure
|
|
11
|
+
- Handle message batching
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import json
|
|
15
|
+
import logging
|
|
16
|
+
from typing import Optional, Any, Dict, List, Union
|
|
17
|
+
|
|
18
|
+
from .schema import (
|
|
19
|
+
MCPMessage,
|
|
20
|
+
MCPError,
|
|
21
|
+
MCPErrorCode,
|
|
22
|
+
MCPTool,
|
|
23
|
+
MCPResource,
|
|
24
|
+
MCPToolResult,
|
|
25
|
+
MCPServerCapabilities,
|
|
26
|
+
MCPServerInfo,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
logger = logging.getLogger(__name__)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class MCPProtocolError(Exception):
|
|
34
|
+
"""Exception raised for protocol-level errors."""
|
|
35
|
+
def __init__(self, code: int, message: str, data: Any = None):
|
|
36
|
+
super().__init__(message)
|
|
37
|
+
self.code = code
|
|
38
|
+
self.message = message
|
|
39
|
+
self.data = data
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class MCPProtocol:
|
|
43
|
+
"""
|
|
44
|
+
MCP Protocol handler for JSON-RPC 2.0 communication.
|
|
45
|
+
|
|
46
|
+
Provides static methods for message parsing, creation, and validation.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
# Protocol version
|
|
50
|
+
JSONRPC_VERSION = "2.0"
|
|
51
|
+
MCP_PROTOCOL_VERSION = "2024-11-05"
|
|
52
|
+
|
|
53
|
+
@staticmethod
|
|
54
|
+
def parse(data: str) -> MCPMessage:
|
|
55
|
+
"""
|
|
56
|
+
Parse a JSON-RPC message from string.
|
|
57
|
+
|
|
58
|
+
Args:
|
|
59
|
+
data: JSON string to parse
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
MCPMessage object
|
|
63
|
+
|
|
64
|
+
Raises:
|
|
65
|
+
MCPProtocolError: If parsing fails or message is invalid
|
|
66
|
+
"""
|
|
67
|
+
try:
|
|
68
|
+
obj = json.loads(data)
|
|
69
|
+
except json.JSONDecodeError as e:
|
|
70
|
+
raise MCPProtocolError(
|
|
71
|
+
MCPErrorCode.PARSE_ERROR,
|
|
72
|
+
f"Invalid JSON: {str(e)}"
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
# Validate basic structure
|
|
76
|
+
if not isinstance(obj, dict):
|
|
77
|
+
raise MCPProtocolError(
|
|
78
|
+
MCPErrorCode.INVALID_REQUEST,
|
|
79
|
+
"Message must be a JSON object"
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
# Check JSON-RPC version
|
|
83
|
+
if obj.get("jsonrpc") != MCPProtocol.JSONRPC_VERSION:
|
|
84
|
+
raise MCPProtocolError(
|
|
85
|
+
MCPErrorCode.INVALID_REQUEST,
|
|
86
|
+
f"Invalid JSON-RPC version: {obj.get('jsonrpc')}"
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
return MCPMessage.from_dict(obj)
|
|
90
|
+
|
|
91
|
+
@staticmethod
|
|
92
|
+
def serialize(msg: MCPMessage) -> str:
|
|
93
|
+
"""
|
|
94
|
+
Serialize an MCPMessage to JSON string.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
msg: MCPMessage to serialize
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
JSON string
|
|
101
|
+
"""
|
|
102
|
+
return msg.to_json()
|
|
103
|
+
|
|
104
|
+
@staticmethod
|
|
105
|
+
def create_response(id: int, result: Any) -> MCPMessage:
|
|
106
|
+
"""
|
|
107
|
+
Create a success response message.
|
|
108
|
+
|
|
109
|
+
Args:
|
|
110
|
+
id: Request ID to respond to
|
|
111
|
+
result: Result data
|
|
112
|
+
|
|
113
|
+
Returns:
|
|
114
|
+
MCPMessage response
|
|
115
|
+
"""
|
|
116
|
+
return MCPMessage(id=id, result=result)
|
|
117
|
+
|
|
118
|
+
@staticmethod
|
|
119
|
+
def create_error(id: Optional[int], code: int, message: str, data: Any = None) -> MCPMessage:
|
|
120
|
+
"""
|
|
121
|
+
Create an error response message.
|
|
122
|
+
|
|
123
|
+
Args:
|
|
124
|
+
id: Request ID (can be None for parse errors)
|
|
125
|
+
code: Error code
|
|
126
|
+
message: Error message
|
|
127
|
+
data: Optional additional error data
|
|
128
|
+
|
|
129
|
+
Returns:
|
|
130
|
+
MCPMessage error response
|
|
131
|
+
"""
|
|
132
|
+
return MCPMessage(
|
|
133
|
+
id=id,
|
|
134
|
+
error=MCPError(code=code, message=message, data=data)
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
@staticmethod
|
|
138
|
+
def create_notification(method: str, params: Optional[Dict] = None) -> MCPMessage:
|
|
139
|
+
"""
|
|
140
|
+
Create a notification message (no response expected).
|
|
141
|
+
|
|
142
|
+
Args:
|
|
143
|
+
method: Method name
|
|
144
|
+
params: Optional parameters
|
|
145
|
+
|
|
146
|
+
Returns:
|
|
147
|
+
MCPMessage notification
|
|
148
|
+
"""
|
|
149
|
+
return MCPMessage(method=method, params=params)
|
|
150
|
+
|
|
151
|
+
# =========================================================================
|
|
152
|
+
# MCP-specific response creators
|
|
153
|
+
# =========================================================================
|
|
154
|
+
|
|
155
|
+
@staticmethod
|
|
156
|
+
def create_initialize_response(
|
|
157
|
+
id: int,
|
|
158
|
+
server_info: MCPServerInfo,
|
|
159
|
+
capabilities: MCPServerCapabilities
|
|
160
|
+
) -> MCPMessage:
|
|
161
|
+
"""
|
|
162
|
+
Create response for 'initialize' request.
|
|
163
|
+
|
|
164
|
+
Args:
|
|
165
|
+
id: Request ID
|
|
166
|
+
server_info: Server information
|
|
167
|
+
capabilities: Server capabilities
|
|
168
|
+
|
|
169
|
+
Returns:
|
|
170
|
+
MCPMessage response
|
|
171
|
+
"""
|
|
172
|
+
return MCPProtocol.create_response(id, {
|
|
173
|
+
"protocolVersion": MCPProtocol.MCP_PROTOCOL_VERSION,
|
|
174
|
+
"serverInfo": server_info.to_dict(),
|
|
175
|
+
"capabilities": capabilities.to_dict()
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
@staticmethod
|
|
179
|
+
def create_tools_list_response(id: int, tools: List[MCPTool]) -> MCPMessage:
|
|
180
|
+
"""
|
|
181
|
+
Create response for 'tools/list' request.
|
|
182
|
+
|
|
183
|
+
Args:
|
|
184
|
+
id: Request ID
|
|
185
|
+
tools: List of available tools
|
|
186
|
+
|
|
187
|
+
Returns:
|
|
188
|
+
MCPMessage response
|
|
189
|
+
"""
|
|
190
|
+
return MCPProtocol.create_response(id, {
|
|
191
|
+
"tools": [t.to_dict() for t in tools]
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
@staticmethod
|
|
195
|
+
def create_tools_call_response(id: int, result: MCPToolResult) -> MCPMessage:
|
|
196
|
+
"""
|
|
197
|
+
Create response for 'tools/call' request.
|
|
198
|
+
|
|
199
|
+
Args:
|
|
200
|
+
id: Request ID
|
|
201
|
+
result: Tool execution result
|
|
202
|
+
|
|
203
|
+
Returns:
|
|
204
|
+
MCPMessage response
|
|
205
|
+
"""
|
|
206
|
+
return MCPProtocol.create_response(id, result.to_dict())
|
|
207
|
+
|
|
208
|
+
@staticmethod
|
|
209
|
+
def create_resources_list_response(id: int, resources: List[MCPResource]) -> MCPMessage:
|
|
210
|
+
"""
|
|
211
|
+
Create response for 'resources/list' request.
|
|
212
|
+
|
|
213
|
+
Args:
|
|
214
|
+
id: Request ID
|
|
215
|
+
resources: List of available resources
|
|
216
|
+
|
|
217
|
+
Returns:
|
|
218
|
+
MCPMessage response
|
|
219
|
+
"""
|
|
220
|
+
return MCPProtocol.create_response(id, {
|
|
221
|
+
"resources": [r.to_dict() for r in resources]
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
@staticmethod
|
|
225
|
+
def create_resources_read_response(id: int, contents: List[Dict]) -> MCPMessage:
|
|
226
|
+
"""
|
|
227
|
+
Create response for 'resources/read' request.
|
|
228
|
+
|
|
229
|
+
Args:
|
|
230
|
+
id: Request ID
|
|
231
|
+
contents: List of resource contents
|
|
232
|
+
|
|
233
|
+
Returns:
|
|
234
|
+
MCPMessage response
|
|
235
|
+
"""
|
|
236
|
+
return MCPProtocol.create_response(id, {
|
|
237
|
+
"contents": contents
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
# =========================================================================
|
|
241
|
+
# Error response helpers
|
|
242
|
+
# =========================================================================
|
|
243
|
+
|
|
244
|
+
@staticmethod
|
|
245
|
+
def method_not_found(id: int, method: str) -> MCPMessage:
|
|
246
|
+
"""Create METHOD_NOT_FOUND error response."""
|
|
247
|
+
return MCPProtocol.create_error(
|
|
248
|
+
id,
|
|
249
|
+
MCPErrorCode.METHOD_NOT_FOUND,
|
|
250
|
+
f"Method not found: {method}"
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
@staticmethod
|
|
254
|
+
def invalid_params(id: int, message: str) -> MCPMessage:
|
|
255
|
+
"""Create INVALID_PARAMS error response."""
|
|
256
|
+
return MCPProtocol.create_error(
|
|
257
|
+
id,
|
|
258
|
+
MCPErrorCode.INVALID_PARAMS,
|
|
259
|
+
message
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
@staticmethod
|
|
263
|
+
def tool_not_found(id: int, tool_name: str) -> MCPMessage:
|
|
264
|
+
"""Create TOOL_NOT_FOUND error response."""
|
|
265
|
+
return MCPProtocol.create_error(
|
|
266
|
+
id,
|
|
267
|
+
MCPErrorCode.TOOL_NOT_FOUND,
|
|
268
|
+
f"Tool not found: {tool_name}"
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
@staticmethod
|
|
272
|
+
def resource_not_found(id: int, uri: str) -> MCPMessage:
|
|
273
|
+
"""Create RESOURCE_NOT_FOUND error response."""
|
|
274
|
+
return MCPProtocol.create_error(
|
|
275
|
+
id,
|
|
276
|
+
MCPErrorCode.RESOURCE_NOT_FOUND,
|
|
277
|
+
f"Resource not found: {uri}"
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
@staticmethod
|
|
281
|
+
def internal_error(id: Optional[int], message: str) -> MCPMessage:
|
|
282
|
+
"""Create INTERNAL_ERROR error response."""
|
|
283
|
+
return MCPProtocol.create_error(
|
|
284
|
+
id,
|
|
285
|
+
MCPErrorCode.INTERNAL_ERROR,
|
|
286
|
+
message
|
|
287
|
+
)
|
|
288
|
+
|
|
@@ -0,0 +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
|
+
|