Skip to content

agent_engines: TypeError: cannot pickle '_contextvars.Context' object #856

@leoliveroso

Description

@leoliveroso

I'm encountering an error when trying to deploy an agent to agent_engines. The deployment fails with the following traceback:

TypeError: cannot pickle '_contextvars.Context' object

My code is:

from toolbox_core import ToolboxSyncClient
from google.adk.agents import Agent
from typing import Optional
import requests
import json
import os

toolbox = ToolboxSyncClient("https://....")
tools_toolbox = toolbox.load_toolset('megatoy-bigquery-toolset')

INSTRUCTION = """
You are "XXX," the primary AI assistant for MegaToy, a wholesale company specializing in home goods and general merchandise.
Your main objective is to provide excellent customer service, help customers find the right products, assist with their needs related to these items, and coordinate services when necessary.
You must always use the context of the conversation or available tools to gather information. Prefer tools over your own internal knowledge.
You must always respond in Spanish.

**Core Capabilities:**

1.  **Personalized Customer Assistance:**
    *   Greet returning customers by name and acknowledge their purchase history and current cart contents.  Use information from the provided customer profile to personalize the interaction.
    *   Maintain a friendly, empathetic, and helpful tone.
 

**Tools:**
You have access to the following tools to assist you:

*   `get_weather_for_city: When the user asks for the weather in a specific city.



**Constraints:**

*   You must use markdown to render any tables.
*   **Never mention "tool_code", "tool_outputs", or "print statements" to the user.** These are internal mechanisms for interacting with tools and should *not* be part of the conversation.  Focus solely on providing a natural and helpful customer experience.  Do not reveal the underlying implementation details.
*   Always confirm actions with the user before executing them (e.g., "Would you like me to update your cart?").
*   Be proactive in offering help and anticipating customer needs.
*   Don't output code even if user asks for it.


**Product Image Display:**

*   Include the image along with the product name, price, and other relevant details in the table or list presented to the user.


"""

## --- Functions ---
def get_weather_for_city(city_name: str) -> Optional[dict]:
    """
    Obtiene la latitud y longitud de una ciudad usando Google Geocoding API
    y luego obtiene el clima usando OpenWeatherMap API.
    Las claves API se obtienen de las variables de entorno.

    Args:
        city_name (str): El nombre de la ciudad.

    Returns:
        dict: Un diccionario con la información del clima, o None si ocurre un error.
    """
    # Obtener claves API de las variables de entorno
    google_api_key = os.getenv("MAPS_GOOGLE_API_KEY", "")
    weather_api_key = google_api_key

    if not google_api_key:
        print("Error: La variable de entorno GOOGLE_API_KEY no está configurada.")
        return None
    if not weather_api_key:
        print("Error: La variable de entorno OPENWEATHERMAP_API_KEY no está configurada.")
        return None

    # Paso 1: Obtener latitud y longitud usando Google Geocoding API
    geocode_url = f"https://maps.googleapis.com/maps/api/geocode/json?address={city_name}&key={google_api_key}"
    
    try:
        response = requests.get(geocode_url)
        response.raise_for_status()
        geocode_data = response.json()

        if geocode_data['status'] == 'OK':
            location = geocode_data['results'][0]['geometry']['location']
            latitude = location['lat']
            longitude = location['lng']
            print(f"Coordenadas para {city_name}: Latitud={latitude}, Longitud={longitude}")

            # Paso 2: Obtener el clima usando las coordenadas (ejemplo con OpenWeatherMap)
            weather_url = f"https://weather.googleapis.com/v1/currentConditions:lookup?key={weather_api_key}&location.latitude={latitude}&location.longitude={longitude}"
            
            weather_response = requests.get(weather_url)
            weather_response.raise_for_status()
            weather_data = weather_response.json()
            
            return weather_data
        else:
            print(f"Error al geocodificar {city_name}: {geocode_data['status']}")
            if 'error_message' in geocode_data:
                print(f"Mensaje de error de Google: {geocode_data['error_message']}")
            return None

    except requests.exceptions.HTTPError as http_err:
        print(f"Error HTTP: {http_err}")
        return None
    except requests.exceptions.RequestException as req_err:
        print(f"Error en la solicitud: {req_err}")
        return None
    except KeyError as key_err:
        print(f"Error al parsear la respuesta JSON (KeyError): {key_err}")
        return None
    except IndexError:
        print(f"No se encontraron resultados para la ciudad: {city_name}")
        return None



