Skip to content

Commit 114a110

Browse files
committed
Restore MCP connection bridge while honoring resolved external access
1 parent 7d0cb06 commit 114a110

1 file changed

Lines changed: 112 additions & 26 deletions

File tree

TablePro/Core/MCP/MCPConnectionBridge.swift

Lines changed: 112 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -359,54 +359,140 @@ public actor MCPConnectionBridge {
359359
let cachedTables = await MainActor.run {
360360
SchemaService.shared.tables(for: connectionId)
361361
}
362+
363+
let (driver, _) = try await resolveDriver(connectionId)
364+
362365
let tables: [TableInfo]
363366
if !cachedTables.isEmpty {
364367
tables = cachedTables
365368
} else {
366-
let (driver, _) = try await resolveDriver(connectionId)
367369
tables = try await DatabaseManager.shared.trackOperation(sessionId: connectionId) {
368370
try await driver.fetchTables()
369371
}
370372
}
371373

372-
let resources = tables.map { table in
373-
JsonValue.object([
374-
"uri": .string("tablepro://connection/\(connectionId.uuidString)/schema/\(table.name)"),
374+
let limitedTables = Array(tables.prefix(100))
375+
376+
var tableSchemas: [JsonValue] = []
377+
for table in limitedTables {
378+
let columns = try await DatabaseManager.shared.trackOperation(sessionId: connectionId) {
379+
try await driver.fetchColumns(table: table.name)
380+
}
381+
382+
let jsonCols: [JsonValue] = columns.map { col in
383+
.object([
384+
"name": .string(col.name),
385+
"data_type": .string(col.dataType),
386+
"is_nullable": .bool(col.isNullable),
387+
"is_primary_key": .bool(col.isPrimaryKey)
388+
])
389+
}
390+
391+
tableSchemas.append(.object([
375392
"name": .string(table.name),
376-
"mimeType": .string("application/json")
377-
])
393+
"type": .string(table.type.rawValue),
394+
"columns": .array(jsonCols)
395+
]))
378396
}
379-
return .object(["resources": .array(resources)])
380-
}
381397

382-
private func resolveConnection(_ connectionId: UUID) async throws -> DatabaseConnection {
383-
let connection = await MainActor.run {
384-
DatabaseManager.shared.connectionState(connectionId).connection
398+
var result: [String: JsonValue] = ["tables": .array(tableSchemas)]
399+
if tables.count > 100 {
400+
result["truncated"] = .bool(true)
401+
result["total_tables"] = .int(tables.count)
385402
}
386-
guard let connection else {
387-
throw MCPDataLayerError.notConnected(connectionId)
403+
404+
return .object(result)
405+
}
406+
407+
func fetchHistoryResource(
408+
connectionId: UUID,
409+
limit: Int,
410+
search: String?,
411+
dateFilter: String?
412+
) async throws -> JsonValue {
413+
let filter: DateFilter
414+
switch dateFilter {
415+
case "today": filter = .today
416+
case "thisWeek": filter = .thisWeek
417+
case "thisMonth": filter = .thisMonth
418+
default: filter = .all
419+
}
420+
421+
let entries = await QueryHistoryManager.shared.fetchHistory(
422+
limit: limit,
423+
connectionId: connectionId,
424+
searchText: search,
425+
dateFilter: filter
426+
)
427+
428+
let jsonEntries: [JsonValue] = entries.map { entry in
429+
var obj: [String: JsonValue] = [
430+
"id": .string(entry.id.uuidString),
431+
"query": .string(entry.query),
432+
"database_name": .string(entry.databaseName),
433+
"executed_at": .string(ISO8601DateFormatter().string(from: entry.executedAt)),
434+
"execution_time_ms": .double(entry.executionTime * 1_000),
435+
"row_count": .int(entry.rowCount),
436+
"was_successful": .bool(entry.wasSuccessful)
437+
]
438+
if let errorMsg = entry.errorMessage {
439+
obj["error_message"] = .string(errorMsg)
440+
}
441+
return .object(obj)
388442
}
389-
return connection
443+
444+
return .object(["history": .array(jsonEntries)])
390445
}
391446

392-
private func resolveDriver(_ connectionId: UUID) async throws -> (any DatabaseDriver, DatabaseType) {
393-
let state = await MainActor.run {
394-
DatabaseManager.shared.connectionState(connectionId)
447+
private func resolveDriver(_ connectionId: UUID) async throws -> (DatabaseDriver, DatabaseType) {
448+
let pending: DatabaseConnection? = await MainActor.run {
449+
switch DatabaseManager.shared.connectionState(connectionId) {
450+
case .live: return nil
451+
case .stored(let connection): return connection
452+
case .unknown: return nil
453+
}
395454
}
396-
guard let connection = state.connection else {
397-
throw MCPDataLayerError.notConnected(connectionId)
455+
if let pending {
456+
try await connectIfNeeded(pending)
398457
}
399-
guard let session = state.session, let driver = session.driver else {
400-
throw MCPDataLayerError.notConnected(connectionId)
458+
return try await MainActor.run {
459+
switch DatabaseManager.shared.connectionState(connectionId) {
460+
case .live(let driver, let session):
461+
return (driver, session.connection.type)
462+
case .stored, .unknown:
463+
throw MCPDataLayerError.notConnected(connectionId)
464+
}
465+
}
466+
}
467+
468+
private func connectIfNeeded(_ connection: DatabaseConnection) async throws {
469+
try await DatabaseManager.shared.ensureConnected(connection)
470+
}
471+
472+
private func resolveSession(_ connectionId: UUID) async throws -> ConnectionSession {
473+
try await MainActor.run {
474+
guard let session = DatabaseManager.shared.activeSessions[connectionId] else {
475+
throw MCPDataLayerError.notConnected(connectionId)
476+
}
477+
return session
478+
}
479+
}
480+
481+
private func resolveConnection(_ connectionId: UUID) async throws -> DatabaseConnection {
482+
try await MainActor.run {
483+
let connections = ConnectionStorage.shared.loadConnections()
484+
guard let connection = connections.first(where: { $0.id == connectionId }) else {
485+
throw MCPDataLayerError.invalidArgument("Connection not found: \(connectionId)")
486+
}
487+
return connection
401488
}
402-
return (driver, connection.type)
403489
}
404490

405-
private static func stripTrailingSemicolons(_ sql: String) -> String {
406-
var result = sql.trimmingCharacters(in: .whitespacesAndNewlines)
491+
static func stripTrailingSemicolons(_ query: String) -> String {
492+
var result = query.trimmingCharacters(in: .whitespacesAndNewlines)
407493
while result.hasSuffix(";") {
408-
result.removeLast()
409-
result = result.trimmingCharacters(in: .whitespacesAndNewlines)
494+
result = String(result.dropLast())
495+
.trimmingCharacters(in: .whitespacesAndNewlines)
410496
}
411497
return result
412498
}

0 commit comments

Comments
 (0)