libentry 1.24.9__py3-none-any.whl → 1.25.1__py3-none-any.whl

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.
libentry/mcp/client.py CHANGED
@@ -9,7 +9,7 @@ from threading import Semaphore, Thread
9
9
  from time import sleep
10
10
  from types import GeneratorType
11
11
  from typing import Any, Dict, Iterable, List, Optional, Tuple, Type, Union
12
- from urllib.parse import urlencode, urljoin
12
+ from urllib.parse import urlencode
13
13
 
14
14
  import httpx
15
15
  from pydantic import BaseModel, TypeAdapter
@@ -371,7 +371,7 @@ class APIClient(SubroutineMixIn, MCPMixIn):
371
371
  raise err
372
372
 
373
373
  def _http_request(self, request: HTTPRequest, timeout: float) -> HTTPResponse:
374
- full_url = urljoin(self.base_url, request.path)
374
+ full_url = self.base_url.rstrip("/") + "/" + request.path.lstrip("/")
375
375
  headers = (
376
376
  {**self.headers}
377
377
  if request.options.headers is None else
libentry/mcp/service.py CHANGED
@@ -10,10 +10,10 @@ from dataclasses import dataclass
10
10
  from queue import Empty, Queue
11
11
  from threading import Lock
12
12
  from types import GeneratorType
13
- from typing import Any, Callable, Dict, Generator, Iterable, List, Optional, Type, Union
13
+ from typing import Any, Callable, Dict, Generator, Iterable, List, Literal, Optional, Tuple, Type, Union
14
14
 
15
15
  from flask import Flask, request as flask_request
16
- from pydantic import BaseModel, TypeAdapter
16
+ from pydantic import BaseModel, Field, TypeAdapter
17
17
 
18
18
  from libentry import json, logger
19
19
  from libentry.mcp import api
@@ -21,8 +21,8 @@ from libentry.mcp.api import APIInfo, list_api_info
21
21
  from libentry.mcp.types import BlobResourceContents, CallToolRequestParams, CallToolResult, Implementation, \
22
22
  InitializeRequestParams, InitializeResult, JSONRPCError, JSONRPCNotification, JSONRPCRequest, JSONRPCResponse, \
23
23
  ListResourcesResult, ListToolsResult, MIME, ReadResourceRequestParams, ReadResourceResult, Resource, SSE, \
24
- ServerCapabilities, SubroutineError, SubroutineResponse, TextContent, TextResourceContents, Tool, ToolProperty, \
25
- ToolSchema, ToolsCapability
24
+ ServerCapabilities, SubroutineError, SubroutineResponse, TextContent, TextResourceContents, Tool, ToolSchema, \
25
+ ToolsCapability
26
26
  from libentry.schema import APISignature, get_api_signature, query_api
27
27
 
28
28
  try:
@@ -805,9 +805,11 @@ class FlaskServer(Flask):
805
805
  logger.info("Initializing Flask application.")
806
806
  existing_routes = {}
807
807
 
808
- routes = self._create_routes(self.service)
809
- self.service_routes.update(routes)
810
- existing_routes.update(self.service_routes)
808
+ input_services = self.service if isinstance(self.service, (List, Tuple)) else [self.service]
809
+ for input_service in input_services:
810
+ routes = self._create_routes(input_service)
811
+ self.service_routes.update(routes)
812
+ existing_routes.update(self.service_routes)
811
813
 
812
814
  for builtin_service in self.builtin_services:
813
815
  routes = self._create_routes(builtin_service, existing_routes)
@@ -904,26 +906,116 @@ class GunicornApplication(BaseApplication):
904
906
  return FlaskServer(service)
905
907
 
906
908
 
909
+ class RunServiceConfig(BaseModel):
910
+ """Run service config."""
911
+
912
+ host: str = Field(
913
+ title="Hostname",
914
+ description=(
915
+ "The hostname of the server that runs the service. "
916
+ "IP address or domain name."
917
+ ),
918
+ default="0.0.0.0"
919
+ )
920
+ port: int = Field(
921
+ title="Port number",
922
+ description="The port that the service listened to.",
923
+ )
924
+ num_workers: int = Field(
925
+ title="Number of workers",
926
+ description="The number of workers (processes) to run the service.",
927
+ default=1
928
+ )
929
+ num_threads: int = Field(
930
+ title="Number of threads",
931
+ description="The number of threads for each worker.",
932
+ default=20
933
+ )
934
+ num_connections: Optional[int] = Field(
935
+ title="Max number of connections",
936
+ description="The maximum number of simultaneous clients (or socket connections).",
937
+ default=1024
938
+ )
939
+ backlog: Optional[int] = Field(
940
+ title="The maximum number of pending connections",
941
+ description="The maximum number of pending connections.",
942
+ default=2048
943
+ )
944
+ worker_class: Literal["sync", "gthread", "eventlet", "gevent", "tornado"] = Field(
945
+ title="The type of workers to use",
946
+ description="The type of workers to use.",
947
+ default="gthread"
948
+ )
949
+ timeout: int = Field(
950
+ title="Worker timeout",
951
+ description="Workers silent for more than this many seconds are killed and restarted.",
952
+ default=60
953
+ )
954
+ keyfile: Optional[str] = Field(
955
+ title="SSL key file",
956
+ description="SSL key file.",
957
+ default=None
958
+ )
959
+ keyfile_password: Optional[str] = Field(
960
+ title="SSL key file password",
961
+ description="SSL key file password.",
962
+ default=None
963
+ )
964
+ certfile: Optional[str] = Field(
965
+ title="SSL certificate file",
966
+ description="SSL certificate file.",
967
+ default=None
968
+ )
969
+
970
+
907
971
  def run_service(
908
972
  service_type: Union[Type, Callable],
909
973
  service_config=None,
910
- host: str = "0.0.0.0",
911
- port: int = 8888,
912
- num_workers: int = 1,
913
- num_threads: int = 20,
914
- num_connections: Optional[int] = 1000,
915
- backlog: Optional[int] = 1000,
916
- worker_class: str = "gthread",
917
- timeout: int = 60,
974
+ run_config: Optional[RunServiceConfig] = None,
975
+ *,
976
+ host: Optional[str] = None,
977
+ port: Optional[int] = None,
978
+ num_workers: Optional[int] = None,
979
+ num_threads: Optional[int] = None,
980
+ num_connections: Optional[int] = None,
981
+ backlog: Optional[int] = None,
982
+ worker_class: Optional[str] = None,
983
+ timeout: Optional[int] = None,
918
984
  keyfile: Optional[str] = None,
919
985
  keyfile_password: Optional[str] = None,
920
986
  certfile: Optional[str] = None
921
- ):
987
+ ) -> None:
988
+ kwargs = {}
989
+ if host is not None:
990
+ kwargs["host"] = host
991
+ if port is not None:
992
+ kwargs["port"] = port
993
+ if num_workers is not None:
994
+ kwargs["num_workers"] = num_workers
995
+ if num_threads is not None:
996
+ kwargs["num_threads"] = num_threads
997
+ if num_connections is not None:
998
+ kwargs["num_connections"] = num_connections
999
+ if backlog is not None:
1000
+ kwargs["backlog"] = backlog
1001
+ if worker_class is not None:
1002
+ kwargs["worker_class"] = worker_class
1003
+ if timeout is not None:
1004
+ kwargs["timeout"] = timeout
1005
+ if keyfile is not None:
1006
+ kwargs["keyfile"] = keyfile
1007
+ if keyfile_password is not None:
1008
+ kwargs["keyfile_password"] = keyfile_password
1009
+ if certfile is not None:
1010
+ kwargs["certfile"] = certfile
1011
+
1012
+ if run_config is None:
1013
+ run_config = RunServiceConfig(**kwargs)
1014
+ else:
1015
+ for name, value in kwargs.items():
1016
+ setattr(run_config, name, value)
1017
+
922
1018
  logger.info("Starting gunicorn server.")