root_agent = Agent(
    name="megatoy_service_agent",
    description="A customer service agent for Megatoy, for demo presentation.",
    model="gemini-2.5-pro-preview-03-25",
    instruction=INSTRUCTION,
    tools=[get_weather_for_city, *tools_toolbox],
        
)

We followed the documentation from:

We ran some local tests such as:

app = reasoning_engines.AdkApp(
    agent=root_agent,
    enable_tracing=True,
)

session = await app.create_session(user_id="u_123")

for event in app.stream_query(
    user_id="u_123",
    session_id=session.id,
    message="cual es el clima en la ciudad de méxico",
):
    print(event)

Everything worked fine locally. However, when running the following code:

dependencies = [
        "google-cloud-aiplatform[adk,agent_engines]",
        "toolbox_core",
    ]

remote_app = agent_engines.create(
    agent_engine=root_agent,
    requirements=dependencies,
    gcs_dir_name=gcs_dir_name,
    display_name=display_name,
    description=description,
    env_vars=env_vars,
)

I get the following error:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[10], line 1
----> 1 remote_app = agent_engines.create(
      2     agent_engine=root_agent,
      3     requirements=dependencies,
      4     gcs_dir_name=gcs_dir_name,
      5     display_name=display_name,
      6     description=description,
      7     env_vars=env_vars,
      8 )

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\site-packages\vertexai\agent_engines\__init__.py:147, in create(agent_engine, requirements, display_name, description, gcs_dir_name, extra_packages, env_vars)
     61 def create(
     62     agent_engine: Optional[Union[Queryable, OperationRegistrable]] = None,
     63     *,
   (...)     71     ] = None,
     72 ) -> AgentEngine:
     73     """Creates a new Agent Engine.
     74 
     75     The Agent Engine will be an instance of the `agent_engine` that
   (...)    145         nonexistent file.
    146     """
--> 147     return AgentEngine.create(
    148         agent_engine=agent_engine,
    149         requirements=requirements,
    150         display_name=display_name,
    151         description=description,
    152         gcs_dir_name=gcs_dir_name,
    153         extra_packages=extra_packages,
    154         env_vars=env_vars,
    155     )

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\site-packages\vertexai\agent_engines\_agent_engines.py:449, in AgentEngine.create(cls, agent_engine, requirements, display_name, description, gcs_dir_name, extra_packages, env_vars)
    447 staging_bucket = initializer.global_config.staging_bucket
    448 if agent_engine is not None:
--> 449     agent_engine = _validate_agent_engine_or_raise(agent_engine)
    450     _validate_staging_bucket_or_raise(staging_bucket)
    451 if agent_engine is None:

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\site-packages\vertexai\agent_engines\_agent_engines.py:874, in _validate_agent_engine_or_raise(agent_engine)
    866         raise ValueError(
    867             "Invalid register_operations signature. This might be due to a "
    868             "missing `self` argument in the "
    869             "agent_engine.register_operations method."
    870         ) from err
    872 if isinstance(agent_engine, Cloneable):
    873     # Avoid undeployable states.
--> 874     agent_engine = agent_engine.clone()
    875 return agent_engine

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\site-packages\vertexai\preview\reasoning_engines\templates\adk.py:387, in AdkApp.clone(self)
    383 """Returns a clone of the ADK application."""
    384 import copy
    386 return AdkApp(
--> 387     agent=copy.deepcopy(self._tmpl_attrs.get("agent")),
    388     enable_tracing=self._tmpl_attrs.get("enable_tracing"),
    389     session_service_builder=self._tmpl_attrs.get("session_service_builder"),
    390     artifact_service_builder=self._tmpl_attrs.get("artifact_service_builder"),
    391     env_vars=self._tmpl_attrs.get("env_vars"),
    392 )

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:153, in deepcopy(x, memo, _nil)
    151 copier = getattr(x, "__deepcopy__", None)
    152 if copier is not None:
--> 153     y = copier(memo)
    154 else:
    155     reductor = dispatch_table.get(cls)

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\site-packages\pydantic\main.py:938, in BaseModel.__deepcopy__(self, memo)
    936 cls = type(self)
    937 m = cls.__new__(cls)
