Description
I'm trying to get the MCP server to work with Windsurf. I'm not sure if this is an issue with how i'm creating the server or something to do with how Windsurf expects MCP servers to respond. So starting out with a question.
I can get Windsurf to detect the MCP server and it sees the tools listed, but at the same time it's showing 0 tools available and if i try and get Cascade to invoke any of the tools it doesn't think it has any. It's possible from looking at the Firecrawl MCP source and doing some inference that Windsurf expects the tools to be listed as resources as well, but if anyone has any guidance or experience here it would be a great help?
Below is the quick code i threw together to test this from Windsurf along with a screenshot of what i'm seeing in Windsurf.
Thanks
final class App: Sendable {
let logger = Logger(label: "com.example.mcp-server")
let server: Server
init() async {
let server = Server(name: "TestMCPServer", version: "1.0", capabilities: .init(logging: Server.Capabilities.Logging(),
resources: .init(subscribe: true, listChanged: true),
tools: .init(listChanged: true)
))
await server.withMethodHandler(ListResources.self) { _ in
let resources = [
Resource(name: "Tools", uri: "www.glacio.tech", description: "List of available tools for MCP")
]
return .init(resources: resources)
}
//// Register a tool list handler
await server.withMethodHandler(ListTools.self) { _ in
let tools = [
Tool(
name: "weather",
description: "Get current weather for a location",
inputSchema: .object([
"location": .string("City name or coordinates"),
"units": .string("Units of measurement, e.g., metric, imperial")
]),
),
Tool(
name: "calculator",
description: "Perform calculations",
inputSchema: .object([
"expression": .string("Mathematical expression to evaluate")
])
)
]
return .init(tools: tools)
}
//// Register a tool call handler
await server.withMethodHandler(CallTool.self) { params in
switch params.name {
case "weather":
let location = params.arguments?["location"]?.stringValue ?? "Unknown"
let units = params.arguments?["units"]?.stringValue ?? "metric"
let weatherData = getWeatherData(location: location, units: units) // Your implementation
return .init(
content: [.text("Weather for \(location): \(weatherData.temperature)°, \(weatherData.conditions)")],
isError: false
)
case "calculator":
if let expression = params.arguments?["expression"]?.stringValue {
let result = evaluateExpression(expression) // Your implementation
return .init(content: [.text("\(result)")], isError: false)
} else {
return .init(content: [.text("Missing expression parameter")], isError: true)
}
default:
return .init(content: [.text("Unknown tool")], isError: true)
}
}
self.server = server
}
func start() async throws {
print("CLI app has exited.")
// Create MCP service and other services
let transport = StdioTransport(logger: logger)
let mcpService = MCPService(server: server, transport: transport)
// Create service group with signal handling
let serviceGroup = ServiceGroup(
services: [mcpService],
configuration: .init(gracefulShutdownSignals: [.sigterm, .sigint]), logger: logger
)
// Run the service group - this blocks until shutdown
try await serviceGroup.run()
}
}
try! await App().start()
struct MCPService: Service {
let server: Server
let transport: StdioTransport
init(server: Server, transport: StdioTransport) {
self.server = server
self.transport = transport
}
func run() async throws {
// Start the server
try await server.start(transport: transport)
// Keep running until external cancellation
try await Task.sleep(for: .seconds(10000))
}
func shutdown() async throws {
// Gracefully shutdown the server
await server.stop()
}
}
struct WeatherDataType {
var temperature: Double
var conditions: String
}
func getWeatherData(location: String, units: String) -> WeatherDataType {
return WeatherDataType(temperature: 80, conditions: "Sunny")
}
func evaluateExpression(_ expression: String) -> String {
"Evaluated \(expression)"
}
