From 9094f3027fe3f0ff63ff314b2522bec8caecbaf2 Mon Sep 17 00:00:00 2001 From: Ngo Quoc Dat Date: Sat, 10 Oct 2026 18:20:48 +0700 Subject: [PATCH] feat(settings): rename the Integrations pane to MCP --- .../skills/release/references/blog-post.md | 2 +- CHANGELOG.md | 1 + TablePro/Core/MCP/MCPApprovalPresenter.swift | 2 +- .../Core/MCP/Outside/MCPClientSession.swift | 2 +- .../MCPStreamableHttpClientTransport.swift | 2 +- .../Menu/AppDelegate+MainMenuActions.swift | 2 +- TablePro/Core/Menu/AppMenuBuilder.swift | 4 +- TablePro/Resources/Localizable.xcstrings | 206 ++++++++++++++++++ ...IntegrationsActivityWindowController.swift | 5 +- .../Settings/AIProviderDetailSheet.swift | 2 +- .../Sections/MCPOutsideServersSection.swift | 8 +- .../Views/Settings/Sections/MCPSection.swift | 2 +- TablePro/Views/Settings/SettingsView.swift | 2 +- .../Core/Menu/MainMenuBuilderTests.swift | 10 + .../Settings/SettingsWindowTitleTests.swift | 14 ++ .../AuxiliaryWindowCloseUITests.swift | 6 +- .../SettingsWindowTitleUITests.swift | 2 +- docs/customization/settings.mdx | 18 +- docs/developers/index.mdx | 2 +- docs/developers/mcp-tools.mdx | 4 +- docs/developers/pairing.mdx | 2 +- docs/developers/tokens.mdx | 8 +- docs/developers/versioning.mdx | 4 +- docs/features/ai-assistant.mdx | 2 +- docs/features/keyboard-shortcuts.mdx | 2 +- docs/features/mcp-outside-servers.mdx | 4 +- docs/features/mcp.mdx | 6 +- docs/integrations/mcp-clients.mdx | 8 +- docs/integrations/raycast.mdx | 2 +- docs/security/privacy.mdx | 6 +- 30 files changed, 282 insertions(+), 58 deletions(-) diff --git a/.claude/skills/release/references/blog-post.md b/.claude/skills/release/references/blog-post.md index 24b5cd6681..9618ef9d8a 100644 --- a/.claude/skills/release/references/blog-post.md +++ b/.claude/skills/release/references/blog-post.md @@ -112,7 +112,7 @@ Browsershot::html($html)->windowSize(2400, 1500)->setScreenshotType('png') - Second person, present tense. Contractions are fine here. - Numbers instead of adjectives: "400 MB at idle", "three round trips", never "much faster". - Backticks on shortcuts, SQL keywords, identifiers, paths and config keys. Bold for menu paths: - `**Settings > Integrations**`. + `**Settings > MCP**`. - Tables only for tabular things, two per post at most. - State a limit flatly and without apology. Never call a competitor bad; say what it costs. - No em dashes, no banned words (`scripts/banned-words.txt` in the TablePro repo), US spelling to diff --git a/CHANGELOG.md b/CHANGELOG.md index c575254ec8..2dea88351a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Settings > Integrations is now Settings > MCP, and TablePro > Integrations… is now MCP Activity…. - Settings > Sync names what stops iCloud Sync, such as full iCloud storage or a signed-out account, with the action that clears it. ### Fixed diff --git a/TablePro/Core/MCP/MCPApprovalPresenter.swift b/TablePro/Core/MCP/MCPApprovalPresenter.swift index 42a09eb729..744e352dc6 100644 --- a/TablePro/Core/MCP/MCPApprovalPresenter.swift +++ b/TablePro/Core/MCP/MCPApprovalPresenter.swift @@ -46,7 +46,7 @@ struct MCPApprovalAlertPresenter: MCPApprovalPresenting { request.connectionName, request.databaseType ) - let pointer = String(localized: "Change this in Settings > Integrations.") + let pointer = String(localized: "Change this in Settings > MCP.") return opening + "\n\n" + Self.consequence(of: request.memory) + " " + pointer } diff --git a/TablePro/Core/MCP/Outside/MCPClientSession.swift b/TablePro/Core/MCP/Outside/MCPClientSession.swift index 9458b90347..a8d33f58ea 100644 --- a/TablePro/Core/MCP/Outside/MCPClientSession.swift +++ b/TablePro/Core/MCP/Outside/MCPClientSession.swift @@ -25,7 +25,7 @@ internal enum MCPClientError: Error, Equatable, Sendable { internal var localizedMessage: String { switch self { case .notConfigured: - return String(localized: "This server has no credential. Add its token in Settings > Integrations.") + return String(localized: "This server has no credential. Add its token in Settings > MCP.") case .timedOut: return String(localized: "The server did not answer in time.") case .transport(let detail): diff --git a/TablePro/Core/MCP/Transport/MCPStreamableHttpClientTransport.swift b/TablePro/Core/MCP/Transport/MCPStreamableHttpClientTransport.swift index d81d9064dd..ce809235e4 100644 --- a/TablePro/Core/MCP/Transport/MCPStreamableHttpClientTransport.swift +++ b/TablePro/Core/MCP/Transport/MCPStreamableHttpClientTransport.swift @@ -30,7 +30,7 @@ public actor MCPStreamableHttpClientTransport { private static let namedMethods: Set = ["tools/call", "resources/read", "prompts/get"] private static let unavailableMessage = - "TablePro's MCP server is not reachable. Make sure TablePro is running and the MCP server is enabled in Settings > Integrations." + "TablePro's MCP server is not reachable. Make sure TablePro is running and the MCP server is enabled in Settings > MCP." private let configuration: MCPStreamableHttpClientConfiguration private let credentialsProvider: any MCPUpstreamCredentialsProviding diff --git a/TablePro/Core/Menu/AppDelegate+MainMenuActions.swift b/TablePro/Core/Menu/AppDelegate+MainMenuActions.swift index f7b37cb947..05045fc86b 100644 --- a/TablePro/Core/Menu/AppDelegate+MainMenuActions.swift +++ b/TablePro/Core/Menu/AppDelegate+MainMenuActions.swift @@ -29,7 +29,7 @@ extension AppDelegate: NSMenuItemValidation { SoftwareUpdater.shared.checkForUpdates() } - @objc func openIntegrations(_ sender: Any?) { + @objc func openMCPActivity(_ sender: Any?) { WindowOpener.shared.openIntegrationsActivity() } diff --git a/TablePro/Core/Menu/AppMenuBuilder.swift b/TablePro/Core/Menu/AppMenuBuilder.swift index eb1d744a42..e458203e1b 100644 --- a/TablePro/Core/Menu/AppMenuBuilder.swift +++ b/TablePro/Core/Menu/AppMenuBuilder.swift @@ -25,8 +25,8 @@ enum AppMenuBuilder { ), MenuItemFactory.separator, MenuItemFactory.item( - String(localized: "Integrations…"), - action: #selector(AppDelegate.openIntegrations(_:)) + String(localized: "MCP Activity…"), + action: #selector(AppDelegate.openMCPActivity(_:)) ), MenuItemFactory.separator, MenuItemFactory.item( diff --git a/TablePro/Resources/Localizable.xcstrings b/TablePro/Resources/Localizable.xcstrings index 15652cf6bf..f1287ae6a7 100644 --- a/TablePro/Resources/Localizable.xcstrings +++ b/TablePro/Resources/Localizable.xcstrings @@ -34459,6 +34459,7 @@ } }, "Change this in Settings > Integrations." : { + "extractionState" : "stale", "localizations" : { "fr" : { "stringUnit" : { @@ -34468,6 +34469,46 @@ } } }, + "Change this in Settings > MCP." : { + "localizations" : { + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Modifiez ce réglage dans Réglages > MCP." + } + }, + "ko" : { + "stringUnit" : { + "state" : "translated", + "value" : "설정 > MCP에서 변경할 수 있습니다." + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bunu Ayarlar > MCP bölümünden değiştirin." + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Thay đổi trong Cài đặt > MCP." + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "可在“设置 > MCP”中更改。" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "可在「設定 > MCP」中變更。" + } + } + } + }, "Change Type" : { "localizations" : { "fr" : { @@ -93142,6 +93183,7 @@ } }, "Integrations" : { + "extractionState" : "stale", "localizations" : { "fr" : { "stringUnit" : { @@ -93182,6 +93224,7 @@ } }, "Integrations Activity" : { + "extractionState" : "stale", "localizations" : { "fr" : { "stringUnit" : { @@ -93263,6 +93306,7 @@ } }, "Integrations…" : { + "extractionState" : "stale", "localizations" : { "fr" : { "stringUnit" : { @@ -105492,6 +105536,86 @@ } } }, + "MCP Activity" : { + "localizations" : { + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Activité MCP" + } + }, + "ko" : { + "stringUnit" : { + "state" : "translated", + "value" : "MCP 활동" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "MCP Etkinliği" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hoạt động MCP" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "MCP 活动" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "MCP 活動" + } + } + } + }, + "MCP Activity…" : { + "localizations" : { + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Activité MCP…" + } + }, + "ko" : { + "stringUnit" : { + "state" : "translated", + "value" : "MCP 활동…" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "MCP Etkinliği…" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hoạt động MCP…" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "MCP 活动…" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "MCP 活動…" + } + } + } + }, "MCP query execution" : { "localizations" : { "fr" : { @@ -151485,6 +151609,7 @@ } }, "Runs the claude command line tool so chat bills against your Claude subscription. Database tools need the MCP server turned on in Settings > Integrations." : { + "extractionState" : "stale", "localizations" : { "fr" : { "stringUnit" : { @@ -151524,6 +151649,46 @@ } } }, + "Runs the claude command line tool so chat bills against your Claude subscription. Database tools need the MCP server turned on in Settings > MCP." : { + "localizations" : { + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Exécute l’outil en ligne de commande claude pour que la discussion soit facturée sur votre abonnement Claude. Les outils de base de données nécessitent d’activer le serveur MCP dans Réglages > MCP." + } + }, + "ko" : { + "stringUnit" : { + "state" : "translated", + "value" : "claude 명령줄 도구를 실행하므로 채팅 사용량은 Claude 구독에 청구됩니다. 데이터베이스 도구를 사용하려면 설정 > MCP에서 MCP 서버를 켜야 합니다." + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "claude komut satırı aracını çalıştırır, böylece sohbet Claude aboneliğinizden düşer. Veritabanı araçları için Ayarlar > MCP altında MCP sunucusunun açık olması gerekir." + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Chạy công cụ dòng lệnh claude nên phần chat sẽ tính vào gói đăng ký Claude của bạn. Các công cụ cơ sở dữ liệu cần bật máy chủ MCP trong Cài đặt > MCP." + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "运行 claude 命令行工具,因此聊天会计入你的 Claude 订阅。数据库工具需要在“设置 > MCP”中开启 MCP 服务器。" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "執行 claude 命令列工具,因此聊天會計入你的 Claude 訂閱。資料庫工具需要在「設定 > MCP」中開啟 MCP 伺服器。" + } + } + } + }, "Runs the Google Cloud SQL Auth Proxy against an instance connection name." : { "localizations" : { "fr" : { @@ -194420,6 +194585,7 @@ } }, "This server has no credential. Add its token in Settings > Integrations." : { + "extractionState" : "stale", "localizations" : { "fr" : { "stringUnit" : { @@ -194429,6 +194595,46 @@ } } }, + "This server has no credential. Add its token in Settings > MCP." : { + "localizations" : { + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ce serveur n’a pas d’identifiant. Ajoutez son jeton dans Réglages > MCP." + } + }, + "ko" : { + "stringUnit" : { + "state" : "translated", + "value" : "이 서버에 자격 증명이 없습니다. 설정 > MCP에서 토큰을 추가하세요." + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bu sunucunun kimlik bilgisi yok. Token'ını Ayarlar > MCP bölümünden ekleyin." + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Máy chủ này chưa có thông tin xác thực. Hãy thêm token của nó trong Cài đặt > MCP." + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "此服务器没有凭据。请在“设置 > MCP”中添加其令牌。" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "此伺服器沒有憑證。請在「設定 > MCP」中加入其權杖。" + } + } + } + }, "This server has no databases yet." : { "localizations" : { "fr" : { diff --git a/TablePro/Views/Integrations/IntegrationsActivityWindowController.swift b/TablePro/Views/Integrations/IntegrationsActivityWindowController.swift index 41fa850e68..3ba9882b19 100644 --- a/TablePro/Views/Integrations/IntegrationsActivityWindowController.swift +++ b/TablePro/Views/Integrations/IntegrationsActivityWindowController.swift @@ -6,9 +6,6 @@ import AppKit import SwiftUI -/// Hosts the activity log and connected clients in an AppKit window so the app no longer needs a -/// SwiftUI scene for it. One instance is kept for the app's lifetime, matching the single-window -/// scene it replaces. @MainActor internal final class IntegrationsActivityWindowController: NSWindowController { private static var shared: IntegrationsActivityWindowController? @@ -32,7 +29,7 @@ internal final class IntegrationsActivityWindowController: NSWindowController { detailMinimumThickness: 520 ) - let window = NSWindow.titled(String(localized: "Integrations Activity"), contentViewController: split) + let window = NSWindow.titled(String(localized: "MCP Activity"), contentViewController: split) window.identifier = NSUserInterfaceItemIdentifier(WindowIdentifier.integrationsActivity) window.styleMask = [.titled, .closable, .miniaturizable, .resizable] window.contentMinSize = NSSize(width: 720, height: 400) diff --git a/TablePro/Views/Settings/AIProviderDetailSheet.swift b/TablePro/Views/Settings/AIProviderDetailSheet.swift index 5f33b352fc..a6c4efc3f3 100644 --- a/TablePro/Views/Settings/AIProviderDetailSheet.swift +++ b/TablePro/Views/Settings/AIProviderDetailSheet.swift @@ -226,7 +226,7 @@ struct AIProviderDetailSheet: View { } header: { Text("Claude Code") } footer: { - Text("Runs the claude command line tool so chat bills against your Claude subscription. Database tools need the MCP server turned on in Settings > Integrations.") + Text("Runs the claude command line tool so chat bills against your Claude subscription. Database tools need the MCP server turned on in Settings > MCP.") .font(.caption) .foregroundStyle(.secondary) } diff --git a/TablePro/Views/Settings/Sections/MCPOutsideServersSection.swift b/TablePro/Views/Settings/Sections/MCPOutsideServersSection.swift index 91c67abef0..385e0631dc 100644 --- a/TablePro/Views/Settings/Sections/MCPOutsideServersSection.swift +++ b/TablePro/Views/Settings/Sections/MCPOutsideServersSection.swift @@ -5,12 +5,8 @@ import SwiftUI -/// The MCP servers somebody else runs that a session may call. -/// -/// Its own section rather than a line in **Integrations**, because it is the opposite direction: -/// everything above it is what an outside client may ask of TablePro, and this is what TablePro may -/// ask of an outside server. It sits below them for that reason, and it works whether or not the -/// built-in server is switched on. +/// Below the built-in server's sections because it is the opposite direction: what TablePro may ask +/// of an outside server. It works whether or not the built-in server is on. internal struct MCPOutsideServersSection: View { @ObservedObject private var store = MCPServerStore.shared diff --git a/TablePro/Views/Settings/Sections/MCPSection.swift b/TablePro/Views/Settings/Sections/MCPSection.swift index f5429e6300..d66ea53fb9 100644 --- a/TablePro/Views/Settings/Sections/MCPSection.swift +++ b/TablePro/Views/Settings/Sections/MCPSection.swift @@ -43,7 +43,7 @@ struct MCPSection: View { } var body: some View { - Section(String(localized: "Integrations")) { + Section { Toggle(String(localized: "Enable MCP Server"), isOn: $settings.enabled) if showsStatus { diff --git a/TablePro/Views/Settings/SettingsView.swift b/TablePro/Views/Settings/SettingsView.swift index c926e88299..615920ba07 100644 --- a/TablePro/Views/Settings/SettingsView.swift +++ b/TablePro/Views/Settings/SettingsView.swift @@ -18,7 +18,7 @@ enum SettingsPane: String, CaseIterable { case .profiles: String(localized: "Profiles") case .notifications: String(localized: "Notifications") case .ai: String(localized: "AI") - case .mcp: String(localized: "Integrations") + case .mcp: "MCP" case .plugins: String(localized: "Plugins") case .sync: String(localized: "Sync") /// The stored rawValue stays "account": it is the tab item identifier and the pane the diff --git a/TableProTests/Core/Menu/MainMenuBuilderTests.swift b/TableProTests/Core/Menu/MainMenuBuilderTests.swift index 36537af719..c01009f62c 100644 --- a/TableProTests/Core/Menu/MainMenuBuilderTests.swift +++ b/TableProTests/Core/Menu/MainMenuBuilderTests.swift @@ -40,6 +40,16 @@ struct MainMenuStructureTests { #expect(MainMenuLink.changelog == "https://docs.tablepro.app/changelog") } + @Test("The app menu opens MCP Activity without an active connection") + func mcpActivityIsReachable() throws { + let app = try #require(buildMenu().items.first { $0.title == "TablePro" }?.submenu) + let item = try #require(app.items.first { $0.title == String(localized: "MCP Activity…") }) + #expect(item.action == #selector(AppDelegate.openMCPActivity(_:))) + #expect(item.target == nil) + #expect(item.keyEquivalent.isEmpty) + #expect(AppDelegate().validateMenuItem(item)) + } + @Test("Top level order follows the macOS HIG") func topLevelOrder() { let titles = buildMenu().items.map(\.title) diff --git a/TableProTests/Views/Settings/SettingsWindowTitleTests.swift b/TableProTests/Views/Settings/SettingsWindowTitleTests.swift index 0f2816dda9..fae5a327a4 100644 --- a/TableProTests/Views/Settings/SettingsWindowTitleTests.swift +++ b/TableProTests/Views/Settings/SettingsWindowTitleTests.swift @@ -73,6 +73,20 @@ final class SettingsWindowTitleTests: XCTestCase { XCTAssertEqual(window.title, SettingsPane.keyboard.title) } + func testAStoredMCPPaneRestoresThePaneTitledMCP() { + AppStorageEnvironment.shared.defaults.set("mcp", forKey: PreferenceKeys.selectedSettingsPane.name) + + let (_, window) = makePanes() + + XCTAssertEqual(window.title, "MCP") + } + + // The rawValue is the persisted pane and the tab item identifier, so it outlives any title. + func testPaneIdentifiersSurviveTitleChanges() { + XCTAssertEqual(SettingsPane.mcp.rawValue, "mcp") + XCTAssertEqual(SettingsPane.account.rawValue, "account") + } + func testAskingForNoPaneReadsTheStoredPaneRatherThanStayingPut() { let (panes, window) = makePanes() panes.select(.plugins) diff --git a/TableProUITests/AuxiliaryWindowCloseUITests.swift b/TableProUITests/AuxiliaryWindowCloseUITests.swift index e4c35588b3..0b60853d97 100644 --- a/TableProUITests/AuxiliaryWindowCloseUITests.swift +++ b/TableProUITests/AuxiliaryWindowCloseUITests.swift @@ -1,7 +1,7 @@ import XCTest /// Command W has to close the window in front. It was bound to a command only a connection -/// window answered, so it did nothing in Settings, in the integrations activity window, or in +/// window answered, so it did nothing in Settings, in the MCP Activity window, or in /// any viewer the app opens, and the welcome window had to answer that command by hand to get /// its own shortcut back. /// @@ -39,9 +39,9 @@ final class AuxiliaryWindowCloseUITests: UITestCase { assertCommandWCloses(openWindow("settings", from: "Settings…", in: app), in: app) } - func testCommandWClosesTheIntegrationsActivityWindow() throws { + func testCommandWClosesTheMCPActivityWindow() throws { let app = try launchShowingWelcome() - assertCommandWCloses(openWindow("integrations-activity", from: "Integrations…", in: app), in: app) + assertCommandWCloses(openWindow("integrations-activity", from: "MCP Activity…", in: app), in: app) } /// The welcome window used to answer the editor's own close command to get Command W back. diff --git a/TableProUITests/SettingsWindowTitleUITests.swift b/TableProUITests/SettingsWindowTitleUITests.swift index edea74c622..27b893be9c 100644 --- a/TableProUITests/SettingsWindowTitleUITests.swift +++ b/TableProUITests/SettingsWindowTitleUITests.swift @@ -14,7 +14,7 @@ final class SettingsWindowTitleUITests: UITestCase { let settingsWindow = app.windows["settings"] XCTAssertTrue(settingsWindow.waitToExist(timeout: 10)) - for pane in ["Keyboard", "Appearance", "Plugins", "Editor", "General"] { + for pane in ["Keyboard", "Appearance", "MCP", "Plugins", "Editor", "General"] { let paneButton = app.toolbars.buttons[pane] XCTAssertTrue(paneButton.waitToExist(timeout: 10)) paneButton.click() diff --git a/docs/customization/settings.mdx b/docs/customization/settings.mdx index 377051a4dd..8b6fddf0d9 100644 --- a/docs/customization/settings.mdx +++ b/docs/customization/settings.mdx @@ -19,7 +19,7 @@ The settings window is app-wide: a value on any of these twelve tabs holds for e Credential profiles and SSH servers, and which connections use each. Which finished operations notify you when TablePro is in the background. Providers, inline suggestions, context, slash commands. - MCP server, tokens, clients, activity. + MCP server, tokens, clients, activity. Manage drivers, exporters, and themes. iCloud sync and what it carries. Activation, devices, team. @@ -95,14 +95,14 @@ What a fresh install ships with, so one glance down this column says what you ch | AI | Include query results | Off | | AI | Max schema tables | 20 | | AI | Connection policy | Ask Each Time | -| Integrations | Enable MCP Server | Off | -| Integrations | Port | 23508 | -| Integrations | Default row limit | 500 | -| Integrations | Maximum row limit | 10,000 | -| Integrations | Query timeout | 30 seconds | -| Integrations | Log MCP queries in history | On | -| Integrations | Require authentication | On | -| Integrations | Approval | Ask Once for Each Connection | +| MCP | Enable MCP Server | Off | +| MCP | Port | 23508 | +| MCP | Default row limit | 500 | +| MCP | Maximum row limit | 10,000 | +| MCP | Query timeout | 30 seconds | +| MCP | Log MCP queries in history | On | +| MCP | Require authentication | On | +| MCP | Approval | Ask Once for Each Connection | | Sync | Sync this Mac with iCloud | Off | | Sync | Passwords (keychain sync) | Off | diff --git a/docs/developers/index.mdx b/docs/developers/index.mdx index 5668e06fc8..35ff40337d 100644 --- a/docs/developers/index.mdx +++ b/docs/developers/index.mdx @@ -52,7 +52,7 @@ connection's **External Clients** level and Safe Mode apply exactly as they do o policy does not: it governs the assistant, not other apps. Each request lands in the activity log with the token behind it, and a statement is stored as a -SHA-256 digest rather than as text. Open **Settings > Integrations** and click **View Activity** to +SHA-256 digest rather than as text. Open **Settings > MCP** and click **View Activity** to read it. ## Versioning diff --git a/docs/developers/mcp-tools.mdx b/docs/developers/mcp-tools.mdx index a9b8e13906..92494934f9 100644 --- a/docs/developers/mcp-tools.mdx +++ b/docs/developers/mcp-tools.mdx @@ -15,7 +15,7 @@ In the tables below, required arguments come first and optional ones follow in p - The result comes back twice: as JSON text in `content[0]`, and as a typed object in `structuredContent`. Read `structuredContent`. - Timestamps are ISO 8601, error text is redacted, and "a result set" means `columns[]`, `rows[][]`, `row_count`, `rows_affected`, `execution_time_ms`, `is_truncated`, plus `status_message`, `database` and `schema` when they apply. -Row limits default to the server's **Default row limit** setting (500) and are capped by **Maximum row limit** (10,000). Timeouts default to **Query timeout** (30 seconds) and are capped at 300. Both live in **Settings > Integrations**. +Row limits default to the server's **Default row limit** setting (500) and are capped by **Maximum row limit** (10,000). Timeouts default to **Query timeout** (30 seconds) and are capped at 300. Both live in **Settings > MCP**. ## Tool index @@ -36,7 +36,7 @@ Fourteen tools need `tools:write`: `connect`, `disconnect`, `switch_database`, ` Past the scope, a call clears three more gates: 1. **Connection allowlist.** A token limited to named connections gets `-33007` for anything else. -2. **Connection policy.** **External Clients** set to **Blocked** hides the connection: `list_connections` omits it and any tool that names it is refused. An AI policy of **Never** does the same. Otherwise the first call that touches a connection asks the user, as often as **Settings > Integrations > Approval** says. That question is always a dialog on the user's Mac, never an elicitation: a client that could answer it could also grant itself the connection. It has no deadline, so the client owns the timeout, and a refusal stands for 60 seconds before the question can be put again. +2. **Connection policy.** **External Clients** set to **Blocked** hides the connection: `list_connections` omits it and any tool that names it is refused. An AI policy of **Never** does the same. Otherwise the first call that touches a connection asks the user, as often as **Settings > MCP > Approval** says. That question is always a dialog on the user's Mac, never an elicitation: a client that could answer it could also grant itself the connection. It has no deadline, so the client owns the timeout, and a refusal stands for 60 seconds before the question can be put again. 3. **Safe Mode.** A write goes through the connection's Safe Mode, which may ask the user to confirm it or to authenticate. See [Approvals](/developers/mcp-protocol#approvals-and-input-required). `confirm_destructive_operation` needs `admin` as well, so it takes a Full Access token, and **Read Only** refuses it outright whatever the token carries. No token skips the user's approval. diff --git a/docs/developers/pairing.mdx b/docs/developers/pairing.mdx index 58450e6384..0d72244fd0 100644 --- a/docs/developers/pairing.mdx +++ b/docs/developers/pairing.mdx @@ -107,7 +107,7 @@ and **Expiration** (never, 1, 7, 30 or 90 days). The link's parameters are a req Approving mints the token, holds the plaintext against a one-time code for 5 minutes, and opens the redirect. Pairing again mints a second token rather than replacing the first, so an extension that re-pairs should stop using its old one. Revoke either under -**Settings > Integrations > Authentication**. +**Settings > MCP > Authentication**. ## Security properties diff --git a/docs/developers/tokens.mdx b/docs/developers/tokens.mdx index 0a82e8954c..3d86ef04e7 100644 --- a/docs/developers/tokens.mdx +++ b/docs/developers/tokens.mdx @@ -25,7 +25,7 @@ Anonymous loopback is the floor and cannot be raised: the scope check refuses `t ## Require authentication -**Settings > Integrations > Authentication > Require authentication** is on by default. Turning it on for the first time with no tokens yet mints a **Read & Write** token named "Default token" and reveals the plaintext once. +**Settings > MCP > Authentication > Require authentication** is on by default. Turning it on for the first time with no tokens yet mints a **Read & Write** token named "Default token" and reveals the plaintext once. With the toggle off, a request from your own machine with no `Authorization` header is accepted as the anonymous loopback caller in the table above. Presenting an `Authorization` header still goes through normal token validation, so an invalid token is rejected either way. The server is loopback only, with no remote mode. @@ -47,7 +47,7 @@ The effective permission is the lower of the token's scope and the connection's ## Creating a token -Pairing is the usual route: see [Pairing](/developers/pairing). To mint one by hand, open **Settings > Integrations > Authentication**, click **Generate Token**, and pick a name, permission level, connection allowlist and expiry. The plaintext is shown once. +Pairing is the usual route: see [Pairing](/developers/pairing). To mint one by hand, open **Settings > MCP > Authentication**, click **Generate Token**, and pick a name, permission level, connection allowlist and expiry. The plaintext is shown once. ## Expiry @@ -59,7 +59,7 @@ Mint the replacement before you retire the old one; two tokens for one client ar ## Revocation -The token list in **Settings > Integrations > Authentication** shows prefix, name, permission level, allowlist, last use, and expiry. Each row offers: +The token list in **Settings > MCP > Authentication** shows prefix, name, permission level, allowlist, last use, and expiry. Each row offers: - **Revoke**: marks the token inactive. It stays in the list and cannot be reactivated. - **Delete…**: removes the row entirely. @@ -91,7 +91,7 @@ The plaintext is `tp_` followed by 32 base64url-encoded random bytes. Tokens liv ## Activity log -Every authentication, tool call, resource read, and query is recorded in `~/Library/Application Support/TablePro/mcp-audit.db` with the token id, never the plaintext. Open it with **Settings > Integrations > View Activity…**. +Every authentication, tool call, resource read, and query is recorded in `~/Library/Application Support/TablePro/mcp-audit.db` with the token id, never the plaintext. Open it with **Settings > MCP > View Activity…**. | Field | Values | |-------|--------| diff --git a/docs/developers/versioning.mdx b/docs/developers/versioning.mdx index 85ab0f09c5..600516f662 100644 --- a/docs/developers/versioning.mdx +++ b/docs/developers/versioning.mdx @@ -62,9 +62,9 @@ These can change in any release, without notice: `/v1/integrations/exchange`. - The handshake file at `~/Library/Application Support/TablePro/mcp-handshake.json`. Use the bundled `tablepro-mcp` bridge instead of parsing it. -- Token storage. Tokens are managed in **Settings > Integrations**. +- Token storage. Tokens are managed in **Settings > MCP**. - The audit log at `~/Library/Application Support/TablePro/mcp-audit.db`. Read it through the - activity window. + **MCP Activity** window. - The connections file at `~/Library/Application Support/TablePro/connections.json`. Its shape can shift between minor versions; use `list_connections` instead. diff --git a/docs/features/ai-assistant.mdx b/docs/features/ai-assistant.mdx index 5bd0504e92..17424a2d1e 100644 --- a/docs/features/ai-assistant.mdx +++ b/docs/features/ai-assistant.mdx @@ -45,7 +45,7 @@ With no preference, start with Claude or OpenAI on an API key: both take a key, ### Claude Agent -Install Claude Code, run `claude /login` in Terminal, then pick Opus, Sonnet, or Haiku. Replies bill against your Claude subscription instead of an API key. The provider answers from your schema when the MCP server is on in **Settings > Integrations**, and falls back to plain chat when it is off. +Install Claude Code, run `claude /login` in Terminal, then pick Opus, Sonnet, or Haiku. Replies bill against your Claude subscription instead of an API key. The provider answers from your schema when the MCP server is on in **Settings > MCP**, and falls back to plain chat when it is off. The `claude` tool runs headless here. Claude Code is built for you to use directly rather than as a backend for other apps, so this path can break with any Claude Code release. Your subscription is governed by Anthropic's [Consumer Terms](https://www.anthropic.com/legal/consumer-terms) and [Usage Policy](https://www.anthropic.com/legal/aup), which TablePro cannot grant rights under. Replies also count against the limits you share with claude.ai and your own Claude Code sessions, so running out here stops your work there. For a metered path on commercial terms, add the **Claude** provider with an API key. diff --git a/docs/features/keyboard-shortcuts.mdx b/docs/features/keyboard-shortcuts.mdx index b67a5b8e6c..a8fa95f7ea 100644 --- a/docs/features/keyboard-shortcuts.mdx +++ b/docs/features/keyboard-shortcuts.mdx @@ -171,7 +171,7 @@ See [Filtering](/features/filtering) for the filter bar itself. ## Tabs and windows -`Cmd+W` closes whatever is in front. In a connection window that is the current editor tab, and the File menu reads **Close Tab**. Settings, Integrations, a JSON or PHP viewer, and the welcome window have no tabs, so it closes the window and the menu reads **Close Window**. While the connections strip holds the keyboard it closes the highlighted entry, and the menu names it; an entry that is its connection's last one takes the connection with it. +`Cmd+W` closes whatever is in front. In a connection window that is the current editor tab, and the File menu reads **Close Tab**. Settings, MCP Activity, a JSON or PHP viewer, and the welcome window have no tabs, so it closes the window and the menu reads **Close Window**. While the connections strip holds the keyboard it closes the highlighted entry, and the menu names it; an entry that is its connection's last one takes the connection with it. | Action | Shortcut | |--------|----------| diff --git a/docs/features/mcp-outside-servers.mdx b/docs/features/mcp-outside-servers.mdx index b8027f3805..085ae3268c 100644 --- a/docs/features/mcp-outside-servers.mdx +++ b/docs/features/mcp-outside-servers.mdx @@ -14,7 +14,7 @@ A session with an outside server allowed can ask it for a ticket, a runbook, a d ## Adding a server -Open **Settings > Integrations**, scroll to **Outside MCP Servers**, and click **Add Server…**. +Open **Settings > MCP**, scroll to **Outside MCP Servers**, and click **Add Server…**. | Field | What it takes | |-------|---------------| @@ -54,7 +54,7 @@ What an outside server sends back is text the assistant reads. A result that rea Every outbound call is written to the activity log before the request leaves, with the server, the session, the connection, the tool name, the payload size and a short hash of the payload. The arguments themselves are not stored: they carry table names and values, and a log that kept them would be a second copy of what it exists to watch. -Open it from **Settings > Integrations > View Activity…**. +Open it from **Settings > MCP > View Activity…**. ## Names diff --git a/docs/features/mcp.mdx b/docs/features/mcp.mdx index 4ab1165402..2d533520ea 100644 --- a/docs/features/mcp.mdx +++ b/docs/features/mcp.mdx @@ -5,7 +5,7 @@ description: Built-in Model Context Protocol server that lets AI clients query y The [MCP](https://modelcontextprotocol.io) server binds `127.0.0.1` and nothing else: no remote mode, no TLS certificate, no setting that opens it to your network. Claude Desktop, Claude Code, Cursor, and Zed reach your databases through the connections you already saved, and never see a password. -This page covers the **Settings > Integrations** pane. The protocol itself, the tool catalog, the prompts and the token model live under [Developers](/developers). +This page covers the **Settings > MCP** pane. The protocol itself, the tool catalog, the prompts and the token model live under [Developers](/developers). TablePro MCP settings @@ -14,7 +14,7 @@ This page covers the **Settings > Integrations** pane. The protocol itself, the ## Starting and stopping -Open **Settings > Integrations** and turn on **Enable MCP Server**. The **Status** row underneath is how you check it before touching a client config: it reads **Running on port 23508**, or **Stopped**, or the reason it failed. +Open **Settings > MCP** and turn on **Enable MCP Server**. The **Status** row underneath is how you check it before touching a client config: it reads **Running on port 23508**, or **Stopped**, or the reason it failed. Leaving the toggle off does not keep the server down. It starts on demand when a client launches the bundled `tablepro-mcp` bridge and when you pair an extension, so turning the toggle off stops the listener but not those paths. @@ -75,7 +75,7 @@ With the toggle off, a caller on your own machine is accepted without a token, b ## Activity and connected clients -**View Activity…** opens a separate window with two sections: +**View Activity…** opens the **MCP Activity** window, also on **TablePro > MCP Activity…**. It has two sections: - **Activity Log**: every authentication, tool call, resource read and query, with the token behind it, the category, the connection, and the outcome. Filter by time, category or token, search, and export the filtered view to CSV. Retained for 90 days. Statements are recorded as a SHA-256 digest, not as text. - **Connected Clients**: clients that have called in the last five minutes, with the client name, the token, and when they were first and last seen. **Disconnect** revokes that client's token, so the client has to pair again. diff --git a/docs/integrations/mcp-clients.mdx b/docs/integrations/mcp-clients.mdx index 750ab2c080..c51460e46b 100644 --- a/docs/integrations/mcp-clients.mdx +++ b/docs/integrations/mcp-clients.mdx @@ -100,7 +100,7 @@ Run `goose session` and ask for the tool list to confirm. ## Setup snippets in TablePro -Click **Connect a Client…** in **Settings > Integrations**. The sheet covers Claude Desktop, Claude Code, Cursor, and Zed, with numbered steps and copyable snippets that already carry the right binary path for your install. +Click **Connect a Client…** in **Settings > MCP**. The sheet covers Claude Desktop, Claude Code, Cursor, and Zed, with numbered steps and copyable snippets that already carry the right binary path for your install. ## What the config leaves out @@ -118,7 +118,7 @@ For a narrower scope than `readWrite`, or a connection allowlist, use the [HTTP ## HTTP transport -Use HTTP when the client cannot spawn a local process. Mint a token in **Settings > Integrations > Authentication** and point the client at the server: +Use HTTP when the client cannot spawn a local process. Mint a token in **Settings > MCP > Authentication** and point the client at the server: ```json { @@ -133,7 +133,7 @@ Use HTTP when the client cannot spawn a local process. Mint a token in **Setting } ``` -Replace `23508` with the port shown in **Settings > Integrations**. Other clients use the same `url` plus `headers` shape, sometimes under `type: streamable-http`. Check the client's docs. +Replace `23508` with the port shown in **Settings > MCP**. Other clients use the same `url` plus `headers` shape, sometimes under `type: streamable-http`. Check the client's docs. Three things change on this route. The server binds `127.0.0.1` over plain HTTP with no remote mode and no TLS, so a client on another machine needs an SSH port forward. `GET /mcp` answers `405`, so a client that opens a `GET` stream for notifications fails; notifications ride the response stream of the request they belong to. And `2025-11-25` and `2025-06-18` still work through the old `initialize` handshake and `Mcp-Session-Id`, while `2025-03-26` is refused. @@ -155,7 +155,7 @@ The bridge writes its failure to stderr and as a JSON-RPC error, so the message ### TablePro is not running -The bridge could not launch the app, or got no trusted handshake within 10 seconds. Open TablePro and check that **Settings > Integrations** shows the server running; if it does, toggle **Enable MCP Server** off and on, then relaunch the client. +The bridge could not launch the app, or got no trusted handshake within 10 seconds. Open TablePro and check that **Settings > MCP** shows the server running; if it does, toggle **Enable MCP Server** off and on, then relaunch the client. ### The local MCP endpoint did not prove it belongs to TablePro diff --git a/docs/integrations/raycast.mdx b/docs/integrations/raycast.mdx index c2a08e0cde..5091c44ea6 100644 --- a/docs/integrations/raycast.mdx +++ b/docs/integrations/raycast.mdx @@ -26,7 +26,7 @@ code back to Raycast, which exchanges it for a token over localhost. [Pairing](/ documents the protocol. Re-run the command whenever you want a fresh token. The previous one keeps working until you revoke -it in **Settings > Integrations**. +it in **Settings > MCP**. ## Commands diff --git a/docs/security/privacy.mdx b/docs/security/privacy.mdx index f65c3930c1..bcf47493da 100644 --- a/docs/security/privacy.mdx +++ b/docs/security/privacy.mdx @@ -12,7 +12,7 @@ Three requests leave a stock install without you asking: one usage heartbeat a d | [Plugin catalog](#the-plugin-catalog) | `raw.githubusercontent.com` | Yes | None | | [AI provider](#ai-providers) | whichever provider you add | No provider is configured on a fresh install | Delete the provider, or turn off **Enable AI Features** | | [iCloud sync](#icloud-sync) | your own iCloud account | No | **Settings > Sync** | -| [MCP clients](#the-mcp-server) | nowhere: it listens on `127.0.0.1` | Off, but starts on demand | **Settings > Integrations** | +| [MCP clients](#the-mcp-server) | nowhere: it listens on `127.0.0.1` | Off, but starts on demand | **Settings > MCP** | | [License and team library](#license-checks-and-the-team-library) | `api.tablepro.app` | Only after you activate a license | Do not activate one | | [Your databases](#your-database-connections) | the hosts you type into the connection form | Only what you connect to | Do not connect | | Crash reports | Nowhere. The app has no crash reporter. | - | - | @@ -63,7 +63,7 @@ A chat turn carries: - The connection's [AI Rules](/features/ai-assistant#per-connection-ai-rules) text, if you wrote any. - Any images you paste into the composer, and the conversation so far. -In Edit and Agent modes the model calls `execute_query` itself, and the rows it gets back become part of the conversation, so they go to the provider on the next turn. Those results are capped by the row limits in **Settings > Integrations**: 500 rows by default, 10,000 at most. +In Edit and Agent modes the model calls `execute_query` itself, and the rows it gets back become part of the conversation, so they go to the provider on the next turn. Those results are capped by the row limits in **Settings > MCP**: 500 rows by default, 10,000 at most. Per connection, the **AI Policy** picker in the connection form's Options section takes **Use Default**, **Always Allow**, **Ask Each Time**, or **Never**. The app-wide default is **Ask Each Time**, which asks once per connection per chat session before the first send. **Never** blocks the chat panel and external AI tool calls against that connection. @@ -100,7 +100,7 @@ It is off by default, but it starts on demand: the bundled bridge and the pairin 1. **Require authentication**, on by default. With it on, a request that arrives without an `Authorization` header is refused. Turn it off and a loopback caller with no header is allowed instead, capped at `tools:read` and `resources:read` however much it asks for. 2. The token's scope and its connection allowlist. 3. The connection's **External Clients** level: **Blocked**, **Read Only** (the default for a new connection), or **Read & Write**. The effective permission is the lower of that and the token's scope. -4. The connection's **AI Policy** of **Never**, its [Safe Mode](/features/safe-mode) level, and the **Approval** setting under **Settings > Integrations**, which decides how often a client is asked before it reaches a connection. +4. The connection's **AI Policy** of **Never**, its [Safe Mode](/features/safe-mode) level, and the **Approval** setting under **Settings > MCP**, which decides how often a client is asked before it reaches a connection. Loopback-only describes where the server binds, not everything that can reach it. The server returns CORS headers for two remote origins, `claude.ai` and `app.cursor.com`, so a page you have open there can call your local server from your own browser. The four gates above are what stands between such a call and your data, which is the reason to leave **Require authentication** on.