--> 938 _object_setattr(m, '__dict__', deepcopy(self.__dict__, memo=memo))
    939 _object_setattr(m, '__pydantic_extra__', deepcopy(self.__pydantic_extra__, memo=memo))
    940 # This next line doesn't need a deepcopy because __pydantic_fields_set__ is a set[str],
    941 # and attempting a deepcopy would be marginally slower.

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:146, in deepcopy(x, memo, _nil)
    144 copier = _deepcopy_dispatch.get(cls)
    145 if copier is not None:
--> 146     y = copier(x, memo)
    147 else:
    148     if issubclass(cls, type):

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:231, in _deepcopy_dict(x, memo, deepcopy)
    229 memo[id(x)] = y
    230 for key, value in x.items():
--> 231     y[deepcopy(key, memo)] = deepcopy(value, memo)
    232 return y

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:146, in deepcopy(x, memo, _nil)
    144 copier = _deepcopy_dispatch.get(cls)
    145 if copier is not None:
--> 146     y = copier(x, memo)
    147 else:
    148     if issubclass(cls, type):

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:206, in _deepcopy_list(x, memo, deepcopy)
    204 append = y.append
    205 for a in x:
--> 206     append(deepcopy(a, memo))
    207 return y

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:172, in deepcopy(x, memo, _nil)
    170                 y = x
    171             else:
--> 172                 y = _reconstruct(x, memo, *rv)
    174 # If is its own copy, don't memoize.
    175 if y is not x:

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:271, in _reconstruct(x, memo, func, args, state, listiter, dictiter, deepcopy)
    269 if state is not None:
    270     if deep:
--> 271         state = deepcopy(state, memo)
    272     if hasattr(y, '__setstate__'):
    273         y.__setstate__(state)

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:146, in deepcopy(x, memo, _nil)
    144 copier = _deepcopy_dispatch.get(cls)
    145 if copier is not None:
--> 146     y = copier(x, memo)
    147 else:
    148     if issubclass(cls, type):

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:231, in _deepcopy_dict(x, memo, deepcopy)
    229 memo[id(x)] = y
    230 for key, value in x.items():
--> 231     y[deepcopy(key, memo)] = deepcopy(value, memo)
    232 return y

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:172, in deepcopy(x, memo, _nil)
    170                 y = x
    171             else:
--> 172                 y = _reconstruct(x, memo, *rv)
    174 # If is its own copy, don't memoize.
    175 if y is not x:

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:271, in _reconstruct(x, memo, func, args, state, listiter, dictiter, deepcopy)
    269 if state is not None:
    270     if deep:
--> 271         state = deepcopy(state, memo)
    272     if hasattr(y, '__setstate__'):
    273         y.__setstate__(state)

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:146, in deepcopy(x, memo, _nil)
    144 copier = _deepcopy_dispatch.get(cls)
    145 if copier is not None:
--> 146     y = copier(x, memo)
    147 else:
    148     if issubclass(cls, type):

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:231, in _deepcopy_dict(x, memo, deepcopy)
    229 memo[id(x)] = y
    230 for key, value in x.items():
--> 231     y[deepcopy(key, memo)] = deepcopy(value, memo)
    232 return y

    [... skipping similar frames: deepcopy at line 172 (2 times), _deepcopy_dict at line 231 (1 times), _reconstruct at line 271 (1 times), deepcopy at line 146 (1 times)]

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:271, in _reconstruct(x, memo, func, args, state, listiter, dictiter, deepcopy)
    269 if state is not None:
    270     if deep:
--> 271         state = deepcopy(state, memo)
    272     if hasattr(y, '__setstate__'):
    273         y.__setstate__(state)

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:146, in deepcopy(x, memo, _nil)
    144 copier = _deepcopy_dispatch.get(cls)
    145 if copier is not None:
--> 146     y = copier(x, memo)
    147 else:
    148     if issubclass(cls, type):

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:231, in _deepcopy_dict(x, memo, deepcopy)
    229 memo[id(x)] = y
    230 for key, value in x.items():
--> 231     y[deepcopy(key, memo)] = deepcopy(value, memo)
    232 return y

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:172, in deepcopy(x, memo, _nil)
    170                 y = x
    171             else:
