mcp-server-patterns — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited mcp-server-patterns (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.
When designing, building, or debugging Model Context Protocol (MCP) servers that expose tools, resources, or prompts to AI agents. Use when implementing the server side of MCP — registering capabilities, handling requests, managing transport, and following protocol conventions.
MCP is the standard protocol for extending AI agents with external capabilities. A well-built MCP server is the difference between an agent that can only talk and one that can act.
| Type | Purpose | Agent interaction | Example |
|---|---|---|---|
| Tools | Actions agents invoke | Agent calls with args, gets result | create-file, run-query, send-email |
| Resources | Data agents read | Agent requests by URI, gets content | file://, db://schema, config://env |
| Prompts | Reusable templates | Agent fills arguments, gets formatted prompt | code-review, summarize, translate |
| Transport | Use when | Characteristics |
|---|---|---|
| stdio | Local tools, CLI integration, dev/test | Process-based, simple, synchronous feel |
| Streamable HTTP | Remote servers, multi-client, production | Scalable, stateless, HTTP-based |
Project structure (TypeScript/Node.js):
mcp-server-[name]/
src/
index.ts # Server initialization and transport setup
tools/
index.ts # Tool registration aggregator
[tool-name].ts # One file per tool
resources/
index.ts # Resource registration aggregator
[resource-name].ts # One file per resource
prompts/
index.ts # Prompt registration aggregator
[prompt-name].ts # One file per prompt
lib/
errors.ts # Custom MCP error classes
schemas.ts # Shared Zod schemas
tests/
tools/
[tool-name].test.ts
integration/
stdio.test.ts # Full server integration via stdio
package.json
tsconfig.jsonTool registration pattern:
import { z } from "zod";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
const InputSchema = z.object({
filePath: z.string().describe("Absolute path to the target file"),
content: z.string().describe("Content to write to the file"),
overwrite: z.boolean().default(false).describe("Whether to overwrite existing files"),
});
export function registerCreateFileTool(server: McpServer) {
server.tool(
"create-file",
"Create a new file with the specified content at the given path",
InputSchema.shape,
async ({ filePath, content, overwrite }) => {
// Validate path is within allowed directories
validatePath(filePath);
// Check existing file
if (!overwrite && await fileExists(filePath)) {
return {
content: [{ type: "text", text: `Error: File already exists at ${filePath}. Use overwrite: true to replace.` }],
isError: true,
};
}
await writeFile(filePath, content);
return {
content: [{ type: "text", text: `Successfully created file at ${filePath} (${content.length} bytes)` }],
};
}
);
}Resource registration pattern:
export function registerFileResource(server: McpServer) {
// Static resource
server.resource(
"project-config",
"config://project",
"The project's configuration file",
async (uri) => ({
contents: [{
uri: uri.href,
mimeType: "application/json",
text: await readFile("./config.json", "utf-8"),
}],
})
);
// Dynamic resource with URI template
server.resource(
"source-file",
new ResourceTemplate("file:///{path}", { list: undefined }),
"Read a source file by path",
async (uri, { path }) => ({
contents: [{
uri: uri.href,
mimeType: getMimeType(path),
text: await readFile(path, "utf-8"),
}],
})
);
}Prompt registration pattern:
export function registerCodeReviewPrompt(server: McpServer) {
server.prompt(
"code-review",
"Generate a structured code review for the given diff",
{
diff: z.string().describe("The git diff to review"),
severity: z.enum(["quick", "thorough", "security"]).default("thorough")
.describe("Review depth level"),
},
({ diff, severity }) => ({
messages: [{
role: "user",
content: {
type: "text",
text: `Review this code diff at ${severity} level:\n\n${diff}\n\nProvide findings as: [SEVERITY] file:line - description`,
},
}],
})
);
}Transport setup:
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
const server = new McpServer({
name: "my-mcp-server",
version: "1.0.0",
});
// Register all capabilities
registerTools(server);
registerResources(server);
registerPrompts(server);
// stdio transport (local/CLI)
const transport = new StdioServerTransport();
await server.connect(transport);
// OR: Streamable HTTP transport (remote/production)
// const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined });
// app.post("/mcp", async (req, res) => { await transport.handleRequest(req, res); });Error handling (mandatory):
import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js";
// In tool handlers:
if (!isValid(input)) {
throw new McpError(
ErrorCode.InvalidParams,
`Invalid input: ${validationErrors.join(", ")}`
);
}
// For "soft" errors (operation failed but not a protocol error):
return {
content: [{ type: "text", text: `Operation failed: ${reason}` }],
isError: true,
};Security considerations:
npx @modelcontextprotocol/inspector node dist/index.jspackage.json has correct bin entry for stdio servers"type": "module" set if using ESMBefore marking an MCP server task done:
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.