923
- if num_connections is None or num_connections < num_threads * 2:
924
- num_connections = num_threads * 2
925
- if backlog is None or backlog < num_threads * 2:
926
- backlog = num_threads * 2
927
1019
 
928
1020
  def ssl_context(config, _default_ssl_context_factory):
929
1021
  import ssl
@@ -931,21 +1023,21 @@ def run_service(
931
1023
  context.load_cert_chain(
932
1024
  certfile=config.certfile,
933
1025
  keyfile=config.keyfile,
934
- password=keyfile_password
1026
+ password=run_config.keyfile_password
935
1027
  )
936
1028
  context.minimum_version = ssl.TLSVersion.TLSv1_3
937
1029
  return context
938
1030
 
939
1031
  options = {
940
- "bind": f"{host}:{port}",
941
- "workers": num_workers,
942
- "threads": num_threads,
943
- "timeout": timeout,
944
- "worker_connections": num_connections,
945
- "backlog": backlog,
946
- "keyfile": keyfile,
947
- "certfile": certfile,
948
- "worker_class": worker_class,
1032
+ "bind": f"{run_config.host}:{run_config.port}",
1033
+ "workers": run_config.num_workers,
1034
+ "threads": run_config.num_threads,
1035
+ "timeout": run_config.timeout,
1036
+ "worker_connections": run_config.num_connections,
1037
+ "backlog": run_config.backlog,
1038
+ "keyfile": run_config.keyfile,
1039
+ "certfile": run_config.certfile,
1040
+ "worker_class": run_config.worker_class,
949
1041
  "ssl_context": ssl_context
950
1042
  }
951
1043
  for name, value in options.items():
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: libentry
3
- Version: 1.24.9
3
+ Version: 1.25.1
4
4
  Summary: Entries for experimental utilities.
5
5
  Home-page: https://github.com/XoriieInpottn/libentry
6
6
  Author: xi
@@ -12,8 +12,8 @@ libentry/test_api.py,sha256=Xw7B7sH6g1iCTV5sFzyBF3JAJzeOr9xg0AyezTNsnIk,4452
12
12
  libentry/utils.py,sha256=O7P6GadtUIjq0N2IZH7PhHZDUM3NebzcqyDqytet7CM,683
13
13
  libentry/mcp/__init__.py,sha256=1oLL20yLB1GL9IbFiZD8OReDqiCpFr-yetIR6x1cNkI,23
14
14
  libentry/mcp/api.py,sha256=GDErVCz_hh_ZeMxLS8bTPyBUhCTHw3Mm-nGFMV2W2yo,3669
15
- libentry/mcp/client.py,sha256=3HmKAsFenPlDk1lfSdXL9GJwfCSU92uQS04zvZGeJfQ,23065
16
- libentry/mcp/service.py,sha256=qA6I9Mi-eudRYwVGhff1_aAImK424bhASlsWaHP8XNI,34971
15
+ libentry/mcp/client.py,sha256=qFbigNIOJvEf8ZICN2K8nnmVcITIzDhJgaw3c0P-WXM,23078
16
+ libentry/mcp/service.py,sha256=PpdQBxqKPiZ2tpnsqDYiC29_yjMjK9J3VWynn4uvpVg,38109
17
17
  libentry/mcp/types.py,sha256=aAoVO4jjqEvDzNneuZapmRYonLLnGsbcLoypVyRNNYg,12389
18
18
  libentry/service/__init__.py,sha256=1oLL20yLB1GL9IbFiZD8OReDqiCpFr-yetIR6x1cNkI,23
19
19
  libentry/service/common.py,sha256=OVaW2afgKA6YqstJmtnprBCqQEUZEWotZ6tHavmJJeU,42
@@ -22,10 +22,10 @@ libentry/service/list.py,sha256=ElHWhTgShGOhaxMUEwVbMXos0NQKjHsODboiQ-3AMwE,1397
22
22
  libentry/service/running.py,sha256=FrPJoJX6wYxcHIysoatAxhW3LajCCm0Gx6l7__6sULQ,5105
23
23
  libentry/service/start.py,sha256=mZT7b9rVULvzy9GTZwxWnciCHgv9dbGN2JbxM60OMn4,1270
24
24
  libentry/service/stop.py,sha256=wOpwZgrEJ7QirntfvibGq-XsTC6b3ELhzRW2zezh-0s,1187
25
- libentry-1.24.9.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
26
- libentry-1.24.9.dist-info/METADATA,sha256=LttWBo7s_rfqrsHN336XQWPOMKeHggHufl2q8i4ieos,1135
27
- libentry-1.24.9.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
28
- libentry-1.24.9.dist-info/entry_points.txt,sha256=1v_nLVDsjvVJp9SWhl4ef2zZrsLTBtFWgrYFgqvQBgc,61
29
- libentry-1.24.9.dist-info/top_level.txt,sha256=u2uF6-X5fn2Erf9PYXOg_6tntPqTpyT-yzUZrltEd6I,9
30
- libentry-1.24.9.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
31
- libentry-1.24.9.dist-info/RECORD,,
25
+ libentry-1.25.1.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
26
+ libentry-1.25.1.dist-info/METADATA,sha256=7HVCqasAkkqvvXhodRtTmaoZTG4FC70Q6CxsgZWnC8U,1135
27
+ libentry-1.25.1.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
28
+ libentry-1.25.1.dist-info/entry_points.txt,sha256=1v_nLVDsjvVJp9SWhl4ef2zZrsLTBtFWgrYFgqvQBgc,61
29
+ libentry-1.25.1.dist-info/top_level.txt,sha256=u2uF6-X5fn2Erf9PYXOg_6tntPqTpyT-yzUZrltEd6I,9
30
+ libentry-1.25.1.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
31
+ libentry-1.25.1.dist-info/RECORD,,