mcp-security
Use when securing MCP servers, preventing prompt injection, implementing authorization, validating user input, or building secure multi-agent pipelines. Provides 5-layer defense architecture patterns.
fastmcp
FastMCP TypeScript framework patterns for MCP servers. Auto-loads when building MCP servers, creating tools/resources/prompts, implementing authentication, configuring transports, or working with FastMCP in TypeScript.
Full skill instructions
FastMCP is a TypeScript framework for building Model Context Protocol (MCP) servers. This skill provides patterns for tools, resources, prompts, authentication, and transport configuration.
npm install fastmcp
import { FastMCP } from "fastmcp";
import { z } from "zod";
const server = new FastMCP({
name: "My Server",
version: "1.0.0",
});
server.start({ transportType: "stdio" });
server.addTool({
name: "add",
description: "Add two numbers",
parameters: z.object({
a: z.number(),
b: z.number(),
}),
execute: async (args) => {
return String(args.a + args.b);
},
});
server.addTool({
name: "sayHello",
description: "Say hello",
execute: async () => {
return "Hello, world!";
},
});
server.addTool({
name: "download",
parameters: z.object({ url: z.string() }),
execute: async (args, { log }) => {
log.info("Downloading file...", { url: args.url });
// ... process ...
log.info("Downloaded file");
return "done";
},
});
server.addTool({
name: "download",
execute: async (args, { reportProgress }) => {
await reportProgress({ progress: 0, total: 100 });
// ... process ...
await reportProgress({ progress: 100, total: 100 });
return "done";
},
});
server.addTool({
name: "generateText",
parameters: z.object({ prompt: z.string() }),
annotations: {
streamingHint: true,
readOnlyHint: true,
},
execute: async (args, { streamContent }) => {
await streamContent({ type: "text", text: "Starting...\n" });
const words = "The quick brown fox".split(" ");
for (const word of words) {
await streamContent({ type: "text", text: word + " " });
await new Promise(resolve => setTimeout(resolve, 300));
}
return;
},
});
server.addTool({
name: "download",
description: "Download a file",
parameters: z.object({ url: z.string() }),
execute: async (args) => {
return {
content: [
{ type: "text", text: "First message" },
{ type: "text", text: "Second message" },
],
};
},
});
import { imageContent } from "fastmcp";
server.addTool({
name: "getImage",
execute: async (args) => {
return imageContent({
url: "https://example.com/image.png",
});
// Or: path: "/path/to/image.png"
// Or: buffer: Buffer.from(...)
},
});
import { audioContent } from "fastmcp";
server.addTool({
name: "getAudio",
execute: async (args) => {
return audioContent({
url: "https://example.com/audio.mp3",
});
},
});
import { UserError } from "fastmcp";
server.addTool({
name: "download",
execute: async (args) => {
if (args.url.startsWith("https://example.com")) {
throw new UserError("This URL is not allowed");
}
return "done";
},
});
server.addTool({
name: "fetch-content",
description: "Fetch content from a URL",
parameters: z.object({ url: z.string() }),
annotations: {
title: "Web Content Fetcher",
readOnlyHint: true,
openWorldHint: true,
},
execute: async (args) => {
return await fetchWebpageContent(args.url);
},
});
server.addTool({
name: "admin-tool",
description: "An admin-only tool",
canAccess: (auth) => auth?.role === "admin",
execute: async () => "Welcome, admin!",
});
import { type } from "arktype";
server.addTool({
name: "fetch-arktype",
parameters: type({ url: "string" }),
execute: async (args) => {
return await fetchWebpageContent(args.url);
},
});
import * as v from "valibot";
server.addTool({
name: "fetch-valibot",
parameters: v.object({ url: v.string() }),
execute: async (args) => {
return await fetchWebpageContent(args.url);
},
});
server.addResource({
uri: "file:///logs/app.log",
name: "Application Logs",
mimeType: "text/plain",
async load() {
return {
text: await readLogFile(),
};
},
});
server.addResource({
uri: "file:///logs/app.log",
async load() {
return {
blob: 'base64-encoded-data'
};
},
});
server.addResourceTemplate({
uriTemplate: "file:///logs/{name}.log",
name: "Application Logs",
mimeType: "text/plain",
arguments: [
{
name: "name",
description: "Name of the log",
required: true,
},
],
async load({ name }) {
return {
text: `Log content for ${name}`,
};
},
});
server.addResourceTemplate({
uriTemplate: "file:///logs/{name}.log",
arguments: [
{
name: "name",
description: "Name of the log",
required: true,
complete: async (value) => {
if (value === "Example") {
return { values: ["Example Log"] };
}
return { values: [] };
},
},
],
async load({ name }) {
return {
text: `Log content for ${name}`,
};
},
});
server.addTool({
name: "get_user_data",
parameters: z.object({ userId: z.string() }),
execute: async (args) => {
return {
content: [
{
type: "resource",
resource: await server.embedded(`user://profile/${args.userId}`),
},
],
};
},
});
server.addPrompt({
name: "git-commit",
description: "Generate a Git commit message",
arguments: [
{
name: "changes",
description: "Git diff or description of changes",
required: true,
},
],
load: async (args) => {
return "Generate a concise commit message:\n\n" + args.changes;
},
});
server.addPrompt({
name: "countryPoem",
description: "Writes a poem about a country",
load: async ({ name }) => {
return "Write a poem about " + name + "!";
},
arguments: [
{
name: "name",
description: "Name of the country",
required: true,
complete: async (value) => {
if (value === "Germ") {
return { values: ["Germany"] };
}
return { values: [] };
},
},
],
});
server.addPrompt({
name: "countryPoem",
description: "Writes a poem about a country",
load: async ({ name }) => {
return "Write a poem about " + name + "!";
},
arguments: [
{
name: "name",
description: "Name of the country",
required: true,
enum: ["Germany", "France", "Italy"],
},
],
});
const server = new FastMCP({
name: "My Server",
version: "1.0.0",
authenticate: (request) => {
const apiKey = request.headers["x-api-key"];
if (apiKey !== "expected-key") {
throw new Response(null, {
status: 401,
statusText: "Unauthorized",
});
}
return { id: 1 };
},
});
server.addTool({
name: "sayHello",
execute: async (args, { session }) => {
return "Hello, " + session.id + "!";
},
});
const server = new FastMCP<{ role: "admin" | "user" }>({
authenticate: async (request) => {
const role = request.headers["x-role"] as string;
return { role: role === "admin" ? "admin" : "user" };
},
name: "My Server",
version: "1.0.0",
});
server.addTool({
name: "admin-dashboard",
description: "An admin-only tool",
canAccess: (auth) => auth?.role === "admin",
execute: async () => {
return "Welcome to the admin dashboard!";
},
});
server.addTool({
name: "public-info",
description: "A tool available to everyone",
execute: async () => {
return "This is public information.";
},
});
import { FastMCP } from "fastmcp";
import { GoogleProvider } from "fastmcp/auth";
const authProxy = new GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
baseUrl: "https://your-server.com",
scopes: ["openid", "profile", "email"],
});
const server = new FastMCP({
name: "My Server",
oauth: {
enabled: true,
authorizationServer: authProxy.getAuthorizationServerMetadata(),
proxy: authProxy,
},
});
const sessionCounters = new Map<string, number>();
server.addTool({
name: "increment_counter",
description: "Increment a per-session counter",
parameters: z.object({}),
execute: async (args, context) => {
if (!context.sessionId) {
return "Session ID not available (requires HTTP transport)";
}
const counter = sessionCounters.get(context.sessionId) || 0;
const newCounter = counter + 1;
sessionCounters.set(context.sessionId, newCounter);
return "Counter: " + newCounter;
},
});
server.on("connect", (event) => {
console.log("Client connected:", event.session);
});
server.on("disconnect", (event) => {
console.log("Client disconnected:", event.session);
});
server.on("connect", (event) => {
const session = event.session;
console.log("Initial roots:", session.roots);
session.on("rootsChanged", (event) => {
console.log("Roots changed:", event.roots);
});
session.on("error", (event) => {
console.error("Error:", event.error);
});
});
await session.requestSampling({
messages: [
{
role: "user",
content: {
type: "text",
text: "What files are in the current directory?",
},
},
],
systemPrompt: "You are a helpful file system assistant.",
includeContext: "thisServer",
maxTokens: 100,
});
server.start({
transportType: "httpStream",
httpStream: {
port: 8080,
},
});
server.start({
transportType: "httpStream",
httpStream: {
port: 8080,
endpoint: "/mcp",
},
});
server.start({
transportType: "httpStream",
httpStream: {
port: 8080,
stateless: true,
},
});
server.start({
transportType: "httpStream",
httpStream: {
port: 8080,
},
});
// SSE automatically available at http://localhost:8080/sse
server.start({
transportType: "stdio",
});
import { FastMCP, Logger } from "fastmcp";
class CustomLogger implements Logger {
debug(...args: unknown[]): void {
console.log("[DEBUG]", new Date().toISOString(), ...args);
}
error(...args: unknown[]): void {
console.error("[ERROR]", new Date().toISOString(), ...args);
}
info(...args: unknown[]): void {
console.info("[INFO]", new Date().toISOString(), ...args);
}
log(...args: unknown[]): void {
console.log("[LOG]", new Date().toISOString(), ...args);
}
warn(...args: unknown[]): void {
console.warn("[WARN]", new Date().toISOString(), ...args);
}
}
const server = new FastMCP({
name: "My Server",
version: "1.0.0",
logger: new CustomLogger(),
});
const server = new FastMCP({
name: "My Server",
version: "1.0.0",
health: {
enabled: true,
message: "healthy",
path: "/healthz",
status: 200,
},
});
const server = new FastMCP({
name: "My Server",
version: "1.0.0",
ping: {
enabled: true,
intervalMs: 10000,
logLevel: "debug",
},
});
const server = new FastMCP({
name: "My Server",
version: "1.0.0",
instructions: "This server provides file management tools. Use the list_files tool to see available files.",
});
# Development mode with hot reload
npx fastmcp dev src/server.ts
# HTTP streaming transport
npx fastmcp dev src/server.ts --transport http-stream --port 8080
# Stateless mode
npx fastmcp dev src/server.ts --transport http-stream --port 8080 --stateless true
# Or via environment variable
FASTMCP_STATELESS=true npx fastmcp dev src/server.ts
UserError for user-facing errorsreportProgressstreamContent with streamingHint: truecanAccess for role-based access controllog object for debuggingUse when securing MCP servers, preventing prompt injection, implementing authorization, validating user input, or building secure multi-agent pipelines. Provides 5-layer defense architecture patterns.
Validate and fix parallel prompts for required sections
Create a new Claude Code agent skill with proper folder structure and SKILL.md format. Use when the user wants to add a model-invoked skill that Claude uses autonomously based on context. Handles skill folder creation with SKILL.md and optional reference files.
Design system management for building and reusing UI components, tokens, and patterns. Use when working with component libraries, design tokens, style guides, or reusable UI patterns to ensure consistency and promote component reuse.
Port management for local development with git worktrees. Use when setting up local development environments, booking ports for services to avoid collisions between parallel worktrees, or configuring docker-compose with dynamic ports.
Automatic QA test lifecycle management, naming conventions, and directory structure. Use when creating, organizing, or tracking QA tests to ensure proper naming, directory structure, and status transitions.
Create a new Claude Code slash command with proper YAML frontmatter structure. Use when the user wants to add a custom slash command to a plugin. Handles command file creation with description, argument hints, allowed tools, and all advanced features.
Dependency version alignment and conflict resolution for parallel development. Use when extracting dependencies from Tech Specs to ensure version compatibility with existing project dependencies and transitive dependencies.
Review code changes between commits for security, logic, performance, and style issues
Create detailed user persona with guided questions
Sync git-branchless stack with main branch - fetch, rebase, and handle merges
Undo git-branchless operations - recover from mistakes interactively
Generate, edit, and beat-sync AI video with leading models in one workspace.
The world's fastest calendar for remote work
Transform Your Design with AI Designer by ImgCreator.ai
Revolutionizing Video Production with AI-Powered Creativity
Extend an image past the frame and let AI fill the new aspect ratio.
Discover your celebrity doppelgänger with StarByFace!
ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.
Opus.ai: Revolutionize Your Web Experience