mcp-server-creation — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited mcp-server-creation (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
How to build MCP servers from scratch in TypeScript and Python. Covers project setup, transport configuration, tool/resource/prompt registration, lifecycle hooks, and testing.
# Initialize project
mkdir my-mcp-server && cd my-mcp-server
npm init -y
npm install @modelcontextprotocol/sdk zod
npm install -D typescript @types/node
npx tsc --init// src/index.ts - Minimal MCP server with stdio transport
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
const server = new McpServer({
name: "my-server",
version: "1.0.0",
});
// Register a tool
server.tool(
"greet",
"Greet a user by name. Use when the user wants a personalized greeting.",
{ name: z.string().describe("The person's name") },
async ({ name }) => ({
content: [{ type: "text", text: `Hello, ${name}!` }],
})
);
// Start with stdio transport
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("MCP server running on stdio");
}
main().catch(console.error);# Initialize project
mkdir my-mcp-server && cd my-mcp-server
pip install mcp# server.py - Minimal MCP server with stdio transport
import asyncio
from mcp.server import Server
from mcp.server.stdio import stdio_server
import mcp.types as types
server = Server("my-server")
@server.list_tools()
async def list_tools() -> list[types.Tool]:
return [
types.Tool(
name="greet",
description="Greet a user by name. Use when the user wants a personalized greeting.",
inputSchema={
"type": "object",
"properties": {
"name": {"type": "string", "description": "The person's name"}
},
"required": ["name"]
}
)
]
@server.call_tool()
async def call_tool(name: str, arguments: dict) -> list[types.TextContent]:
if name == "greet":
return [types.TextContent(type="text", text=f"Hello, {arguments['name']}!")]
raise ValueError(f"Unknown tool: {name}")
async def main():
async with stdio_server() as (read_stream, write_stream):
await server.run(read_stream, write_stream, server.create_initialization_options())
if __name__ == "__main__":
asyncio.run(main())For remote MCP servers accessible over HTTP.
// TypeScript - SSE transport
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
import express from "express";
const app = express();
const server = new McpServer({ name: "my-server", version: "1.0.0" });
// Register tools on server...
app.get("/sse", async (req, res) => {
const transport = new SSEServerTransport("/messages", res);
await server.connect(transport);
});
app.post("/messages", async (req, res) => {
// Handle incoming messages from the transport
await transport.handlePostMessage(req, res);
});
app.listen(3001, () => console.error("MCP SSE server on port 3001"));Handle server initialization and shutdown gracefully.
const server = new McpServer({ name: "my-server", version: "1.0.0" });
// The server handles lifecycle automatically, but you can add cleanup
process.on("SIGINT", async () => {
console.error("Shutting down MCP server...");
await server.close();
process.exit(0);
});
process.on("SIGTERM", async () => {
await server.close();
process.exit(0);
});Test your MCP server using the MCP Inspector or programmatically with an in-memory client.
# Use MCP Inspector for interactive testing
npx @modelcontextprotocol/inspector node dist/index.js// Programmatic testing with in-memory transport
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
async function testServer() {
const server = new McpServer({ name: "test", version: "1.0.0" });
// Register tools...
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
await server.connect(serverTransport);
const client = new Client({ name: "test-client", version: "1.0.0" });
await client.connect(clientTransport);
// Call a tool
const result = await client.callTool({ name: "greet", arguments: { name: "World" } });
console.assert(result.content[0].text === "Hello, World!");
await client.close();
await server.close();
}Register your MCP server in Claude Desktop's config.
// ~/Library/Application Support/Claude/claude_desktop_config.json (macOS)
{
"mcpServers": {
"my-server": {
"command": "node",
"args": ["/absolute/path/to/dist/index.js"],
"env": {
"API_KEY": "your-key-here"
}
}
}
}| Component | TypeScript Import |
|---|---|
| Server | @modelcontextprotocol/sdk/server/mcp.js |
| Stdio | @modelcontextprotocol/sdk/server/stdio.js |
| SSE | @modelcontextprotocol/sdk/server/sse.js |
| InMemory | @modelcontextprotocol/sdk/inMemory.js |
| Client | @modelcontextprotocol/sdk/client/index.js |
| Transport | Use Case |
|---|---|
| stdio | Local tools, CLI integration, Claude Desktop |
| SSE | Remote servers, web-accessible tools |
| In-memory | Testing, same-process communication |
MCP Inspector: npx @modelcontextprotocol/inspector <command> <args>
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.