--> 172                 y = _reconstruct(x, memo, *rv)
    174 # If is its own copy, don't memoize.
    175 if y is not x:

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:297, in _reconstruct(x, memo, func, args, state, listiter, dictiter, deepcopy)
    295     for key, value in dictiter:
    296         key = deepcopy(key, memo)
--> 297         value = deepcopy(value, memo)
    298         y[key] = value
    299 else:

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:172, in deepcopy(x, memo, _nil)
    170                 y = x
    171             else:
--> 172                 y = _reconstruct(x, memo, *rv)
    174 # If is its own copy, don't memoize.
    175 if y is not x:

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:288, in _reconstruct(x, memo, func, args, state, listiter, dictiter, deepcopy)
    286 if deep:
    287     for item in listiter:
--> 288         item = deepcopy(item, memo)
    289         y.append(item)
    290 else:

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:146, in deepcopy(x, memo, _nil)
    144 copier = _deepcopy_dispatch.get(cls)
    145 if copier is not None:
--> 146     y = copier(x, memo)
    147 else:
    148     if issubclass(cls, type):

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:211, in _deepcopy_tuple(x, memo, deepcopy)
    210 def _deepcopy_tuple(x, memo, deepcopy=deepcopy):
--> 211     y = [deepcopy(a, memo) for a in x]
    212     # We're not going to put the tuple in the memo, but it's still important we
    213     # check for it, in case the tuple contains recursive mutable structures.
    214     try:

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:211, in <listcomp>(.0)
    210 def _deepcopy_tuple(x, memo, deepcopy=deepcopy):
--> 211     y = [deepcopy(a, memo) for a in x]
    212     # We're not going to put the tuple in the memo, but it's still important we
    213     # check for it, in case the tuple contains recursive mutable structures.
    214     try:

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:172, in deepcopy(x, memo, _nil)
    170                 y = x
    171             else:
--> 172                 y = _reconstruct(x, memo, *rv)
    174 # If is its own copy, don't memoize.
    175 if y is not x:

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:271, in _reconstruct(x, memo, func, args, state, listiter, dictiter, deepcopy)
    269 if state is not None:
    270     if deep:
--> 271         state = deepcopy(state, memo)
    272     if hasattr(y, '__setstate__'):
    273         y.__setstate__(state)

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:146, in deepcopy(x, memo, _nil)
    144 copier = _deepcopy_dispatch.get(cls)
    145 if copier is not None:
--> 146     y = copier(x, memo)
    147 else:
    148     if issubclass(cls, type):

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:211, in _deepcopy_tuple(x, memo, deepcopy)
    210 def _deepcopy_tuple(x, memo, deepcopy=deepcopy):
--> 211     y = [deepcopy(a, memo) for a in x]
    212     # We're not going to put the tuple in the memo, but it's still important we
    213     # check for it, in case the tuple contains recursive mutable structures.
    214     try:

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:211, in <listcomp>(.0)
    210 def _deepcopy_tuple(x, memo, deepcopy=deepcopy):
--> 211     y = [deepcopy(a, memo) for a in x]
    212     # We're not going to put the tuple in the memo, but it's still important we
    213     # check for it, in case the tuple contains recursive mutable structures.
    214     try:

    [... skipping similar frames: deepcopy at line 146 (1 times)]

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:231, in _deepcopy_dict(x, memo, deepcopy)
    229 memo[id(x)] = y
    230 for key, value in x.items():
--> 231     y[deepcopy(key, memo)] = deepcopy(value, memo)
    232 return y

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:172, in deepcopy(x, memo, _nil)
    170                 y = x
    171             else:
--> 172                 y = _reconstruct(x, memo, *rv)
    174 # If is its own copy, don't memoize.
    175 if y is not x:

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:271, in _reconstruct(x, memo, func, args, state, listiter, dictiter, deepcopy)
    269 if state is not None:
    270     if deep:
--> 271         state = deepcopy(state, memo)
    272     if hasattr(y, '__setstate__'):
    273         y.__setstate__(state)

    [... skipping similar frames: deepcopy at line 146 (1 times)]

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:211, in _deepcopy_tuple(x, memo, deepcopy)
    210 def _deepcopy_tuple(x, memo, deepcopy=deepcopy):
--> 211     y = [deepcopy(a, memo) for a in x]
    212     # We're not going to put the tuple in the memo, but it's still important we
    213     # check for it, in case the tuple contains recursive mutable structures.
    214     try:

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:211, in <listcomp>(.0)
    210 def _deepcopy_tuple(x, memo, deepcopy=deepcopy):
