This guide walks you through building a custom MCP client that connects to the BookYourPTO MCP server. Use this if you're building your own AI tool, automation, or integration.
The BookYourPTO MCP server supports two transport modes:
| Transport | Endpoint | Use case |
|---|---|---|
| SSE (Server-Sent Events) | /sse | Remote connections over HTTP |
BookYourPTO MCP uses OAuth 2.0 with PKCE for authentication. Your client must implement the standard MCP OAuth flow: discover server metadata, register dynamically, open a browser for user login, and exchange the authorization code for an access token. The MCP SDK handles most of this automatically.
mcp.bookyourpto.com| Language | SDK |
|---|---|
| TypeScript/JavaScript | @modelcontextprotocol/sdk |
| Python | mcp |
| Go | go-sdk |
| Rust | rust-sdk |
| Java/Kotlin | java-sdk |
The MCP SDK handles the OAuth flow automatically. When connecting, the SDK will:
/.well-known/oauth-authorization-server/register endpointimport { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
const transport = new SSEClientTransport(
new URL("https://mcp.bookyourpto.com/sse")
);
const client = new Client({
name: "my-custom-client",
version: "1.0.0",
});
// The SDK handles OAuth automatically — a browser window will open
// for the user to sign in on BookYourPTO's domain
await client.connect(transport);
console.log("Connected to BookYourPTO MCP");
from mcp import ClientSession
from mcp.client.sse import sse_client
# The SDK handles OAuth automatically
async with sse_client("https://mcp.bookyourpto.com/sse") as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
print("Connected to BookYourPTO MCP")
Once connected (and authenticated via OAuth), list the available tools:
const tools = await client.listTools();
for (const tool of tools.tools) {
console.log(`${tool.name}: ${tool.description}`);
}
tools = await session.list_tools()
for tool in tools.tools:
print(f"{tool.name}: {tool.description}")
This will return all BookYourPTO tools. See the Tools Reference for details.
Authentication is already complete (handled by OAuth during connection). You can call any tool immediately:
// Check leave balance
const result = await client.callTool({
name: "get_leave_balance",
arguments: {
year: 2026,
},
});
console.log(result.content);
# Check leave balance
result = await session.call_tool(
"get_leave_balance",
arguments={"year": 2026},
)
print(result.content)
const result = await client.callTool({
name: "create_leave_request",
arguments: {
userId: "user-id-here",
leaveTypeId: "leave-type-id-here",
startDate: "2026-03-15",
endDate: "2026-03-16",
reason: "Personal day",
},
});
The MCP server exposes read-only resources for context:
// List available resources
const resources = await client.listResources();
// Read a specific resource
const orgSettings = await client.readResource({
uri: "bypto://org-settings",
});
console.log(orgSettings.contents);
Available resources:
| URI | Description |
|---|---|
bypto://org-settings | Organization configuration |
bypto://leave-types | Available leave types |
bypto://team-directory | Team members with roles |
SSE connections may drop due to network issues. Implement reconnection logic:
async function connectWithRetry(maxRetries = 5) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const transport = new SSEClientTransport(
new URL("https://mcp.bookyourpto.com/sse")
);
const client = new Client({
name: "my-client",
version: "1.0.0",
});
await client.connect(transport);
return client;
} catch (error) {
console.error(`Attempt ${attempt} failed:`, error.message);
if (attempt < maxRetries) {
await new Promise((r) => setTimeout(r, 2000 * attempt));
}
}
}
throw new Error("Failed to connect after retries");
}
// Always close the connection when done
await client.close();