MCP Server Template

MCP Server Template

A skeleton template for building MCP servers with SEP-1865 interactive widget support, dual authentication (OAuth + API Key), and Cloudflare Workers deployment.

Category
Visit Server

README

{{SERVER_NAME}} MCP Server

MCP Apps server with SEP-1865 interactive widget support, dual authentication (OAuth + API Key), and Cloudflare Workers deployment.

Quick Start

1. Replace Placeholders

Search and replace these placeholders in all files:

Placeholder Description Example
{{SERVER_NAME}} Human-readable name "Currency Converter"
{{SERVER_ID}} kebab-case identifier "currency-converter"
{{McpAgentClassName}} PascalCase class name "CurrencyConverterMcp"
{{SERVER_DESCRIPTION}} Brief description "Convert currencies using real-time exchange rates"
{{WIDGET_TITLE}} Widget HTML title "Currency Converter Widget"
{{GITHUB_ORG}} GitHub organization "your-org"

2. Update wrangler.jsonc

  1. Replace {{SERVER_ID}} with your server ID
  2. Replace {{McpAgentClassName}} with your class name
  3. Update the custom domain pattern

3. Install and Build

npm install
npm run build:widgets

4. Set Secrets

wrangler secret put WORKOS_CLIENT_ID
wrangler secret put WORKOS_API_KEY

5. Deploy

Deployment is automatic via Cloudflare Workers Builds when you push to GitHub.

For manual deployment (not recommended):

npm run deploy

Project Structure

src/
  index.ts              # Entry point with dual auth routing
  server.ts             # McpAgent class (OAuth path)
  api-key-handler.ts    # API key authentication with LRU cache
  types.ts              # Environment bindings
  server-instructions.ts # LLM system prompt instructions

  auth/
    authkit-handler.ts  # WorkOS OAuth with PKCE
    apiKeys.ts          # API key validation
    auth-utils.ts       # User lookup, HTML pages
    props.ts            # Auth context type
    session-types.ts    # Session interfaces

  helpers/
    assets.ts           # loadHtml() for widget loading

  resources/
    ui-resources.ts     # SEP-1865 UI resource definitions

  tools/
    descriptions.ts     # Tool metadata (4-part pattern)

  shared/
    logger.ts           # Structured logging

  optional/             # Advanced features (delete if not needed)

web/
  widgets/
    widget.html         # Widget entry point
    widget.tsx          # React widget component
  components/           # shadcn/ui components
  lib/                  # Utilities (cn, types)
  styles/               # Tailwind CSS
  dist/widgets/         # Built output (gitignored)

Adding New Tools

When adding a tool, update these locations:

1. Tool Metadata (src/tools/descriptions.ts)

"your-tool": {
  title: "Your Tool",
  description: {
    part1_purpose: "What it does...",
    part2_returns: "Returns X, Y, Z...",
    part3_useCase: "Use when...",
    part4_constraints: "Note: limitations..."
  },
  examples: [...]
}

2. Server Registration (src/server.ts)

registerAppTool(
  this.server,
  "your-tool",
  {
    title: TOOL_METADATA["your-tool"].title,
    description: getToolDescription("your-tool"),
    inputSchema: { /* Zod schema */ },
    _meta: { [RESOURCE_URI_META_KEY]: widgetResource.uri }
  },
  async (args) => { /* implementation */ }
);

3. API Key Handler (src/api-key-handler.ts)

Duplicate the tool registration for API key authentication path.

SEP-1865 MCP Apps Pattern

This skeleton uses the Two-Part Registration pattern:

  1. PART 1: Register Resource - UI HTML template from Assets
  2. PART 2: Register Tool - Links to resource via _meta[RESOURCE_URI_META_KEY]

Data flows:

Tool Result -> structuredContent -> postMessage -> Widget State

Authentication

OAuth 2.1 (OAuth-capable clients)

  • Flow: /authorize -> WorkOS AuthKit -> /callback -> Tools
  • PKCE support (RFC 7636)
  • Centralized login at panel.wtyczki.ai
  • Example clients: Claude Desktop

API Key (Non-OAuth clients)

  • Header: Authorization: Bearer wtyk_xxxxx
  • Keys generated via panel.wtyczki.ai
  • LRU cache prevents memory leaks
  • Example clients: AnythingLLM, Cursor

Widget Development

Key Concepts

  • React 18 with useApp() hook from @modelcontextprotocol/ext-apps/react
  • Tailwind CSS with automatic dark mode (via host context)
  • Fixed 600px height container (mandatory for MCP Apps)
  • viteSingleFile inlines all JS/CSS into single HTML

Development

# Build widget
npm run build:widgets

# Watch mode
npm run dev:widget

# Full dev (server + widget watch)
npm run dev:full

Widget Lifecycle

const { app } = useApp({
  onAppCreated: (app) => {
    app.ontoolinput = (params) => { /* tool called */ };
    app.ontoolresult = (result) => { /* display result */ };
    app.onhostcontextchanged = (ctx) => { /* theme change */ };
    app.onteardown = async () => { /* cleanup */ };
  }
});

Configuration Files

File Purpose
wrangler.jsonc Cloudflare Workers config (bindings, routes)
vite.config.ts Widget build config
package.json Dependencies and scripts
tsconfig.json TypeScript config (server)
web/tsconfig.json TypeScript config (widget)

Environment Variables

Set via wrangler secret put:

Variable Required Description
WORKOS_CLIENT_ID Yes WorkOS client ID
WORKOS_API_KEY Yes WorkOS API key (starts with sk_)
AI_GATEWAY_TOKEN No AI Gateway token (if using Workers AI)

Common Issues

Widget not loading

  1. Check npm run build:widgets completed successfully
  2. Verify web/dist/widgets/widget.html exists
  3. Check ASSETS binding in wrangler.jsonc

Authentication failures

  1. Verify WORKOS_CLIENT_ID and WORKOS_API_KEY secrets are set
  2. Check USER_SESSIONS KV namespace is configured
  3. Ensure custom domain is set up in Cloudflare

Tool not appearing

  1. Check tool is registered in BOTH server.ts AND api-key-handler.ts
  2. Verify tool name matches exactly in all locations
  3. Check handleToolsList() includes the tool schema

Production Checklist

  • [ ] All {{PLACEHOLDER}} values replaced
  • [ ] wrangler.jsonc configured with correct IDs
  • [ ] Secrets set via wrangler secret put
  • [ ] Custom domain configured in Cloudflare
  • [ ] GitHub repository connected to Cloudflare Workers Builds
  • [ ] Widget builds successfully (npm run build:widgets)
  • [ ] Type checking passes (npm run type-check)

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
E2B

E2B

Using MCP to run code via e2b.

Official
Featured