Building a Paid MCP Server with Cloudflare Workers and Stripe
Model Context Protocol (MCP) is gaining attention as a protocol that standardizes interactions with AI models. In this article, we'll explain a practical method for building a paid MCP server by combining Cloudflare Workers and Stripe. What is an MCP Server? MCP is a protocol that provides tools to AI models and enables the models to use them. By building a server that implements this protocol, you can provide APIs that can be used by various AI models. Architecture Overview This project combines the following components: Cloudflare Workers runs the MCP server in a serverless environment. Stripe handles billing for paid features, and we've also implemented user authentication via GitHub OAuth. Additionally, we utilize the WordPress.org API as a data source. Core Component Implementation 1. Basic Structure of the MCP Server The MCP server instantiates the McpServer class and defines tools in the init() method. export class MyMCP extends PaidMcpAgent { server = new McpServer({ name: "WordPress.org Search API", version: "0.1.0", }); async init() { // Tool definitions... } } 2. Implementing Paid Tools Paid tools are defined using the paidTool method: this.paidTool( "wporg_query_themes", { search: z.string().optional().describe("Search keyword"), // Other parameters... }, async ({ search, tag, author, page, per_page, browse, fields }) => { // Implementation logic... return await fetchThemesApi("query_themes", params, fields); }, generatePaidToolConfig("search WordPress.org themes") ) Here, we specify the tool name, parameter schema definition, execution function, and billing configuration. 3. Core Implementation of Stripe Integration The PaidMcpAgent class is central to Stripe integration: export abstract class experimental_PaidMcpAgent extends McpAgent { stripe(): Stripe { return new Stripe(this.env.STRIPE_SECRET_KEY, {...}); } async getCurrentCustomerID() { // Get/create the user's Stripe customer ID } paidTool(/*...*/) { // Implementation of paid tool definition } } This class provides key functions such as initializing the Stripe instance, managing customer IDs, checking billing status, and creating checkout sessions. 4. Billing Flow When a paid tool is invoked, the following flow is executed: First, the user's customer ID is verified (existing or newly created). Next, it checks if payment has already been made (subscription or one-time payment). If unpaid, a Stripe checkout session is created and a payment link is presented to the user. Once payment is completed, tool execution is permitted. 5. GitHub Authentication Integration The authentication flow is implemented using OAuthProvider: export default new OAuthProvider({ apiRoute: "/sse", apiHandler: MyMCP.mount("/sse"), defaultHandler: GitHubHandler, authorizeEndpoint: "/authorize", tokenEndpoint: "/token", clientRegistrationEndpoint: "/register", }); This configuration enables authentication using GitHub, allowing for user identification and personalized billing. Implementation Points State Management We use Cloudflare Workers' Durable Objects to maintain billing states for each user: export type PaymentState = { stripe?: StripeState; }; type StripeState = { paidToolCalls: string[]; subscriptions: string[]; customerId: string; paidToolsToCheckoutSession: Record; }; This state allows tracking of tools that users have already paid for. Generating Billing Configurations export function generatePaidToolConfig(featureName: string) { return { priceId: process.env.STRIPE_PRICE_ID, successUrl: "https://example.com/success", meterEvent: "api_usage", paymentReason: `Payment required to use ${featureName} feature`, } } This function makes it easy to generate billing configurations for each tool. Application Patterns for Implementation Mix of Free and Paid Tools You can mix free and paid tools within the same MCP server: // Free tool this.server.tool("free_tool", /*...*/); // Paid tool this.paidTool("paid_tool", /*...*/); Usage-Based Billing Model You can also implement usage-based billing using the meterEvent parameter: this.paidTool( "metered_tool", /*...*/, { priceId: "price_xxx", meterEvent: "api_usage_count" } ) Conclusion By combining Cloudflare Workers and Stripe, you can build a scalable and easily manageable paid MCP server. This implementation pattern serves as a practical template for developers who want to provide API services to AI models. As the standardization of the MCP protocol progresses, these server implementations will likely become increasingly importan

Model Context Protocol (MCP) is gaining attention as a protocol that standardizes interactions with AI models. In this article, we'll explain a practical method for building a paid MCP server by combining Cloudflare Workers and Stripe.
What is an MCP Server?
MCP is a protocol that provides tools to AI models and enables the models to use them. By building a server that implements this protocol, you can provide APIs that can be used by various AI models.
Architecture Overview
This project combines the following components:
Cloudflare Workers runs the MCP server in a serverless environment. Stripe handles billing for paid features, and we've also implemented user authentication via GitHub OAuth. Additionally, we utilize the WordPress.org API as a data source.
Core Component Implementation
1. Basic Structure of the MCP Server
The MCP server instantiates the McpServer
class and defines tools in the init()
method.
export class MyMCP extends PaidMcpAgent<Env, State, Props> {
server = new McpServer({
name: "WordPress.org Search API",
version: "0.1.0",
});
async init() {
// Tool definitions...
}
}
2. Implementing Paid Tools
Paid tools are defined using the paidTool
method:
this.paidTool(
"wporg_query_themes",
{
search: z.string().optional().describe("Search keyword"),
// Other parameters...
},
async ({ search, tag, author, page, per_page, browse, fields }) => {
// Implementation logic...
return await fetchThemesApi("query_themes", params, fields);
},
generatePaidToolConfig("search WordPress.org themes")
)
Here, we specify the tool name, parameter schema definition, execution function, and billing configuration.
3. Core Implementation of Stripe Integration
The PaidMcpAgent
class is central to Stripe integration:
export abstract class experimental_PaidMcpAgent<...> extends McpAgent<...> {
stripe(): Stripe {
return new Stripe(this.env.STRIPE_SECRET_KEY, {...});
}
async getCurrentCustomerID() {
// Get/create the user's Stripe customer ID
}
paidTool<Args extends ZodRawShape>(/*...*/) {
// Implementation of paid tool definition
}
}
This class provides key functions such as initializing the Stripe instance, managing customer IDs, checking billing status, and creating checkout sessions.
4. Billing Flow
When a paid tool is invoked, the following flow is executed:
First, the user's customer ID is verified (existing or newly created). Next, it checks if payment has already been made (subscription or one-time payment).
If unpaid, a Stripe checkout session is created and a payment link is presented to the user. Once payment is completed, tool execution is permitted.
5. GitHub Authentication Integration
The authentication flow is implemented using OAuthProvider:
export default new OAuthProvider({
apiRoute: "/sse",
apiHandler: MyMCP.mount("/sse"),
defaultHandler: GitHubHandler,
authorizeEndpoint: "/authorize",
tokenEndpoint: "/token",
clientRegistrationEndpoint: "/register",
});
This configuration enables authentication using GitHub, allowing for user identification and personalized billing.
Implementation Points
State Management
We use Cloudflare Workers' Durable Objects to maintain billing states for each user:
export type PaymentState = {
stripe?: StripeState;
};
type StripeState = {
paidToolCalls: string[];
subscriptions: string[];
customerId: string;
paidToolsToCheckoutSession: Record<string, string | null>;
};
This state allows tracking of tools that users have already paid for.
Generating Billing Configurations
export function generatePaidToolConfig(featureName: string) {
return {
priceId: process.env.STRIPE_PRICE_ID,
successUrl: "https://example.com/success",
meterEvent: "api_usage",
paymentReason: `Payment required to use ${featureName} feature`,
}
}
This function makes it easy to generate billing configurations for each tool.
Application Patterns for Implementation
Mix of Free and Paid Tools
You can mix free and paid tools within the same MCP server:
// Free tool
this.server.tool("free_tool", /*...*/);
// Paid tool
this.paidTool("paid_tool", /*...*/);
Usage-Based Billing Model
You can also implement usage-based billing using the meterEvent
parameter:
this.paidTool(
"metered_tool",
/*...*/,
{
priceId: "price_xxx",
meterEvent: "api_usage_count"
}
)
Conclusion
By combining Cloudflare Workers and Stripe, you can build a scalable and easily manageable paid MCP server. This implementation pattern serves as a practical template for developers who want to provide API services to AI models.
As the standardization of the MCP protocol progresses, these server implementations will likely become increasingly important. We encourage you to apply these concepts to your own services.
References
- Paid MCP tool SDK: https://github.com/stripe/agent-toolkit/tree/main/typescript/src/cloudflare
- Example of simple paid MCP server: https://github.com/stripe/agent-toolkit/tree/main/typescript/examples/cloudflare
- Example of the remote MCP server with GitHub OAuth: https://github.com/cloudflare/ai/tree/main/demos/remote-mcp-github-oauth