xiaohongshu
xiaohongshu
mcp-server-writing
Creates production-ready MCP servers with tools, resources, and prompts using TypeScript SDK or Python FastMCP. Use when building MCP integrations for Claude or LLM applications.
Full skill instructions
Guide creation of production-ready Model Context Protocol (MCP) servers following official SDK patterns, security best practices, and real-world implementation patterns.
| Factor | TypeScript | Python FastMCP |
|---|---|---|
| Type Safety | Excellent (Zod/Ajv) | Good (type hints) |
| Schema Validation | Built-in with Zod | Decorator-based |
| Prototyping Speed | Medium | Fast |
| Production Readiness | High | High |
| Ecosystem | Node.js, npm | pip, uv |
Recommendation: Use TypeScript for production servers with complex schemas. Use Python FastMCP for rapid prototyping or when integrating with Python libraries.
TypeScript:
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
const server = new Server(
{ name: "my-mcp-server", version: "1.0.0" },
{ capabilities: { tools: {} } },
);
Python FastMCP:
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("my-mcp-server", json_response=True)
Tools are functions the LLM can call. Always include:
description explaining what the tool doesinputSchema with property descriptionsTypeScript (Low-Level API):
import {
CallToolRequestSchema,
ListToolsRequestSchema,
Tool,
} from "@modelcontextprotocol/sdk/types.js";
const TOOLS: Tool[] = [
{
name: "process_data",
description:
"Validates and transforms input data. Returns structured result with any validation errors.",
inputSchema: {
type: "object",
properties: {
data: {
type: "string",
description: "Raw data string to process",
},
format: {
type: "string",
enum: ["json", "csv", "xml"],
description: "Expected input format",
},
},
required: ["data", "format"],
},
},
];
server.setRequestHandler(ListToolsRequestSchema, () => ({ tools: TOOLS }));
Python FastMCP:
@mcp.tool()
def process_data(data: str, format: str = "json") -> dict:
"""Validates and transforms input data.
Args:
data: Raw data string to process
format: Expected input format (json, csv, xml)
Returns:
Structured result with validation errors if any
"""
# Implementation here
return {"success": True, "processed": data}
Critical: Always validate inputs before processing. Use Ajv for TypeScript.
import Ajv from "ajv";
const ajv = new Ajv();
const validateProcessDataArgs = ajv.compile({
type: "object",
properties: {
data: { type: "string" },
format: { type: "string", enum: ["json", "csv", "xml"] },
},
required: ["data", "format"],
});
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
if (name === "process_data") {
// Validate inputs
if (!validateProcessDataArgs(args)) {
return {
content: [
{
type: "text",
text: JSON.stringify({
error: "Validation failed",
details: validateProcessDataArgs.errors,
suggestion: "Check input parameters match the schema",
}),
},
],
isError: true,
};
}
// Process valid inputs
const result = processData(args.data, args.format);
return {
content: [{ type: "text", text: JSON.stringify(result) }],
};
}
return {
content: [{ type: "text", text: `Unknown tool: ${name}` }],
isError: true,
};
});
Resources expose data the LLM can read. Use for configuration, status, or reference data.
TypeScript:
import {
ListResourcesRequestSchema,
ReadResourceRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
server.setRequestHandler(ListResourcesRequestSchema, () => ({
resources: [
{
uri: "config://settings",
name: "Application Settings",
description: "Current server configuration",
mimeType: "application/json",
},
],
}));
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
if (request.params.uri === "config://settings") {
return {
contents: [
{
uri: "config://settings",
mimeType: "application/json",
text: JSON.stringify({ theme: "dark", version: "1.0.0" }),
},
],
};
}
throw new Error(`Unknown resource: ${request.params.uri}`);
});
Python FastMCP:
@mcp.resource("config://settings")
def get_settings() -> str:
"""Current server configuration."""
return json.dumps({"theme": "dark", "version": "1.0.0"})
Prompts are reusable templates the LLM can request.
Python FastMCP:
@mcp.prompt()
def review_code(code: str, language: str = "python") -> str:
"""Generate a code review prompt."""
return f"Please review this {language} code for best practices:\n\n{code}"
Critical for MCP: Log to stderr, NEVER stdout. stdout is reserved for JSON-RPC.
// utils/logger.ts
class Logger {
private log(level: string, message: string, context?: object): void {
const entry = {
timestamp: new Date().toISOString(),
level,
message,
service: "my-mcp-server",
...context,
};
// CRITICAL: Use stderr, not stdout
console.error(JSON.stringify(entry));
}
info(message: string, context?: object): void {
this.log("INFO", message, context);
}
error(message: string, context?: object, error?: Error): void {
this.log("ERROR", message, {
...context,
error: error
? { name: error.name, message: error.message, stack: error.stack }
: undefined,
});
}
}
export const logger = new Logger();
TypeScript:
async function main(): Promise<void> {
const transport = new StdioServerTransport();
await server.connect(transport);
logger.info("MCP Server started", { transport: "stdio" });
}
main().catch((error) => {
logger.error("Fatal error", {}, error);
process.exit(1);
});
Python FastMCP:
if __name__ == "__main__":
mcp.run(transport="stdio")
// Always return actionable suggestions with errors
if (!validateArgs(args)) {
return {
content: [
{
type: "text",
text: JSON.stringify({
success: false,
errors: [
{
field: "partner_id",
message: "Invalid UUID format",
suggestion: "Use format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
},
],
}),
},
],
isError: true,
};
}
// Limit input length before regex processing
const MAX_INPUT_LENGTH = 50_000;
function safeInput(text: string): string {
return text.length > MAX_INPUT_LENGTH
? text.slice(0, MAX_INPUT_LENGTH)
: text;
}
// Use in tool handlers
const safeText = safeInput(args.text);
const matches = safeText.match(/pattern/);
@mcp.resource("users://{user_id}/profile")
def get_user_profile(user_id: str) -> str:
"""Get user profile by ID."""
user = fetch_user(user_id)
return json.dumps({"id": user_id, "name": user.name, "role": user.role})
Before deploying your MCP server:
description fieldsdescriptionisError: true flagsuggestioninterface ToolError {
field: string;
message: string;
suggestion: string;
}
function createErrorResponse(errors: ToolError[]) {
return {
content: [
{
type: "text",
text: JSON.stringify({ success: false, errors }),
},
],
isError: true,
};
}
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
const startTime = Date.now();
logger.info("Tool invocation started", {
tool: name,
args_keys: Object.keys(args || {}),
});
try {
const result = await handleTool(name, args);
logger.info("Tool invocation completed", {
tool: name,
duration_ms: Date.now() - startTime,
});
return result;
} catch (error) {
logger.error(
"Tool invocation failed",
{
tool: name,
duration_ms: Date.now() - startTime,
},
error,
);
throw error;
}
});
Cause: Logging to stdout instead of stderr
Solution: Change all console.log() to console.error() for logging
Cause: Missing isError: true in response
Solution: Add isError: true to all error responses
Cause: ReDoS vulnerability with unbounded input
Solution: Limit input length with safeInput() function
xiaohongshu
technical spec
product ux expert
database patterns
Conduct multi-agent task orchestration and workflow coordination.
Initialize project with Conductor artifacts (product definition,
Expert in web animations, transitions, and motion design using Framer Motion and CSS
Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...
PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.
Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...
Display project status, active tracks, and next actions
Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.
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