telnyx-mcp-server-fastmcp 0.1.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.
Files changed (40) hide show
  1. telnyx_mcp_server/__init__.py +0 -0
  2. telnyx_mcp_server/__main__.py +23 -0
  3. telnyx_mcp_server/config.py +148 -0
  4. telnyx_mcp_server/mcp.py +148 -0
  5. telnyx_mcp_server/server.py +497 -0
  6. telnyx_mcp_server/telnyx/__init__.py +1 -0
  7. telnyx_mcp_server/telnyx/client.py +363 -0
  8. telnyx_mcp_server/telnyx/services/__init__.py +0 -0
  9. telnyx_mcp_server/telnyx/services/assistants.py +155 -0
  10. telnyx_mcp_server/telnyx/services/call_control.py +217 -0
  11. telnyx_mcp_server/telnyx/services/cloud_storage.py +289 -0
  12. telnyx_mcp_server/telnyx/services/connections.py +92 -0
  13. telnyx_mcp_server/telnyx/services/embeddings.py +52 -0
  14. telnyx_mcp_server/telnyx/services/messaging.py +93 -0
  15. telnyx_mcp_server/telnyx/services/messaging_profiles.py +196 -0
  16. telnyx_mcp_server/telnyx/services/numbers.py +193 -0
  17. telnyx_mcp_server/telnyx/services/secrets.py +74 -0
  18. telnyx_mcp_server/tools/__init__.py +126 -0
  19. telnyx_mcp_server/tools/assistants.py +313 -0
  20. telnyx_mcp_server/tools/call_control.py +242 -0
  21. telnyx_mcp_server/tools/cloud_storage.py +183 -0
  22. telnyx_mcp_server/tools/connections.py +78 -0
  23. telnyx_mcp_server/tools/embeddings.py +80 -0
  24. telnyx_mcp_server/tools/messaging.py +57 -0
  25. telnyx_mcp_server/tools/messaging_profiles.py +123 -0
  26. telnyx_mcp_server/tools/phone_numbers.py +161 -0
  27. telnyx_mcp_server/tools/secrets.py +75 -0
  28. telnyx_mcp_server/tools/sms_conversations.py +455 -0
  29. telnyx_mcp_server/tools/webhooks.py +111 -0
  30. telnyx_mcp_server/utils/__init__.py +0 -0
  31. telnyx_mcp_server/utils/error_handler.py +30 -0
  32. telnyx_mcp_server/utils/logger.py +32 -0
  33. telnyx_mcp_server/utils/service.py +33 -0
  34. telnyx_mcp_server/webhook/__init__.py +25 -0
  35. telnyx_mcp_server/webhook/handler.py +596 -0
  36. telnyx_mcp_server/webhook/server.py +369 -0
  37. telnyx_mcp_server_fastmcp-0.1.3.dist-info/METADATA +430 -0
  38. telnyx_mcp_server_fastmcp-0.1.3.dist-info/RECORD +40 -0
  39. telnyx_mcp_server_fastmcp-0.1.3.dist-info/WHEEL +4 -0
  40. telnyx_mcp_server_fastmcp-0.1.3.dist-info/entry_points.txt +3 -0
