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.
Quick Start
In this guide, you’ll install the LeanMCP CLI, create a new project, and build a real image generation service using Gemini’s Nano Banana API — complete with tools, resources, and schema validation that AI agents can discover and use.
Prerequisites
Step 1: Install the CLI
Verify the installation:
Step 2: Create Your Project
leanmcp create my-mcp-server
The CLI will ask:
Install dependencies? → Yes
Start dev server? → Yes
Project structure:
my-mcp-server/
├── main.ts # Entry point
├── package.json
├── tsconfig.json
└── mcp/
└── example/
└── index.ts # Example service
Step 3: Server is Running
After creation, the server starts automatically:
Server running on http://localhost:3001
MCP endpoint: http://localhost:3001/mcp
Health check: http://localhost:3001/health
To restart later:
cd my-mcp-server
npm run dev
Step 4: Test Your MCP
Use the MCP Inspector:
npx @modelcontextprotocol/inspector http://localhost:3001/mcp
Or test with curl:
curl http://localhost:3001/mcp \
-X POST \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {},
"clientInfo": { "name": "test", "version": "1.0.0" }
}
}'
Step 5: Add Gemini Image Generation
Let’s build a real example: image generation with Gemini (Nano Banana).
Create mcp/gemini/index.ts:
import { Tool , Resource , SchemaConstraint , Optional } from "@leanmcp/core" ;
import fs from "fs" ;
import path from "path" ;
// --- Input Schema ---
class GenerateImageInput {
@ SchemaConstraint ({
description: "Text description of the image to generate" ,
minLength: 1
})
prompt !: string ;
@ Optional ()
@ SchemaConstraint ({
description: "Model: nano-banana (fast) or nano-banana-pro (advanced)" ,
enum: [ "nano-banana" , "nano-banana-pro" ],
default: "nano-banana"
})
model ?: "nano-banana" | "nano-banana-pro" ;
@ Optional ()
@ SchemaConstraint ({
description: "Aspect ratio" ,
enum: [ "1:1" , "16:9" , "9:16" , "4:3" ],
default: "1:1"
})
aspectRatio ?: string ;
}
// --- Service ---
export class GeminiImageService {
private apiKey = process . env . GEMINI_API_KEY || "" ;
private baseUrl = "https://generativelanguage.googleapis.com/v1beta/models" ;
private outputDir = path . join ( process . cwd (), "generated-images" );
private modelMap = {
"nano-banana" : "gemini-2.5-flash-image" ,
"nano-banana-pro" : "gemini-3-pro-image-preview"
};
constructor () {
if ( ! fs . existsSync ( this . outputDir )) {
fs . mkdirSync ( this . outputDir , { recursive: true });
}
}
@ Tool ({
description: "Generate an image from text using Gemini (Nano Banana)" ,
inputClass: GenerateImageInput
})
async generateImage ( input : GenerateImageInput ) {
const modelKey = input . model || "nano-banana" ;
const modelName = this . modelMap [ modelKey ];
const response = await fetch (
` ${ this . baseUrl } / ${ modelName } :generateContent?key= ${ this . apiKey } ` ,
{
method: "POST" ,
headers: { "Content-Type" : "application/json" },
body: JSON . stringify ({
contents: [{ parts: [{ text: input . prompt }] }],
generationConfig: {
responseModalities: [ "IMAGE" ],
imageConfig: { aspectRatio: input . aspectRatio || "1:1" }
}
})
}
);
const result = await response . json ();
const imageData = result . candidates ?.[ 0 ]?. content ?. parts ?.[ 0 ]?. inlineData ?. data ;
// Save to disk
const filename = `gemini_ ${ Date . now () } .png` ;
const filepath = path . join ( this . outputDir , filename );
fs . writeFileSync ( filepath , Buffer . from ( imageData , "base64" ));
return { success: true , savedTo: filepath , filename };
}
@ Resource ({ description: "Available Gemini models" , mimeType: "application/json" })
getModels () {
return {
contents: [{
uri: "gemini://models" ,
mimeType: "application/json" ,
text: JSON . stringify ({
"nano-banana" : "Fast, 1K resolution" ,
"nano-banana-pro" : "Advanced, up to 4K"
})
}]
};
}
}
Add your API key to .env:
GEMINI_API_KEY = your-key-here
Step 6: Build for Production
npm run build
npm run start
Or set a custom port:
What You Built
You now have a working MCP server with:
Tool : generateImage - Generate images from text prompts
Resource : getModels - Lists available Gemini models
Auto-discovery - Services in mcp/ are automatically registered
Next Steps
Tools Create more tools for AI to execute
Resources Expose data to AI agents
Prompts Template prompts for AI
Auth Secure your MCP server
Deployment Deploy to production
CLI Reference All CLI commands