How to Create a New API Endpoint in Palmier Pro: The Complete Guide
Creating a new API endpoint in Palmier Pro requires implementing an async handler method in MCPHTTPServer.swift, registering the URL path in the handle(data:connection:transport:) dispatcher, and testing against http://127.0.0.1:<port>/your-path since the application runs a local MCP HTTP server instead of a traditional REST API.
Palmier Pro is a macOS application that exposes functionality through a lightweight MCP (Mac Control Protocol) HTTP server rather than a conventional REST API. If you are extending the palmier-io/palmier-pro codebase to add custom functionality, you must create a new API endpoint within this actor-based Swift architecture. This guide provides the exact implementation details, including specific file paths and method signatures from the source code.
Understanding the MCP HTTP Server Architecture
Palmier Pro does not expose a traditional REST API. Instead, it runs a tiny MCP HTTP server that listens on 127.0.0.1 and handles requests under specific paths. The server is implemented as a Swift actor, which means all request handling must use async/await patterns to maintain thread safety.
The central request dispatcher is the handle(data:connection:transport:) method located in Sources/PalmierPro/Agent/MCP/MCPHTTPServer.swift. This method parses incoming HTTP requests and routes them to the appropriate handlers based on the URL path.
Step 1: Create the Handler Method in MCPHTTPServer.swift
Open Sources/PalmierPro/Agent/MCP/MCPHTTPServer.swift and add a private helper method that constructs the HTTPResponse. This method should perform your business logic—such as querying the current project or triggering a tool—and return a properly encoded response.
For example, to create an endpoint that returns the current project title as JSON:
private func handleProjectTitle() async -> HTTPResponse {
// The project registry is the single source of truth for open projects.
let title = await ProjectRegistry.shared.current?.title ?? "Untitled"
let json = try! JSONEncoder().encode(["title": title])
return HTTPResponse(
statusCode: 200,
headers: ["Content-Type": "application/json"],
bodyData: json
)
}
All request parsing and response generation happen in this file, making it the required location for any new endpoint logic.
Step 2: Register the New Path in the Request Dispatcher
Inside the same file, locate the handle(data:connection:transport:) method (approximately lines 66-89). You must add a path check that recognizes your new endpoint URL and invokes the handler you created in Step 1.
Insert the following logic after the existing guard request.path == "/mcp" || request.path == "/" else check:
if request.path == "/my-new-endpoint" {
let response = await handleProjectTitle()
writeResponse(response, on: connection, transport: transport)
return
}
The final structure should look like this:
guard request.path == "/mcp" || request.path == "/" else {
sendRaw("HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\n\r\n", on: connection, keepAlive: false)
return
}
// New endpoint registration
if request.path == "/my-new-endpoint" {
let response = await handleProjectTitle()
writeResponse(response, on: connection, transport: transport)
return
}
// Existing GET handling for the generic "/mcp" endpoint
if request.method.uppercased() == "GET" {
// ...
}
Because the server runs as an actor, you must call your handler with await and use the existing writeResponse(_:on:transport:) helper to send data back to the client.
Step 3: Test the Endpoint Locally
Run the application with swift run and identify the port number from the console output (Log.mcp.info("listener start port=…")). Alternatively, read the port from macOS defaults:
curl http://127.0.0.1:$(defaults read com.palmier.pro MCPPort)/my-new-endpoint
You should receive a JSON response:
{ "title": "My Awesome Video" }
If the request returns a 404 error, verify that the path string matches exactly—including the leading slash—and that the server has finished initializing.
Optional: Add Client-Side Integration and UI Styling
If your endpoint will be called from the Agent UI or a custom script, construct the URL using the same port logic:
let port = try! MCPPortProvider.shared.port
let url = URL(string: "http://127.0.0.1:\(port)/my-new-endpoint")!
let data = try! Data(contentsOf: url)
print(String(decoding: data, as: UTF8.self))
When adding UI elements that trigger this endpoint, use the design constants defined in Sources/PalmierPro/UI/AppTheme.swift to maintain consistent spacing, colors, and fonts across the application.
Summary
- Palmier Pro uses an MCP HTTP server running on
127.0.0.1rather than a traditional REST API, requiring actor-safeasynchandlers. - New endpoints require two changes to
Sources/PalmierPro/Agent/MCP/MCPHTTPServer.swift: create a private handler method that returnsHTTPResponse, and register the path inhandle(data:connection:transport:). - Testing uses
curlwith the port retrieved fromcom.palmier.prodefaults or the console logs. - Optional UI integration should leverage
AppTheme.swiftfor styling consistency.
Frequently Asked Questions
Does Palmier Pro expose a traditional REST API?
No. According to the Palmier Pro source code, the application runs a lightweight MCP (Mac Control Protocol) HTTP server that listens on localhost (127.0.0.1). This architecture uses Swift actors and async/await patterns rather than traditional synchronous REST controllers.
What file contains the MCP HTTP server implementation?
The core implementation lives in Sources/PalmierPro/Agent/MCP/MCPHTTPServer.swift. This file contains the MCPHTTPServer actor class and the handle(data:connection:transport:) method that serves as the central request dispatcher for all endpoints.
Why must new endpoint handlers be marked as async?
The MCPHTTPServer is implemented as a Swift actor, which isolates its state to prevent data races. All methods that interact with the server's internal state, including request handlers, must be async to allow the actor to serialize access. The handler must also be called with await from the dispatcher.
How do I determine the port number for the MCP server?
The port is dynamically assigned and stored in macOS defaults under the key MCPPort for the bundle identifier com.palmier.pro. Retrieve it using defaults read com.palmier.pro MCPPort in the terminal, or programmatically via MCPPortProvider.shared.port in Swift code.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →