Install
$ agentstack add skill-viktorbezdek-skillstack-mcp-server ✓ 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 No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ 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.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
MCP Server Development
Overview
Comprehensive skill for developing Model Context Protocol (MCP) servers. MCP is a standardized protocol that enables AI agents (like Claude) to access external tools, data sources, and services through a unified interface.
Covers: MCP protocol fundamentals, building servers in Python (FastMCP) and TypeScript, agent-centric tool design, Claude Code integration (plugins, skills, hooks), production deployment, evaluation-driven development, and plugin packaging.
When to Use
- Building new MCP servers from scratch
- Integrating external APIs or services as MCP tools
- Creating Claude Code plugins
- Designing tools optimized for AI agent consumption
- Configuring MCP servers for Claude Desktop or other clients
- Writing evaluations to test MCP server quality
- Implementing security, caching, or production patterns
When NOT to Use
- Designing tool interfaces or consolidation patterns for agents (use tool-design)
- Prompt engineering or prompt optimization (use prompt-engineering)
- Building the actual business logic your tools wrap (that's application development)
- Debugging Claude's behavior when calling tools (that's a Claude usage issue)
Decision Tree
What are you building?
│
├─ New MCP server
│ ├─ Python codebase or data/ML integration? → FastMCP (Python)
│ ├─ TypeScript/Node.js codebase? → @modelcontextprotocol/sdk (TypeScript)
│ └─ Need both? → Build in Python first, add TypeScript wrapper if needed
│
├─ Existing server needs improvement
│ ├─ Tools return inconsistent formats? → Add output schemas + CHARACTER_LIMIT
│ ├─ Tools fail on edge cases? → Add validation (Pydantic/Zod) + error handling
│ ├─ Context window overflow? → Optimize responses (paginate, truncate, summarize)
│ └─ Security concerns? → Add path validation, destructiveHint, confirmation flags
│
├─ Deploying to production
│ ├─ Local only? → STDIO transport
│ ├─ Remote service? → Streamable HTTP transport
│ ├─ Server-to-client notifications or streaming? → Streamable HTTP with optional SSE responses
│ └─ Older client compatibility required? → Also expose legacy HTTP+SSE endpoints
│
└─ Not sure if MCP is the right approach
├─ Wrapping an API for Claude? → Yes, MCP server
├─ Building a full web application? → No, use Next.js/Python web framework
└─ Just need Claude to read files? → No, Claude can do that natively
Quick Start
Language Selection
Choose Python (FastMCP) when: Primary codebase is Python, integrating with data science/ML, or need rapid prototyping.
Choose TypeScript when: Primary codebase is Node.js/TypeScript, building full-stack apps, or need advanced type safety.
Python Quick Start (FastMCP)
from fastmcp import FastMCP
from pydantic import Field
from typing import Annotated
mcp = FastMCP("my-server")
@mcp.tool()
def search_items(
query: str,
limit: Annotated[int, Field(ge=1, le=100)] = 10
) -> dict:
"""Search for items matching the query."""
results = perform_search(query, limit)
return {"results": results, "count": len(results)}
@mcp.resource("data://config")
def get_config() -> dict:
return {"setting": "value"}
if __name__ == "__main__":
mcp.run() # STDIO transport (default)
TypeScript Quick Start
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" });
server.registerTool("search_items", {
title: "Search Items",
description: "Search for items matching the query",
inputSchema: z.object({
query: z.string(),
limit: z.number().int().min(1).max(100).default(10),
}).strict(),
annotations: { readOnlyHint: true },
}, async (params) => {
const results = await performSearch(params.query, params.limit);
return { content: [{ type: "text", text: JSON.stringify({ results, count: results.length }, null, 2) }] };
});
const transport = new StdioServerTransport();
await server.connect(transport);
Core Concepts
MCP Components
| Component | Purpose | Example | |-----------|---------|---------| | Tools | Executable functions for AI to call | search_repos, create_issue | | Resources | Read-only data sources | data://config, file://readme.md | | Prompts | Reusable prompt templates | explain_code, summarize_document |
Transport Types
| Transport | Use Case | |-----------|----------| | STDIO | Local processes, Claude Desktop (default, most common) | | Streamable HTTP | Remote services; one MCP endpoint supporting POST and optional GET/SSE | | Legacy HTTP+SSE | Backwards compatibility for clients pinned to the 2024-11-05 transport |
Current MCP transport guidance defines stdio and Streamable HTTP as the standard transports. Do not design a new remote server as separate "HTTP" and "SSE" transports. Streamable HTTP uses HTTP POST for JSON-RPC messages and may use SSE to stream multiple server messages from the MCP endpoint. For compatibility, older clients may still need the legacy HTTP+SSE pair alongside the new endpoint.
MCP Configuration
{
"mcpServers": {
"server-name": {
"command": "python",
"args": ["-m", "my_server"],
"env": {"API_KEY": "***"}
}
}
}
Anti-Patterns
| Anti-Pattern | Problem | Solution | |---|---|---| | Wrapping REST endpoints 1:1 as tools | Tools mirror API structure, not agent workflows | Design workflow-oriented tools: create_issue_with_labels instead of create_issue + add_labels | | No output format constraints | Responses bloat context window with irrelevant data | Enforce CHARACTER_LIMIT (25,000 chars) with truncation; return only what the agent needs | | Missing input validation | Malformed inputs crash the server or produce garbage | Python: Pydantic Field() with constraints; TypeScript: Zod schemas with .strict() | | Generic error messages | Agent cannot self-correct when tools fail | Return actionable errors: "Rate limit exceeded, retry after 60s" not "Error: 429" | | Tools without annotations | Agent doesn't know if a tool is safe or destructive | Set readOnlyHint, destructiveHint, idempotentHint annotations appropriately | | Unpaginated list operations | Large datasets overwhelm the context window | Implement pagination with limit/offset parameters | | Storing secrets in tool parameters | API keys leak into conversation logs | Use environment variables; reference via env in MCP config | | No response format standardization | Each tool returns data in a different structure | Support both JSON and Markdown; define consistent response schema per tool |
Best Practices Summary
Tool Design
- Design workflow-oriented tools, not API endpoint wrappers
- Use descriptive names with service prefix:
{service}_{action}_{resource} - Optimize for AI context window efficiency
- Provide actionable error messages
Input/Output
- Support both JSON and Markdown response formats
- Implement pagination for list operations
- Enforce CHARACTER_LIMIT (typically 25,000) with truncation
Validation
- Python: Use Pydantic
Field()with constraints - TypeScript: Use Zod schemas with
.strict() - Sanitize file paths and external identifiers
Security
- Validate file paths against allowed directories
- Use confirmation flags for destructive operations
- Set
destructiveHintannotation for state-changing tools - Store secrets in environment variables
- For Streamable HTTP, validate
Origin, bind local servers to localhost, require authentication, and include the negotiatedMCP-Protocol-Versionheader on HTTP requests
See [Extended Patterns](references/extended-patterns.md) for the full development workflow, Claude Code plugin integration, evaluation creation, complete reference file listings, and script documentation.
Additional Resources
- MCP Specification:
https://modelcontextprotocol.io/specification/2025-11-25 - MCP Transports:
https://modelcontextprotocol.io/specification/2025-11-25/basic/transports - FastMCP:
https://github.com/jlowin/fastmcp - Claude Code Docs:
https://docs.anthropic.com/claude-code
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: viktorbezdek
- Source: viktorbezdek/skillstack
- 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.