Package Exports
- mcp-ts-template
- mcp-ts-template/index.js
Readme
mcp-ts-template
Production-grade TypeScript template for building Model Context Protocol (MCP) servers. Ships with declarative tools/resources, robust error handling, DI, easy auth, optional OpenTelemetry, and first-class support for both local and edge (Cloudflare Workers) runtimes.
✨ Features
- Declarative Tools & Resources: Define capabilities in single, self-contained files. The framework handles registration and execution.
- Elicitation Support: Tools can interactively prompt the user for missing parameters during execution, streamlining user workflows.
- Robust Error Handling: A unified
McpError
system ensures consistent, structured error responses across the server. - Pluggable Authentication: Secure your server with zero-fuss support for
none
,jwt
, oroauth
modes. - Abstracted Storage: Swap storage backends (
in-memory
,filesystem
,Supabase
,Cloudflare KV/R2
) without changing business logic. Features secure opaque cursor pagination, parallel batch operations, and comprehensive validation. - Full-Stack Observability: Get deep insights with structured logging (Pino) and optional, auto-instrumented OpenTelemetry for traces and metrics.
- Dependency Injection: Built with
tsyringe
for a clean, decoupled, and testable architecture. - Service Integrations: Pluggable services for external APIs, including LLM providers (OpenRouter) and text-to-speech (ElevenLabs).
- Rich Built-in Utility Suite: Helpers for parsing (PDF, YAML, CSV), scheduling, security, and more.
- Edge-Ready: Write code once and run it seamlessly on your local machine or at the edge on Cloudflare Workers.
🛠️ Included Capabilities
This template includes working examples to get you started.
Tools
Tool | Description |
---|---|
template_echo_message |
Echoes a message back with optional formatting and repetition. |
template_cat_fact |
Fetches a random cat fact from an external API. |
template_madlibs_elicitation |
Demonstrates elicitation by asking for words to complete a story. |
template_code_review_sampling |
Uses the LLM service to perform a simulated code review. |
template_image_test |
Returns a test image as a base64-encoded data URI. |
Resources
Resource | URI | Description |
---|---|---|
echo |
echo://{message} |
A simple resource that echoes back a message. |
Prompts
Prompt | Description |
---|---|
code-review |
A structured prompt for guiding an LLM to perform a code review. |
🚀 Getting Started
MCP Client Settings/Configuration
Add the following to your MCP Client configuration file (e.g., cline_mcp_settings.json
).
{
"mcpServers": {
"mcp-ts-template": {
"type": "stdio",
"command": "bunx",
"args": ["mcp-ts-template@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info",
"STORAGE_PROVIDER_TYPE": "filesystem",
"STORAGE_FILESYSTEM_PATH": "/path/to/your/storage"
}
}
}
}
Prerequisites
- Bun v1.2.21 or higher.
Installation
- Clone the repository:
git clone https://github.com/cyanheads/mcp-ts-template.git
- Navigate into the directory:
cd mcp-ts-template
- Install dependencies:
bun install
⚙️ Configuration
All configuration is centralized and validated at startup in src/config/index.ts
. Key environment variables in your .env
file include:
Variable | Description | Default |
---|---|---|
MCP_TRANSPORT_TYPE |
The transport to use: stdio or http . |
http |
MCP_HTTP_PORT |
The port for the HTTP server. | 3010 |
MCP_HTTP_HOST |
The hostname for the HTTP server. | 127.0.0.1 |
MCP_AUTH_MODE |
Authentication mode: none , jwt , or oauth . |
none |
MCP_AUTH_SECRET_KEY |
Required for jwt auth mode. A 32+ character secret. |
(none) |
OAUTH_ISSUER_URL |
Required for oauth auth mode. URL of the OIDC provider. |
(none) |
STORAGE_PROVIDER_TYPE |
Storage backend: in-memory , filesystem , supabase , cloudflare-kv , r2 . |
in-memory |
STORAGE_FILESYSTEM_PATH |
Required for filesystem storage. Path to the storage directory. |
(none) |
SUPABASE_URL |
Required for supabase storage. Your Supabase project URL. |
(none) |
SUPABASE_SERVICE_ROLE_KEY |
Required for supabase storage. Your Supabase service role key. |
(none) |
OTEL_ENABLED |
Set to true to enable OpenTelemetry. |
false |
LOG_LEVEL |
The minimum level for logging (debug , info , warn , error ). |
info |
OPENROUTER_API_KEY |
API key for OpenRouter LLM service. | (none) |
Authentication & Authorization
- Modes:
none
(default),jwt
(requiresMCP_AUTH_SECRET_KEY
), oroauth
(requiresOAUTH_ISSUER_URL
andOAUTH_AUDIENCE
). - Enforcement: Wrap your tool/resource
logic
functions withwithToolAuth([...])
orwithResourceAuth([...])
to enforce scope checks. Scope checks are bypassed for developer convenience when auth mode isnone
.
Storage
- Service: A DI-managed
StorageService
provides a consistent API for persistence. Never accessfs
or other storage SDKs directly from tool logic. - Providers: The default is
in-memory
. Node-only providers includefilesystem
. Edge-compatible providers includesupabase
,cloudflare-kv
, andcloudflare-r2
. - Multi-Tenancy: The
StorageService
requirescontext.tenantId
. This is automatically propagated from thetid
claim in a JWT when auth is enabled. - Advanced Features:
- Secure Pagination: Opaque cursors with tenant ID binding prevent cross-tenant attacks
- Batch Operations: Parallel execution for
getMany()
,setMany()
,deleteMany()
- TTL Support: Time-to-live with proper expiration handling across all providers
- Comprehensive Validation: Centralized input validation for tenant IDs, keys, and options
Observability
- Structured Logging: Pino is integrated out-of-the-box. All logs are JSON and include the
RequestContext
. - OpenTelemetry: Disabled by default. Enable with
OTEL_ENABLED=true
and configure OTLP endpoints. Traces, metrics (duration, payload sizes), and errors are automatically captured for every tool call.
▶️ Running the Server
Local Development
Build and run the production version:
# One-time build bun rebuild # Run the built server bun start:http # or bun start:stdio
Run checks and tests:
bun devcheck # Lints, formats, type-checks, and more bun run test # Runs the test suite (Do not use 'bun test' directly as it may not work correctly)
Cloudflare Workers
- Build the Worker bundle:
bun build:worker
- Run locally with Wrangler:
bun deploy:dev
- Deploy to Cloudflare:
bun deploy:prod
Note: The
wrangler.toml
file is pre-configured to enablenodejs_compat
for best results.
📂 Project Structure
Directory | Purpose & Contents |
---|---|
src/mcp-server/tools/definitions |
Your tool definitions (*.tool.ts ). This is where you add new capabilities. |
src/mcp-server/resources/definitions |
Your resource definitions (*.resource.ts ). This is where you add new data sources. |
src/mcp-server/transports |
Implementations for HTTP and STDIO transports, including auth middleware. |
src/storage |
The StorageService abstraction and all storage provider implementations. |
src/services |
Integrations with external services (e.g., the default OpenRouter LLM provider). |
src/container |
Dependency injection container registrations and tokens. |
src/utils |
Core utilities for logging, error handling, performance, security, and telemetry. |
src/config |
Environment variable parsing and validation with Zod. |
tests/ |
Unit and integration tests, mirroring the src/ directory structure. |
🧑💻 Agent Development Guide
For a strict set of rules when using this template with an AI agent, please refer to AGENTS.md
. Key principles include:
- Logic Throws, Handlers Catch: Never use
try/catch
in your tool/resourcelogic
. Throw anMcpError
instead. - Use Elicitation for Missing Input: If a tool requires user input that wasn't provided, use the
elicitInput
function from theSdkContext
to ask the user for it. - Pass the Context: Always pass the
RequestContext
object through your call stack. - Use the Barrel Exports: Register new tools and resources only in the
index.ts
barrel files.
❓ FAQ
- Does this work with both STDIO and Streamable HTTP?
- Yes. Both transports are first-class citizens. Use
bun run dev:stdio
orbun run dev:http
.
- Yes. Both transports are first-class citizens. Use
- Can I deploy this to the edge?
- Yes. The template is designed for Cloudflare Workers. Run
bun run build:worker
and deploy with Wrangler.
- Yes. The template is designed for Cloudflare Workers. Run
- Do I have to use OpenTelemetry?
- No, it is disabled by default. Enable it by setting
OTEL_ENABLED=true
in your.env
file.
- No, it is disabled by default. Enable it by setting
- How do I publish my server to the MCP Registry?
- Follow the step-by-step guide in
docs/publishing-mcp-server-registry.md
.
- Follow the step-by-step guide in
🤝 Contributing
Issues and pull requests are welcome! If you plan to contribute, please run the local checks and tests before submitting your PR.
bun run devcheck
bun test
📜 License
This project is licensed under the Apache 2.0 License. See the LICENSE file for details.