28.1 C
Canberra
Thursday, January 29, 2026

SwiftMCP Consumer | Cocoanetics


It’s 5 months for the reason that launch of SwiftMCP 1.0 and I’ve been sluggish cooking some enhancements for it. It was rewarding to see a little bit of on this package deal, judging by points and forks I might see on GitHub. Right this moment, I’m revealing the work for the client-side I’ve performed throughout this time.

The primary model of SwiftMCP naturally focussed completely on the server-side. You’ll be able to annotate any class or actor with @MCPServer and that might expose its features with the @MCPTool attribute through MCP. Metadata is gleaned from the documentation feedback for the perform and parameters. This implies – as a developer – you don’t must spend any additional effort to show instruments on your app through MCP. You solely must suppose what API floor you want to expose after which design the features such that they’ve simple to grasp and documented prototypes.

SwiftMCP takes the metadata it derives straight out of your code through macros and generates API responses. The initialize response accommodates all MCP instrument descriptions, and their enter schemas. Due to the place MCP comes from – offering textual content enter to LLMs – no thought appears to have been given to the concept there may very well be structured responses. Subsequently MCP spec is lacking output schemas.

In distinction the OpenAPI spec does have output schemas in addition to a level of assist for error responses. This may develop into related additional down.

The Case for the Consumer

Regardless of this limitation MCP has develop into the de issue normal for JSON RPC perform calling. If you’re designing an API for an LLM, why not additionally name these instruments from your personal applications?

Earlier than right now, should you needed to name into any MCP Server you would need to assemble JSON messages and ship these off to your server. Possibly some open supply framework would make this barely much less bothersome, but it surely’s nonetheless not very “Swift-y”.

Having mentioned that, it’s price mentioning that SwiftMCP additionally will serve the instruments through OpenAPI JSON RPC perform calling, should you allow this characteristic. You can then use a proxy generator what builds you Swift sorts and features. You then might conveniently work together with this native code.

That obtained me considering: I do have all meta info inside the @MCPServer macro. So not less than for the code that you simply management you could possibly generate the client-side proxy. For arbitrary different MCP Servers you could possibly not less than generate consumer code with the JSON sorts from the enter schemas.

A number of frequent sorts get mapped to JSON strings which an extra format specifier. For instance Date will get mapped to String with format date-time. So for MCP Servers that inform us the format we are able to derive the native Swift sorts from this. Different sorts with comparable remedy are URL, UUID and Knowledge.

At the moment the one solution to get the native output/return sorts is to have an identical OpenAPI spec for the MCP Server and “steal” the categories from there. Static sorts for customized errors are a lot more durable to drag off, in order that was out-of-scope for now.

State of affairs 1 – You Management the Code for Server and Consumer

In the event you management each side of the equation, then you might be most fortunate. The @MCPServer macro has gained a brand new capability to generat client-code for you. You awake the sleeper agent by including `generateClient: true` to the macro. This causes it to generated a nested Consumer sort inside the sort.

@MCPServer(generateClient: true)
actor Calculator {
    @MCPTool
    func add(a: Int, b: Int) -> Int {
        a + b
    }
}

Then to connect with the consumer proxy, you specify a configuration for the transport and instantiate a proxy.

let url = URL(string: "http://localhost:8080/sse")!
let config = MCPServerConfig.sse(config: MCPServerSseConfig(url: url))
let proxy = MCPServerProxy(config: config)
attempt await proxy.join()

let consumer = Calculator.Consumer(proxy: proxy)
let outcome = attempt await consumer.add(a: 2, b: 3)

The consumer API floor will precisely match the unique features with one exception: All features are actually throws as a result of an issue might happen on the consumer with speaking with the server.

This path will retain all sorts, together with Int and Double (which each get despatched as quantity in JSON) and in addition struct. Every type which might be Codable and Sendable can be utilized.

This opens up the use case that you’ve got your MCP code in a shared package deal to permit you importing the MCPServer each out of your servers and shoppers, together with structs you wish to use as enter or output.

State of affairs 2 – You Management Solely the Consumer Code

