#!/usr/bin/env node
/**
* Planning Center Online (PCO) MCP Server
*
* Provides tools to interact with the Planning Center API across all modules:
* People, Services, Giving, Groups, Calendar, and Check-Ins.
*
* Authentication: Set PCO_APP_ID and PCO_SECRET environment variables.
* Get credentials at: https://api.planningcenteronline.com/oauth/applications
*
* Usage (stdio):
* PCO_APP_ID=your_app_id PCO_SECRET=your_secret node dist/index.js
*
* Usage (HTTP):
* PCO_APP_ID=your_app_id PCO_SECRET=your_secret TRANSPORT=http node dist/index.js
*/
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
import express from "express";
import { registerPeopleTools } from "./tools/people.js";
import { registerServicesTools } from "./tools/services.js";
import { registerGivingTools } from "./tools/giving.js";
import { registerGroupsTools } from "./tools/groups.js";
import { registerCalendarTools } from "./tools/calendar.js";
import { registerCheckInsTools } from "./tools/checkins.js";
// ─── Server Initialization ──────────────────────────────────────────────────
const server = new McpServer({
name: "planning-center-mcp-server",
version: "1.0.0",
});
// Register all module tools
registerPeopleTools(server);
registerServicesTools(server);
registerGivingTools(server);
registerGroupsTools(server);
registerCalendarTools(server);
registerCheckInsTools(server);
// ─── Transport: stdio ───────────────────────────────────────────────────────
async function runStdio(): Promise<void> {
if (!process.env.PCO_APP_ID || !process.env.PCO_SECRET) {
console.error(
"ERROR: Missing required environment variables.\n" +
"Set PCO_APP_ID and PCO_SECRET to your Planning Center Personal Access Token credentials.\n" +
"Get them at: https://api.planningcenteronline.com/oauth/applications"
);
process.exit(1);
}
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Planning Center MCP server running via stdio");
}
// ─── Transport: Streamable HTTP ──────────────────────────────────────────────
async function runHTTP(): Promise<void> {
if (!process.env.PCO_APP_ID || !process.env.PCO_SECRET) {
console.error(
"ERROR: Missing required environment variables.\n" +
"Set PCO_APP_ID and PCO_SECRET to your Planning Center Personal Access Token credentials.\n" +
"Get them at: https://api.planningcenteronline.com/oauth/applications"
);
process.exit(1);
}
const app = express();
app.use(express.json());
// Health check
app.get("/health", (_req, res) => {
res.json({ status: "ok", server: "planning-center-mcp-server", version: "1.0.0" });
});
// MCP endpoint
app.post("/mcp", async (req, res) => {
const transport = new StreamableHTTPServerTransport({
sessionIdGenerator: undefined,
enableJsonResponse: true,
});
res.on("close", () => transport.close());
await server.connect(transport);
await transport.handleRequest(req, res, req.body as Record<string, unknown>);
});
const port = parseInt(process.env.PORT ?? "3000", 10);
app.listen(port, () => {
console.error(`Planning Center MCP server running at http://localhost:${port}/mcp`);
});
}
// ─── Entry Point ─────────────────────────────────────────────────────────────
const transport = process.env.TRANSPORT ?? "stdio";
if (transport === "http") {
runHTTP().catch((error: unknown) => {
console.error("Server error:", error);
process.exit(1);
});
} else {
runStdio().catch((error: unknown) => {
console.error("Server error:", error);
process.exit(1);
});
}