Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.leanmcp.com/llms.txt

Use this file to discover all available pages before exploring further.

The official MCP SDK gives you the bare minimum to build an MCP server. LeanMCP builds on top of it — the same way Next.js builds on React. You take the underlying protocol, build a framework on top, and make it production-ready. Building an MCP locally is easy. The official SDK works fine for that. But here’s the thing — when you want to add the real features that actually matter for production MCPs, it becomes really tough:
  • Authentication — connecting with Clerk, Auth0, Cognito, Firebase
  • Elicitation — collecting user input during tool execution
  • MCP UI & Apps — rendering components in clients
  • Remote deployment — running your MCP on a server
These are the features that separate a toy from a production service. And the official SDK leaves you completely on your own for all of them.

What LeanMCP Does

LeanMCP abstracts the hard parts. Instead of writing 600-700 lines of code just to set up authentication, you write 20-30 lines and run a few CLI commands. That’s it. We integrate with the auth providers you already use — Clerk, Auth0, AWS Cognito, Firebase, Google Cloud. We handle the JWT validation, JWKS fetching, token extraction, scope checking. You just add a decorator. And it’s entirely open source, just like the official MCP SDK. MIT license. Fork it, extend it, contribute to it.

Deployment: LeanMCP + LeanMCP Platform

Think of it like Next.js + Vercel. You can deploy Next.js anywhere — AWS, GCP, your own servers. But Vercel gives you optimized deployment, edge functions, and observability out of the box. Same with LeanMCP. You can deploy to any platform you want — AWS, GCP, Railway, Render — you’re not locked in. But if you want optimized deployment with built-in observability, monitoring, and zero-config setup, LeanMCP’s platform handles that for you with leanmcp deploy.

Why Opinionated Matters

MCP is a developing protocol. People don’t realize the places where they can go wrong. One example: developers often use elicitation to collect authentication tokens. Seems reasonable, right? But it’s a security vulnerability. When you use elicitation, the data passes through the MCP client — both the client and server see the token in plain text. If the client is compromised, the token is stolen. The correct approach is using the protocol’s _meta.authorization.token field, which is handled by the client and never visible in tool responses. Without guidance, you’d never know this. LeanMCP enforces these best practices by design — so you don’t accidentally expose vulnerabilities.

The Relationship

LeanMCP is built on top of the official SDK. It doesn’t replace it — it extends it.

Why Does This Matter?

Local Development is Easy Either Way

Building a basic MCP on your local machine is straightforward with either SDK:
// Official MCP SDK - works fine for basics
const server = new McpServer({ name: "my-server" });
server.tool("hello", "Say hello", { name: z.string() }, async ({ name }) => {
  return { content: [{ type: "text", text: `Hello, ${name}!` }] };
});
// LeanMCP - also simple
@Tool({ description: "Say hello" })
hello(input: { name: string }) {
  return `Hello, ${input.name}!`;
}
No significant difference for basic tools.

The Problem: Production Features

When you need real production features, the official SDK leaves you on your own:
FeatureOfficial MCP SDKLeanMCP
AuthenticationDIY (~600-700 lines)@leanmcp/auth (~20-30 lines)
ElicitationManual implementation@leanmcp/elicitation decorator
OAuth ProvidersBuild from scratchClerk, Auth0, Cognito, Firebase built-in
HTTP TransportBasicProduction-ready with session management
DeploymentManualleanmcp deploy

Code Comparison: Authentication

Official MCP SDK (~600-700 lines)

// You have to build everything yourself:
// 1. JWT validation
// 2. JWKS fetching and caching
// 3. Token extraction from requests
// 4. Scope validation
// 5. Error handling
// 6. Refresh token logic
// 7. Provider-specific quirks

import jwt from 'jsonwebtoken';
import jwksClient from 'jwks-rsa';

const client = jwksClient({
  jwksUri: 'https://your-provider/.well-known/jwks.json',
  cache: true,
  rateLimit: true,
});

function getKey(header, callback) {
  client.getSigningKey(header.kid, (err, key) => {
    const signingKey = key?.getPublicKey();
    callback(null, signingKey);
  });
}

async function validateToken(token: string) {
  return new Promise((resolve, reject) => {
    jwt.verify(token, getKey, {
      issuer: 'https://your-provider/',
      audience: 'your-audience',
    }, (err, decoded) => {
      if (err) reject(err);
      else resolve(decoded);
    });
  });
}

// ... 500+ more lines for middleware, error handling, 
// scope checking, provider setup, etc.

LeanMCP (~20-30 lines)

import { AuthProvider, Authenticated } from "@leanmcp/auth";

const auth = new AuthProvider('clerk', {
  secretKey: process.env.CLERK_SECRET_KEY!
});

await auth.init();

@Authenticated(auth)
export class MyService {
  @Tool({ description: "Protected tool" })
  async getData() {
    // authUser available automatically
    return { userId: authUser.sub };
  }
}
3 CLI commands + 20-30 lines of code vs 600-700 lines of boilerplate.

Built-in Provider Support

LeanMCP integrates with popular auth providers out of the box:
ProviderSetup
Clerknew AuthProvider('clerk', { secretKey })
Auth0new AuthProvider('auth0', { domain, audience })
AWS Cognitonew AuthProvider('cognito', { userPoolId, region })
Firebasenew AuthProvider('firebase', { projectId })
Google Cloudnew AuthProvider('gcp', { projectId })
Customnew AuthProvider('custom', { jwksUri, issuer })
No need to learn each provider’s quirks — LeanMCP handles it.

Opinionated Best Practices

The MCP protocol is evolving. Without guidance, developers make mistakes that create security vulnerabilities.

Example: Auth Tokens in Elicitation

A common mistake is using elicitation to collect authentication tokens:
// ❌ DANGEROUS: Don't do this!
@Tool({ description: "Login" })
async login() {
  const token = await elicit({
    message: "Enter your API token",
    schema: { token: { type: "string" } }
  });
  
  // Now both client AND server have seen the token
  // If client is compromised, token is exposed
}
Why this is wrong:
  • Elicitation passes data through the MCP client
  • Client sees the token in plain text
  • If client is malicious or compromised, token is stolen
The correct approach: Authentication tokens should flow through the MCP protocol’s _meta.authorization.token field — handled by the client, never visible in tool responses. LeanMCP enforces this pattern automatically with @Authenticated.

Both Are Open Source

Official MCP SDKLeanMCP
LicenseMITMIT
Sourcegithub.com/modelcontextprotocolgithub.com/Leanmcp-Community
FoundationProtocol implementationFramework on top
LeanMCP is entirely open source. You can fork it, extend it, or contribute to it.

When to Use Each

Use Official MCP SDK if:

  • Building a simple, local-only MCP
  • You want full control over everything
  • You’re experimenting or learning the protocol
  • You don’t need auth, elicitation, or deployment

Use LeanMCP if:

  • Building for production
  • You need authentication (Clerk, Auth0, Cognito, etc.)
  • You want elicitation with proper validation
  • You want to deploy remotely
  • You prefer convention over configuration
  • You want security best practices enforced

Summary

AspectOfficial MCP SDKLeanMCP
PhilosophyMinimal, DIYOpinionated, batteries-included
AuthBuild yourselfBuilt-in providers
ElicitationManualDecorators
DeploymentManualleanmcp deploy
Code for auth~600-700 lines~20-30 lines
Best practicesYour responsibilityEnforced by framework
LeanMCP is to MCP SDK what Next.js is to React — same foundation, more structure, faster to production.

Get Started

Build your first MCP with LeanMCP

Add Auth

Set up authentication