--> 211     y = [deepcopy(a, memo) for a in x]
    212     # We're not going to put the tuple in the memo, but it's still important we
    213     # check for it, in case the tuple contains recursive mutable structures.
    214     try:

    [... skipping similar frames: deepcopy at line 146 (1 times)]

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:231, in _deepcopy_dict(x, memo, deepcopy)
    229 memo[id(x)] = y
    230 for key, value in x.items():
--> 231     y[deepcopy(key, memo)] = deepcopy(value, memo)
    232 return y

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:172, in deepcopy(x, memo, _nil)
    170                 y = x
    171             else:
--> 172                 y = _reconstruct(x, memo, *rv)
    174 # If is its own copy, don't memoize.
    175 if y is not x:

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:271, in _reconstruct(x, memo, func, args, state, listiter, dictiter, deepcopy)
    269 if state is not None:
    270     if deep:
--> 271         state = deepcopy(state, memo)
    272     if hasattr(y, '__setstate__'):
    273         y.__setstate__(state)

    [... skipping similar frames: deepcopy at line 146 (1 times)]

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:231, in _deepcopy_dict(x, memo, deepcopy)
    229 memo[id(x)] = y
    230 for key, value in x.items():
--> 231     y[deepcopy(key, memo)] = deepcopy(value, memo)
    232 return y

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:146, in deepcopy(x, memo, _nil)
    144 copier = _deepcopy_dispatch.get(cls)
    145 if copier is not None:
--> 146     y = copier(x, memo)
    147 else:
    148     if issubclass(cls, type):

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:206, in _deepcopy_list(x, memo, deepcopy)
    204 append = y.append
    205 for a in x:
--> 206     append(deepcopy(a, memo))
    207 return y

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:172, in deepcopy(x, memo, _nil)
    170                 y = x
    171             else:
--> 172                 y = _reconstruct(x, memo, *rv)
    174 # If is its own copy, don't memoize.
    175 if y is not x:

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:271, in _reconstruct(x, memo, func, args, state, listiter, dictiter, deepcopy)
    269 if state is not None:
    270     if deep:
--> 271         state = deepcopy(state, memo)
    272     if hasattr(y, '__setstate__'):
    273         y.__setstate__(state)

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:146, in deepcopy(x, memo, _nil)
    144 copier = _deepcopy_dispatch.get(cls)
    145 if copier is not None:
--> 146     y = copier(x, memo)
    147 else:
    148     if issubclass(cls, type):

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:211, in _deepcopy_tuple(x, memo, deepcopy)
    210 def _deepcopy_tuple(x, memo, deepcopy=deepcopy):
--> 211     y = [deepcopy(a, memo) for a in x]
    212     # We're not going to put the tuple in the memo, but it's still important we
    213     # check for it, in case the tuple contains recursive mutable structures.
    214     try:

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:211, in <listcomp>(.0)
    210 def _deepcopy_tuple(x, memo, deepcopy=deepcopy):
--> 211     y = [deepcopy(a, memo) for a in x]
    212     # We're not going to put the tuple in the memo, but it's still important we
    213     # check for it, in case the tuple contains recursive mutable structures.
    214     try:

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:146, in deepcopy(x, memo, _nil)
    144 copier = _deepcopy_dispatch.get(cls)
    145 if copier is not None:
--> 146     y = copier(x, memo)
    147 else:
    148     if issubclass(cls, type):

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:231, in _deepcopy_dict(x, memo, deepcopy)
    229 memo[id(x)] = y
    230 for key, value in x.items():
--> 231     y[deepcopy(key, memo)] = deepcopy(value, memo)
    232 return y

File c:\Users\demo\miniconda3\envs\portalup-demos\Lib\copy.py:161, in deepcopy(x, memo, _nil)
    159 reductor = getattr(x, "__reduce_ex__", None)
    160 if reductor is not None:
--> 161     rv = reductor(4)
    162 else:
    163     reductor = getattr(x, "__reduce__", None)

TypeError: cannot pickle '_contextvars.Context' object

Thank you!

Metadata

Metadata

Assignees

Labels

agent engine[Component] This issue is related to Agent Engine deploymentmcp[Component] Issues about MCP support

Type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions