Mcp

Integrating Your Own MCP Client

Build a custom MCP client that connects to the BookYourPTO MCP server using the SSE transport.

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.

Overview

The BookYourPTO MCP server supports two transport modes:

TransportEndpointUse case
SSE (Server-Sent Events)/sseRemote 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.

Prerequisites

  • The hosted BookYourPTO MCP server at mcp.bookyourpto.com
  • An MCP client library for your language

MCP SDKs by language

LanguageSDK
TypeScript/JavaScript@modelcontextprotocol/sdk
Pythonmcp
Gogo-sdk
Rustrust-sdk
Java/Kotlinjava-sdk

Step 1: Connect via SSE with OAuth

The MCP SDK handles the OAuth flow automatically. When connecting, the SDK will:

  1. Discover the server's OAuth metadata at /.well-known/oauth-authorization-server
  2. Register your client dynamically via the /register endpoint
  3. Open a browser for the user to sign in on BookYourPTO's domain
  4. Exchange the authorization code for an access token (with PKCE)
  5. Connect to the SSE endpoint with the Bearer token

TypeScript

import { 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");

Python

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")

Step 2: Discover Available Tools

Once connected (and authenticated via OAuth), list the available tools:

TypeScript

const tools = await client.listTools();

for (const tool of tools.tools) {
  console.log(`${tool.name}: ${tool.description}`);
}

Python

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.

Step 3: Call a Tool

Authentication is already complete (handled by OAuth during connection). You can call any tool immediately:

TypeScript

// Check leave balance
const result = await client.callTool({
  name: "get_leave_balance",
  arguments: {
    year: 2026,
  },
});

console.log(result.content);

Python

# Check leave balance
result = await session.call_tool(
    "get_leave_balance",
    arguments={"year": 2026},
)

print(result.content)

Example: Create a leave request

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",
  },
});

Step 5: Read Resources

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:

URIDescription
bypto://org-settingsOrganization configuration
bypto://leave-typesAvailable leave types
bypto://team-directoryTeam members with roles

Connection Lifecycle

Reconnection

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");
}

Clean shutdown

// Always close the connection when done
await client.close();

Key References