Skip to content

Commit 8786925

Browse files
committed
Merge branch 'main' into refactor/hig-pr1-keyboard-shortcuts
2 parents a0fb38e + 53f55e6 commit 8786925

150 files changed

Lines changed: 10821 additions & 4343 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
### Added
1111

12+
- External API for Raycast, Cursor, Claude Desktop, and other MCP clients: URL scheme, stdio MCP transport, pairing flow, activity log
13+
- UUID-keyed deep links: `tablepro://connect/<uuid>`, `.../table/<name>`, `.../query?sql=...`, `tablepro://integrations/pair?...`, `tablepro://integrations/start-mcp`
14+
- stdio MCP transport via bundled `tablepro-mcp` CLI at `Contents/MacOS/tablepro-mcp`. Reads handshake file, no token needed
15+
- Per-connection `External Access` setting (`blocked`, `readOnly`, `readWrite`). Defaults to `readOnly`. Bounds token reach via `MIN(token.scope, connection.externalAccess)`
16+
- Pairing flow with PKCE code exchange. One-click token issuance for Raycast and other extensions
17+
- Activity log at `~/Library/Application Support/TablePro/mcp-audit.db`. Viewable in Settings > Integrations > Activity Log. 90-day retention
18+
- New MCP tools: `list_recent_tabs`, `search_query_history`, `open_connection_window`, `open_table_tab`, `focus_query_tab`
1219
- PostgreSQL ICU collation provider in Create Database (PG 15+). Provider picker is added when the server reports PG 15 or newer. ICU locale list comes from `pg_collation`. SQL emission is version-aware: PG 16+ uses unified `LOCALE`, PG 15 uses `ICU_LOCALE` with `LC_COLLATE 'C' LC_CTYPE 'C'`.
1320
- Connection URL parsing: SSH `user:password@host` split, `safeModeLevel` from TablePlus URLs, case-insensitive query params
1421
- Connection URL export: SSH password, Redis database index, MongoDB auth params (`authSource`, `authMechanism`, `replicaSet`), and multi-host
@@ -36,6 +43,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3643
- Explain with AI no longer has a default shortcut; the menu entry remains and users can rebind in Settings > Keyboard.
3744
- File menu "Save Changes" renamed to "Save".
3845
- View menu Show/Hide labels now flip based on panel state (Show Sidebar / Hide Sidebar, Show Inspector / Hide Inspector, Show Filters / Hide Filters, Show History / Hide History, Show Results / Hide Results).
46+
- MCP server lazy-starts on first external request. Manual enable in Settings is no longer required
47+
- Settings tab renamed from "MCP" to "Integrations" with new sections for connected clients, activity log, and pairing
48+
- Integrations settings: rename MCP Server section to Integrations, restructure with searchable activity log, native list with keyboard navigation, accessibility labels, color-blind-safe status icons.
49+
- Activity log gained an Export… button that writes the current filtered list to CSV.
50+
- Connection Advanced settings: AI Policy and External Clients now share a single External Access section. The External Clients picker uses a segmented control.
3951
- Storage and sync singletons accept dependencies via init for test isolation, matching Apple's URLSession and UserDefaults convention. Production callers using `.shared` are unchanged. `SQLFavoriteStorage` is now an actor so its first access no longer blocks the main thread on SQLite setup.
4052
- Create Database dialog is now driver-driven. Each driver discovers its own valid options (PostgreSQL queries `pg_collation` and `pg_database`, MySQL/MariaDB query `information_schema.character_sets`/`collations`). The hardcoded macOS-flavored locale list is gone. Engines that don't support creation hide the Create button instead of failing on click.
4153
- Introduced TableRows, Row, and Delta value types in TablePro/Models/Query/ as the foundation for the data grid row model rewrite. No callers migrated yet (Phase C.1 of the DataGrid refactor).
@@ -75,9 +87,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7587
- Data grid cell focus ring redraws when the user toggles Light or Dark mode mid-session, picking up the system's appearance-aware focus indicator color
7688
- Data grid keeps sortedIDs and cachedRowCount paired by calling updateCache() immediately after the SwiftUI bridge writes new sortedIDs to the coordinator, removing a window where the cached count and the sort permutation could disagree
7789
- Display formats memoized per tab on MainContentCoordinator keyed by schema version, smart-detection setting, and format-overrides version, so ValueDisplayDetector.detect runs once per result schema instead of on every SwiftUI body evaluation
90+
- MCP HTTP router replaced with a route registry. `MCPRouter` now matches paths and methods against a list of `MCPRouteHandler` values; `/mcp` traffic and `/v1/integrations/exchange` traffic each live in their own handler file under `Core/MCP/Routes/`. OPTIONS preflight is handled once at the router level for every path
91+
- `MCPAuthGuard` and `MCPConnectionBridge` route concurrent dedup through a shared `OnceTask` actor (`Core/Concurrency/OnceTask.swift`). Cleanup of in-flight slots happens in `defer` inside the actor, so a cancelled or thrown caller no longer leaves a stale entry behind.
92+
93+
### Removed (BREAKING)
94+
95+
- `tablepro://connect/<name>/...` deep links. Replace with UUID-keyed paths from "Copy Connection Deep Link" in the sidebar context menu. User-saved bookmarks must be regenerated
96+
- MCP server data directory moved from `~/Library/Application Support/com.TablePro/` to `~/Library/Application Support/TablePro/`. Existing tokens, audit log, and handshake files are not migrated. Re-pair Raycast, Cursor, Claude Desktop, and any other external clients after upgrading. Delete the old directory with `rm -rf ~/Library/Application Support/com.TablePro`
7897

