— No reviews yet
0 installs
18 views
0.0% view→install
Install
$ agentstack add skill-bobmatnyc-claude-mpm-skills-mcp ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ● Filesystem access Used
- ● Shell / process execution Used
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Are you the author of Mcp? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claimAbout
MCP (Model Context Protocol) - AI-Native Server Development
Overview
Model Context Protocol (MCP) is an open standard for connecting AI assistants to external data sources and tools. Build servers that expose tools (functions LLMs can call), resources (data LLMs can read), and prompts (templates LLMs can use).
Key Concepts:
- Tools: Functions LLMs can execute (read files, query APIs, run commands)
- Resources: Data sources LLMs can access (files, databases, APIs)
- Prompts: Reusable templates with arguments for common tasks
- Client-Server: MCP servers expose capabilities, clients (like Claude Desktop) consume them
- Transport: STDIO (local), SSE (Server-Sent Events), HTTP (network)
Official SDKs:
- TypeScript:
@modelcontextprotocol/sdk - Python:
mcp
Installation:
# TypeScript server
npx @modelcontextprotocol/create-server@latest my-server
cd my-server && npm install
# Python server
pip install mcp
# Or use uv (recommended)
uv pip install mcp
Quick Start - TypeScript Server
1. Create Server with CLI
# Interactive setup
npx @modelcontextprotocol/create-server@latest my-filesystem-server
# Options prompt:
# - Server name: my-filesystem-server
# - Language: TypeScript
# - Include example tools: Yes
2. Define Tools
// src/index.ts
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import * as fs from "fs/promises";
import * as path from "path";
const server = new Server(
{
name: "filesystem-server",
version: "1.0.0",
},
{
capabilities: {
tools: {},
},
}
);
// List available tools
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "read_file",
description: "Read contents of a file",
inputSchema: {
type: "object",
properties: {
path: {
type: "string",
description: "Path to the file to read",
},
},
required: ["path"],
},
},
{
name: "list_directory",
description: "List contents of a directory",
inputSchema: {
type: "object",
properties: {
path: {
type: "string",
description: "Directory path to list",
},
},
required: ["path"],
},
},
],
};
});
// Handle tool calls
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
switch (name) {
case "read_file": {
const filePath = args.path as string;
const content = await fs.readFile(filePath, "utf-8");
return {
content: [{ type: "text", text: content }],
};
}
case "list_directory": {
const dirPath = args.path as string;
const entries = await fs.readdir(dirPath, { withFileTypes: true });
const listing = entries
.map((entry) => `${entry.isDirectory() ? "📁" : "📄"} ${entry.name}`)
.join("\n");
return {
content: [{ type: "text", text: listing }],
};
}
default:
throw new Error(`Unknown tool: ${name}`);
}
});
// Start server
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Filesystem MCP server running on stdio");
}
main();
3. Configure Claude Desktop
// ~/Library/Application Support/Claude/claude_desktop_config.json (macOS)
// %APPDATA%/Claude/claude_desktop_config.json (Windows)
{
"mcpServers": {
"filesystem": {
"command": "node",
"args": ["/absolute/path/to/my-filesystem-server/build/index.js"]
}
}
}
4. Build and Test
# Build TypeScript
npm run build
# Restart Claude Desktop (Cmd+Q and reopen)
# Server appears in 🔌 menu
Quick Start - Python Server
1. Create Server
# server.py
import asyncio
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp.types import Tool, TextContent
import json
import os
# Create server instance
app = Server("filesystem-server")
# Define tools
@app.list_tools()
async def list_tools() -> list[Tool]:
return [
Tool(
name="read_file",
description="Read contents of a file",
inputSchema={
"type": "object",
"properties": {
"path": {"type": "string", "description": "File path to read"}
},
"required": ["path"],
},
),
Tool(
name="list_directory",
description="List directory contents",
inputSchema={
"type": "object",
"properties": {
"path": {"type": "string", "description": "Directory path"}
},
"required": ["path"],
},
),
]
# Handle tool calls
@app.call_tool()
async def call_tool(name: str, arguments: dict) -> list[TextContent]:
if name == "read_file":
file_path = arguments["path"]
with open(file_path, "r") as f:
content = f.read()
return [TextContent(type="text", text=content)]
elif name == "list_directory":
dir_path = arguments["path"]
entries = os.listdir(dir_path)
listing = "\n".join(
f"{'📁' if os.path.isdir(os.path.join(dir_path, e)) else '📄'} {e}"
for e in entries
)
return [TextContent(type="text", text=listing)]
else:
raise ValueError(f"Unknown tool: {name}")
# Start server
async def main():
async with stdio_server() as (read_stream, write_stream):
await app.run(read_stream, write_stream, app.create_initialization_options())
if __name__ == "__main__":
asyncio.run(main())
2. Configure Claude Desktop
{
"mcpServers": {
"filesystem": {
"command": "python",
"args": ["/absolute/path/to/server.py"]
}
}
}
3. Test
# Test server standalone
python server.py
# Restart Claude Desktop
# Tools appear in 🔌 menu
Resources - Exposing Data to LLMs
Resources provide read-only access to data sources.
TypeScript Resource Example
import {
ListResourcesRequestSchema,
ReadResourceRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
// List available resources
server.setRequestHandler(ListResourcesRequestSchema, async () => {
return {
resources: [
{
uri: "file:///docs/readme.md",
name: "README",
description: "Project README documentation",
mimeType: "text/markdown",
},
{
uri: "file:///config/settings.json",
name: "Settings",
description: "Application settings",
mimeType: "application/json",
},
],
};
});
// Handle resource reads
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
const uri = request.params.uri;
if (uri.startsWith("file://")) {
const filePath = uri.replace("file://", "");
const content = await fs.readFile(filePath, "utf-8");
return {
contents: [
{
uri,
mimeType: "text/plain",
text: content,
},
],
};
}
throw new Error(`Unknown resource: ${uri}`);
});
Python Resource Example
from mcp.types import Resource, ResourceContent
@app.list_resources()
async def list_resources() -> list[Resource]:
return [
Resource(
uri="file:///docs/readme.md",
name="README",
description="Project README",
mimeType="text/markdown",
),
Resource(
uri="file:///config/settings.json",
name="Settings",
description="App settings",
mimeType="application/json",
),
]
@app.read_resource()
async def read_resource(uri: str) -> ResourceContent:
if uri.startswith("file://"):
file_path = uri.replace("file://", "")
with open(file_path, "r") as f:
content = f.read()
return ResourceContent(uri=uri, mimeType="text/plain", text=content)
raise ValueError(f"Unknown resource: {uri}")
Prompts - Reusable Templates
Prompts are templates that LLMs can use with arguments.
TypeScript Prompt Example
import {
ListPromptsRequestSchema,
GetPromptRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
// List prompts
server.setRequestHandler(ListPromptsRequestSchema, async () => {
return {
prompts: [
{
name: "code_review",
description: "Review code for best practices",
arguments: [
{
name: "language",
description: "Programming language",
required: true,
},
{
name: "code",
description: "Code to review",
required: true,
},
],
},
],
};
});
// Handle prompt requests
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
if (name === "code_review") {
const language = args?.language || "unknown";
const code = args?.code || "";
return {
messages: [
{
role: "user",
content: {
type: "text",
text: `Review this ${language} code for best practices, security issues, and improvements:\n\n\`\`\`${language}\n${code}\n\`\`\``,
},
},
],
};
}
throw new Error(`Unknown prompt: ${name}`);
});
Python Prompt Example
from mcp.types import Prompt, PromptMessage, PromptArgument
@app.list_prompts()
async def list_prompts() -> list[Prompt]:
return [
Prompt(
name="code_review",
description="Review code for best practices",
arguments=[
PromptArgument(
name="language", description="Programming language", required=True
),
PromptArgument(name="code", description="Code to review", required=True),
],
)
]
@app.get_prompt()
async def get_prompt(name: str, arguments: dict) -> list[PromptMessage]:
if name == "code_review":
language = arguments.get("language", "unknown")
code = arguments.get("code", "")
return [
PromptMessage(
role="user",
content={
"type": "text",
"text": f"Review this {language} code:\n\n```{language}\n{code}\n```",
},
)
]
raise ValueError(f"Unknown prompt: {name}")
Advanced Patterns
1. Error Handling
// TypeScript
server.setRequestHandler(CallToolRequestSchema, async (request) => {
try {
const { name, arguments: args } = request.params;
if (name === "risky_operation") {
// Validate inputs
if (!args.required_param) {
throw new Error("Missing required parameter: required_param");
}
// Perform operation with proper error handling
const result = await performRiskyOperation(args.required_param);
return {
content: [{ type: "text", text: JSON.stringify(result) }],
};
}
} catch (error) {
// Return error to LLM with helpful message
return {
content: [
{
type: "text",
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
},
],
isError: true,
};
}
});
# Python
@app.call_tool()
async def call_tool(name: str, arguments: dict) -> list[TextContent]:
try:
if name == "risky_operation":
if "required_param" not in arguments:
raise ValueError("Missing required parameter: required_param")
result = await perform_risky_operation(arguments["required_param"])
return [TextContent(type="text", text=json.dumps(result))]
except Exception as e:
return [TextContent(type="text", text=f"Error: {str(e)}", isError=True)]
2. Async Operations
// TypeScript - Async API calls
import axios from "axios";
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
if (name === "fetch_api_data") {
const url = args.url as string;
const response = await axios.get(url);
return {
content: [
{
type: "text",
text: JSON.stringify(response.data, null, 2),
},
],
};
}
});
# Python - Async database queries
import aiosqlite
@app.call_tool()
async def call_tool(name: str, arguments: dict) -> list[TextContent]:
if name == "query_database":
query = arguments["query"]
async with aiosqlite.connect("database.db") as db:
async with db.execute(query) as cursor:
rows = await cursor.fetchall()
result = json.dumps(rows)
return [TextContent(type="text", text=result)]
3. Environment Variables & Configuration
// TypeScript - Load config from environment
import dotenv from "dotenv";
dotenv.config();
const API_KEY = process.env.API_KEY;
const BASE_URL = process.env.BASE_URL || "https://api.example.com";
server.setRequestHandler(CallToolRequestSchema, async (request) => {
if (request.params.name === "api_call") {
const response = await fetch(`${BASE_URL}/endpoint`, {
headers: { Authorization: `Bearer ${API_KEY}` },
});
// ...
}
});
# Python - Load config from environment
import os
from dotenv import load_dotenv
load_dotenv()
API_KEY = os.getenv("API_KEY")
BASE_URL = os.getenv("BASE_URL", "https://api.example.com")
@app.call_tool()
async def call_tool(name: str, arguments: dict) -> list[TextContent]:
if name == "api_call":
headers = {"Authorization": f"Bearer {API_KEY}"}
async with aiohttp.ClientSession() as session:
async with session.get(f"{BASE_URL}/endpoint", headers=headers) as resp:
data = await resp.json()
return [TextContent(type="text", text=json.dumps(data))]
4. Streaming Responses (Large Data)
// TypeScript - Stream large file contents
server.setRequestHandler(CallToolRequestSchema, async (request) => {
if (request.params.name === "read_large_file") {
const filePath = request.params.arguments.path as string;
const stream = fs.createReadStream(filePath, { encoding: "utf-8" });
let content = "";
for await (const chunk of stream) {
content += chunk;
// Could yield chunks incrementally in future MCP versions
}
return {
content: [{ type: "text", text: content }],
};
}
});
5. Dynamic Tool Registration
// TypeScript - Register tools from config
interface ToolConfig {
name: string;
description: string;
schema: object;
handler: (args: any) => Promise;
}
const toolRegistry = new Map();
function registerTool(config: ToolConfig) {
toolRegistry.set(config.name, config);
}
// Register custom tools
registerTool({
name: "custom_tool",
description: "Dynamically registered tool",
schema: {
type: "object",
properties: {
input: { type: "string" },
},
},
handler: async (args) => {
return { result: `Processed: ${args.input}` };
},
});
// List tools dynamically
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: Array.from(toolRegistry.values()).map((tool) => ({
name: tool.name,
description: tool.description,
inputSchema
…
## Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- **Author:** [bobmatnyc](https://github.com/bobmatnyc)
- **Source:** [bobmatnyc/claude-mpm-skills](https://github.com/bobmatnyc/claude-mpm-skills)
- **License:** MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.