Skip to content

Commit dcaeb5a

Browse files
Copilotrabbyn
andcommitted
Fix schema discovery compatibility with Fabric Data Warehouse
Co-authored-by: rabbyn <[email protected]>
1 parent 10a186b commit dcaeb5a

File tree

1 file changed

+46
-164
lines changed

1 file changed

+46
-164
lines changed

mcp_server.py

Lines changed: 46 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -231,180 +231,62 @@ async def handle_discover_schema(arguments: dict) -> list[types.TextContent]:
231231
return [types.TextContent(type="text", text=format_schema_response(current_config["schema_cache"]))]
232232

233233
try:
234-
from db import run_query
234+
from db import get_table_schema
235235

236-
# Try Fabric Data Warehouse compatible schema discovery
237-
# First get basic table and column information
238-
try:
239-
basic_schema_query = """
240-
SELECT
241-
t.TABLE_SCHEMA,
242-
t.TABLE_NAME,
243-
t.TABLE_TYPE,
244-
c.COLUMN_NAME,
245-
c.DATA_TYPE,
246-
c.CHARACTER_MAXIMUM_LENGTH,
247-
c.NUMERIC_PRECISION,
248-
c.NUMERIC_SCALE,
249-
c.IS_NULLABLE,
250-
c.COLUMN_DEFAULT,
251-
c.ORDINAL_POSITION
252-
FROM INFORMATION_SCHEMA.TABLES t
253-
JOIN INFORMATION_SCHEMA.COLUMNS c ON t.TABLE_NAME = c.TABLE_NAME AND t.TABLE_SCHEMA = c.TABLE_SCHEMA
254-
WHERE t.TABLE_TYPE = 'BASE TABLE'
255-
AND t.TABLE_SCHEMA NOT IN ('sys', 'INFORMATION_SCHEMA')
256-
ORDER BY t.TABLE_SCHEMA, t.TABLE_NAME, c.ORDINAL_POSITION
257-
"""
258-
259-
cols, rows = run_query(basic_schema_query)
260-
261-
# Process basic schema data
262-
basic_schema_data = {}
263-
for row in rows:
264-
schema_name = row[0]
265-
table_name = row[1]
266-
table_type = row[2]
267-
column_name = row[3]
268-
data_type = row[4]
269-
max_length = row[5]
270-
precision = row[6]
271-
scale = row[7]
272-
is_nullable = row[8]
273-
default_value = row[9]
274-
ordinal = row[10]
275-
276-
full_table_name = f"{schema_name}.{table_name}"
277-
278-
if full_table_name not in basic_schema_data:
279-
basic_schema_data[full_table_name] = {
280-
"schema": schema_name,
281-
"table_name": table_name,
282-
"table_type": table_type,
283-
"columns": []
284-
}
236+
# Use the simplified schema discovery from db.py which handles Fabric compatibility
237+
print("Starting Fabric-compatible schema discovery...")
238+
schema_data = get_table_schema()
239+
240+
if not schema_data:
241+
return [types.TextContent(type="text", text="❌ Schema discovery failed. Please check your connection and permissions.")]
242+
243+
# Convert the schema format to match what the frontend expects
244+
formatted_schema = {}
245+
relationships = [] # No relationships available from basic schema
246+
247+
for table_name, columns in schema_data.items():
248+
# Split schema.table if present, otherwise assume dbo schema
249+
if '.' in table_name:
250+
schema_name, table_only = table_name.split('.', 1)
251+
else:
252+
schema_name = 'dbo'
253+
table_only = table_name
285254

255+
formatted_schema[table_name] = {
256+
"schema": schema_name,
257+
"table_name": table_only,
258+
"table_type": "BASE TABLE",
259+
"columns": []
260+
}
261+
262+
for col in columns:
286263
col_info = {
287-
"name": column_name,
288-
"data_type": data_type,
289-
"position": ordinal,
290-
"is_nullable": is_nullable == "YES",
291-
"key_type": "" # Will be populated separately
264+
"name": col["column_name"],
265+
"data_type": col["data_type"],
266+
"position": col.get("ordinal_position", 0),
267+
"is_nullable": col["is_nullable"] == "YES",
268+
"key_type": "PK" if col.get("is_primary_key", False) else ""
292269
}
293270

294-
if max_length:
295-
col_info["max_length"] = max_length
296-
if precision:
297-
col_info["precision"] = precision
298-
if scale:
299-
col_info["scale"] = scale
300-
if default_value:
301-
col_info["default"] = default_value
271+
# Add optional column metadata if available
272+
if col.get("max_length"):
273+
col_info["max_length"] = col["max_length"]
274+
if col.get("numeric_precision"):
275+
col_info["precision"] = col["numeric_precision"]
276+
if col.get("numeric_scale"):
277+
col_info["scale"] = col["numeric_scale"]
278+
if col.get("column_default"):
279+
col_info["default"] = col["column_default"]
302280