7998
### Fixed
8099

100+
- File associations for `.sql`, `.sqlite`, `.duckdb`, and related extensions disabled in Finder's Open With menu. The custom UTIs (`com.tablepro.sql`, `com.tablepro.sqlite-db`, `com.tablepro.duckdb`) were declared under `UTImportedTypeDeclarations` instead of `UTExportedTypeDeclarations`, so Launch Services treated them as "imported" claims and ranked them below other apps. SQL is now `LSHandlerRank: Owner`, SQLite is `Default`, DuckDB is `Owner`/`Editor`, and `com.tablepro.sqlite-db` conforms to `com.apple.sqlite3`.
81101
- Crash on macOS 26 when opening SQL Preview (NSColor.cgColor calls deprecated colorSpaceName)
82102
- Connection form: `usePrivateKey=true` from URL no longer disables Test/Create buttons
83103
- Transient connections from URL clean up keychain entries on connection failure
@@ -88,6 +108,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
88108
- Persist group deletions before firing the sync notification, fixing a race that could re-upload deleted groups via iCloud.
89109
- Persist connection deletions before firing the sync notification, fixing the same race for deleted connections.
90110
- Refuse to generate SQL when the database dialect cannot be resolved, instead of silently emitting unquoted identifiers.
111+
- MCP `execute_query`: strip trailing semicolons before appending `LIMIT/OFFSET`, fixing `syntax error at or near LIMIT` for queries like `select * from t;`.
112+
- MCP `export_data`: tightened table name validation to reject double-dot, leading-dot, and trailing-dot identifiers (e.g. `schema..table`). `quoteQualifiedIdentifier` now rejects empty segments instead of producing `"schema".""."table"`.
113+
- MCP `focus_query_tab`: re-validate that the resolved tab still belongs to the authorized connection between the auth check and the window raise, closing a TOCTOU window where a tab could be re-bound to a different connection.
114+
- MCP pairing: cap pending exchange codes at 50 to prevent unbounded memory growth from repeated pairing attempts.
115+
- Pairing approval no longer grants access on Return key; Approve must be clicked. Deny remains the cancel action and Escape still dismisses.
116+
- Pairing approval shows a live countdown for the 5-minute exchange code window and disables Approve when it runs out.
117+
- Pairing approval connection list is searchable with Select All / Deselect All controls and bounded height for many connections.
118+
- Token deletion now requires confirmation in a destructive alert, with the token name in the message. Backspace on a selected token in the list shows the same alert.
119+
- Disconnect on a connected client now requires confirmation before tearing down the session.
120+
- Token list switched to a native macOS list with keyboard navigation, multi-select, and a context menu (Revoke, Copy ID, Delete…). "Deactivate" was renamed to "Revoke" so the UI matches the documented language.
121+
- Activity log layout fixed: the inner list no longer nests inside the settings Form, so vertical scrolling has a single owner. Connection column shows the connection name instead of the UUID prefix and falls back to "Deleted connection (…)" when the connection is gone.
122+
- Activity log gained search across action, token, connection, and details, plus a 90-day retention notice.
123+
- Token reveal warning banner uses thin material with an orange border so it stays visible in Dark Mode.
124+
- Token, audit, and pairing sheets use a flexible minimum height so they no longer clip with larger Dynamic Type sizes.
125+
- Token list "Last used" now uses RelativeDateTimeFormatter so localized strings read correctly (e.g. "5 minutes ago" in en) instead of the broken duplicated " ago" suffix.
126+
- Token reveal, audit refresh, and copy buttons now expose VoiceOver accessibility labels in addition to tooltips.
91127