@@ -0,0 +1,313 @@
1
+ """Assistant related MCP tools."""
2
+
3
+ from typing import Any, Dict
4
+
5
+ from pydantic import Field
6
+
7
+ from ..mcp import mcp
8
+ from ..telnyx.services.assistants import AssistantsService
9
+ from ..utils.error_handler import handle_telnyx_error
10
+ from ..utils.logger import get_logger
11
+ from ..utils.service import get_authenticated_service
12
+
13
+ logger = get_logger(__name__)
14
+
15
+
16
+ @mcp.tool()
17
+ async def create_assistant(request: Dict[str, Any]) -> Dict[str, Any]:
18
+ """Create a new AI Assistant. The user will provide some details (sometimes
19
+ detailed, sometimes vague) about the agent they want to create.
20
+
21
+ Args:
22
+ name: Required. Name of the assistant. If not provided, will be generated based on context.
23
+ model: Required. Model to use for the assistant. Defaults to meta-llama/Meta-Llama-3.1-70B-Instruct.
24
+ instructions: Required. Core instructions or behaviors for the agent.
25
+ description: Optional. A summary of the agent's purpose.
26
+ tools: Optional. List of tools for the assistant, each containing:
27
+ - type: Required. Type of tool ("function", "retrieval", "webhook",
28
+ "hangup", "send_dtmf", "transfer").
29
+ - function: Optional. For function tools, contains:
30
+ - name: Required. Name of the function.
31
+ - description: Optional. Description of the function.
32
+ - parameters: Required. Parameters schema for the function.
33
+ - retrieval: Optional. For retrieval tools, contains:
34
+ - bucket_ids: Required. List of bucket IDs for retrieval.
35
+ - max_num_results: Optional. Maximum number of results to retrieve.
36
+ - webhook: Optional. For webhook tools, contains:
37
+ - name: Required. The name of the tool.
38
+ - description: Required. The description of the tool.
39
+ - url: Required. The URL of the external tool to be called. This URL can be
40
+ templated like: https://example.com/api/v1/{id}, where {id} is a
41
+ placeholder for a value that will be provided by the assistant if
42
+ path_parameters are provided with the id attribute.
43
+ - method: Optional. The HTTP method to be used. Possible values:
44
+ [GET, POST, PUT, DELETE, PATCH]. Default value: POST.
45
+ - headers: Optional. Array of header objects with:
46
+ - name: String name of the header.
47
+ - value: String value of the header. Supports mustache templating.
48
+ e.g., Bearer {{#integration_secret}}test-secret{{/integration_secret}}.
49
+ Secrets can be found in `list_integration_secrets`
50
+ - body_parameters: Optional. JSON Schema object describing the body parameters:
51
+ - properties: Object defining the properties of the body parameters.
52
+ - required: Array of strings listing required properties.
53
+ - type: String. Possible value: "object".
54
+ - path_parameters: Optional. JSON Schema object describing the path parameters:
55
+ - properties: Object defining the properties of the path parameters.
56
+ - required: Array of strings listing required properties.
57
+ - type: String. Possible value: "object".
58
+ - query_parameters: Optional. JSON Schema object describing the query parameters:
59
+ - properties: Object defining the properties of the query parameters.
60
+ - required: Array of strings listing required properties.
61
+ - type: String. Possible value: "object".
62
+ - hangup: Optional. For hangup tools, contains:
63
+ - description: Optional. Description of the hangup function. Defaults to
64
+ "This tool is used to hang up the call."
65
+ - send_dtmf: Optional. For DTMF tools, contains an empty object. This tool
66
+ allows sending DTMF tones during a call.
67
+ - transfer: Optional. For transfer tools, contains:
68
+ - targets: Required. Array of transfer targets, each with:
69
+ - name: Optional. Name of the target.
70
+ - to: Required. Destination number or SIP URI.
71
+ - from: Required. Number or SIP URI placing the call.
72
+ - custom_headers: Optional. Array of custom SIP headers, each with:
73
+ - name: Required. Name of the header.
74
+ - value: Required. Value of the header. Supports mustache templating.
75
+ greeting: Optional. A short welcoming message. Will be generated if not provided.
76
+ llm_api_key_ref: Optional. LLM API key reference.
77
+ transcription: Optional. Transcription settings with:
78
+ - model: Optional. Model to use for transcription.
79
+ messaging_settings: Optional. Messaging settings with:
80
+ - default_messaging_profile_id: Optional. Default messaging profile ID.
81
+ - delivery_status_webhook_url: Optional. Webhook URL for delivery status updates.
82
+ insight_settings: Optional. Insight settings with:
83
+ - insight_group_id: Optional. Insight group ID.
84
+ dynamic_variables_webhook_url: Optional. Dynamic variables webhook URL.
85
+ dynamic_variables: Optional. Dynamic variables dictionary.
86
+
87
+ Returns:
88
+ Dict[str, Any]: Response data
89
+ """
90
+ try:
91
+ service = get_authenticated_service(AssistantsService)
92
+ return service.create_assistant(request)
93
+ except Exception as e:
94
+ logger.error(f"Error creating assistant: {e}")
95
+ raise handle_telnyx_error(e)
96
+
97
+
98
+ @mcp.tool()
99
+ async def list_assistants() -> Dict[str, Any]:
100
+ """List all AI Assistants.
101
+
102
+ Returns:
103
+ Dict[str, Any]: List of assistants
104
+ """
105
+ try:
106
+ service = get_authenticated_service(AssistantsService)
107
+ return service.list_assistants()
108
+ except Exception as e:
109
+ logger.error(f"Error listing assistants: {e}")
110
+ raise handle_telnyx_error(e)
111
+
112
+
113
+ @mcp.tool()
114
+ async def get_assistant(request: Dict[str, Any]) -> Dict[str, Any]:
115
+ """Get an AI Assistant by ID.
116
+
117
+ Args:
118
+ assistant_id: Required. Assistant ID.
119
+ fetch_dynamic_variables_from_webhook: Optional boolean. Whether to fetch dynamic variables from webhook.
120
+ from_: Optional. From parameter for dynamic variables.
121
+ to: Optional. To parameter for dynamic variables.
122
+ call_control_id: Optional. Call control ID for dynamic variables.
123
+
124
+ Returns:
125
+ Dict[str, Any]: Response data
126
+ """
127
+ try:
128
+ service = get_authenticated_service(AssistantsService)
129
+ return service.get_assistant(
130
+ assistant_id=request["assistant_id"],
131
+ fetch_dynamic_variables_from_webhook=request.get(
132
+ "fetch_dynamic_variables_from_webhook"
133
+ ),
134
+ from_=request.get("from_"),
135
+ to=request.get("to"),
136
+ call_control_id=request.get("call_control_id"),
137
+ )
138
+ except Exception as e:
139
+ logger.error(f"Error getting assistant: {e}")
140
+ raise handle_telnyx_error(e)
141
+
142
+
143
+ @mcp.tool()
144
+ async def update_assistant(
145
+ assistant_id: str, request: Dict[str, Any]
146
+ ) -> Dict[str, Any]:
147
+ """Update an AI Assistant. Once there is an agent created, you can talk the
148
+ user about what can be updated in an easy manner, rather than asking for a
149
+ long list of fields to update.
150
+
151
+ Args:
152
+ assistant_id: Required. ID of the assistant to update.
153
+ name: Optional. Name of the assistant.
154
+ model: Optional. Model to use for the assistant.
155
+ instructions: Optional. Core instructions or behaviors for the agent.
156
+ description: Optional. A summary of the agent's purpose.
157
+ tools: Optional. List of tools for the assistant, each containing:
158
+ - type: Required. Type of tool (ANY of "hangup", "retrieval", "send_dtmf",
159
+ "transfer", "webhook").
160
+ - retrieval: Optional. For retrieval tools, contains:
161
+ - bucket_ids: Required. List of bucket IDs for retrieval.
162
+ - max_num_results: Optional. Maximum number of results to retrieve.
163
+ - webhook: Optional. For webhook tools, contains:
164
+ - name: Required. The name of the tool.
165
+ - description: Required. The description of the tool.
166
+ - url: Required. The URL of the external tool to be called. This URL can be
167
+ templated like: https://example.com/api/v1/{id}, where {id} is a
168
+ placeholder for a value that will be provided by the assistant if
169
+ path_parameters are provided with the id attribute.
170
+ - method: Optional. The HTTP method to be used. Possible values:
171
+ [GET, POST, PUT, DELETE, PATCH]. Default value: POST.
172
+ - headers: Optional. Array of header objects with:
173
+ - name: String name of the header.
174
+ - value: String value of the header. Supports mustache templating,
175
+ e.g., Bearer {{#integration_secret}}test-secret{{/integration_secret}}.
176
+ Secrets can be found in `list_integration_secrets`
177
+ - body_parameters: Optional. JSON Schema object describing the body parameters:
178
+ - properties: Object defining the properties of the body parameters.
179
+ - required: Array of strings listing required properties.
180
+ - type: String. Possible value: "object".
181
+ - path_parameters: Optional. JSON Schema object describing the path parameters:
182
+ - properties: Object defining the properties of the path parameters.
183
+ - required: Array of strings listing required properties.
184
+ - type: String. Possible value: "object".
185
+ - query_parameters: Optional. JSON Schema object describing the query parameters:
186
+ - properties: Object defining the properties of the query parameters.
187
+ - required: Array of strings listing required properties.
188
+ - type: String. Possible value: "object".
189
+ - hangup: Optional. For hangup tools, contains:
190
+ - description: Optional. Description of the hangup function.
191
+ - send_dtmf: Optional. For DTMF tools, contains an empty object. This tool
192
+ allows sending DTMF tones during a call.
193
+ - transfer: Optional. For transfer tools, contains:
194
+ - targets: Required. Array of transfer targets, each with:
195
+ - name: Optional. Name of the target.
196
+ - to: Required. Destination number or SIP URI.
197
+ - from: Required. Number or SIP URI placing the call.
198
+ - custom_headers: Optional. Array of custom SIP headers, each with:
199
+ - name: Required. Name of the header.
200
+ - value: Required. Value of the header. Supports mustache templating.
201
+ eg: {{#integration_secret}}test-secret{{/integration_secret}}
202
+ to be used with integration secrets (Available secrets can be
203
+ found in `list_integration_secrets`)
204
+ greeting: Optional. A short welcoming message used by the agent.
205
+ llm_api_key_ref: Optional. LLM API key reference. This is meant to be used
206
+ for models provided by external vendors. eg: openai, anthropic, Groq, xai-org.
207
+ Available secrets can be found in `list_integration_secrets`
208
+ transcription: Optional. Transcription settings with:
209
+ - model: Optional. Model to use for transcription.
210
+ telephony_settings: Optional. Telephony settings with:
211
+ - default_texml_app_id: Optional. Default TeXML application ID.
212
+ messaging_settings: Optional. Messaging settings with:
213
+ - default_messaging_profile_id: Optional. Default messaging profile ID.
214
+ - delivery_status_webhook_url: Optional. Webhook URL for delivery status updates.
215
+ insight_settings: Optional. Insight settings with:
216
+ - insight_group_id: Optional. Insight group ID.
217
+ dynamic_variables_webhook_url: Optional. Dynamic variables webhook URL.
218
+ dynamic_variables: Optional. Dynamic variables dictionary.
219
+
220
+ Returns:
221
+ Dict[str, Any]: Response data
222
+ """
223
+ try:
224
+ service = get_authenticated_service(AssistantsService)
225
+ return service.update_assistant(assistant_id, request)
226
+ except Exception as e:
227
+ logger.error(f"Error updating assistant: {e}")
228
+ raise handle_telnyx_error(e)
229
+
230
+
231
+ @mcp.tool()
232
+ async def mcp_telnyx_delete_assistant(
233
+ id: str = Field(..., description="Assistant ID as string"),
234
+ ) -> Dict[str, Any]:
235
+ """Delete an AI Assistant.
236
+
237
+ Args:
238
+ id: Assistant ID as string
239
+
240
+ Returns:
241
+ Dict[str, Any]: Response data containing deletion status
242
+ """
243
+ try:
244
+ service = get_authenticated_service(AssistantsService)
245
+ return service.delete_assistant(id)
246
+ except Exception as e:
247
+ logger.error(f"Error deleting assistant: {e}")
248
+ raise handle_telnyx_error(e)
249
+
250
+
251
+ @mcp.tool()
252
+ async def get_assistant_texml(
253
+ assistant_id: str = Field(..., description="Assistant ID"),
254
+ ) -> str:
255
+ """Get an assistant's TEXML by ID.
256
+
257
+ Args:
258
+ assistant_id: Assistant ID
259
+
260
+ Returns:
261
+ str: Assistant TEXML content
262
+ """
263
+ try:
264
+ service = get_authenticated_service(AssistantsService)
265
+ return service.get_assistant_texml(assistant_id)
266
+ except Exception as e:
267
+ logger.error(f"Error getting assistant TEXML: {e}")
268
+ raise handle_telnyx_error(e)
269
+
270
+
271
+ @mcp.tool()
272
+ async def start_assistant_call(
273
+ assistant_id: str,
274
+ to: str,
275
+ from_: str,
276
+ ) -> Dict[str, Any]:
277
+ """Start a call using an AI Assistant with a phone number.
278
+
279
+ Args:
280
+ assistant_id: Required. ID of the assistant to use for the call.
281
+ to: Required. Destination phone number to call.
282
+ from_: Required. Source phone number to call from (must be a number on your Telnyx account).
283
+
284
+ Returns:
285
+ Dict[str, Any]: Response data from the call initiation
286
+ """
287
+ try:
288
+ # First, get the assistant to retrieve the default_texml_app_id
289
+ service = get_authenticated_service(AssistantsService)
290
+ assistant = service.get_assistant(assistant_id=assistant_id)
291
+
292
+ # Extract the default_texml_app_id from the assistant
293
+ if (
294
+ not assistant
295
+ or not assistant.get("telephony_settings")
296
+ or not assistant["telephony_settings"].get("default_texml_app_id")
297
+ ):
298
+ raise ValueError(
299
+ "The assistant does not have a default TeXML application ID configured"
300
+ )
301
+
302
+ default_texml_app_id = assistant["telephony_settings"][
303
+ "default_texml_app_id"
304
+ ]
305
+
306
+ # Start the call
307
+ response = service.start_assistant_call(
308
+ default_texml_app_id=default_texml_app_id, to=to, from_=from_
309
+ )
310
+ return response
311
+ except Exception as e:
312
+ logger.error(f"Error starting assistant call: {e}")
313
+ raise handle_telnyx_error(e)
@@ -0,0 +1,242 @@
1
+ """Call control related MCP tools."""
2
+
3
+ from typing import Any, Dict
4
+
5
+ from ..mcp import mcp
6
+ from ..telnyx.services.call_control import CallControlService
7
+ from ..utils.error_handler import handle_telnyx_error
8
+ from ..utils.logger import get_logger
9
+ from ..utils.service import get_authenticated_service
10
+
11
+ logger = get_logger(__name__)
12
+
13
+
14
+ @mcp.tool()
15
+ async def list_call_control_applications(
16
+ request: Dict[str, Any],
17
+ ) -> Dict[str, Any]:
18
+ """List call control applications.
19
+
20
+ Args:
21
+ page: Optional integer. Page number. Defaults to 1.
22
+ page_size: Optional integer. Page size. Defaults to 20.
23
+ filter_application_name_contains: Optional. Filter by application name (case-insensitive, min 3 characters).
24
+ filter_outbound_voice_profile_id: Optional. Filter by associated outbound voice profile ID.
25
+ sort: Optional. Sort order for results (created_at, connection_name, active). Defaults to created_at.
26
+
27
+ Returns:
28
+ Dict[str, Any]: Response data
29
+ """
30
+ try:
31
+ service = get_authenticated_service(CallControlService)
32
+ return service.list_call_control_applications(request)
33
+ except Exception as e:
34
+ logger.error(f"Error listing call control applications: {e}")
35
+ raise handle_telnyx_error(e)
36
+
37
+
38
+ @mcp.tool()
39
+ async def get_call_control_application(
40
+ request: Dict[str, Any],
41
+ ) -> Dict[str, Any]:
42
+ """Retrieve a specific call control application.
43
+
44
+ Args:
45
+ id: Required. Identifies the call control application.
46
+
47
+ Returns:
48
+ Dict[str, Any]: Response data
49
+ """
50
+ try:
51
+ service = get_authenticated_service(CallControlService)
52
+ return service.get_call_control_application(request)
53
+ except Exception as e:
54
+ logger.error(f"Error retrieving call control application: {e}")
55
+ raise handle_telnyx_error(e)
56
+
57
+
58
+ @mcp.tool()
59
+ async def create_call_control_application(
60
+ request: Dict[str, Any],
61
+ ) -> Dict[str, Any]:
62
+ """Create a call control application.
63
+
64
+ Args:
65
+ application_name: Required. A user-assigned name to help manage the application.
66
+ webhook_event_url: Required. The URL where webhooks related to this connection will be sent. Must include a scheme, such as 'https'.
67
+ active: Optional boolean. Specifies whether the connection can be used. Defaults to True.
68
+ anchorsite_override: Optional. Directs Telnyx to route media through the site with the lowest round-trip time. Defaults to "Latency".
69
+ dtmf_type: Optional. Sets the type of DTMF digits sent from Telnyx to this Connection. Defaults to "RFC 2833".
70
+ first_command_timeout: Optional boolean. Specifies whether calls should hangup after timing out.
71
+ first_command_timeout_secs: Optional integer. Seconds to wait before timing out a dial command. Defaults to 30.
72
+ inbound: Optional dictionary. Inbound call settings with these possible keys:
73
+ - channel_limit: Optional integer. Maximum number of concurrent inbound calls.
74
+ - shaken_stir_enabled: Optional boolean. Enable SHAKEN/STIR verification for inbound calls.
75
+ - sip_subdomain: Optional string. SIP subdomain for the application.
76
+ - sip_subdomain_receive_settings: Optional string. Settings for SIP subdomain receiving.
77
+ outbound: Optional dictionary. Outbound call settings with these possible keys:
78
+ - channel_limit: Optional integer. Maximum number of concurrent outbound calls.
79
+ - outbound_voice_profile_id: Optional string. ID of the outbound voice profile to use.
80
+ webhook_api_version: Optional. Determines which webhook format will be used. Defaults to "1".
81
+ webhook_event_failover_url: Optional. The failover URL for webhooks if the primary URL fails.
82
+ webhook_timeout_secs: Optional integer. Seconds to wait before timing out a webhook.
83
+ Returns:
84
+ Dict[str, Any]: Response data
85
+ """
86
+ try:
87
+ service = get_authenticated_service(CallControlService)
88
+ return service.create_call_control_application(request)
89
+ except Exception as e:
90
+ logger.error(f"Error creating call control application: {e}")
91
+ raise handle_telnyx_error(e)
92
+
93
+
94
+ @mcp.tool()
95
+ async def make_call(request: Dict[str, Any]) -> Dict[str, Any]:
96
+ """Make a call.
97
+
98
+ Args:
99
+ to: Required. Destination number or SIP URI.
100
+ from_: Required. Source number.
101
+ connection_id: Optional. Connection ID of a call control application to use for the call (same as call_control_application_id).
102
+
103
+ Returns:
104
+ Dict[str, Any]: Response data
105
+ """
106
+ try:
107
+ service = get_authenticated_service(CallControlService)
108
+ return service.make_call(request)
109
+ except Exception as e:
110
+ logger.error(f"Error making call: {e}")
111
+ raise handle_telnyx_error(e)
112
+
113
+
114
+ @mcp.tool()
115
+ async def hangup(request: Dict[str, Any]) -> Dict[str, Any]:
116
+ """Hang up a call.
117
+
118
+ Args:
119
+ call_control_id: Required. Call control ID.
120
+
121
+ Returns:
122
+ Dict[str, Any]: Response data
123
+ """
124
+ try:
125
+ call_control_id = request.pop("call_control_id")
126
+ service = get_authenticated_service(CallControlService)
127
+ return service.hangup(call_control_id, request)
128
+ except Exception as e:
129
+ logger.error(f"Error hanging up call: {e}")
130
+ raise handle_telnyx_error(e)
131
+
132
+
133
+ @mcp.tool()
134
+ async def playback_start(request: Dict[str, Any]) -> Dict[str, Any]:
135
+ """Start audio playback on a call.
136
+
137
+ Args:
138
+ call_control_id: Required. Call control ID.
139
+ audio_url: Required. URL of audio file to play.
140
+ loop: Optional. Number of times to loop the audio. Valid values: infinity, 1, 2, 3, 4, 5.
141
+ overlay: Optional boolean. Whether to overlay the audio on existing audio. Defaults to False.
142
+ stop: Optional. Which audio to stop. Valid values: current, all.
143
+ target_legs: Optional. Which leg(s) to play the audio on. Valid values: self, peer, both.
144
+
145
+ Returns:
146
+ Dict[str, Any]: Response data
147
+ """
148
+ try:
149
+ call_control_id = request.pop("call_control_id")
150
+ service = get_authenticated_service(CallControlService)
151
+ return service.playback_start(call_control_id, request)
152
+ except Exception as e:
153
+ logger.error(f"Error starting playback: {e}")
154
+ raise handle_telnyx_error(e)
155
+
156
+
157
+ @mcp.tool()
158
+ async def playback_stop(request: Dict[str, Any]) -> Dict[str, Any]:
159
+ """Stop audio playback on a call.
160
+
161
+ Args:
162
+ call_control_id: Required. Call control ID.
163
+ overlay: Optional boolean. Whether to stop overlay audio. Defaults to False.
164
+ stop: Optional. Which audio to stop. Valid values: current, all.
165
+
166
+ Returns:
167
+ Dict[str, Any]: Response data
168
+ """
169
+ try:
170
+ call_control_id = request.pop("call_control_id")
171
+ service = get_authenticated_service(CallControlService)
172
+ return service.playback_stop(call_control_id, request)
173
+ except Exception as e:
174
+ logger.error(f"Error stopping playback: {e}")
175
+ raise handle_telnyx_error(e)
176
+
177
+
178
+ @mcp.tool()
179
+ async def send_dtmf(request: Dict[str, Any]) -> Dict[str, Any]:
180
+ """Send DTMF tones on a call.
181
+
182
+ Args:
183
+ call_control_id: Required. Call control ID.
184
+ digits: Required. DTMF digits to send (0-9, *, #, w, W).
185
+ duration_millis: Optional integer. Duration of each digit in milliseconds. Defaults to 500.
186
+
187
+ Returns:
188
+ Dict[str, Any]: Response data
189
+ """
190
+ try:
191
+ call_control_id = request.pop("call_control_id")
192
+ service = get_authenticated_service(CallControlService)
193
+ return service.send_dtmf(call_control_id, request)
194
+ except Exception as e:
195
+ logger.error(f"Error sending DTMF: {e}")
196
+ raise handle_telnyx_error(e)
197
+
198
+
199
+ @mcp.tool()
200
+ async def speak(request: Dict[str, Any]) -> Dict[str, Any]:
201
+ """Speak text on a call using text-to-speech.
202
+
203
+ Args:
204
+ call_control_id: Required. Call control ID.
205
+ payload: Required. Text to speak.
206
+ voice: Required. Voice to use. Defaults to female
207
+ payload_type: Optional. Type of payload. Valid values: text, ssml. Defaults to "text".
208
+ service_level: Optional. Service level for TTS. Valid values: basic, premium. Defaults to "basic".
209
+ stop: Optional. Which audio to stop. Valid values: current, all.
210
+ language: Optional. Language code (e.g., 'en-US', 'arb').
211
+
212
+ Returns:
213
+ Dict[str, Any]: Response data
214
+ """
215
+ try:
216
+ call_control_id = request.pop("call_control_id")
217
+ service = get_authenticated_service(CallControlService)
218
+ return service.speak(call_control_id, request)
219
+ except Exception as e:
220
+ logger.error(f"Error speaking text: {e}")
221
+ raise handle_telnyx_error(e)
222
+
223
+
224
+ @mcp.tool()
225
+ async def transfer(request: Dict[str, Any]) -> Dict[str, Any]:
226
+ """Transfer a call to a new destination.
227
+
228
+ Args:
229
+ call_control_id: Required. Call control ID.
230
+ to: Required. Destination number or SIP URI.
231
+ from_: Required. Source number.
232
+
233
+ Returns:
234
+ Dict[str, Any]: Response data
235
+ """
236
+ try:
237
+ call_control_id = request.pop("call_control_id")
238
+ service = get_authenticated_service(CallControlService)
239
+ return service.transfer(call_control_id, request)
240
+ except Exception as e:
241
+ logger.error(f"Error transferring call: {e}")
242
+ raise handle_telnyx_error(e)