Skip to content

Commit ac927cd

Browse files
ochafikclaude
andcommitted
fix: update Swift host example for new AppBridge API + fix multi-line doc comments
- Update McpHostViewModel callback signatures to match new AppBridge API: - onMessage now receives (role, content) instead of params object - onOpenLink now receives url string directly - onSizeChange now receives (width, height) directly - onLoggingMessage now receives (level, data, logger) directly - sendToolInput now takes arguments dictionary directly - sendToolResult now takes dictionary directly - Fix Swift type generator to handle multi-line descriptions as proper doc comments instead of raw text that breaks compilation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent 1354767 commit ac927cd

File tree

3 files changed

+301
-21
lines changed

3 files changed

+301
-21
lines changed

examples/basic-host-swift/Sources/BasicHostApp/McpHostViewModel.swift

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -398,38 +398,36 @@ class ToolCallInfo: ObservableObject, Identifiable {
398398
bridge.onInitialized = { [weak self] in
399399
Task { @MainActor in
400400
guard let self = self else { return }
401-
let params = McpUiToolInputParams(
402-
arguments: self.input.mapValues { AnyCodable($0) }
403-
)
404-
try? await bridge.sendToolInput(params)
401+
let arguments = self.input.mapValues { AnyCodable($0) }
402+
try? await bridge.sendToolInput(arguments: arguments)
405403
if let result = self.result {
406404
try? await self.sendToolResult(result, to: bridge)
407405
}
408406
}
409407
}
410408

411-
bridge.onMessage = { params in
412-
print("[Host] Message from Guest UI: \(params.role)")
409+
bridge.onMessage = { role, content in
410+
print("[Host] Message from Guest UI: \(role)")
413411
return McpUiMessageResult(isError: false)
414412
}
415413

416-
bridge.onOpenLink = { params in
417-
print("[Host] Open link request: \(params.url)")
418-
if let urlObj = URL(string: params.url) {
414+
bridge.onOpenLink = { url in
415+
print("[Host] Open link request: \(url)")
416+
if let urlObj = URL(string: url) {
419417
await MainActor.run {
420418
UIApplication.shared.open(urlObj)
421419
}
422420
}
423421
return McpUiOpenLinkResult(isError: false)
424422
}
425423

426-
bridge.onLoggingMessage = { params in
427-
print("[Host] Guest UI log [\(params.level)]: \(params.data.value)")
424+
bridge.onLoggingMessage = { level, data, logger in
425+
print("[Host] Guest UI log [\(level)]: \(data.value)")
428426
}
429427

430-
bridge.onSizeChange = { [weak self] params in
431-
print("[Host] Size change: \(params.width ?? 0) x \(params.height ?? 0)")
432-
if let height = params.height {
428+
bridge.onSizeChange = { [weak self] width, height in
429+
print("[Host] Size change: \(width ?? 0) x \(height ?? 0)")
430+
if let height = height {
433431
Task { @MainActor in
434432
self?.preferredHeight = CGFloat(height)
435433
}
@@ -487,17 +485,20 @@ class ToolCallInfo: ObservableObject, Identifiable {
487485
}
488486

489487
private func sendToolResult(_ result: ToolResult, to bridge: AppBridge) async throws {
490-
let contentItems: [McpUiToolResultNotificationParamsContentItem] = result.content.compactMap { c in
488+
let contentDicts: [[String: Any]] = result.content.compactMap { c in
491489
switch c {
492490
case .text(let text):
493-
return .text(McpUiToolResultNotificationParamsContentItemText(type: "text", text: text))
491+
return ["type": "text", "text": text]
494492
case .image(let data, let mimeType, _):
495-
return .image(McpUiToolResultNotificationParamsContentItemImage(type: "image", data: data, mimeType: mimeType))
493+
return ["type": "image", "data": data, "mimeType": mimeType]
496494
default:
497495
return nil
498496
}
499497
}
500-
let params = McpUiToolResultParams(content: contentItems, isError: result.isError)
498+
let params: [String: AnyCodable] = [
499+
"content": AnyCodable(contentDicts),
500+
"isError": AnyCodable(result.isError ?? false)
501+
]
501502
try await bridge.sendToolResult(params)
502503
}
503504

scripts/generate-swift-types.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ function generateEnum(name: string, schema: JsonSchema): void {
369369
return ` case ${caseName} = "${value}"`;
370370
});
371371

372-
const desc = schema.description ? `/// ${schema.description}\n` : "";
372+
const desc = formatSwiftDocComment(schema.description);
373373
typeDefinitions.push(`${desc}public enum ${canonical}: String, Codable, Sendable, Equatable {
374374
${cases.join("\n")}
375375
}`);
@@ -419,7 +419,9 @@ function generateStruct(
419419

420420
const propLines = properties
421421
.map((p) => {
422-
const desc = p.description ? ` /// ${p.description}\n` : "";
422+
const desc = p.description
423+
? p.description.split('\n').map(line => ` /// ${line}`).join('\n') + '\n'
424+
: "";
423425
const typeDecl = p.isOptional ? `${p.type}?` : p.type;
424426
return `${desc} public var ${p.swiftName}: ${typeDecl}`;
425427
})
@@ -453,7 +455,7 @@ ${keyLines}
453455
.map((p) => ` self.${p.swiftName} = ${p.swiftName}`)
454456
.join("\n");
455457

456-
const desc = schema.description ? `/// ${schema.description}\n` : "";
458+
const desc = formatSwiftDocComment(schema.description);
457459
typeDefinitions.push(`${desc}public struct ${canonical}: Codable, Sendable, Equatable {
458460
${propLines}${codingKeys}
459461
@@ -469,6 +471,15 @@ function capitalize(s: string): string {
469471
return s.charAt(0).toUpperCase() + s.slice(1);
470472
}
471473

474+
function formatSwiftDocComment(description: string | undefined): string {
475+
if (!description) return "";
476+
// Split into lines and prefix each with ///
477+
return description
478+
.split('\n')
479+
.map(line => `/// ${line}`)
480+
.join('\n') + '\n';
481+
}
482+
472483
function generate(): string {
473484
const schema: SchemaDoc = JSON.parse(readFileSync(SCHEMA_FILE, "utf-8"));
474485
const defs = schema.$defs;

0 commit comments

Comments
 (0)