| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134 |
- import json
- import sys
- class McpProtocolHandler:
- protocol_version = '2025-06-18'
- server_name = 'fms-mcp-gateway'
- server_version = '0.1.0'
- def __init__(self, gateway_app):
- self.gateway_app = gateway_app
- self.initialized = False
- def handle_message(self, message):
- if not isinstance(message, dict):
- return self._error_response(None, -32600, 'Invalid Request')
- if 'id' in message:
- return self.handle_request(message)
- method = str(message.get('method') or '').strip()
- if method == 'notifications/initialized':
- self.initialized = True
- return None
- return None
- def handle_request(self, request):
- request_id = request.get('id')
- method = str(request.get('method') or '').strip()
- try:
- if method == 'initialize':
- self.initialized = True
- return self._success_response(
- request_id,
- {
- 'protocolVersion': self.protocol_version,
- 'capabilities': {
- 'tools': {
- 'listChanged': False,
- }
- },
- 'serverInfo': {
- 'name': self.server_name,
- 'version': self.server_version,
- },
- },
- )
- if method == 'tools/list':
- tools = [self._normalize_tool(tool) for tool in self.gateway_app.list_tools()]
- return self._success_response(request_id, {'tools': tools})
- if method == 'tools/call':
- params = request.get('params') or {}
- tool_name = params.get('name')
- arguments = params.get('arguments') or {}
- tool_result = self.gateway_app.call_tool(tool_name, arguments)
- structured_content = tool_result.get('data') or {}
- return self._success_response(
- request_id,
- {
- 'content': [
- {
- 'type': 'text',
- 'text': self._render_text(structured_content),
- }
- ],
- 'structuredContent': structured_content,
- 'isError': False,
- },
- )
- return self._error_response(request_id, -32601, 'Method not found: {0}'.format(method or '<empty>'))
- except Exception as exc:
- if method == 'tools/call':
- return self._success_response(
- request_id,
- {
- 'content': [
- {
- 'type': 'text',
- 'text': str(exc),
- }
- ],
- 'isError': True,
- },
- )
- return self._error_response(request_id, -32000, str(exc))
- def run_stdio(self, stdin=None, stdout=None):
- stdin = stdin or sys.stdin
- stdout = stdout or sys.stdout
- for raw_line in stdin:
- line = str(raw_line).strip()
- if not line:
- continue
- try:
- message = json.loads(line)
- except ValueError:
- response = self._error_response(None, -32700, 'Parse error')
- else:
- response = self.handle_message(message)
- if response is None:
- continue
- stdout.write(json.dumps(response, ensure_ascii=False) + '\n')
- if hasattr(stdout, 'flush'):
- stdout.flush()
- return 0
- def _normalize_tool(self, tool):
- normalized = dict(tool)
- if 'input_schema' in normalized:
- normalized['inputSchema'] = normalized.pop('input_schema')
- return normalized
- @staticmethod
- def _render_text(structured_content):
- if not structured_content:
- return 'ok'
- return json.dumps(structured_content, ensure_ascii=False)
- @staticmethod
- def _success_response(request_id, result):
- return {
- 'jsonrpc': '2.0',
- 'id': request_id,
- 'result': result,
- }
- @staticmethod
- def _error_response(request_id, code, message):
- return {
- 'jsonrpc': '2.0',
- 'id': request_id,
- 'error': {
- 'code': code,
- 'message': message,
- },
- }
|