deepctl-cmd-mcp 0.1.0__tar.gz

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.
@@ -0,0 +1,32 @@
1
+ Metadata-Version: 2.4
2
+ Name: deepctl-cmd-mcp
3
+ Version: 0.1.0
4
+ Summary: MCP server command for deepctl to interact with Deepgram's AI assistant service
5
+ Author-email: Deepgram <devrel@deepgram.com>
6
+ License-Expression: MIT
7
+ Requires-Python: >=3.10
8
+ Description-Content-Type: text/markdown
9
+ Requires-Dist: deepctl-core>=0.1.0
10
+ Requires-Dist: mcp>=1.0.0
11
+ Requires-Dist: rich>=13.9.4
12
+ Requires-Dist: click>=8.1.7
13
+ Requires-Dist: pydantic>=2.10.1
14
+ Requires-Dist: httpx>=0.28.1
15
+ Provides-Extra: dev
16
+ Requires-Dist: pytest>=8.3.3; extra == "dev"
17
+ Requires-Dist: pytest-asyncio>=0.24.0; extra == "dev"
18
+ Requires-Dist: pytest-cov>=6.0.0; extra == "dev"
19
+ Requires-Dist: pytest-mock>=3.14.0; extra == "dev"
20
+ Requires-Dist: mypy>=1.13.0; extra == "dev"
21
+ Requires-Dist: ruff>=0.8.1; extra == "dev"
22
+
23
+ # deepctl-cmd-mcp
24
+
25
+ This package provides two ways to interact with Deepgram's AI assistant:
26
+
27
+ 1. **MCP Server**: Run an MCP server that exposes Deepgram's AI assistant tools
28
+ 2. **Python Client**: Standalone Python client for interacting with Deepgram's AI API
29
+
30
+ ## Installation
31
+
32
+ This package is installed as part of the main deepctl CLI.
@@ -0,0 +1,10 @@
1
+ # deepctl-cmd-mcp
2
+
3
+ This package provides two ways to interact with Deepgram's AI assistant:
4
+
5
+ 1. **MCP Server**: Run an MCP server that exposes Deepgram's AI assistant tools
6
+ 2. **Python Client**: Standalone Python client for interacting with Deepgram's AI API
7
+
8
+ ## Installation
9
+
10
+ This package is installed as part of the main deepctl CLI.
@@ -0,0 +1,50 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "deepctl-cmd-mcp"
7
+ version = "0.1.0"
8
+ description = "MCP server command for deepctl to interact with Deepgram's AI assistant service"
9
+ readme = "README.md"
10
+ authors = [{ name = "Deepgram", email = "devrel@deepgram.com" }]
11
+ requires-python = ">=3.10"
12
+ license = "MIT"
13
+ dependencies = [
14
+ "deepctl-core>=0.1.0",
15
+ "mcp>=1.0.0",
16
+ "rich>=13.9.4",
17
+ "click>=8.1.7",
18
+ "pydantic>=2.10.1",
19
+ "httpx>=0.28.1",
20
+ ]
21
+
22
+ [project.entry-points."deepctl.commands"]
23
+ mcp = "deepctl_cmd_mcp.command:McpCommand"
24
+
25
+ [project.optional-dependencies]
26
+ dev = [
27
+ "pytest>=8.3.3",
28
+ "pytest-asyncio>=0.24.0",
29
+ "pytest-cov>=6.0.0",
30
+ "pytest-mock>=3.14.0",
31
+ "mypy>=1.13.0",
32
+ "ruff>=0.8.1",
33
+ ]
34
+
35
+ [tool.setuptools.packages.find]
36
+ where = ["src"]
37
+ include = ["deepctl_cmd_mcp*"]
38
+
39
+ [tool.ruff]
40
+ line-length = 88
41
+ target-version = "py310"
42
+
43
+ [tool.ruff.lint]
44
+ select = ["E", "F", "I", "N", "W", "B", "Q"]
45
+ ignore = ["E501"]
46
+
47
+ [tool.mypy]
48
+ python_version = "3.10"
49
+ warn_return_any = true
50
+ warn_unused_configs = true
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,14 @@
1
+ """MCP server command for deepctl."""
2
+
3
+ from .command import McpCommand
4
+ from .gnosis import GnosisClient, GnosisRequest, GnosisResponse
5
+ from .models import MCPServerResult, TransportType
6
+
7
+ __all__ = [
8
+ "McpCommand",
9
+ "GnosisClient",
10
+ "GnosisRequest",
11
+ "GnosisResponse",
12
+ "MCPServerResult",
13
+ "TransportType",
14
+ ]
@@ -0,0 +1,8 @@
1
+ """Main entry point for running gnosis module directly."""
2
+
3
+ from .gnosis import main
4
+
5
+ if __name__ == "__main__":
6
+ import asyncio
7
+
8
+ asyncio.run(main())
@@ -0,0 +1,387 @@
1
+ """MCP server command for deepctl."""
2
+
3
+ import os
4
+ from typing import Any, Dict, List, Optional
5
+
6
+ from deepctl_core import AuthManager, BaseCommand, Config, DeepgramClient
7
+ from mcp.server.fastmcp import Context, FastMCP
8
+ from rich.console import Console
9
+
10
+ from .gnosis import GnosisClient
11
+ from .models import MCPServerResult, TransportType
12
+
13
+ console = Console()
14
+
15
+
16
+ class McpCommand(BaseCommand):
17
+ """MCP server command for interacting with Deepgram's AI assistant."""
18
+
19
+ name = "mcp"
20
+ help = "Run an MCP server that connects to Deepgram's AI assistant service"
21
+ short_help = "Run MCP server for Deepgram AI"
22
+
23
+ # MCP doesn't require existing auth to start, but can use it
24
+ requires_auth = False
25
+ requires_project = False
26
+ ci_friendly = True
27
+
28
+ def get_arguments(self) -> List[Dict[str, Any]]:
29
+ """Get command arguments and options."""
30
+ return [
31
+ {
32
+ "names": ["--transport", "-t"],
33
+ "help": (
34
+ "Transport mode: stdio (default), sse, "
35
+ "or streamable-http"
36
+ ),
37
+ "type": str,
38
+ "default": "stdio",
39
+ "required": False,
40
+ "is_option": True,
41
+ },
42
+ {
43
+ "names": ["--port", "-p"],
44
+ "help": "Port number for HTTP server (default: 8000)",
45
+ "type": int,
46
+ "default": 8000,
47
+ "required": False,
48
+ "is_option": True,
49
+ },
50
+ {
51
+ "names": ["--host"],
52
+ "help": "Host address for HTTP server (default: 127.0.0.1)",
53
+ "type": str,
54
+ "default": "127.0.0.1",
55
+ "required": False,
56
+ "is_option": True,
57
+ },
58
+ {
59
+ "names": ["--api-key"],
60
+ "help": (
61
+ "Override API key for Deepgram AI service (falls back to "
62
+ "profile or DEEPGRAM_API_KEY env var)"
63
+ ),
64
+ "type": str,
65
+ "required": False,
66
+ "is_option": True,
67
+ },
68
+ {
69
+ "names": ["--gnosis-url"],
70
+ "help": "Base URL for Deepgram AI service",
71
+ "type": str,
72
+ "default": "https://gnosis.deepgram.com",
73
+ "required": False,
74
+ "is_option": True,
75
+ },
76
+ {
77
+ "names": ["--debug"],
78
+ "help": "Enable debug logging",
79
+ "is_flag": True,
80
+ "is_option": True,
81
+ },
82
+ ]
83
+
84
+ def handle(
85
+ self,
86
+ config: Config,
87
+ auth_manager: AuthManager,
88
+ client: DeepgramClient,
89
+ **kwargs: Any,
90
+ ) -> Any:
91
+ """Handle MCP server command."""
92
+ transport = kwargs.get("transport", "stdio").lower()
93
+ port = kwargs.get("port", 8000)
94
+ host = kwargs.get("host", "127.0.0.1")
95
+ gnosis_api_key = kwargs.get("api_key") or os.getenv("DEEPGRAM_API_KEY")
96
+ # Fallback to stored credentials if no key provided
97
+ if not gnosis_api_key:
98
+ gnosis_api_key = auth_manager.get_api_key()
99
+ gnosis_url = kwargs.get("gnosis_url", "https://gnosis.deepgram.com")
100
+ debug = kwargs.get("debug", False)
101
+
102
+ # Validate transport type
103
+ valid_transports = ["stdio", "sse", "streamable-http"]
104
+ if transport not in valid_transports:
105
+ console.print(
106
+ f"[red]Invalid transport type:[/red] {transport}. "
107
+ f"Must be one of: {', '.join(valid_transports)}"
108
+ )
109
+ return MCPServerResult(
110
+ status="error", message=f"Invalid transport type: {transport}"
111
+ )
112
+
113
+ # Store configuration in environment for the MCP server
114
+ if isinstance(gnosis_api_key, str) and gnosis_api_key:
115
+ # Expose for child processes / downstream code
116
+ os.environ["DEEPGRAM_API_KEY"] = gnosis_api_key
117
+ os.environ["DEEPGRAM_GNOSIS_URL"] = gnosis_url
118
+ if debug:
119
+ os.environ["DEEPGRAM_MCP_DEBUG"] = "1"
120
+
121
+ # Create and run the MCP server
122
+ mcp_server = create_mcp_server()
123
+
124
+ try:
125
+ if transport == "stdio":
126
+ console.print(
127
+ "[blue]Starting MCP server in stdio mode...[/blue]"
128
+ )
129
+ mcp_server.run()
130
+ elif transport == "sse":
131
+ console.print(
132
+ f"[blue]Starting MCP SSE server on {host}:{port}...[/blue]"
133
+ )
134
+ mcp_server.run(transport="sse")
135
+ elif transport == "streamable-http":
136
+ console.print(
137
+ f"[blue]Starting MCP Streamable HTTP server on "
138
+ f"{host}:{port}...[/blue]"
139
+ )
140
+ mcp_server.run(transport="streamable-http")
141
+
142
+ return MCPServerResult(
143
+ status="success",
144
+ message="MCP server stopped",
145
+ transport=TransportType(transport.replace("-", "")),
146
+ port=port if transport != "stdio" else None,
147
+ host=host if transport != "stdio" else None,
148
+ )
149
+
150
+ except KeyboardInterrupt:
151
+ console.print("\n[yellow]MCP server stopped by user[/yellow]")
152
+ return MCPServerResult(
153
+ status="cancelled",
154
+ message="MCP server stopped by user",
155
+ transport=TransportType(transport.replace("-", "")),
156
+ port=port if transport != "stdio" else None,
157
+ host=host if transport != "stdio" else None,
158
+ )
159
+ except Exception as e:
160
+ console.print(f"[red]Error running MCP server:[/red] {e}")
161
+ return MCPServerResult(
162
+ status="error",
163
+ message=str(e),
164
+ transport=TransportType(transport.replace("-", "")),
165
+ port=port if transport != "stdio" else None,
166
+ host=host if transport != "stdio" else None,
167
+ )
168
+
169
+
170
+ def create_mcp_server() -> FastMCP:
171
+ """Create the MCP server with Deepgram AI assistant tools."""
172
+ # Create FastMCP instance
173
+ mcp = FastMCP("Deepgram AI Assistant")
174
+
175
+ # Get configuration from environment
176
+ gnosis_api_key = os.getenv("DEEPGRAM_API_KEY")
177
+ gnosis_url = os.getenv(
178
+ "DEEPGRAM_GNOSIS_URL", "https://gnosis.deepgram.com"
179
+ )
180
+ debug = os.getenv("DEEPGRAM_MCP_DEBUG", "").lower() in ("1", "true", "yes")
181
+
182
+ # Debug logging to diagnose URL issue
183
+ if debug:
184
+ import sys
185
+
186
+ print(
187
+ f"[DEBUG] DEEPGRAM_GNOSIS_URL from env: {gnosis_url}",
188
+ file=sys.stderr,
189
+ )
190
+
191
+ # Create a shared Gnosis client instance
192
+ try:
193
+ gnosis_client = GnosisClient(
194
+ api_key=gnosis_api_key,
195
+ base_url=gnosis_url,
196
+ debug=debug,
197
+ )
198
+ except ValueError:
199
+ # Client will be None if no API key is available
200
+ gnosis_client = None
201
+
202
+ @mcp.tool()
203
+ async def ask_question(question: str, ctx: Context[Any, Any, Any]) -> str:
204
+ """Ask questions about Deepgram products and services.
205
+
206
+ This is the **catch-all** helper for natural-language queries about
207
+ anything related to Deepgram. Use it for general product or feature
208
+ questions, onboarding advice ("How do I get started with live
209
+ transcription?"), pricing, SDK capabilities, best practices, model
210
+ details, or any other information request that does **not** obviously
211
+ belong to one of the specialised tools below.
212
+
213
+ Example questions that should route to this tool:
214
+ • "What is the difference between pre-recorded and live transcription?"
215
+ • "Does Deepgram offer speaker diarization?"
216
+ • "How accurate is Nova-2 on telephone audio?"
217
+
218
+ Args:
219
+ question: The question to ask about Deepgram (products, services,
220
+ SDKs, APIs, pricing, etc.)
221
+ ctx: MCP context used by FastMCP
222
+ """
223
+ if not gnosis_client:
224
+ return (
225
+ "Error: Deepgram API key not configured. Please set "
226
+ "DEEPGRAM_API_KEY, use the --api-key flag, or store a "
227
+ "credential."
228
+ )
229
+
230
+ if debug:
231
+ await ctx.info(f"Asking question: {question}")
232
+
233
+ try:
234
+ return await gnosis_client.ask_question(
235
+ question,
236
+ system_prompt=(
237
+ "You are a helpful assistant that answers questions about "
238
+ "Deepgram products and services."
239
+ ),
240
+ )
241
+ except Exception as e:
242
+ return f"Error: {str(e)}"
243
+
244
+ @mcp.tool()
245
+ async def check_api_spec(
246
+ api_type: str = "rest",
247
+ endpoint: str = "",
248
+ ctx: Optional[Context[Any, Any, Any]] = None,
249
+ ) -> str:
250
+ """Retrieve Deepgram **API reference** details.
251
+
252
+ Use this tool when the user explicitly asks for endpoint specifics,
253
+ HTTP verbs, WebSocket event schemas, request/response bodies,
254
+ authentication headers, rate limits, or error codes—anything that
255
+ belongs to the formal API specification.
256
+
257
+ Example queries that should trigger this tool:
258
+ • "Show me the REST API spec for /v1/listen"
259
+ • "What fields does the WebSocket start message accept?"
260
+ • "Which status codes can the Transcription API return?"
261
+
262
+ Args:
263
+ api_type: Either 'rest' or 'websocket'. Defaults to 'rest'.
264
+ endpoint: Optional specific endpoint path (e.g., "/v1/listen").
265
+ Leave blank for an overview.
266
+ ctx: MCP context
267
+ """
268
+ if not gnosis_client:
269
+ return (
270
+ "Error: Deepgram API key not configured. Please set "
271
+ "DEEPGRAM_API_KEY, use the --api-key flag, or store a "
272
+ "credential."
273
+ )
274
+
275
+ if ctx and debug:
276
+ await ctx.info(f"Checking API spec: {api_type} {endpoint}")
277
+
278
+ prompt = (
279
+ f"Provide the API specification for Deepgram's {api_type.upper()} "
280
+ )
281
+ if endpoint:
282
+ prompt += f"endpoint: {endpoint}"
283
+ else:
284
+ prompt += "endpoints"
285
+
286
+ try:
287
+ return await gnosis_client.ask_question(
288
+ prompt,
289
+ system_prompt=(
290
+ "You are a technical assistant that provides detailed API "
291
+ "specifications for Deepgram."
292
+ ),
293
+ )
294
+ except Exception as e:
295
+ return f"Error: {str(e)}"
296
+
297
+ @mcp.tool()
298
+ async def get_code_example(
299
+ language: str,
300
+ use_case: str,
301
+ ctx: Optional[Context[Any, Any, Any]] = None,
302
+ ) -> str:
303
+ """Return **ready-to-run code samples** that integrate Deepgram.
304
+
305
+ Use this when the user asks for sample code or snippets in a particular
306
+ language or SDK, e.g. "Give me a Python example for real-time
307
+ transcription" or "Show a JavaScript snippet for batch processing".
308
+
309
+ Args:
310
+ language: Target programming language (python, javascript,
311
+ typescript, go, java, csharp, etc.)
312
+ use_case: The scenario for the snippet (e.g., "real-time
313
+ transcription", "batch processing").
314
+ ctx: MCP context
315
+ """
316
+ if not gnosis_client:
317
+ return (
318
+ "Error: Deepgram API key not configured. Please set "
319
+ "DEEPGRAM_API_KEY, use the --api-key flag, or store a "
320
+ "credential."
321
+ )
322
+
323
+ if ctx and debug:
324
+ await ctx.info(f"Getting code example: {language} for {use_case}")
325
+
326
+ prompt = f"Provide a {language} code example for: {use_case}"
327
+
328
+ try:
329
+ return await gnosis_client.ask_question(
330
+ prompt,
331
+ system_prompt=(
332
+ f"You are a code assistant that provides {language} "
333
+ f"code examples for Deepgram."
334
+ ),
335
+ )
336
+ except Exception as e:
337
+ return f"Error: {str(e)}"
338
+
339
+ @mcp.tool()
340
+ async def search_docs(
341
+ query: str,
342
+ category: str = "all",
343
+ ctx: Optional[Context[Any, Any, Any]] = None,
344
+ ) -> str:
345
+ """Keyword search across official Deepgram documentation.
346
+
347
+ Ideal for requests that mention "documentation", "docs", "guide",
348
+ or when the user wants a how-to or tutorial section. The search can
349
+ be narrowed to specific categories like guides, SDK references, or
350
+ API reference.
351
+
352
+ Example queries:
353
+ • "Find the docs page about audio formats"
354
+ • "Search the guides for diarization"
355
+
356
+ Args:
357
+ query: Search terms to look for.
358
+ category: One of 'guides', 'api-reference', 'sdks', or 'all'.
359
+ Defaults to 'all'.
360
+ ctx: MCP context
361
+ """
362
+ if not gnosis_client:
363
+ return (
364
+ "Error: Deepgram API key not configured. Please set "
365
+ "DEEPGRAM_API_KEY, use the --api-key flag, or store a "
366
+ "credential."
367
+ )
368
+
369
+ if ctx and debug:
370
+ await ctx.info(f"Searching docs: {query} in {category}")
371
+
372
+ search_prompt = f"Search Deepgram documentation for: {query}"
373
+ if category != "all":
374
+ search_prompt += f" (category: {category})"
375
+
376
+ try:
377
+ return await gnosis_client.ask_question(
378
+ search_prompt,
379
+ system_prompt=(
380
+ "You are a documentation assistant that helps find "
381
+ "relevant information in Deepgram's docs."
382
+ ),
383
+ )
384
+ except Exception as e:
385
+ return f"Error: {str(e)}"
386
+
387
+ return mcp
@@ -0,0 +1,372 @@
1
+ """Gnosis API client for Deepgram's AI assistant service."""
2
+
3
+ import asyncio
4
+ import json
5
+ import os
6
+ import sys
7
+ from typing import Any, Dict, List, Optional
8
+
9
+ import httpx
10
+ from pydantic import BaseModel, Field
11
+
12
+
13
+ class GnosisRequest(BaseModel):
14
+ """Request model for Gnosis API."""
15
+
16
+ messages: List[Dict[str, str]] = Field(
17
+ ..., description="List of messages in the conversation"
18
+ )
19
+ model: str = Field(
20
+ default="deepgram", description="Model to use for generation"
21
+ )
22
+ temperature: float = Field(
23
+ default=0.7, description="Temperature for generation"
24
+ )
25
+ max_tokens: Optional[int] = Field(
26
+ default=None, description="Maximum tokens to generate"
27
+ )
28
+
29
+
30
+ class GnosisResponse(BaseModel):
31
+ """Response model from Gnosis API."""
32
+
33
+ choices: List[Dict[str, Any]] = Field(
34
+ default_factory=list, description="Response choices"
35
+ )
36
+ usage: Optional[Dict[str, Any]] = Field(
37
+ default=None, description="Token usage information"
38
+ )
39
+ model: Optional[str] = Field(default=None, description="Model used")
40
+ id: Optional[str] = Field(default=None, description="Response ID")
41
+ created: Optional[int] = Field(
42
+ default=None, description="Creation timestamp"
43
+ )
44
+
45
+
46
+ class GnosisClient:
47
+ """Client for interacting with Deepgram's Gnosis API."""
48
+
49
+ def __init__(
50
+ self,
51
+ api_key: Optional[str] = None,
52
+ base_url: str = "https://gnosis.deepgram.com",
53
+ timeout: float = 30.0,
54
+ debug: bool = False,
55
+ ):
56
+ """Initialize the Gnosis client.
57
+
58
+ Args:
59
+ api_key: Deepgram API key. If not provided, will check
60
+ DEEPGRAM_API_KEY env var.
61
+ base_url: Base URL for Gnosis API.
62
+ timeout: Request timeout in seconds.
63
+ debug: Enable debug logging.
64
+ """
65
+ self.api_key = api_key or os.getenv("DEEPGRAM_API_KEY")
66
+ self.base_url = base_url.rstrip("/")
67
+ self.timeout = timeout
68
+ self.debug = debug
69
+
70
+ if not self.api_key:
71
+ raise ValueError(
72
+ "API key is required. Provide it as a parameter or set "
73
+ "DEEPGRAM_API_KEY environment variable."
74
+ )
75
+
76
+ async def call(
77
+ self,
78
+ messages: List[Dict[str, str]],
79
+ model: str = "deepgram",
80
+ temperature: float = 0.7,
81
+ max_tokens: Optional[int] = None,
82
+ ) -> str:
83
+ """Make a request to the Gnosis API.
84
+
85
+ Args:
86
+ messages: List of message dictionaries with 'role' and 'content'
87
+ keys.
88
+ model: Model to use for generation.
89
+ temperature: Temperature for generation.
90
+ max_tokens: Maximum tokens to generate.
91
+
92
+ Returns:
93
+ The response content from Gnosis.
94
+
95
+ Raises:
96
+ httpx.HTTPStatusError: If the API returns an error status.
97
+ Exception: For other errors during the request.
98
+ """
99
+ request = GnosisRequest(
100
+ messages=messages,
101
+ model=model,
102
+ temperature=temperature,
103
+ max_tokens=max_tokens,
104
+ )
105
+
106
+ if self.debug:
107
+ print(
108
+ f"[DEBUG] Request: {request.model_dump_json()}",
109
+ file=sys.stderr,
110
+ )
111
+
112
+ async with httpx.AsyncClient() as client:
113
+ try:
114
+ response = await client.post(
115
+ f"{self.base_url}/v1/chat/completions",
116
+ json=request.model_dump(),
117
+ headers={
118
+ "Authorization": f"token {self.api_key}",
119
+ "Content-Type": "application/json",
120
+ },
121
+ timeout=self.timeout,
122
+ )
123
+ response.raise_for_status()
124
+
125
+ if self.debug:
126
+ print(
127
+ f"[DEBUG] Response: {response.text}", file=sys.stderr
128
+ )
129
+
130
+ gnosis_response = GnosisResponse(**response.json())
131
+ if gnosis_response.choices and gnosis_response.choices[0].get(
132
+ "message", {}
133
+ ).get("content"):
134
+ return str(
135
+ gnosis_response.choices[0]["message"]["content"]
136
+ )
137
+
138
+ return "No response from Deepgram AI"
139
+ except httpx.HTTPStatusError as e:
140
+ if self.debug:
141
+ print(f"[DEBUG] HTTP Error: {e}", file=sys.stderr)
142
+ print(
143
+ f"[DEBUG] Response: {e.response.text}", file=sys.stderr
144
+ )
145
+ return (
146
+ f"HTTP Error {e.response.status_code}: {e.response.text}"
147
+ )
148
+ except Exception as e:
149
+ error_msg = f"Error calling Deepgram AI: {str(e)}"
150
+ if self.debug:
151
+ import traceback
152
+
153
+ print(f"[DEBUG] {error_msg}", file=sys.stderr)
154
+ traceback.print_exc()
155
+ return error_msg
156
+
157
+ async def ask_question(
158
+ self, question: str, system_prompt: Optional[str] = None
159
+ ) -> str:
160
+ """Ask a question to Gnosis with an optional system prompt.
161
+
162
+ Args:
163
+ question: The question to ask.
164
+ system_prompt: Optional system prompt to set context.
165
+
166
+ Returns:
167
+ The response from Gnosis.
168
+ """
169
+ messages = []
170
+ if system_prompt:
171
+ messages.append({"role": "system", "content": system_prompt})
172
+ messages.append({"role": "user", "content": question})
173
+
174
+ return await self.call(messages)
175
+
176
+ async def chat(
177
+ self,
178
+ messages: List[Dict[str, str]],
179
+ system_prompt: Optional[str] = None,
180
+ ) -> str:
181
+ """Have a conversation with Gnosis.
182
+
183
+ Args:
184
+ messages: List of messages in the conversation.
185
+ system_prompt: Optional system prompt to prepend.
186
+
187
+ Returns:
188
+ The response from Gnosis.
189
+ """
190
+ all_messages = []
191
+ if system_prompt:
192
+ all_messages.append({"role": "system", "content": system_prompt})
193
+ all_messages.extend(messages)
194
+
195
+ return await self.call(all_messages)
196
+
197
+
198
+ async def main() -> None:
199
+ """Main function for standalone CLI usage."""
200
+ import argparse
201
+
202
+ # Create parser
203
+ parser = argparse.ArgumentParser(
204
+ prog="deepctl_cmd_mcp.gnosis",
205
+ description="Interact with Deepgram's AI assistant API",
206
+ formatter_class=argparse.RawDescriptionHelpFormatter,
207
+ epilog="""
208
+ Examples:
209
+ # Ask a single question
210
+ python -m deepctl_cmd_mcp.gnosis "What is Deepgram?"
211
+
212
+ # Ask with a custom system prompt
213
+ python -m deepctl_cmd_mcp.gnosis "Explain streaming" \\
214
+ --system-prompt "You are a technical expert"
215
+
216
+ # Interactive chat mode
217
+ python -m deepctl_cmd_mcp.gnosis --chat
218
+
219
+ # JSON output for integration
220
+ python -m deepctl_cmd_mcp.gnosis "What models are available?" \\
221
+ --json-output
222
+
223
+ # Debug mode to see API calls
224
+ python -m deepctl_cmd_mcp.gnosis "Test question" --debug
225
+ """,
226
+ )
227
+
228
+ parser.add_argument(
229
+ "question",
230
+ nargs="?",
231
+ help="Question to ask Deepgram AI (omit for interactive chat mode)",
232
+ )
233
+ parser.add_argument(
234
+ "--url",
235
+ type=str,
236
+ default="https://gnosis.deepgram.com",
237
+ help="Base URL for Deepgram AI API",
238
+ )
239
+ parser.add_argument(
240
+ "--api-key",
241
+ help="Deepgram API key (defaults to DEEPGRAM_API_KEY env var)",
242
+ )
243
+ parser.add_argument(
244
+ "--system-prompt",
245
+ help="System prompt to set context",
246
+ )
247
+ parser.add_argument(
248
+ "--chat",
249
+ action="store_true",
250
+ help="Enable interactive chat mode",
251
+ )
252
+ parser.add_argument(
253
+ "--model",
254
+ default="deepgram",
255
+ help="Model to use (default: deepgram)",
256
+ )
257
+ parser.add_argument(
258
+ "--temperature",
259
+ type=float,
260
+ default=0.7,
261
+ help="Temperature for generation (default: 0.7)",
262
+ )
263
+ parser.add_argument(
264
+ "--max-tokens",
265
+ type=int,
266
+ help="Maximum tokens to generate",
267
+ )
268
+ parser.add_argument(
269
+ "--debug",
270
+ action="store_true",
271
+ help="Enable debug output",
272
+ )
273
+ parser.add_argument(
274
+ "--json-output",
275
+ action="store_true",
276
+ help="Output raw JSON response",
277
+ )
278
+
279
+ args = parser.parse_args()
280
+
281
+ # Check if we have a question or chat mode
282
+ if not args.question and not args.chat:
283
+ parser.print_help()
284
+ sys.exit(1)
285
+
286
+ try:
287
+ client = GnosisClient(
288
+ api_key=args.api_key,
289
+ base_url=args.url,
290
+ debug=args.debug,
291
+ )
292
+ except ValueError as e:
293
+ print(f"Error: {e}", file=sys.stderr)
294
+ sys.exit(1)
295
+
296
+ try:
297
+ if args.chat:
298
+ # Interactive chat mode
299
+ print("Deepgram AI Chat ('exit' to quit, 'clear' to reset)")
300
+ print("-" * 60)
301
+
302
+ history: list[dict[str, str]] = []
303
+ if args.system_prompt:
304
+ print(f"System: {args.system_prompt}")
305
+ print("-" * 60)
306
+
307
+ while True:
308
+ try:
309
+ user_input = input("\nYou: ").strip()
310
+ except (EOFError, KeyboardInterrupt):
311
+ print("\nGoodbye!")
312
+ break
313
+
314
+ if user_input.lower() in ["exit", "quit"]:
315
+ print("\nGoodbye!")
316
+ break
317
+ elif user_input.lower() == "clear":
318
+ history = []
319
+ print("\nChat history cleared.")
320
+ continue
321
+ elif not user_input:
322
+ continue
323
+
324
+ # Add to history
325
+ history.append({"role": "user", "content": user_input})
326
+
327
+ # Get response
328
+ response = await client.chat(
329
+ history, system_prompt=args.system_prompt
330
+ )
331
+
332
+ # Add response to history
333
+ history.append({"role": "assistant", "content": response})
334
+
335
+ # Display response
336
+ print(f"\nDeepgram AI: {response}")
337
+
338
+ else:
339
+ # Single question mode
340
+ if args.json_output:
341
+ # For JSON output, get the raw response
342
+ messages = []
343
+ if args.system_prompt:
344
+ messages.append(
345
+ {"role": "system", "content": args.system_prompt}
346
+ )
347
+ messages.append({"role": "user", "content": args.question})
348
+
349
+ # We need to modify the client to return the full response
350
+ # For now, just get the text response
351
+ response = await client.ask_question(
352
+ args.question, args.system_prompt
353
+ )
354
+ result = {
355
+ "question": args.question,
356
+ "response": response,
357
+ "model": args.model,
358
+ }
359
+ print(json.dumps(result, indent=2))
360
+ else:
361
+ response = await client.ask_question(
362
+ args.question, args.system_prompt
363
+ )
364
+ print(response)
365
+
366
+ except Exception as e:
367
+ print(f"Error: {e}", file=sys.stderr)
368
+ sys.exit(1)
369
+
370
+
371
+ if __name__ == "__main__":
372
+ asyncio.run(main())
@@ -0,0 +1,24 @@
1
+ """Models for the MCP command."""
2
+
3
+ from enum import Enum
4
+ from typing import Optional
5
+
6
+ from pydantic import BaseModel
7
+
8
+
9
+ class TransportType(str, Enum):
10
+ """Transport types for MCP server."""
11
+
12
+ STDIO = "stdio"
13
+ SSE = "sse"
14
+ STREAMABLEHTTP = "streamablehttp"
15
+
16
+
17
+ class MCPServerResult(BaseModel):
18
+ """Result of MCP server operation."""
19
+
20
+ status: str
21
+ message: str
22
+ transport: Optional[TransportType] = None
23
+ port: Optional[int] = None
24
+ host: Optional[str] = None
@@ -0,0 +1,32 @@
1
+ Metadata-Version: 2.4
2
+ Name: deepctl-cmd-mcp
3
+ Version: 0.1.0
4
+ Summary: MCP server command for deepctl to interact with Deepgram's AI assistant service
5
+ Author-email: Deepgram <devrel@deepgram.com>
6
+ License-Expression: MIT
7
+ Requires-Python: >=3.10
8
+ Description-Content-Type: text/markdown
9
+ Requires-Dist: deepctl-core>=0.1.0
10
+ Requires-Dist: mcp>=1.0.0
11
+ Requires-Dist: rich>=13.9.4
12
+ Requires-Dist: click>=8.1.7
13
+ Requires-Dist: pydantic>=2.10.1
14
+ Requires-Dist: httpx>=0.28.1
15
+ Provides-Extra: dev
16
+ Requires-Dist: pytest>=8.3.3; extra == "dev"
17
+ Requires-Dist: pytest-asyncio>=0.24.0; extra == "dev"
18
+ Requires-Dist: pytest-cov>=6.0.0; extra == "dev"
19
+ Requires-Dist: pytest-mock>=3.14.0; extra == "dev"
20
+ Requires-Dist: mypy>=1.13.0; extra == "dev"
21
+ Requires-Dist: ruff>=0.8.1; extra == "dev"
22
+
23
+ # deepctl-cmd-mcp
24
+
25
+ This package provides two ways to interact with Deepgram's AI assistant:
26
+
27
+ 1. **MCP Server**: Run an MCP server that exposes Deepgram's AI assistant tools
28
+ 2. **Python Client**: Standalone Python client for interacting with Deepgram's AI API
29
+
30
+ ## Installation
31
+
32
+ This package is installed as part of the main deepctl CLI.
@@ -0,0 +1,13 @@
1
+ README.md
2
+ pyproject.toml
3
+ src/deepctl_cmd_mcp/__init__.py
4
+ src/deepctl_cmd_mcp/__main__.py
5
+ src/deepctl_cmd_mcp/command.py
6
+ src/deepctl_cmd_mcp/gnosis.py
7
+ src/deepctl_cmd_mcp/models.py
8
+ src/deepctl_cmd_mcp.egg-info/PKG-INFO
9
+ src/deepctl_cmd_mcp.egg-info/SOURCES.txt
10
+ src/deepctl_cmd_mcp.egg-info/dependency_links.txt
11
+ src/deepctl_cmd_mcp.egg-info/entry_points.txt
12
+ src/deepctl_cmd_mcp.egg-info/requires.txt
13
+ src/deepctl_cmd_mcp.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [deepctl.commands]
2
+ mcp = deepctl_cmd_mcp.command:McpCommand
@@ -0,0 +1,14 @@
1
+ deepctl-core>=0.1.0
2
+ mcp>=1.0.0
3
+ rich>=13.9.4
4
+ click>=8.1.7
5
+ pydantic>=2.10.1
6
+ httpx>=0.28.1
7
+
8
+ [dev]
9
+ pytest>=8.3.3
10
+ pytest-asyncio>=0.24.0
11
+ pytest-cov>=6.0.0
12
+ pytest-mock>=3.14.0
13
+ mypy>=1.13.0
14
+ ruff>=0.8.1
@@ -0,0 +1 @@
1
+ deepctl_cmd_mcp