The LiteLead MCP (Model Context Protocol) Server is a Node.js-based server that provides AI assistants with structured access to LiteLead data stored in Firebase/Firestore. It exposes a set of tools for retrieving customers, contacts, orders, users, roles, and staff information through a standardized MCP interface.
The server is built on the following key components:
@modelcontextprotocol/sdk for server implementation{
"@modelcontextprotocol/sdk": "^1.20.2",
"firebase": "^12.4.0",
"firebase-admin": "^13.5.0",
"express": "^5.1.0",
"zod": "^3.25.76",
"cors": "^2.8.5"
}
# Install dependencies
npm install
# Run the server
npm start -- --auth-key YOUR_AUTH_KEY_HERE
# Get help
npm run start:help
The server supports the following CLI arguments:
| Argument | Short | Required | Description |
|---|---|---|---|
--auth-key <key> |
-a |
Yes | MCP authentication key for Firebase |
--emulator |
-e |
No | Use Firebase emulator (default: production) |
--transport <type> |
N/A | No | Transport type: stdio or http (default: stdio) |
--help |
-h |
No | Display help information |
While CLI arguments are recommended, the following environment variables are supported as fallbacks:
MCP_AUTH_KEY: Authentication key (used if --auth-key not provided)EMULATOR: Set to "true" to use emulator (used if --emulator not provided)# Start with authentication key
node index.js --auth-key YOUR_AUTH_KEY_HERE
# Start with Firebase emulator
node index.js --auth-key YOUR_AUTH_KEY_HERE --emulator
# Start with HTTP transport
node index.js --auth-key YOUR_AUTH_KEY_HERE --transport http
# Short form
node index.js -a YOUR_AUTH_KEY_HERE -e
The default transport mode uses standard input/output for communication. This is ideal for local integrations and CLI-based AI assistants.
node index.js --auth-key YOUR_AUTH_KEY_HERE
The HTTP transport mode runs an Express server that accepts MCP requests via HTTP POST.
node index.js --auth-key YOUR_AUTH_KEY_HERE --transport http
The server will start on http://localhost:3000/mcp (configurable via PORT environment variable).
Features:
The server provides the following tools for data retrieval:
These tools retrieve multiple records with cursor-based pagination support:
| Tool | Description | Documentation |
|---|---|---|
getCustomers |
Retrieve customers with pagination support | docs/tools/getCustomers.md |
getContacts |
Retrieve contacts for a specific customer | docs/tools/getContacts.md |
getOrders |
Retrieve orders with nested data | docs/tools/getOrders.md |
getOrdersByCustomerId |
Retrieve orders for a specific customer with pagination | docs/tools/getOrdersByCustomerId.md |
getUsers |
Retrieve users with pagination support | docs/tools/getUsers.md |
getRoles |
Retrieve roles with pagination support | docs/tools/getRoles.md |
getStaff |
Retrieve staff members with pagination support | docs/tools/getStaff.md |
These tools retrieve individual records by ID:
| Tool | Description | Documentation |
|---|---|---|
getCustomerById |
Retrieve a single customer by document ID | docs/tools/getCustomerById.md |
getCustomerContactById |
Retrieve a specific contact for a customer | docs/tools/getCustomerContactById.md |
getOrderById |
Retrieve a single order with populated references | docs/tools/getOrderById.md |
getOrderStatus |
Get order status information by numeric order ID | docs/tools/getOrderStatus.md |
getUserById |
Retrieve a single user by document ID | docs/tools/getUserById.md |
getRoleById |
Retrieve a single role by document ID | docs/tools/getRoleById.md |
getStaffById |
Retrieve a single staff member by document ID | docs/tools/getStaffById.md |
These tools retrieve configuration data:
| Tool | Description | Documentation |
|---|---|---|
getOrderLocations |
Retrieve configured order locations | docs/tools/getOrderLocations.md |
getOrderStages |
Retrieve configured order stages | docs/tools/getOrderStages.md |
getOrderStatusGroups |
Retrieve configured order status groups | docs/tools/getOrderStatusGroups.md |
These tools allow creating or modifying data:
| Tool | Description | Documentation |
|---|---|---|
createOrder |
Create a new order with transactional ID generation | docs/tools/createOrder.md |
createCustomer |
Create a new customer with transactional ID generation | docs/tools/createCustomer.md |
createContact |
Create a new contact with transactional ID generation | docs/tools/createContact.md |
Collection tools support:
Single record tools support:
The server uses a two-step authentication process:
mcp_generateCustomToken with the provided MCP auth keyaccountId from token claims to scope all queries// Authentication flow (firebase.js)
const response = await fetch(
`${FIREBASE_FUNCTIONS_URL}/mcp_generateCustomToken`,
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ data: { mcpAuthKey: config.authKey } }),
}
);
const { token } = result.result;
const userCredential = await signInWithCustomToken(auth, token);
const idTokenResult = await userCredential.user.getIdTokenResult();
const accountId = idTokenResult.claims.accountId;
All subsequent Firestore queries are scoped to the authenticated account:
/Accounts/{accountId}/Customers
/Accounts/{accountId}/Orders
/Accounts/{accountId}/Users
...
All data retrieval tools use a unified pagination system with the following features:
{
limit?: number; // 1-100, default: 50
cursor?: string; // Document ID for cursor-based pagination
orderBy?: string; // Field to order by (default varies by tool)
orderDirection?: "asc" | "desc"; // Sort direction
cursorDirection?: "next" | "previous"; // Navigation direction
includeTotal?: boolean; // Include total count (expensive operation)
}
{
limit: number; // Applied limit
hasMore: boolean; // Whether more results exist
nextCursor: string | null; // Cursor for next page
previousCursor: string | null; // Cursor for previous page
total?: number | null; // Total count (if requested)
}
// First page
const result1 = await getCustomers(context, {
limit: 10,
orderBy: "customerId",
orderDirection: "asc"
});
// Next page
const result2 = await getCustomers(context, {
limit: 10,
cursor: result1.pagination.nextCursor,
cursorDirection: "next"
});
// Previous page
const result3 = await getCustomers(context, {
limit: 10,
cursor: result2.pagination.previousCursor,
cursorDirection: "previous"
});
The server implements comprehensive error handling:
null for nested documentslitelead-mcp/
├── index.js # Main server entry point
├── firebase.js # Firebase initialization and auth
├── args.js # CLI argument parsing
├── package.json # Dependencies and scripts
├── tools/
│ ├── getCustomers.js # Customer retrieval tool (paginated)
│ ├── getCustomerById.js # Single customer retrieval
│ ├── getContacts.js # Contact retrieval tool (paginated)
│ ├── getCustomerContactById.js # Single contact retrieval
│ ├── getOrders.js # Order retrieval tool (paginated)
│ ├── getOrderById.js # Single order retrieval with references
│ ├── getOrderStatus.js # Order status retrieval
│ ├── getOrdersByCustomerId.js # Customer-specific orders (paginated)
│ ├── getUsers.js # User retrieval tool (paginated)
│ ├── getUserById.js # Single user retrieval
│ ├── getRoles.js # Role retrieval tool (paginated)
│ ├── getRoleById.js # Single role retrieval
│ ├── getStaff.js # Staff retrieval tool (paginated)
│ ├── getStaffById.js # Single staff retrieval
│ ├── createOrder.js # Order creation tool
│ ├── getOrderLocations.js # Order locations retrieval
│ ├── getOrderStages.js # Order stages retrieval
│ ├── getOrderStatusGroups.js # Order status groups retrieval
│ ├── pagination.js # Shared pagination logic
│ └── dateHelpers.js # Date conversion utilities
└── docs/
├── README.md # This file
├── ARCHITECTURE.md # Architecture documentation
└── tools/ # Individual tool documentation
├── getCustomers.md
├── getCustomerById.md
├── getContacts.md
├── getCustomerContactById.md
├── getOrders.md
├── getOrderById.md
├── getOrderStatus.md
├── getOrdersByCustomerId.md
├── getUsers.md
├── getUserById.md
├── getRoles.md
├── getRoleById.md
├── getStaff.md
├── getStaffById.md
├── createOrder.md
├── getOrderLocations.md
├── getOrderStages.md
└── getOrderStatusGroups.md
To add a new tool:
tools/ directoryindex.jsExample structure:
const { z } = require("zod");
// Define schemas
const inputSchema = {
// ... input parameters
};
const outputSchema = {
// ... output structure
};
// Implement tool
async function myTool({ db, accountId }, params) {
// Implementation
}
module.exports = {
myTool,
inputSchema,
outputSchema,
};
# Run with emulator for local testing
node index.js --auth-key YOUR_KEY --emulator
# Build Docker image
npm run build:docker
The server connects to the LiteLead Firebase project:
{
apiKey: "AIzaSyDyW1B415smNH_aOTfv1cvWSvKMWaBDXoc",
authDomain: "litelead-a6774.firebaseapp.com",
projectId: "litelead-a6774"
}
Firebase Functions URLs:
https://us-central1-litelead-a6774.cloudfunctions.nethttp://127.0.0.1:49991/litelead-a6774/us-central1When contributing to the MCP server:
docs/tools/ISC