clarifai 11.4.1__py3-none-any.whl → 11.4.3__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.
- clarifai/__init__.py +1 -1
- clarifai/cli/base.py +7 -0
- clarifai/cli/model.py +6 -8
- clarifai/client/app.py +2 -1
- clarifai/client/auth/helper.py +6 -4
- clarifai/client/compute_cluster.py +2 -1
- clarifai/client/dataset.py +8 -1
- clarifai/client/deployment.py +2 -1
- clarifai/client/input.py +2 -1
- clarifai/client/model.py +2 -1
- clarifai/client/model_client.py +1 -1
- clarifai/client/module.py +2 -1
- clarifai/client/nodepool.py +2 -1
- clarifai/client/runner.py +2 -1
- clarifai/client/search.py +2 -1
- clarifai/client/user.py +2 -1
- clarifai/client/workflow.py +2 -1
- clarifai/runners/models/mcp_class.py +114 -0
- clarifai/runners/models/model_builder.py +179 -46
- clarifai/runners/models/model_class.py +5 -22
- clarifai/runners/models/model_run_locally.py +0 -4
- clarifai/runners/models/visual_classifier_class.py +75 -0
- clarifai/runners/models/visual_detector_class.py +79 -0
- clarifai/runners/utils/code_script.py +75 -44
- clarifai/runners/utils/const.py +15 -0
- clarifai/runners/utils/data_types/data_types.py +48 -0
- clarifai/runners/utils/data_utils.py +99 -45
- clarifai/runners/utils/loader.py +23 -2
- clarifai/runners/utils/method_signatures.py +4 -4
- clarifai/runners/utils/openai_convertor.py +103 -0
- clarifai/urls/helper.py +80 -12
- clarifai/utils/config.py +19 -0
- clarifai/utils/constants.py +4 -0
- clarifai/utils/logging.py +22 -5
- {clarifai-11.4.1.dist-info → clarifai-11.4.3.dist-info}/METADATA +1 -2
- {clarifai-11.4.1.dist-info → clarifai-11.4.3.dist-info}/RECORD +40 -37
- {clarifai-11.4.1.dist-info → clarifai-11.4.3.dist-info}/WHEEL +1 -1
- {clarifai-11.4.1.dist-info → clarifai-11.4.3.dist-info}/entry_points.txt +0 -0
- {clarifai-11.4.1.dist-info → clarifai-11.4.3.dist-info}/licenses/LICENSE +0 -0
- {clarifai-11.4.1.dist-info → clarifai-11.4.3.dist-info}/top_level.txt +0 -0
clarifai/__init__.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = "11.4.
|
1
|
+
__version__ = "11.4.3"
|
clarifai/cli/base.py
CHANGED
@@ -143,6 +143,13 @@ def dump(ctx_obj, output_format):
|
|
143
143
|
json.dump(ctx_obj.to_dict(), sys.stdout, indent=2)
|
144
144
|
|
145
145
|
|
146
|
+
@config.command(['cat'])
|
147
|
+
@click.pass_obj
|
148
|
+
def env(ctx_obj):
|
149
|
+
"""Print env vars. Use: eval "$(clarifai config env)" """
|
150
|
+
ctx_obj.current.print_env_vars()
|
151
|
+
|
152
|
+
|
146
153
|
@cli.command()
|
147
154
|
@click.argument('api_url', default="https://api.clarifai.com")
|
148
155
|
@click.option('--user_id', required=False, help='User ID')
|
clarifai/cli/model.py
CHANGED
@@ -504,6 +504,10 @@ def local_dev(ctx, model_path):
|
|
504
504
|
|
505
505
|
logger.info(f"Current deployment_id: {deployment_id}")
|
506
506
|
|
507
|
+
logger.info(
|
508
|
+
f"Full url for the model: /users/{user_id}/apps/{app_id}/models/{model.id}/versions/{version.id}"
|
509
|
+
)
|
510
|
+
|
507
511
|
# Now that we have all the context in ctx.obj, we need to update the config.yaml in
|
508
512
|
# the model_path directory with the model object containing user_id, app_id, model_id, version_id
|
509
513
|
config_file = os.path.join(model_path, 'config.yaml')
|
@@ -526,13 +530,9 @@ def local_dev(ctx, model_path):
|
|
526
530
|
ModelBuilder._backup_config(config_file)
|
527
531
|
ModelBuilder._save_config(config_file, config)
|
528
532
|
|
529
|
-
# client_model = Model(
|
530
|
-
# TODO: once we can generate_client_script from ModelBuilder or similar
|
531
|
-
# we should be able to put the exact function call in place.
|
532
|
-
# model_script = model.generate_client_script()
|
533
|
-
|
534
533
|
builder = ModelBuilder(model_path, download_validation_only=True)
|
535
|
-
|
534
|
+
# don't mock for local dev since you need the dependencies to run the code anyways.
|
535
|
+
method_signatures = builder.get_method_signatures(mocking=False)
|
536
536
|
|
537
537
|
from clarifai.runners.utils import code_script
|
538
538
|
|
@@ -546,8 +546,6 @@ def local_dev(ctx, model_path):
|
|
546
546
|
base_url=ctx.obj.current.api_base,
|
547
547
|
)
|
548
548
|
|
549
|
-
# TODO: put in the ClarifaiUrlHelper to create the model url.
|
550
|
-
|
551
549
|
logger.info("""\n
|
552
550
|
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
553
551
|
# About to start up the local dev runner in this terminal...
|
clarifai/client/app.py
CHANGED
@@ -19,6 +19,7 @@ from clarifai.client.workflow import Workflow
|
|
19
19
|
from clarifai.constants.model import TRAINABLE_MODEL_TYPES
|
20
20
|
from clarifai.errors import UserError
|
21
21
|
from clarifai.urls.helper import ClarifaiUrlHelper
|
22
|
+
from clarifai.utils.constants import DEFAULT_BASE
|
22
23
|
from clarifai.utils.logging import display_concept_relations_tree, display_workflow_tree, logger
|
23
24
|
from clarifai.utils.misc import concept_relations_accumulation
|
24
25
|
from clarifai.workflows.utils import get_yaml_output_info_proto, is_same_yaml_model
|
@@ -33,7 +34,7 @@ class App(Lister, BaseClient):
|
|
33
34
|
url: str = None,
|
34
35
|
app_id: str = None,
|
35
36
|
user_id: str = None,
|
36
|
-
base_url: str =
|
37
|
+
base_url: str = DEFAULT_BASE,
|
37
38
|
pat: str = None,
|
38
39
|
token: str = None,
|
39
40
|
root_certificates_path: str = None,
|
clarifai/client/auth/helper.py
CHANGED
@@ -7,10 +7,12 @@ from clarifai_grpc.channel.clarifai_channel import ClarifaiChannel
|
|
7
7
|
from clarifai_grpc.grpc.api import resources_pb2, service_pb2_grpc
|
8
8
|
|
9
9
|
from clarifai import __version__
|
10
|
-
from clarifai.utils.constants import
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
from clarifai.utils.constants import (
|
11
|
+
CLARIFAI_PAT_ENV_VAR,
|
12
|
+
CLARIFAI_SESSION_TOKEN_ENV_VAR,
|
13
|
+
DEFAULT_BASE,
|
14
|
+
DEFAULT_UI,
|
15
|
+
)
|
14
16
|
|
15
17
|
REQUEST_ID_PREFIX_HEADER = "x-clarifai-request-id-prefix"
|
16
18
|
REQUEST_ID_PREFIX = f"sdk-python-{__version__}"
|
@@ -10,6 +10,7 @@ from clarifai.client.base import BaseClient
|
|
10
10
|
from clarifai.client.lister import Lister
|
11
11
|
from clarifai.client.nodepool import Nodepool
|
12
12
|
from clarifai.errors import UserError
|
13
|
+
from clarifai.utils.constants import DEFAULT_BASE
|
13
14
|
from clarifai.utils.logging import logger
|
14
15
|
|
15
16
|
|
@@ -20,7 +21,7 @@ class ComputeCluster(Lister, BaseClient):
|
|
20
21
|
self,
|
21
22
|
compute_cluster_id: str = None,
|
22
23
|
user_id: str = None,
|
23
|
-
base_url: str =
|
24
|
+
base_url: str = DEFAULT_BASE,
|
24
25
|
pat: str = None,
|
25
26
|
token: str = None,
|
26
27
|
root_certificates_path: str = None,
|
clarifai/client/dataset.py
CHANGED
@@ -45,6 +45,7 @@ ClarifaiDatasetType = TypeVar(
|
|
45
45
|
VisualSegmentationDataset,
|
46
46
|
TextClassificationDataset,
|
47
47
|
)
|
48
|
+
from clarifai.utils.constants import DEFAULT_BASE
|
48
49
|
|
49
50
|
|
50
51
|
class Dataset(Lister, BaseClient):
|
@@ -55,7 +56,7 @@ class Dataset(Lister, BaseClient):
|
|
55
56
|
url: str = None,
|
56
57
|
dataset_id: str = None,
|
57
58
|
dataset_version_id: str = None,
|
58
|
-
base_url: str =
|
59
|
+
base_url: str = DEFAULT_BASE,
|
59
60
|
pat: str = None,
|
60
61
|
token: str = None,
|
61
62
|
root_certificates_path: str = None,
|
@@ -685,6 +686,12 @@ class Dataset(Lister, BaseClient):
|
|
685
686
|
Note:
|
686
687
|
This is a beta feature and is subject to change.
|
687
688
|
"""
|
689
|
+
try:
|
690
|
+
import rich # noqa: F401
|
691
|
+
except ImportError:
|
692
|
+
raise UserError(
|
693
|
+
"Rich library is not installed. Please install it using pip install rich>=13.4.2"
|
694
|
+
)
|
688
695
|
self.logger.info("Getting dataset upload status...")
|
689
696
|
dataset_version_id = uuid.uuid4().hex
|
690
697
|
_ = self.create_version(id=dataset_version_id, description="SDK Upload Status")
|
clarifai/client/deployment.py
CHANGED
@@ -2,6 +2,7 @@ from clarifai_grpc.grpc.api import resources_pb2
|
|
2
2
|
|
3
3
|
from clarifai.client.base import BaseClient
|
4
4
|
from clarifai.client.lister import Lister
|
5
|
+
from clarifai.utils.constants import DEFAULT_BASE
|
5
6
|
from clarifai.utils.logging import logger
|
6
7
|
from clarifai.utils.protobuf import dict_to_protobuf
|
7
8
|
|
@@ -13,7 +14,7 @@ class Deployment(Lister, BaseClient):
|
|
13
14
|
self,
|
14
15
|
deployment_id: str = None,
|
15
16
|
user_id: str = None,
|
16
|
-
base_url: str =
|
17
|
+
base_url: str = DEFAULT_BASE,
|
17
18
|
pat: str = None,
|
18
19
|
token: str = None,
|
19
20
|
root_certificates_path: str = None,
|
clarifai/client/input.py
CHANGED
@@ -21,6 +21,7 @@ from clarifai.client.lister import Lister
|
|
21
21
|
from clarifai.constants.dataset import MAX_RETRIES
|
22
22
|
from clarifai.constants.input import MAX_UPLOAD_BATCH_SIZE
|
23
23
|
from clarifai.errors import UserError
|
24
|
+
from clarifai.utils.constants import DEFAULT_BASE
|
24
25
|
from clarifai.utils.logging import logger
|
25
26
|
from clarifai.utils.misc import BackoffIterator, Chunker, clean_input_id
|
26
27
|
|
@@ -33,7 +34,7 @@ class Inputs(Lister, BaseClient):
|
|
33
34
|
user_id: str = None,
|
34
35
|
app_id: str = None,
|
35
36
|
logger_level: str = "INFO",
|
36
|
-
base_url: str =
|
37
|
+
base_url: str = DEFAULT_BASE,
|
37
38
|
pat: str = None,
|
38
39
|
token: str = None,
|
39
40
|
root_certificates_path: str = None,
|
clarifai/client/model.py
CHANGED
@@ -34,6 +34,7 @@ from clarifai.constants.model import (
|
|
34
34
|
)
|
35
35
|
from clarifai.errors import UserError
|
36
36
|
from clarifai.urls.helper import ClarifaiUrlHelper
|
37
|
+
from clarifai.utils.constants import DEFAULT_BASE
|
37
38
|
from clarifai.utils.logging import logger
|
38
39
|
from clarifai.utils.misc import BackoffIterator
|
39
40
|
from clarifai.utils.model_train import (
|
@@ -58,7 +59,7 @@ class Model(Lister, BaseClient):
|
|
58
59
|
url: str = None,
|
59
60
|
model_id: str = None,
|
60
61
|
model_version: Dict = {'id': ""},
|
61
|
-
base_url: str =
|
62
|
+
base_url: str = DEFAULT_BASE,
|
62
63
|
pat: str = None,
|
63
64
|
token: str = None,
|
64
65
|
root_certificates_path: str = None,
|
clarifai/client/model_client.py
CHANGED
@@ -8,7 +8,6 @@ from clarifai_grpc.grpc.api.status import status_code_pb2
|
|
8
8
|
from clarifai.constants.model import MAX_MODEL_PREDICT_INPUTS
|
9
9
|
from clarifai.errors import UserError
|
10
10
|
from clarifai.runners.utils import code_script, method_signatures
|
11
|
-
from clarifai.runners.utils.data_utils import is_openai_chat_format
|
12
11
|
from clarifai.runners.utils.method_signatures import (
|
13
12
|
CompatibilitySerializer,
|
14
13
|
deserialize,
|
@@ -16,6 +15,7 @@ from clarifai.runners.utils.method_signatures import (
|
|
16
15
|
serialize,
|
17
16
|
signatures_from_json,
|
18
17
|
)
|
18
|
+
from clarifai.runners.utils.openai_convertor import is_openai_chat_format
|
19
19
|
from clarifai.utils.logging import logger
|
20
20
|
from clarifai.utils.misc import BackoffIterator, status_is_retryable
|
21
21
|
|
clarifai/client/module.py
CHANGED
@@ -6,6 +6,7 @@ from clarifai.client.base import BaseClient
|
|
6
6
|
from clarifai.client.lister import Lister
|
7
7
|
from clarifai.errors import UserError
|
8
8
|
from clarifai.urls.helper import ClarifaiUrlHelper
|
9
|
+
from clarifai.utils.constants import DEFAULT_BASE
|
9
10
|
from clarifai.utils.logging import logger
|
10
11
|
|
11
12
|
|
@@ -17,7 +18,7 @@ class Module(Lister, BaseClient):
|
|
17
18
|
url: str = None,
|
18
19
|
module_id: str = None,
|
19
20
|
module_version: Dict = {'id': ""},
|
20
|
-
base_url: str =
|
21
|
+
base_url: str = DEFAULT_BASE,
|
21
22
|
pat: str = None,
|
22
23
|
token: str = None,
|
23
24
|
root_certificates_path: str = None,
|
clarifai/client/nodepool.py
CHANGED
@@ -11,6 +11,7 @@ from clarifai.client.deployment import Deployment
|
|
11
11
|
from clarifai.client.lister import Lister
|
12
12
|
from clarifai.client.runner import Runner
|
13
13
|
from clarifai.errors import UserError
|
14
|
+
from clarifai.utils.constants import DEFAULT_BASE
|
14
15
|
from clarifai.utils.logging import logger
|
15
16
|
|
16
17
|
|
@@ -21,7 +22,7 @@ class Nodepool(Lister, BaseClient):
|
|
21
22
|
self,
|
22
23
|
nodepool_id: str = None,
|
23
24
|
user_id: str = None,
|
24
|
-
base_url: str =
|
25
|
+
base_url: str = DEFAULT_BASE,
|
25
26
|
pat: str = None,
|
26
27
|
token: str = None,
|
27
28
|
root_certificates_path: str = None,
|
clarifai/client/runner.py
CHANGED
@@ -2,6 +2,7 @@ from clarifai_grpc.grpc.api import resources_pb2
|
|
2
2
|
|
3
3
|
from clarifai.client.base import BaseClient
|
4
4
|
from clarifai.client.lister import Lister
|
5
|
+
from clarifai.utils.constants import DEFAULT_BASE
|
5
6
|
from clarifai.utils.logging import logger
|
6
7
|
from clarifai.utils.protobuf import dict_to_protobuf
|
7
8
|
|
@@ -13,7 +14,7 @@ class Runner(Lister, BaseClient):
|
|
13
14
|
self,
|
14
15
|
runner_id: str = None,
|
15
16
|
user_id: str = None,
|
16
|
-
base_url: str =
|
17
|
+
base_url: str = DEFAULT_BASE,
|
17
18
|
pat: str = None,
|
18
19
|
token: str = None,
|
19
20
|
root_certificates_path: str = None,
|
clarifai/client/search.py
CHANGED
@@ -17,6 +17,7 @@ from clarifai.constants.search import (
|
|
17
17
|
)
|
18
18
|
from clarifai.errors import UserError
|
19
19
|
from clarifai.schema.search import get_schema
|
20
|
+
from clarifai.utils.constants import DEFAULT_BASE
|
20
21
|
|
21
22
|
|
22
23
|
class Search(Lister, BaseClient):
|
@@ -28,7 +29,7 @@ class Search(Lister, BaseClient):
|
|
28
29
|
metric: str = DEFAULT_SEARCH_METRIC,
|
29
30
|
algorithm: str = DEFAULT_SEARCH_ALGORITHM,
|
30
31
|
pagination: bool = False,
|
31
|
-
base_url: str =
|
32
|
+
base_url: str = DEFAULT_BASE,
|
32
33
|
pat: str = None,
|
33
34
|
token: str = None,
|
34
35
|
root_certificates_path: str = None,
|
clarifai/client/user.py
CHANGED
@@ -12,6 +12,7 @@ from clarifai.client.base import BaseClient
|
|
12
12
|
from clarifai.client.compute_cluster import ComputeCluster
|
13
13
|
from clarifai.client.lister import Lister
|
14
14
|
from clarifai.errors import UserError
|
15
|
+
from clarifai.utils.constants import DEFAULT_BASE
|
15
16
|
from clarifai.utils.logging import logger
|
16
17
|
|
17
18
|
|
@@ -21,7 +22,7 @@ class User(Lister, BaseClient):
|
|
21
22
|
def __init__(
|
22
23
|
self,
|
23
24
|
user_id: str = None,
|
24
|
-
base_url: str =
|
25
|
+
base_url: str = DEFAULT_BASE,
|
25
26
|
pat: str = None,
|
26
27
|
token: str = None,
|
27
28
|
root_certificates_path: str = None,
|
clarifai/client/workflow.py
CHANGED
@@ -14,6 +14,7 @@ from clarifai.client.model import Model
|
|
14
14
|
from clarifai.constants.workflow import MAX_WORKFLOW_PREDICT_INPUTS
|
15
15
|
from clarifai.errors import UserError
|
16
16
|
from clarifai.urls.helper import ClarifaiUrlHelper
|
17
|
+
from clarifai.utils.constants import DEFAULT_BASE
|
17
18
|
from clarifai.utils.logging import logger
|
18
19
|
from clarifai.utils.misc import BackoffIterator, status_is_retryable
|
19
20
|
from clarifai.workflows.export import Exporter
|
@@ -28,7 +29,7 @@ class Workflow(Lister, BaseClient):
|
|
28
29
|
workflow_id: str = None,
|
29
30
|
workflow_version: Dict = {'id': ""},
|
30
31
|
output_config: Dict = {'min_value': 0},
|
31
|
-
base_url: str =
|
32
|
+
base_url: str = DEFAULT_BASE,
|
32
33
|
pat: str = None,
|
33
34
|
token: str = None,
|
34
35
|
root_certificates_path: str = None,
|
@@ -0,0 +1,114 @@
|
|
1
|
+
"""Base class for creating Model Context Protocol (MCP) servers."""
|
2
|
+
|
3
|
+
import asyncio
|
4
|
+
import json
|
5
|
+
from typing import Any
|
6
|
+
|
7
|
+
from fastmcp import Client, FastMCP # use fastmcp v2 not the built in mcp
|
8
|
+
from mcp import types
|
9
|
+
from mcp.shared.exceptions import McpError
|
10
|
+
|
11
|
+
from clarifai.runners.models.model_class import ModelClass
|
12
|
+
|
13
|
+
|
14
|
+
class MCPModelClass(ModelClass):
|
15
|
+
"""Base class for wrapping FastMCP servers as a model running in Clarfai. This handles
|
16
|
+
all the transport between the API and the MCP server here. Simply subclass this and implement
|
17
|
+
the get_server() method to return the FastMCP server instance. The server is then used to
|
18
|
+
handle all the requests and responses.
|
19
|
+
"""
|
20
|
+
|
21
|
+
def load_model(self):
|
22
|
+
# in memory transport provided in fastmcp v2 so we can easily use the client functions.
|
23
|
+
self.client = Client(self.get_server())
|
24
|
+
|
25
|
+
def get_server(self) -> FastMCP:
|
26
|
+
"""Required method for each subclass to implement to return the FastMCP server to use."""
|
27
|
+
raise NotImplementedError("Subclasses must implement get_server() method")
|
28
|
+
|
29
|
+
@ModelClass.method
|
30
|
+
def mcp_transport(self, msg: str) -> str:
|
31
|
+
"""The single model method to get the jsonrpc message and send it to the FastMCP server then
|
32
|
+
return it's response.
|
33
|
+
|
34
|
+
"""
|
35
|
+
|
36
|
+
async def send_notification(client_message: types.ClientNotification) -> None:
|
37
|
+
async with self.client:
|
38
|
+
# Strip the jsonrpc field since send_notification will also pass it in for some reason.
|
39
|
+
client_message = types.ClientNotification.model_validate(
|
40
|
+
client_message.model_dump(
|
41
|
+
by_alias=True, mode="json", exclude_none=True, exclude={"jsonrpc"}
|
42
|
+
)
|
43
|
+
)
|
44
|
+
try:
|
45
|
+
return await self.client.session.send_notification(client_message)
|
46
|
+
except McpError as e:
|
47
|
+
return types.JSONRPCError(jsonrpc="2.0", error=e.error)
|
48
|
+
|
49
|
+
async def send_request(client_message: types.ClientRequest, id: str) -> Any:
|
50
|
+
async with self.client:
|
51
|
+
# Strip the jsonrpc and id fields as send_request sets them again too.
|
52
|
+
client_message = types.ClientRequest.model_validate(
|
53
|
+
client_message.model_dump(
|
54
|
+
by_alias=True, mode="json", exclude_none=True, exclude={"jsonrpc", "id"}
|
55
|
+
)
|
56
|
+
)
|
57
|
+
|
58
|
+
result_type = None
|
59
|
+
if isinstance(client_message.root, types.PingRequest):
|
60
|
+
result_type = types.EmptyResult
|
61
|
+
elif isinstance(client_message.root, types.InitializeRequest):
|
62
|
+
return await self.client.session.initialize()
|
63
|
+
elif isinstance(client_message.root, types.SetLevelRequest):
|
64
|
+
result_type = types.EmptyResult
|
65
|
+
elif isinstance(client_message.root, types.ListResourcesRequest):
|
66
|
+
result_type = types.ListResourcesResult
|
67
|
+
elif isinstance(client_message.root, types.ListResourceTemplatesRequest):
|
68
|
+
result_type = types.ListResourceTemplatesResult
|
69
|
+
elif isinstance(client_message.root, types.ReadResourceRequest):
|
70
|
+
result_type = types.ReadResourceResult
|
71
|
+
elif isinstance(client_message.root, types.SubscribeRequest):
|
72
|
+
result_type = types.EmptyResult
|
73
|
+
elif isinstance(client_message.root, types.UnsubscribeRequest):
|
74
|
+
result_type = types.EmptyResult
|
75
|
+
elif isinstance(client_message.root, types.ListPromptsRequest):
|
76
|
+
result_type = types.ListPromptsResult
|
77
|
+
elif isinstance(client_message.root, types.GetPromptRequest):
|
78
|
+
result_type = types.GetPromptResult
|
79
|
+
elif isinstance(client_message.root, types.CompleteRequest):
|
80
|
+
result_type = types.CompleteResult
|
81
|
+
elif isinstance(client_message.root, types.ListToolsRequest):
|
82
|
+
result_type = types.ListToolsResult
|
83
|
+
elif isinstance(client_message.root, types.CallToolRequest):
|
84
|
+
result_type = types.CallToolResult
|
85
|
+
else:
|
86
|
+
# this is a special case where we need to return the list of tools.
|
87
|
+
raise NotImplementedError(f"Method {client_message.method} not implemented")
|
88
|
+
# Call the mcp server using send_request() or send_notification() depending on the method.
|
89
|
+
try:
|
90
|
+
return await self.client.session.send_request(client_message, result_type)
|
91
|
+
except McpError as e:
|
92
|
+
return types.JSONRPCError(jsonrpc="2.0", id=id, error=e.error)
|
93
|
+
|
94
|
+
# The message coming here is the generic request. We look at it's .method
|
95
|
+
# to determine which client function to call and to further subparse the params.
|
96
|
+
# Note(zeiler): unfortunately the pydantic types in mcp/types.py are not consistent.
|
97
|
+
# The JSONRPCRequest are supposed to have an id but the InitializeRequest
|
98
|
+
# does not have it.
|
99
|
+
d = json.loads(msg)
|
100
|
+
id = d.get('id', "")
|
101
|
+
|
102
|
+
# If we have an id it's a JSONRPCRequest
|
103
|
+
if not d.get('method', '').startswith("notifications/"):
|
104
|
+
client_message = types.ClientRequest.model_validate(d)
|
105
|
+
response = asyncio.run(send_request(client_message, id=id))
|
106
|
+
else: # JSONRPCRequest
|
107
|
+
client_message = types.ClientNotification.model_validate(d)
|
108
|
+
response = asyncio.run(send_notification(client_message))
|
109
|
+
if response is None:
|
110
|
+
response = types.JSONRPCError(
|
111
|
+
jsonrpc="2.0", id=id, error="Got empty response from MCP server."
|
112
|
+
)
|
113
|
+
# return as a serialized json string
|
114
|
+
return response.model_dump_json(by_alias=True, exclude_none=True)
|