ibm-watsonx-orchestrate-mcp-server 1.13.0b0__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.
Files changed (31) hide show
  1. .gitignore +17 -0
  2. __init__.py +0 -0
  3. ibm_watsonx_orchestrate_mcp_server/__init__.py +0 -0
  4. ibm_watsonx_orchestrate_mcp_server/server.py +46 -0
  5. ibm_watsonx_orchestrate_mcp_server/src/__init__.py +10 -0
  6. ibm_watsonx_orchestrate_mcp_server/src/agents/mcp_tools.py +162 -0
  7. ibm_watsonx_orchestrate_mcp_server/src/agents/types.py +122 -0
  8. ibm_watsonx_orchestrate_mcp_server/src/connections/helpers.py +31 -0
  9. ibm_watsonx_orchestrate_mcp_server/src/connections/mcp_tools.py +149 -0
  10. ibm_watsonx_orchestrate_mcp_server/src/connections/types.py +113 -0
  11. ibm_watsonx_orchestrate_mcp_server/src/knowledge_bases/mcp_tools.py +66 -0
  12. ibm_watsonx_orchestrate_mcp_server/src/models/mcp_tools.py +207 -0
  13. ibm_watsonx_orchestrate_mcp_server/src/models/types.py +60 -0
  14. ibm_watsonx_orchestrate_mcp_server/src/toolkits/mcp_tools.py +67 -0
  15. ibm_watsonx_orchestrate_mcp_server/src/toolkits/types.py +19 -0
  16. ibm_watsonx_orchestrate_mcp_server/src/tools/mcp_tools.py +155 -0
  17. ibm_watsonx_orchestrate_mcp_server/src/version_checker.py +7 -0
  18. ibm_watsonx_orchestrate_mcp_server/src/voice_configurations/mcp_tools.py +52 -0
  19. ibm_watsonx_orchestrate_mcp_server/utils/common.py +108 -0
  20. ibm_watsonx_orchestrate_mcp_server/utils/config/__init__.py +2 -0
  21. ibm_watsonx_orchestrate_mcp_server/utils/config/config.py +91 -0
  22. ibm_watsonx_orchestrate_mcp_server/utils/config/types.py +6 -0
  23. ibm_watsonx_orchestrate_mcp_server/utils/files/files.py +14 -0
  24. ibm_watsonx_orchestrate_mcp_server/utils/logging/__init__.py +1 -0
  25. ibm_watsonx_orchestrate_mcp_server/utils/logging/log_config.yaml +19 -0
  26. ibm_watsonx_orchestrate_mcp_server/utils/logging/logger.py +38 -0
  27. ibm_watsonx_orchestrate_mcp_server-1.13.0b0.dist-info/METADATA +12 -0
  28. ibm_watsonx_orchestrate_mcp_server-1.13.0b0.dist-info/RECORD +31 -0
  29. ibm_watsonx_orchestrate_mcp_server-1.13.0b0.dist-info/WHEEL +4 -0
  30. ibm_watsonx_orchestrate_mcp_server-1.13.0b0.dist-info/entry_points.txt +2 -0
  31. pyproject.toml +39 -0