92128
## [0.36.0] - 2026-04-27
93129

TablePro.xcodeproj/project.pbxproj

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
/* Begin PBXBuildFile section */
1010
5A32BBFB2F9D5EAB00BAEB5F /* X509 in Frameworks */ = {isa = PBXBuildFile; productRef = 5A32BBFA2F9D5EAB00BAEB5F /* X509 */; };
11-
5A32BC0B2F9D659100BAEB5F /* mcp-server in CopyFiles */ = {isa = PBXBuildFile; fileRef = 5A32BC002F9D5F1300BAEB5F /* mcp-server */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
11+
5A32BC0B2F9D659100BAEB5F /* tablepro-mcp in CopyFiles */ = {isa = PBXBuildFile; fileRef = 5A32BC002F9D5F1300BAEB5F /* tablepro-mcp */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
1212
5A3A69B82F976F38000AC5B2 /* GhosttyTerminal in Frameworks */ = {isa = PBXBuildFile; productRef = 5A3A69B72F976F38000AC5B2 /* GhosttyTerminal */; };
1313
5A3A69BA2F976F38000AC5B2 /* GhosttyTheme in Frameworks */ = {isa = PBXBuildFile; productRef = 5A3A69B92F976F38000AC5B2 /* GhosttyTheme */; };
1414
5A3BE6FC2F97DB0000611C1F /* TableProPluginKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5A860000100000000 /* TableProPluginKit.framework */; };
@@ -75,6 +75,13 @@
7575
/* End PBXBuildFile section */
7676

7777
/* Begin PBXContainerItemProxy section */
78+
5A32BC0C2F9D659200BAEB5F /* PBXContainerItemProxy */ = {
79+
isa = PBXContainerItemProxy;
80+
containerPortal = 5A1091BF2EF17EDC0055EA7C /* Project object */;
81+
proxyType = 1;
82+
remoteGlobalIDString = 5A32BBFF2F9D5F1300BAEB5F;
83+
remoteInfo = "tablepro-mcp";
84+
};
7885
5A860000B00000000 /* PBXContainerItemProxy */ = {
7986
isa = PBXContainerItemProxy;
8087
containerPortal = 5A1091BF2EF17EDC0055EA7C /* Project object */;
@@ -219,7 +226,7 @@
219226
dstPath = "";
220227
dstSubfolderSpec = 6;
221228
files = (
222-
5A32BC0B2F9D659100BAEB5F /* mcp-server in CopyFiles */,
229+
5A32BC0B2F9D659100BAEB5F /* tablepro-mcp in CopyFiles */,
223230
);
224231
runOnlyForDeploymentPostprocessing = 0;
225232
};
@@ -259,7 +266,7 @@
259266

260267
/* Begin PBXFileReference section */
261268
5A1091C72EF17EDC0055EA7C /* TablePro.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TablePro.app; sourceTree = BUILT_PRODUCTS_DIR; };
262-
5A32BC002F9D5F1300BAEB5F /* mcp-server */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "mcp-server"; sourceTree = BUILT_PRODUCTS_DIR; };
269+
5A32BC002F9D5F1300BAEB5F /* tablepro-mcp */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "tablepro-mcp"; sourceTree = BUILT_PRODUCTS_DIR; };
263270
5A3BE6F82F97DA8100611C1F /* LibSQLDriverPlugin.tableplugin */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LibSQLDriverPlugin.tableplugin; sourceTree = BUILT_PRODUCTS_DIR; };
264271
5A860000100000000 /* TableProPluginKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = TableProPluginKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
265272
5A861000100000000 /* OracleDriver.tableplugin */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = OracleDriver.tableplugin; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -311,8 +318,8 @@
311318
5A32BC082F9D5FC900BAEB5F /* Exceptions for "TablePro" folder in "mcp-server" target */ = {
312319
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
313320
membershipExceptions = (
314-
MCPBridge/main.swift,
315-
MCPBridge/MCPBridgeProxy.swift,
321+
CLI/main.swift,
322+
CLI/MCPBridgeProxy.swift,
316323
);
317324
target = 5A32BBFF2F9D5F1300BAEB5F /* mcp-server */;
318325
};
@@ -452,9 +459,9 @@
452459
5AF312BE2F36FF7500E86682 /* Exceptions for "TablePro" folder in "TablePro" target */ = {
453460
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
454461
membershipExceptions = (
462+
CLI/main.swift,
463+
CLI/MCPBridgeProxy.swift,
455464
Info.plist,
456-
MCPBridge/main.swift,
457-
MCPBridge/MCPBridgeProxy.swift,
458465
);
459466
target = 5A1091C62EF17EDC0055EA7C /* TablePro */;
460467
};
@@ -913,7 +920,7 @@
913920
5ABQR00300000000000000A0 /* BigQueryDriverPlugin.tableplugin */,
914921
5AE4F4742F6BC0640097AC5B /* CloudflareD1DriverPlugin.tableplugin */,
915922
5A3BE6F82F97DA8100611C1F /* LibSQLDriverPlugin.tableplugin */,
916-
5A32BC002F9D5F1300BAEB5F /* mcp-server */,
923+
5A32BC002F9D5F1300BAEB5F /* tablepro-mcp */,
917924
);
918925
name = Products;
919926
sourceTree = "<group>";
@@ -994,6 +1001,7 @@
9941001
buildRules = (
9951002
);
9961003
dependencies = (
1004+
5A32BC0D2F9D659200BAEB5F /* PBXTargetDependency */,
9971005
5A860000C00000000 /* PBXTargetDependency */,
9981006
5A861000C00000000 /* PBXTargetDependency */,
9991007
5A862000C00000000 /* PBXTargetDependency */,
@@ -1050,7 +1058,7 @@
10501058
packageProductDependencies = (
10511059
);
10521060
productName = "mcp-server";
1053-
productReference = 5A32BC002F9D5F1300BAEB5F /* mcp-server */;
1061+
productReference = 5A32BC002F9D5F1300BAEB5F /* tablepro-mcp */;
10541062
productType = "com.apple.product-type.tool";
10551063
};
10561064
5A3BE6F72F97DA8100611C1F /* LibSQLDriverPlugin */ = {
@@ -2024,6 +2032,11 @@
20242032
/* End PBXSourcesBuildPhase section */
20252033

20262034
/* Begin PBXTargetDependency section */
2035+
5A32BC0D2F9D659200BAEB5F /* PBXTargetDependency */ = {
2036+
isa = PBXTargetDependency;
2037+
target = 5A32BBFF2F9D5F1300BAEB5F /* mcp-server */;
2038+
targetProxy = 5A32BC0C2F9D659200BAEB5F /* PBXContainerItemProxy */;
2039+
};
20272040
5A860000C00000000 /* PBXTargetDependency */ = {
20282041
isa = PBXTargetDependency;
20292042
target = 5A860000000000000 /* TableProPluginKit */;
@@ -2402,7 +2415,8 @@
24022415
DEVELOPMENT_TEAM = D7HJ5TFYCU;
24032416
ENABLE_HARDENED_RUNTIME = YES;
24042417
MACOSX_DEPLOYMENT_TARGET = 14.0;
2405-
PRODUCT_NAME = "$(TARGET_NAME)";
2418+
PRODUCT_BUNDLE_IDENTIFIER = "com.TablePro.tablepro-mcp";
2419+
PRODUCT_NAME = "tablepro-mcp";
24062420
SDKROOT = macosx;
24072421
SWIFT_APPROACHABLE_CONCURRENCY = YES;
24082422
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
@@ -2417,7 +2431,8 @@
24172431
DEVELOPMENT_TEAM = D7HJ5TFYCU;
24182432
ENABLE_HARDENED_RUNTIME = YES;
24192433
MACOSX_DEPLOYMENT_TARGET = 14.0;
2420-
PRODUCT_NAME = "$(TARGET_NAME)";
2434+
PRODUCT_BUNDLE_IDENTIFIER = "com.TablePro.tablepro-mcp";
2435+
PRODUCT_NAME = "tablepro-mcp";
24212436
SDKROOT = macosx;
24222437
SWIFT_APPROACHABLE_CONCURRENCY = YES;
24232438
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;

TablePro.xcodeproj/xcshareddata/xcschemes/TablePro.xcscheme

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
</BuildAction>
2626
<TestAction
2727
buildConfiguration = "Debug"
28-
codeCoverageEnabled = "NO"
2928
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
3029
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
3130
shouldUseLaunchSchemeArgsEnv = "YES"

0 commit comments

Comments
 (0)