66
77import argparse
88from dataclasses import dataclass
9+ import os
910import time
1011from typing import Any
1112
2829from typeagent .storage .memory .semrefindex import TermToSemanticRefIndex
2930from typeagent .storage .utils import create_storage_provider
3031
32+ # Example podcast index path for documentation and error messages
33+ _EXAMPLE_PODCAST_INDEX = "tests/testdata/Episode_53_AdrianTchaikovsky_index"
34+
3135
3236class MCPTypeChatModel (typechat .TypeChatLanguageModel ):
3337 """TypeChat language model that uses MCP sampling API instead of direct API calls."""
@@ -142,7 +146,9 @@ async def make_context(
142146 entities_top_k = 50 , topics_top_k = 50 , messages_top_k = None , chunking = None
143147 )
144148
145- query_context = await load_podcast_index_or_database (settings , dbname )
149+ query_context = await load_podcast_database_or_index (
150+ settings , dbname , _podcast_index
151+ )
146152
147153 # Use MCP-based model instead of one that requires API keys
148154 model = MCPTypeChatModel (session )
@@ -161,24 +167,33 @@ async def make_context(
161167 return context
162168
163169
164- async def load_podcast_index_or_database (
170+ async def load_podcast_database_or_index (
165171 settings : ConversationSettings ,
166172 dbname : str | None = None ,
173+ podcast_index : str | None = None ,
167174) -> query .QueryEvalContext [podcast .PodcastMessage , Any ]:
168- if dbname is None :
169- conversation = await podcast .Podcast .read_from_file (
170- "tests/testdata/Episode_53_AdrianTchaikovsky_index" , settings
171- )
172- else :
175+ if dbname is not None :
176+ # Load from SQLite database
173177 conversation = await podcast .Podcast .create (settings )
178+ elif podcast_index is not None :
179+ # Load from JSON index files
180+ conversation = await podcast .Podcast .read_from_file (podcast_index , settings )
181+ else :
182+ raise ValueError (
183+ "Either --database or --podcast-index must be specified. "
184+ "Use --podcast-index to specify the path to podcast index files "
185+ f"(e.g., '{ _EXAMPLE_PODCAST_INDEX } ')."
186+ )
174187 return query .QueryEvalContext (conversation )
175188
176189
177190# Create an MCP server
178191mcp = FastMCP ("typagent" )
179192
180- # Global variable to store database path (set via command-line argument)
193+ # Global variables to store command-line arguments
194+ # (no other straightforward way to pass to tool handlers)
181195_dbname : str | None = None
196+ _podcast_index : str | None = None
182197
183198
184199@dataclass
@@ -245,12 +260,49 @@ async def query_conversation(
245260 "--database" ,
246261 type = str ,
247262 default = None ,
248- help = "Path to the SQLite database file (default: load from JSON file)" ,
263+ help = "Path to a SQLite database file with pre-indexed podcast data" ,
264+ )
265+ parser .add_argument (
266+ "-p" ,
267+ "--podcast-index" ,
268+ type = str ,
269+ default = None ,
270+ help = "Path to podcast index files (excluding '_data.json' suffix), "
271+ f"e.g., '{ _EXAMPLE_PODCAST_INDEX } '" ,
249272 )
250273 args = parser .parse_args ()
251274
252- # Store database path in global variable (no other straightforward way to pass to tool)
275+ # Validate arguments
276+ if args .database is None and args .podcast_index is None :
277+ parser .error (
278+ "Either --database or --podcast-index is required.\n "
279+ "Example: python -m typeagent.mcp.server "
280+ f"--podcast-index { _EXAMPLE_PODCAST_INDEX } "
281+ )
282+
283+ if args .database is not None and args .podcast_index is not None :
284+ parser .error ("Cannot specify both --database and --podcast-index" )
285+
286+ # Validate file existence
287+ if args .database is not None and not os .path .exists (args .database ):
288+ parser .error (
289+ f"Database file not found: { args .database } \n "
290+ "Please provide a valid path to an existing SQLite database."
291+ )
292+
293+ if args .podcast_index is not None :
294+ data_file = args .podcast_index + "_data.json"
295+ if not os .path .exists (data_file ):
296+ parser .error (
297+ f"Podcast index file not found: { data_file } \n "
298+ "Please provide a valid path to podcast index files "
299+ "(without the '_data.json' suffix).\n "
300+ f"Example: { _EXAMPLE_PODCAST_INDEX } "
301+ )
302+
303+ # Store in global variables for tool handlers
253304 _dbname = args .database
305+ _podcast_index = args .podcast_index
254306
255307 # Use stdio transport for simplicity
256308 mcp .run (transport = "stdio" )
0 commit comments