.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # Virtual environments
10
+ .venv
11
+
12
+ uv.lock
13
+
14
+ *.env
15
+
16
+ */.bob/*
17
+ *.DS_STORE*
__init__.py ADDED
File without changes
File without changes
@@ -0,0 +1,46 @@
1
+ import logging
2
+ import sys
3
+ import os
4
+ from ibm_watsonx_orchestrate_mcp_server.utils.logging import setup_logging
5
+ from ibm_watsonx_orchestrate_mcp_server.utils.config import config, MCPTransportTypes
6
+ from fastmcp import FastMCP
7
+ from ibm_watsonx_orchestrate_mcp_server.src import __all_tools__
8
+
9
+ mcp: FastMCP = FastMCP(name=config.server_name)
10
+
11
+ def _configure_logging() -> logging.Logger:
12
+ setup_logging(debug=config.debug)
13
+ return logging.getLogger(config.server_name)
14
+
15
+ def _load_tools() -> None:
16
+ for tool in __all_tools__:
17
+ mcp.tool()(tool)
18
+
19
+ def start_server() -> None:
20
+ logger: logging.Logger = _configure_logging()
21
+
22
+ if config.working_directory:
23
+ os.chdir(config.working_directory)
24
+
25
+ _load_tools()
26
+
27
+ # Start server
28
+ logger.debug(f"🚀 Starting {config.server_name} v{config.version}")
29
+ logger.debug(f"📡 Transport: {config.transport}, Host: {config.host}, Port: {config.port}")
30
+
31
+ try:
32
+ if config.transport in (MCPTransportTypes.HTTP_STREAMABLE, MCPTransportTypes.SSE):
33
+ logger.info(f"🌐 Starting HTTP server on {config.host}:{config.port}")
34
+ mcp.run(transport=config.transport, host=config.host, port=config.port)
35
+ else:
36
+ logger.info("📡 Starting STDIO transport")
37
+ mcp.run()
38
+
39
+ except KeyboardInterrupt:
40
+ logger.info("🛑 Server interrupted by user")
41
+ except Exception as e:
42
+ logger.error(f"💥 Server error: {e}", exc_info=True)
43
+ sys.exit(1)
44
+
45
+ if __name__ == "__main__":
46
+ start_server()
@@ -0,0 +1,10 @@
1
+ from .version_checker import check_version
2
+ from .agents.mcp_tools import __tools__ as agent_tools
3
+ from .tools.mcp_tools import __tools__ as tool_tools
4
+ from .toolkits.mcp_tools import __tools__ as toolkit_tools
5
+ from .knowledge_bases.mcp_tools import __tools__ as knowledge_base_tools
6
+ from .connections.mcp_tools import __tools__ as connection_tools
7
+ from .voice_configurations.mcp_tools import __tools__ as voice_configuration_tools
8
+ from .models.mcp_tools import __tools__ as model_tools
9
+
10
+ __all_tools__ = agent_tools + tool_tools + toolkit_tools + knowledge_base_tools + connection_tools + voice_configuration_tools + model_tools + [check_version]
@@ -0,0 +1,162 @@
1
+ from ibm_watsonx_orchestrate.agent_builder.agents import SpecVersion
2
+ from ibm_watsonx_orchestrate.cli.commands.agents.agents_controller import (
3
+ AgentsController,
4
+ AgentKind
5
+ )
6
+ from ibm_watsonx_orchestrate.cli.common import ListFormats
7
+
8
+ from typing_extensions import Optional, List, Literal
9
+ from ibm_watsonx_orchestrate_mcp_server.utils.common import silent_call;
10
+
11
+ from ibm_watsonx_orchestrate_mcp_server.utils.files.files import get_working_directory_path
12
+ from ibm_watsonx_orchestrate_mcp_server.src.agents.types import ListAgents, CreateAgentOptions, AnyAgent
13
+
14
+ def __get_existing_agent(name: str, kind: str) -> Optional[AnyAgent]:
15
+ """
16
+ Get an existing agent with the given name.
17
+ """
18
+ ac: AgentsController = AgentsController()
19
+ try:
20
+ agent: Optional[AnyAgent] = silent_call(fn=ac.get_agent, name=name, kind=kind)
21
+ return agent
22
+ except:
23
+ return None
24
+
25
+ def list_agents(
26
+ kind: Optional[AgentKind] = None,
27
+ verbose: bool = False
28
+ ) -> ListAgents:
29
+ """
30
+ Get a list of all the agents in watsonx Orchestrate (wxo)
31
+
32
+ Args:
33
+ kind (AgentKind, optional): Return only agents of the kind specified. If None is passed then return everything. Allowed values ['native' | 'external' | 'assistant' | None] (default: None)
34
+ verbose (bool): When set the tool will return the raw agents specifications without resolving ids to names. This should only be done in edge cases as names are more widely used. (default: False)
35
+
36
+ Returns:
37
+ ListAgents: A class containing lists of native, assistant and external agents.
38
+ """
39
+ ac: AgentsController = AgentsController()
40
+ format: Literal[ListFormats.JSON] | None = ListFormats.JSON if not verbose else None
41
+ output: ListAgents = silent_call(fn=ac.list_agents, format=format, kind=kind, verbose=verbose)
42
+
43
+ return output
44
+
45
+ def create_or_update_agent(options: CreateAgentOptions) -> AnyAgent:
46
+ """
47
+ Create or update an agent based on the provided options.
48
+ If the agent name already exists, the agent will be updated with the provided options. Else it will create a new agent.
49
+
50
+ Args:
51
+ options (CreateAgentOptions): The options to use when creating the agent.
52
+
53
+ Returns:
54
+ AnyAgent: The newly created agent.
55
+ """
56
+ ac: AgentsController = AgentsController()
57
+ existing_agents = {
58
+ AgentKind.NATIVE: __get_existing_agent(options.name, AgentKind.NATIVE),
59
+ AgentKind.EXTERNAL: __get_existing_agent(options.name, AgentKind.EXTERNAL),
60
+ AgentKind.ASSISTANT: __get_existing_agent(options.name, AgentKind.ASSISTANT)
61
+ }
62
+ existing_agents_list = [value for value in existing_agents.values() if value is not None]
63
+
64
+ existing_agent = None
65
+ if len(existing_agents_list) == 1:
66
+ existing_agent = existing_agents_list[0]
67
+ elif len(existing_agents_list) > 1:
68
+ raise Exception(f"Multiple agents found with name {options.name} update is ambiguous. Please delete the duplicate and try again.")
69
+
70
+ if not existing_agent:
71
+ if not options.kind:
72
+ options.kind = AgentKind.NATIVE
73
+ agent: AnyAgent = silent_call(fn=ac.generate_agent_spec, **options.model_dump())
74
+ else:
75
+ agent = existing_agent.model_copy(update=options.model_dump(exclude_unset=True))
76
+ silent_call(fn=ac.publish_or_update_agents, agents=[agent])
77
+ agent.spec_version = SpecVersion.V1
78
+ return agent
79
+
80
+ def import_agent(path: str, app_id: Optional[str]) -> List[AnyAgent]:
81
+ """
82
+ Import an agent into the watsonx Orchestrate platform using Agent spec files
83
+
84
+ Args:
85
+ path (str): The absolute of relative path to an agent spec file
86
+ app_id (str | None): An optional app_id which relates an Orchestrate connection object to the Agent. Used for external and assistant Agent authentication.
87
+
88
+ Returns:
89
+ List[AnyAgent]: The newly created agent.
90
+ """
91
+
92
+ working_directory_path: str = get_working_directory_path(path)
93
+ ac: AgentsController = AgentsController()
94
+ agents: List[AnyAgent] = silent_call(ac.import_agent, file=working_directory_path, app_id=app_id)
95
+ silent_call(fn=ac.publish_or_update_agents, agents=agents)
96
+ return agents
97
+
98
+ def remove_agent(name: str, kind: AgentKind) -> str:
99
+ """
100
+ Remove an agent from the watsonx Orchestrate platform
101
+
102
+ Args:
103
+ name (str): The name of the agent to remove
104
+ kind (AgentKind): The kind of agent to remove
105
+
106
+ Returns:
107
+ str: A message indicating the success of the removal
108
+ """
109
+
110
+ ac: AgentsController = AgentsController()
111
+ silent_call(fn=ac.remove_agent, name=name, kind=kind)
112
+
113
+ return f"The Agent {name} successfully removed"
114
+
115
+ def export_agent(name: str, kind: AgentKind, output_file_path: str, agent_only_flag: bool = False) -> str:
116
+ """
117
+ Export an agent from the watsonx Orchestrate platform.
118
+ Args:
119
+ name (str): The name of the agent to export
120
+ kind (AgentKind): The kind of agent to export
121
+ output_file_path (str): The path to export the agent to. Should be a zip file with a '.zip' extension unless the agent_only_flag is set in which case it should a yaml file with a '.yaml' extension.
122
+ agent_only_flag (bool, optional): If set to True, only the agent definition will be exported and not the agent's dependencies. Defaults to False.
123
+
124
+ Returns:
125
+ str: A message indicating the success of the export
126
+ """
127
+ working_directory_output_path: str = get_working_directory_path(output_file_path)
128
+ ac: AgentsController = AgentsController()
129
+ silent_call(fn=ac.export_agent, name=name, kind=kind, output_path=working_directory_output_path, agent_only_flag=agent_only_flag)
130
+
131
+ return f"The Agent {name} successfully exported"
132
+
133
+ def deploy_agent(name: str,) -> str:
134
+ """
135
+ Deploys an agent to the watsonx Orchestrate platform. Promoting it from the draft environment to the live environment. The agent must already have been created or imported into the Orchestrate platform.
136
+
137
+ Args:
138
+ name (str): The name of the agent you want to deploy.
139
+
140
+ Returns:
141
+ str: A message indicating the success of the deployment
142
+ """
143
+ ac: AgentsController = AgentsController()
144
+ silent_call(fn=ac.deploy_agent, name=name)
145
+
146
+ return f"The Agent {name} successfully deployed"
147
+
148
+ def undeploy_agent(name: str,) -> str:
149
+ """
150
+ Undeploys an agent from the watsonx Orchestrate platform. Demoting it from the live environment to the draft environment.
151
+ Args:
152
+ name (str): The name of the agent you want to undeploy.
153
+
154
+ Returns:
155
+ str: A message indicating the success of the undeployment
156
+ """
157
+ ac: AgentsController = AgentsController()
158
+ silent_call(fn=ac.undeploy_agent, name=name)
159
+
160
+ return f"The Agent {name} successfully undeployed"
161
+
162
+ __tools__ = [list_agents, create_or_update_agent, import_agent, remove_agent, export_agent]
@@ -0,0 +1,122 @@
1
+ from typing import Any, TypeAlias
2
+ from ibm_watsonx_orchestrate.agent_builder.agents.agent import Agent
3
+ from ibm_watsonx_orchestrate.agent_builder.agents.external_agent import ExternalAgent
4
+ from ibm_watsonx_orchestrate.agent_builder.agents.assistant_agent import AssistantAgent
5
+ from ibm_watsonx_orchestrate.cli.commands.agents.agents_controller import (
6
+ AgentKind
7
+ )
8
+ from ibm_watsonx_orchestrate.agent_builder.agents.types import (
9
+ ExternalAgentAuthScheme,
10
+ AgentProvider,
11
+ AgentStyle,
12
+ DEFAULT_LLM
13
+ )
14
+
15
+ from typing_extensions import Optional, List
16
+ from pydantic import BaseModel, Field
17
+
18
+ class ListAgents:
19
+ native: List[dict] = []
20
+ assistant: List[dict] = []
21
+ external: List[dict] = []
22
+
23
+ class ExternalAgentAuthConfig(BaseModel):
24
+ token: str = Field(
25
+ description="The apikey, bearer token or client secret required to auth to an external agent"
26
+ )
27
+ grant_type: Optional[str] = Field(
28
+ default=None,
29
+ description="Used when the provider is Salesforce. Defaults to 'client_credentials' if None is passed"
30
+ )
31
+
32
+ class AgentConfig(BaseModel):
33
+ hidden: bool = Field(
34
+ default=False,
35
+ description="Should the agent be hidden in the UI"
36
+ )
37
+ enable_cot: bool = Field(
38
+ default=False,
39
+ description="Should the agent display chain of thought reasoning"
40
+ )
41
+
42
+ class CreateAgentOptions(BaseModel):
43
+ name: str = Field(
44
+ description="Name of the agent you wish to create"
45
+ )
46
+ description: str = Field(
47
+ description="Description of the agent you wish to create. Should be descriptive of what capabilites an agent has to assist in routing from a parent agent"
48
+ )
49
+ title: Optional[str] = Field(
50
+ default=None,
51
+ description="Title of the agent you wish to create. Required for External and Assistant Agents"
52
+ )
53
+ kind: Optional[AgentKind] = Field(
54
+ default=None,
55
+ description="Kind of agent you wish to create"
56
+ )
57
+ instructions: Optional[str] = Field(
58
+ default=None,
59
+ description="Used for native agents. Controls the behaviour of the agent. Should include tool calling directions, collaborator routing instructions, output format requirements and any other guidance the agent should follow"
60
+ )
61
+ api_url: Optional[str] = Field(
62
+ default=None,
63
+ description="Required for External Agents. The API URL of the external agent"
64
+ )
65
+ auth_scheme: ExternalAgentAuthScheme = Field(
66
+ default=ExternalAgentAuthScheme.NONE,
67
+ description="Used for External Agents to control the auth scheme used when authenticating to the api"
68
+ )
69
+ provider: AgentProvider = Field(
70
+ default=AgentProvider.EXT_CHAT,
71
+ description="Used for External Agents to control the provider type of the external agent"
72
+ )
73
+ auth_config: Optional[ExternalAgentAuthConfig] = Field(
74
+ default=None,
75
+ description="Used for External Agents when 'auth_scheme' is not 'None' to pass is secret values like API key, bearer token or client_secret"
76
+ )
77
+ tags: Optional[List[str]] = Field(
78
+ default=None,
79
+ description="Optional tags that will appear in the UI."
80
+ )
81
+ chat_params: Optional[dict[str, Any]] = Field(
82
+ default=None,
83
+ description="Chat parameters in JSON format (e.g., '{\"stream\": true}'). Only needed for External and Assistant Agents"
84
+ )
85
+ config: Optional[AgentConfig] = Field(
86
+ default=None,
87
+ description="Used to configure options on the agent such as if it should appear in the UI or not"
88
+ )
89
+ app_id: Optional[str] = Field(
90
+ default=None,
91
+ description="The name of a connection that contains authentication secrets. Used for external and assistant agents only"
92
+ )
93
+ llm: str = Field(
94
+ default=DEFAULT_LLM,
95
+ description="The LLM model to use for this agent. If not specified, the default will be used. The value provided must be a model in the watsonx Orchestrate platform"
96
+ )
97
+ style: AgentStyle = Field(
98
+ default=AgentStyle.DEFAULT,
99
+ description="The style of the agent. This is used to control the behavior of the agent. Only used for native agents"
100
+ )
101
+ custom_join_tool: Optional[str] = Field(
102
+ default=None,
103
+ description="Used only when style is 'planner'. The name of the custom join tool to use for this agent. Only used for native agents"
104
+ )
105
+ structured_output: Optional[dict] = Field(
106
+ default=None,
107
+ description="Used only when style is 'planner'. A JSON Schema object that defines the desired structure of the agent\'s final output. Only used for native agents"
108
+ )
109
+ collaborators: Optional[List[str]] = Field(
110
+ default=None,
111
+ description="The names of agents that this agent should be able to call as collaborators. Only used for native agents"
112
+ )
113
+ tools: Optional[List[str]] = Field(
114
+ default=None,
115
+ description="The names of tools that this agent should be able to call. Only used for native agents"
116
+ )
117
+ knowledge_base: Optional[List[str]] = Field(
118
+ default=None,
119
+ description="The names of knowledge bases that this agent should be able to access. Only used for native agents"
120
+ )
121
+
122
+ AnyAgent: TypeAlias = Agent | ExternalAgent | AssistantAgent
@@ -0,0 +1,31 @@
1
+ from typing import Optional, List
2
+ from ibm_watsonx_orchestrate.client.connections.connections_client import ConnectionsClient, ListConfigsResponse
3
+ from ibm_watsonx_orchestrate.client.connections.utils import get_connections_client
4
+ from ibm_watsonx_orchestrate_mcp_server.utils.common import silent_call
5
+
6
+ class ConnectionsHelper:
7
+ def __init__(self, connnections_client: Optional[ConnectionsClient] = None):
8
+ self.connections_client: ConnectionsClient | None = connnections_client
9
+
10
+ def __get_connections_client(self) -> ConnectionsClient:
11
+ if self.connections_client:
12
+ return self.connections_client
13
+ else:
14
+ return silent_call(fn=get_connections_client)
15
+
16
+ def get_connection_by_id(self, connection_id: str) -> ListConfigsResponse | None:
17
+ connections_client: ConnectionsClient = self.__get_connections_client()
18
+
19
+ connections: List[ListConfigsResponse]= silent_call(fn=connections_client.get_drafts_by_ids, conn_ids=[connection_id])
20
+
21
+ if len(connections) == 0:
22
+ return None
23
+ if len(connections) > 1:
24
+ raise Exception(f"Multiple connections found with id '{connection_id}'.")
25
+ return connections[0]
26
+
27
+ def get_app_id_by_connection_id(self, connection_id: str) -> str | None:
28
+ connection: ListConfigsResponse | None = self.get_connection_by_id(connection_id)
29
+ if not connection:
30
+ return None
31
+ return connection.app_id
@@ -0,0 +1,149 @@
1
+
2
+ from typing import Any, Literal, List
3
+
4
+ from ibm_watsonx_orchestrate.cli.commands.connections import connections_controller
5
+ from ibm_watsonx_orchestrate.agent_builder.connections.types import ConnectionsListResponse
6
+ from ibm_watsonx_orchestrate.cli.common import ListFormats
7
+ from ibm_watsonx_orchestrate_mcp_server.utils.common import silent_call
8
+ from ibm_watsonx_orchestrate_mcp_server.utils.files.files import get_working_directory_path
9
+ from ibm_watsonx_orchestrate_mcp_server.src.connections.types import ConfigureConnectionsOptions, SetCredentialsConnectionOptions, SetIdentityProviderOptions
10
+
11
+
12
+ def list_connections(verbose: bool=False) -> ConnectionsListResponse | List[dict[str, Any]]:
13
+ """
14
+ Lists the avalible connections available on the watsonx Orchestrate platform.
15
+
16
+ Args:
17
+ verbose (bool): If True then the connections will be returned in a verbose format. Defaults to False.
18
+
19
+ Returns:
20
+ dict[str, Any]: A dictionary containing the connections.
21
+ """
22
+
23
+ format: Literal[ListFormats.JSON] | None = ListFormats.JSON if not verbose else None
24
+ connections: ConnectionsListResponse | List[dict] = silent_call(fn=connections_controller.list_connections, environment=None, verbose=verbose, format=format)
25
+ return connections
26
+
27
+ def create_connection(app_id: str) -> str:
28
+ """
29
+ Creates a connection in the watsonx Orchestrate platform.
30
+
31
+ Args:
32
+ app_id (str): An arbitrary string that will be used to identify the connection.
33
+
34
+ Returns:
35
+ str: A success message indicating the connection was created successfully.
36
+ """
37
+
38
+ silent_call(fn=connections_controller.add_connection, app_id=app_id)
39
+ return f"Connection '{app_id}' created successfully."
40
+
41
+ def remove_connection(app_id: str) -> str:
42
+ """
43
+ Removes a connection from the watsonx Orchestrate platform.
44
+
45
+ Args:
46
+ app_id (str): The app id of the connection to remove.
47
+
48
+ Returns:
49
+ str: A success message indicating the connection was removed successfully.
50
+ """
51
+ silent_call(fn=connections_controller.remove_connection, app_id=app_id)
52
+ return f"Connection '{app_id}' removed successfully."
53
+
54
+ def import_connection(file_path: str) -> str:
55
+ """
56
+ Imports connections from a spec file into the watsonx Orchestrate platform.
57
+
58
+ Args:
59
+ file_path (str): The path to the connections spec file.
60
+
61
+ Returns:
62
+ str: A success message indicating the connections were imported successfully.
63
+ """
64
+ working_directory_file_path: str = get_working_directory_path(file_path)
65
+ silent_call(fn=connections_controller.import_connection, file=working_directory_file_path)
66
+ return f"Connection imported successfully from '{file_path}'."
67
+
68
+ def configure_connection(options: ConfigureConnectionsOptions) -> str:
69
+ """
70
+ Configures a connection for a certain environment in the watsonx Orchestrate platform.
71
+
72
+ Args:
73
+ options (ConfigureConnectionsOptions): The options for configuring the connection.
74
+
75
+ Returns:
76
+ str: A success message indicating the connection was configured successfully.
77
+ """
78
+ silent_call(
79
+ fn=connections_controller.configure_connection,
80
+ app_id=options.app_id,
81
+ environment=options.environment,
82
+ type=options.type,
83
+ kind=options.kind,
84
+ server_url=options.server_url,
85
+ sso=options.sso,
86
+ idp_token_use=options.idp_token_use,
87
+ idp_token_type=options.idp_token_type,
88
+ idp_token_header=options.idp_token_header,
89
+ app_token_header=options.app_token_header,
90
+ )
91
+ return f"Connection '{options.app_id}' configured successfully."
92
+
93
+ def set_credentials_connection(options: SetCredentialsConnectionOptions) -> str:
94
+ """
95
+ Sets the credentials for a connection in the watsonx Orchestrate platform.
96
+ Args:
97
+ options (SetCredentialsConnectionOptions): The options for setting the credentials for the connection.
98
+ Returns:
99
+ str: A success message indicating the credentials were correctly set.
100
+ """
101
+ scope: str | None = " ".join(options.scope) if options.scope else None
102
+ entries: List[str] | None = [f"{k}={v}" for k, v in options.entries.items()] if options.entries else None
103
+
104
+ silent_call(
105
+ fn=connections_controller.set_credentials_connection,
106
+ app_id=options.app_id,
107
+ environment=options.environment,
108
+ username=options.username,
109
+ password=options.password,
110
+ token=options.token,
111
+ api_key=options.api_key,
112
+ client_id=options.client_id,
113
+ client_secret=options.client_secret,
114
+ send_via=options.send_via,
115
+ token_url=options.token_url,
116
+ auth_url=options.auth_url,
117
+ grant_type=options.grant_type,
118
+ scope=scope,
119
+ entries=entries,
120
+ token_entries=options.token_entries,
121
+ auth_entries=options.auth_entries
122
+ )
123
+ return f"Credentials set for connection '{options.app_id}'"
124
+
125
+ def set_identity_provider(options: SetIdentityProviderOptions) -> str:
126
+ """
127
+ Set the identity provider for a connection for sso enabled auth flow.
128
+
129
+ Args:
130
+ options (SetIdentityProviderOptions): The options for setting an identity provider for a connection
131
+
132
+ Returns:
133
+ str: A success message indicating the identity provider was correctly set.
134
+ """
135
+ silent_call(
136
+ fn=connections_controller.set_identity_provider_connection,
137
+ app_id=options.app_id,
138
+ environment=options.environment,
139
+ url=options.url,
140
+ client_id=options.client_id,
141
+ client_secret=options.client_secret,
142
+ scope=options.scope,
143
+ grant_type=options.grant_type,
144
+ token_entries=options.token_entries
145
+ )
146
+
147
+ return f"Identity Provider set for connection '{options.app_id}'"
148
+
149
+ __tools__ = [list_connections, create_connection, remove_connection, import_connection, configure_connection, set_credentials_connection, set_identity_provider]
@@ -0,0 +1,113 @@
1
+ from ibm_watsonx_orchestrate.agent_builder.connections import ConnectionEnvironment, ConnectionKind, ConnectionPreference
2
+ from ibm_watsonx_orchestrate.agent_builder.connections.types import ConnectionSendVia, ConnectionCredentialsEntry
3
+ from pydantic import BaseModel, Field
4
+ from typing import Optional, List
5
+
6
+ class BaseConnectionOptions(BaseModel):
7
+ app_id: str = Field(
8
+ description="The app id of the connection to configure"
9
+ )
10
+ environment: ConnectionEnvironment = Field(
11
+ description="The environemnt you wish to configre the connection for."
12
+ )
13
+
14
+ class ConfigureConnectionsOptions(BaseConnectionOptions):
15
+ type: ConnectionPreference = Field(
16
+ description="The type of connection you wish to configure. Setting type to 'team' will mean the connection's credentials are shared by all users. Setting 'member' will require each user to provide their own credentials for the connection"
17
+ )
18
+ kind: ConnectionKind = Field(
19
+ description="The kind of connection you wish to configure."
20
+ )
21
+ server_url: Optional[str]=Field(
22
+ default=None,
23
+ description="The url the connections credentials will be used against."
24
+ )
25
+ sso: bool = Field(
26
+ default=False,
27
+ description="If true, the connection will be configured to use single sign on. Only supported when kind is 'oauth_auth_on_behalf_of_flow' and is required to be true in that case"
28
+ )
29
+ idp_token_use: Optional[str] = Field(
30
+ default=None,
31
+ description="The token use used by the identity provider when using single sign on. Only supported when sso is true"
32
+ )
33
+ idp_token_type: Optional[str] = Field(
34
+ default=None,
35
+ description="The token type used by the identity provider when using single sign on. Only supported when sso is true"
36
+ )
37
+ idp_token_header: Optional[List[str]] = Field(
38
+ default=None,
39
+ description="Header values for the identity provider token request. Defaults to using 'content-type: application/x-www-form-urlencoded'. Formatted as <header_key>: <header_value>. Only supported when sso is true"
40
+ )
41
+ app_token_header: Optional[List[str]] = Field(
42
+ default=None,
43
+ description="Header values for the application token request. Defaults to using 'content-type: application/x-www-form-urlencoded'. Formatted as <header_key>: <header_value>. Only supported when sso is true"
44
+ )
45
+
46
+ class SetCredentialsConnectionOptions(BaseConnectionOptions):
47
+ username: Optional[str] = Field(
48
+ default=None,
49
+ description="The username to login with. Required when connection kind is 'basic' or 'oauth_auth_password_flow'"
50
+ )
51
+ password: Optional[str] = Field(
52
+ default=None,
53
+ description="The password to login with. Required when connection kind is 'basic' or 'oauth_auth_password_flow'"
54
+ )
55
+ token: Optional[str] = Field(
56
+ default=None,
57
+ description="The bearer token to login with. Required when connection kind is 'bearer'"
58
+ )
59
+ api_key: Optional[str] = Field(
60
+ default=None,
61
+ description="The api key to login with. Required when connection kind is 'api_key'"
62
+ )
63
+ client_id: Optional[str] = Field(
64
+ default=None,
65
+ description="The client id for the OAuth request. Required when connection kind is 'oauth_auth_code_flow', 'oauth_auth_client_credentials_flow', 'oauth_auth_password_flow' or 'oauth_auth_on_behalf_of_flow'"
66
+ )
67
+ client_secret: Optional[str] = Field(
68
+ default=None,
69
+ description="The client secret for the OAuth request. Required when connection kind is 'oauth_auth_code_flow', 'oauth_auth_client_credentials_flow' or 'oauth_auth_password_flow'"
70
+ )
71
+ send_via: Optional[ConnectionSendVia] = Field(
72
+ default=None,
73
+ description="The location where the token will be sent during the OAuth handshake. Used when connection kind is 'oauth_auth_client_credentials_flow'. Defaults to 'header'."
74
+ )
75
+ token_url: Optional[str] = Field(
76
+ default=None,
77
+ description="The url to request the token from. Required when connection kind is 'oauth_auth_code_flow', 'oauth_auth_client_credentials_flow', 'oauth_auth_password_flow' or 'oauth_auth_on_behalf_of_flow'"
78
+ )
79
+ auth_url: Optional[str] = Field(
80
+ default=None,
81
+ description="The url to request the authorization from. Required when connection kind is 'oauth_auth_code_flow'"
82
+ )
83
+ grant_type: Optional[str] = Field(
84
+ default=None,
85
+ description="The grant type of the token requested for the token server. Required when connections kind is 'oauth_auth_on_behalf_of_flow'. Defaults for 'oauth_auth_client_credentials_flow' to 'client_credentials' and for 'oauth_auth_password_flow' it defaults to 'password'"
86
+ )
87
+ scope: Optional[List[str]] = Field(
88
+ default=None,
89
+ description="An optional set of scopes. Used for 'oauth_auth_code_flow', 'oauth_auth_client_credentials_flow' and 'oauth_auth_password_flow'"
90
+ )
91
+ entries: Optional[dict] = Field(
92
+ default=None,
93
+ description="A dictionary containing arbitrary key value pairs to be used in the key_value connection. Required when kind is 'key_value'"
94
+ )
95
+ token_entries: Optional[List[ConnectionCredentialsEntry]] = Field(
96
+ default=None,
97
+ description="A list of optional custom fields to be passed with OAuth token requests. Supported when connection kind is 'oauth_auth_code_flow', 'oauth_auth_client_credentials_flow', 'oauth_auth_password_flow' or 'oauth_auth_on_behalf_of_flow'"
98
+ )
99
+ auth_entries: Optional[List[ConnectionCredentialsEntry]] = Field(
100
+ default=None,
101
+ description="A list of optional custom fields to be passed with OAuth authorization requests. Supported when connection kind is 'oauth_auth_code_flow'. Location must be 'query'."
102
+ )
103
+
104
+ class SetIdentityProviderOptions(BaseConnectionOptions):
105
+ url: str = Field(description="The URL of the identity provider service")
106
+ client_id: str = Field(description="The client id used to authenticate with the identity provider")
107
+ client_secret: str = Field(description="The client secret used to authenticate with the identity provider")
108
+ scope: str = Field(description="The scope used to authenticate with the identity provider")
109
+ grant_type: str = Field(description="The grant type requested from the identity provider")
110
+ token_entries: Optional[List[ConnectionCredentialsEntry]] = Field(
111
+ default=None,
112
+ description="A list of optional custom fields to be passed with OAuth token requests. Supported when connection kind is 'oauth_auth_code_flow', 'oauth_auth_client_credentials_flow', 'oauth_auth_password_flow' or 'oauth_auth_on_behalf_of_flow'"
113
+ )