That is more durable, however I obtained you coated nonetheless. To generate native proxy code for any arbitrary MCP Server there’s now a CLI instrument. This connects to a server (over community or STDIO) and will get the instruments schemas. You’ll be able to compile the utility and name it as proven, or alternatively you possibly can precede it with swift run from the undertaking folder.

SwiftMCPUtility generate-proxy --sse http://localhost:8080/sse -o ToolsProxy.swift

This may generate the code for the native proxy. As said above the limitation right here is that sure sorts can solely be modeled as native sorts if the inputSchema for string values has format info. With out additional info return sorts all must be string.

If the server additionally serves an OpenAPI spec, then this could complement the sort info for output sorts.

SwiftMCPUtility generate-proxy 
  --sse http://localhost:8080/sse 
  --openapi http://localhost:8080/openapi.json 
  -o ToolsProxy.swift

The proxy generator additionally creates nested struct declarations. Let’s have a look at a type of generated proxy features within the ProxyDemoCLI demo.

/**
  Customized description: Performs addition of two numbers
  - Parameter a: First quantity so as to add
  - Parameter b: Second quantity so as to add
  - Returns: The sum of a and b
  */
 public func add(a: Double, b: Double) async throws -> Double {
     var arguments: [String: any Sendable] = [:]
     arguments["a"] = a
     arguments["b"] = b
     let textual content = attempt await proxy.callTool("add", arguments: arguments)
     return attempt MCPClientResultDecoder.decode(Double.self, from: textual content)
 } 

You’ll be able to see how the arguments are put into the arguments dictionary after which the proxy’s callTool features is named for the “add” command. This takes care of the sort conversion in addition to the JSON-RPC messaging. The response then will get transformed again to the native sort of Double.

Right here’s one other instance from the demo that returns a customized struct.

public actor SwiftMCPDemoProxy {
    
    /// A useful resource content material implementation for information within the file system
    public struct RandomFileResponseItem: Codable, Sendable {
        /// The binary content material of the useful resource (if it is a binary useful resource)
        public let blob: Knowledge?
        /// The MIME sort of the useful resource
        public let mimeType: String?
        /// The textual content content material of the useful resource (if it is a textual content useful resource)
        public let textual content: String?
        /// The URI of the useful resource
        public let uri: URL?
    }

    /**
     A perform returning a random file
     - Returns: A a number of easy textual content information
     */
    public func randomFile() async throws -> [RandomFileResponseItem] {
        let textual content = attempt await proxy.callTool("randomFile")
        return attempt MCPClientResultDecoder.decode([RandomFileResponseItem].self, from: textual content)
    }

Right here you possibly can see that the proxy generator created a struct for the return sort. The perform randomFile decodes an array of this sort from the JSON response. This manner you get a statically typed Swift struct as an alternative of a dictionary of arbitrary worth sorts.

Since that is generated code you possibly can really additional customise it and for instance use your personal struct declarations. You simply have to exchange the generated sort with your personal and this can work so long as it matches the JSON.

Against this the identical perform as talked about in situation 1 is ready to reference a public sort and subsequently no additional sort declaration is important.

Conclusion

Please be aware that there may nonetheless be some tough edges as this performance is model new. In the event you discover an issue or have a suggestion please let me know within the GitHub points. How do you employ SwiftMCP?


Classes: Administrative

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

[td_block_social_counter facebook="tagdiv" twitter="tagdivofficial" youtube="tagdiv" style="style8 td-social-boxed td-social-font-icons" tdc_css="eyJhbGwiOnsibWFyZ2luLWJvdHRvbSI6IjM4IiwiZGlzcGxheSI6IiJ9LCJwb3J0cmFpdCI6eyJtYXJnaW4tYm90dG9tIjoiMzAiLCJkaXNwbGF5IjoiIn0sInBvcnRyYWl0X21heF93aWR0aCI6MTAxOCwicG9ydHJhaXRfbWluX3dpZHRoIjo3Njh9" custom_title="Stay Connected" block_template_id="td_block_template_8" f_header_font_family="712" f_header_font_transform="uppercase" f_header_font_weight="500" f_header_font_size="17" border_color="#dd3333"]
- Advertisement -spot_img

Latest Articles