Skip to content

Commit 6ceac26

Browse files
authored
Merge branch 'github:main' into main
2 parents 6c11602 + 48da723 commit 6ceac26

8 files changed

Lines changed: 131 additions & 91 deletions

File tree

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## 0.48.0 - April 23, 2026
9+
### Added
10+
- Context window usage details in chat, including a token breakdown for system instructions, messages, attached files, and tool results.
11+
- Auto Compress setting to compact conversation history and save context tokens.
12+
- Install flow for Xcode's built-in MCP server from settings.
13+
14+
### Changed
15+
- Custom agents and the Auto model are now generally available.
16+
- Removed support for macOS 12.
17+
- Improved UI for model picker tooltips.
18+
19+
### Fixed
20+
- Fixed an issue where GPT-5.4 requests could return a 400 error.
21+
- Fixed an issue where the MCP allowlist did not work correctly.
22+
823
## 0.47.0 - February 4, 2026
924
### Added
1025
- Auto approval for MCP tools, sensitive files, and terminal commands.

Core/Sources/HostApp/ToolsSettings/MCPRegistry/MCPRegistryInstallation.swift

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,55 @@ public class MCPRegistryService: ObservableObject {
9090
public static let shared = MCPRegistryService()
9191
public static let apiVersion = "v0.1"
9292
@AppStorage(\.mcpRegistryBaseURL) var mcpRegistryBaseURL
93-
93+
@Published public private(set) var mcpRegistryEntries: [MCPRegistryEntry]?
94+
9495
private init() {}
9596

97+
/// Fetches the MCP registry allowlist from the language server and updates
98+
/// ``mcpRegistryEntries``. Safe to call from any view's `onAppear` –
99+
/// duplicate in-flight calls are coalesced via the `isRefreshing` flag.
100+
private var isRefreshing = false
101+
102+
public func refreshAllowlist() async {
103+
guard !isRefreshing else { return }
104+
isRefreshing = true
105+
defer { isRefreshing = false }
106+
107+
do {
108+
let service = try getService()
109+
110+
let authStatus = try await service.getXPCServiceAuthStatus()
111+
guard authStatus?.status == .loggedIn else {
112+
Logger.client.info("User not logged in, skipping MCP registry allowlist fetch")
113+
mcpRegistryEntries = nil
114+
return
115+
}
116+
117+
let result = try await service.getMCPRegistryAllowlist()
118+
119+
guard let result = result, !result.mcpRegistries.isEmpty else {
120+
if result == nil {
121+
Logger.client.error("Failed to get allowlist result")
122+
} else {
123+
mcpRegistryEntries = []
124+
}
125+
return
126+
}
127+
128+
if let firstRegistry = result.mcpRegistries.first {
129+
let entry = MCPRegistryEntry(
130+
url: firstRegistry.url,
131+
registryAccess: firstRegistry.registryAccess,
132+
owner: firstRegistry.owner
133+
)
134+
mcpRegistryEntries = [entry]
135+
Logger.client.info("Current MCP Registry Entry: \(entry)")
136+
}
137+
} catch {
138+
Logger.client.error("Failed to get MCP allowlist from registry: \(error)")
139+
}
140+
}
141+
96142
public static func getServerName(from serverDetail: MCPRegistryServerDetail) -> String {
97143
return serverDetail.name
98144
}

Core/Sources/HostApp/ToolsSettings/MCPRegistry/MCPRegistryURLView.swift

Lines changed: 14 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ struct MCPRegistryURLView: View {
1414
@State private var isLoading: Bool = false
1515
@State private var tempURLText: String = ""
1616
@State private var errorMessage: String = ""
17-
@State private var mcpRegistry: [MCPRegistryEntry]? = nil
17+
@ObservedObject private var registryService = MCPRegistryService.shared
1818

1919
private let maxURLLength = 2048
2020
private let mcpRegistryUrlVersion = "/v0.1/servers"
@@ -48,7 +48,7 @@ struct MCPRegistryURLView: View {
4848
}
4949
.buttonStyle(.bordered)
5050
.help("Configure your MCP Registry Base URL")
51-
.disabled(mcpRegistry?.first?.registryAccess == .registryOnly)
51+
.disabled(registryService.mcpRegistryEntries?.first?.registryAccess == .registryOnly)
5252

5353
Button { Task{ await loadMCPServers() } } label: {
5454
HStack(spacing: 0) {
@@ -74,7 +74,7 @@ struct MCPRegistryURLView: View {
7474
urlText: $tempURLText,
7575
maxURLLength: maxURLLength,
7676
isSheet: false,
77-
mcpRegistryEntry: mcpRegistry?.first,
77+
mcpRegistryEntry: registryService.mcpRegistryEntries?.first,
7878
onValidationChange: { _ in
7979
// Only validate, don't update mcpRegistryURL here
8080
},
@@ -115,7 +115,7 @@ struct MCPRegistryURLView: View {
115115
tempURLText = newValue
116116
Task { await updateGalleryWindowIfOpen() }
117117
}
118-
.onChange(of: mcpRegistry) { _ in
118+
.onChange(of: registryService.mcpRegistryEntries) { _ in
119119
Task { await updateGalleryWindowIfOpen() }
120120
}
121121
}
@@ -145,7 +145,7 @@ struct MCPRegistryURLView: View {
145145
mcpRegistryBaseURLHistory.addToHistory(mcpRegistryBaseURL)
146146
errorMessage = ""
147147

148-
MCPServerGalleryWindow.open(serverList: serverList, mcpRegistryEntry: mcpRegistry?.first)
148+
MCPServerGalleryWindow.open(serverList: serverList, mcpRegistryEntry: registryService.mcpRegistryEntries?.first)
149149
} catch {
150150
Logger.client.error("Failed to load MCP servers from registry: \(error.localizedDescription)")
151151
if let serviceError = error as? XPCExtensionServiceError {
@@ -160,44 +160,14 @@ struct MCPRegistryURLView: View {
160160
private func getMCPRegistryAllowlist() async {
161161
isLoading = true
162162
defer { isLoading = false }
163-
do {
164-
let service = try getService()
165-
166-
// Only fetch allowlist if user is logged in
167-
let authStatus = try await service.getXPCServiceAuthStatus()
168-
guard authStatus?.status == .loggedIn else {
169-
Logger.client.info("User not logged in, skipping MCP registry allowlist fetch")
170-
return
171-
}
172-
173-
let result = try await service.getMCPRegistryAllowlist()
174-
175-
guard let result = result, !result.mcpRegistries.isEmpty else {
176-
if result == nil {
177-
Logger.client.error("Failed to get allowlist result")
178-
} else {
179-
mcpRegistry = []
180-
}
181-
return
182-
}
183-
184-
if let firstRegistry = result.mcpRegistries.first {
185-
let entry = MCPRegistryEntry(
186-
url: firstRegistry.url,
187-
registryAccess: firstRegistry.registryAccess,
188-
owner: firstRegistry.owner
189-
)
190-
mcpRegistry = [entry]
191-
Logger.client.info("Current MCP Registry Entry: \(entry)")
192-
193-
// If registryOnly, force the URL to be the registry URL
194-
if entry.registryAccess == .registryOnly {
195-
mcpRegistryBaseURL = entry.url
196-
tempURLText = entry.url
197-
}
198-
}
199-
} catch {
200-
Logger.client.error("Failed to get MCP allowlist from registry: \(error)")
163+
164+
await registryService.refreshAllowlist()
165+
166+
// If registryOnly, force the URL to be the registry URL
167+
if let entry = registryService.mcpRegistryEntries?.first,
168+
entry.registryAccess == .registryOnly {
169+
mcpRegistryBaseURL = entry.url
170+
tempURLText = entry.url
201171
}
202172
}
203173

@@ -211,7 +181,7 @@ struct MCPRegistryURLView: View {
211181
defer { isLoading = false }
212182

213183
// Let the view model handle the entire update flow including clearing and fetching
214-
if let error = await MCPServerGalleryWindow.refreshFromURL(mcpRegistryEntry: mcpRegistry?.first) {
184+
if let error = await MCPServerGalleryWindow.refreshFromURL(mcpRegistryEntry: registryService.mcpRegistryEntries?.first) {
215185
// Display error in the URL view
216186
if let serviceError = error as? XPCExtensionServiceError {
217187
errorMessage = serviceError.underlyingError?.localizedDescription ?? serviceError.localizedDescription

Core/Sources/HostApp/ToolsSettings/MCPXcodeServerInstallView.swift

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ struct MCPXcodeServerInstallView: View {
1313
/// Cached to avoid repeated file I/O during SwiftUI rendering.
1414
@State private var configuredXcodeServerNames: Set<String> = []
1515
@ObservedObject private var mcpToolManager = CopilotMCPToolManagerObservable.shared
16+
@ObservedObject private var registryService = MCPRegistryService.shared
1617

1718
private let requiredXcodeVersion = "26.4"
1819
private let serverName = "xcode"
@@ -39,6 +40,10 @@ struct MCPXcodeServerInstallView: View {
3940
isConfigured || isConnected
4041
}
4142

43+
private var isRegistryOnly: Bool {
44+
registryService.mcpRegistryEntries?.first?.registryAccess == .registryOnly
45+
}
46+
4247
var body: some View {
4348
HStack(alignment: .center, spacing: 16) {
4449
VStack(alignment: .leading, spacing: 0) {
@@ -61,6 +66,7 @@ struct MCPXcodeServerInstallView: View {
6166
.settingsContainerStyle(isExpanded: false)
6267
.onAppear {
6368
checkInstallationStatus()
69+
Task { await registryService.refreshAllowlist() }
6470
}
6571
.onChange(of: mcpToolManager.availableMCPServerTools) { _ in
6672
checkInstallationStatus()
@@ -76,11 +82,13 @@ struct MCPXcodeServerInstallView: View {
7682
Text("Requires Xcode \(requiredXcodeVersion) or later. Current version: \(versionText).")
7783
} else if isConnected {
7884
Text("Xcode's built-in MCP server is connected, enabling richer editor integration.")
85+
} else if isRegistryOnly {
86+
Text("Manual installation of Xcode's built-in MCP server is blocked by your organization's registry policy. Please check the MCP Registry for an approved installation option, or contact your enterprise IT administrator.")
7987
} else if isConfiguredButNotConnected {
8088
Text("Please confirm in Xcode to allow the built-in MCP server.")
8189
} else {
8290
VStack(alignment: .leading, spacing: 4) {
83-
Text("Connect Copilot to Xcodes builtin MCP server to enable richer editor integration.")
91+
Text("Connect Copilot to Xcode's built-in MCP server to enable richer editor integration.")
8492
if let installError {
8593
Text(installError)
8694
.font(.caption)
@@ -96,6 +104,8 @@ struct MCPXcodeServerInstallView: View {
96104
EmptyView()
97105
} else if isConnected {
98106
Text("Connected").foregroundColor(.secondary)
107+
} else if isRegistryOnly {
108+
EmptyView()
99109
} else if isConfiguredButNotConnected {
100110
HStack(spacing: 6) {
101111
ProgressView()

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ You can receive auto-complete type suggestions from GitHub Copilot either by sta
2626

2727
## Requirements
2828

29-
- macOS 12+
30-
- Xcode 8+
29+
- macOS 13+
30+
- Xcode 14+
3131
- A GitHub account
3232

3333
## Getting Started

ReleaseNotes.md

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
1-
### GitHub Copilot for Xcode 0.47.0
1+
### GitHub Copilot for Xcode 0.48.0
22

33
**🚀 Highlights**
44

5-
- **Toolcall Auto Approval**: Streamlined workflow with auto-approval support for MCP tools, sensitive files, and terminal commands.
6-
- **MCP Registry**: The MCP registry and allowlist features are now available (requires editor preview feature flag).
5+
- **Context Window and Auto Compress**: Track context token usage directly from the chat input and automatically compact conversation history to save tokens.
6+
- **Xcode MCP Server Setup**: Install and connect Xcode's built-in MCP server directly from settings.
7+
- **General Availability**: Custom agents and the Auto model are now generally available.
78

8-
**💪 Improvements**
9+
**💪 Changes**
910

10-
- Refined the working set header.
11-
- Improved the details view for MCP tool calls.
11+
- Removed support for macOS 12.
12+
- Improved UI for model picker tooltips.
1213

1314
**🛠️ Bug Fixes**
1415

15-
- Fixed layout issues with tool calls.
16-
- Resolved display issues for Next Edit Suggestions (NES).
17-
- Improved error messaging for SSL certificate failures.
18-
- Addressed various performance issues.
16+
- Fixed an issue where GPT-5.4 requests could return a 400 error.
17+
- Fixed an issue where the MCP allowlist did not work correctly.

Server/package-lock.json

Lines changed: 30 additions & 30 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)