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

May 6, 2025 - 22:15
 0
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<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