303-
basic_schema_data[full_table_name]["columns"].append(col_info)
304-
305-
except Exception as e:
306-
raise Exception(f"Failed to get basic schema information: {e}")
307-
308-
# Try to get primary key information (separate query for Fabric compatibility)
309-
pk_info = {}
310-
try:
311-
pk_query = """
312-
SELECT
313-
tc.TABLE_SCHEMA,
314-
tc.TABLE_NAME,
315-
ku.COLUMN_NAME
316-
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc
317-
JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE ku ON tc.CONSTRAINT_NAME = ku.CONSTRAINT_NAME
318-
AND tc.TABLE_SCHEMA = ku.TABLE_SCHEMA
319-
AND tc.TABLE_NAME = ku.TABLE_NAME
320-
WHERE tc.CONSTRAINT_TYPE = 'PRIMARY KEY'
321-
"""
322-
323-
pk_cols, pk_rows = run_query(pk_query)
324-
325-
for pk_row in pk_rows:
326-
pk_schema = pk_row[0]
327-
pk_table = pk_row[1]
328-
pk_column = pk_row[2]
329-
pk_full_name = f"{pk_schema}.{pk_table}"
330-
331-
if pk_full_name not in pk_info:
332-
pk_info[pk_full_name] = set()
333-
pk_info[pk_full_name].add(pk_column)
334-
335-
except Exception as pk_e:
336-
print(f"Warning: Could not retrieve primary key information: {pk_e}")
337-
338-
# Try to get foreign key information (separate query, may not work in all Fabric configurations)
339-
fk_relationships = []
340-
try:
341-
# Try a simpler FK query that works with more systems
342-
fk_query = """
343-
SELECT
344-
fk.TABLE_SCHEMA as FK_SCHEMA,
345-
fk.TABLE_NAME as FK_TABLE,
346-
fk.COLUMN_NAME as FK_COLUMN,
347-
pk.TABLE_SCHEMA as PK_SCHEMA,
348-
pk.TABLE_NAME as PK_TABLE,
349-
pk.COLUMN_NAME as PK_COLUMN
350-
FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc
351-
JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE fk ON rc.CONSTRAINT_NAME = fk.CONSTRAINT_NAME
352-
AND rc.CONSTRAINT_SCHEMA = fk.CONSTRAINT_SCHEMA
353-
JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE pk ON rc.UNIQUE_CONSTRAINT_NAME = pk.CONSTRAINT_NAME
354-
AND rc.UNIQUE_CONSTRAINT_SCHEMA = pk.CONSTRAINT_SCHEMA
355-
"""
356-
357-
fk_cols, fk_rows = run_query(fk_query)
358-
359-
fk_info = {}
360-
for fk_row in fk_rows:
361-
fk_schema = fk_row[0]
362-
fk_table = fk_row[1]
363-
fk_column = fk_row[2]
364-
pk_schema = fk_row[3]
365-
pk_table = fk_row[4]
366-
pk_column = fk_row[5]
367-
368-
fk_full_name = f"{fk_schema}.{fk_table}"
369-
pk_full_name = f"{pk_schema}.{pk_table}"
370-
371-
if fk_full_name not in fk_info:
372-
fk_info[fk_full_name] = set()
373-
fk_info[fk_full_name].add(fk_column)
374-
375-
fk_relationships.append({
376-
"from_table": fk_full_name,
377-
"from_column": fk_column,
378-
"to_table": pk_full_name,
379-
"to_column": pk_column
380-
})
381-
382-
except Exception as fk_e:
383-
print(f"Warning: Could not retrieve foreign key information: {fk_e}")
384-
print("This is normal for Fabric Data Warehouse - foreign key metadata may not be available")
385-
fk_info = {}
386-
387-
# Combine all information
388-
schema_data = basic_schema_data
389-
for table_name, table_info in schema_data.items():
390-
table_pks = pk_info.get(table_name, set())
391-
table_fks = fk_info.get(table_name, set())
392-
393-
for col in table_info["columns"]:
394-
if col["name"] in table_pks:
395-
col["key_type"] = "PK"
396-
elif col["name"] in table_fks:
397-
col["key_type"] = "FK"
398-
else:
399-
col["key_type"] = ""
281+
formatted_schema[table_name]["columns"].append(col_info)
400282

401283
# Cache the schema
402284
current_config["schema_cache"] = {
403-
"tables": schema_data,
404-
"relationships": fk_relationships,
285+
"tables": formatted_schema,
286+
"relationships": relationships,
405287
"discovered_at": asyncio.get_event_loop().time()
406-
}
407-
288+
}
289+
408290
return [types.TextContent(type="text", text=format_schema_response(current_config["schema_cache"]))]
409291

410292
except Exception as e:

0 commit comments

Comments
 (0)