Mcp server builder
Skill goharabbas321/zeoel-framework/all-skills/mcp-server-builder
Build custom MCP (Model Context Protocol) servers for AI tool integration. Covers server architecture, tool definitions, resource providers, and deployment.From its SKILL.md
npx -y skills add goharabbas321/zeoel-framework --skill mcp-server-builderAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
4.6 KB, ~1.1k tokens by cl100k_base, as published. Nobody here has run it
MCP Server Builder
Overview
The Model Context Protocol (MCP) allows AI agents to use external tools and data sources. This skill covers building custom MCP servers that expose your APIs, databases, and services as tools that AI agents can call.
When to Use
- Exposing your API as tools for Claude Code, Cursor, or other AI agents
- Creating custom integrations (database queries, file operations, API calls)
- Building internal developer tools accessible from AI coding assistants
- Connecting AI agents to proprietary data sources
Server Architecture
// server.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"
const server = new Server(
{ name: "my-mcp-server", version: "1.0.0" },
{ capabilities: { tools: {} } }
)
// List available tools
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
name: "query_database",
description: "Execute a read-only SQL query against the application database",
inputSchema: {
type: "object",
properties: {
query: { type: "string", description: "SQL SELECT query to execute" },
limit: { type: "number", description: "Max rows to return", default: 100 },
},
required: ["query"],
},
},
{
name: "search_docs",
description: "Search the documentation for relevant articles",
inputSchema: {
type: "object",
properties: {
query: { type: "string", description: "Search query" },
category: { type: "string", enum: ["api", "guides", "faq"] },
},
required: ["query"],
},
},
],
}))
// Handle tool calls
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params
switch (name) {
case "query_database": {
// Validate it's a SELECT query only
if (!args.query.trim().toUpperCase().startsWith("SELECT")) {
return { content: [{ type: "text", text: "Error: Only SELECT queries allowed" }] }
}
const results = await db.query(args.query, { limit: args.limit || 100 })
return { content: [{ type: "text", text: JSON.stringify(results, null, 2) }] }
}
case "search_docs": {
const results = await searchEngine.search(args.query, args.category)
return { content: [{ type: "text", text: JSON.stringify(results, null, 2) }] }
}
default:
throw new Error(`Unknown tool: ${name}`)
}
})
// Start server
const transport = new StdioServerTransport()
await server.connect(transport)
Configuration
// claude_desktop_config.json
{
"mcpServers": {
"my-server": {
"command": "node",
"args": ["path/to/server.js"],
"env": {
"DATABASE_URL": "postgresql://...",
"API_KEY": "..."
}
}
}
}
Resource Provider Pattern
import { ListResourcesRequestSchema, ReadResourceRequestSchema } from "@modelcontextprotocol/sdk/types.js"
server.setRequestHandler(ListResourcesRequestSchema, async () => ({
resources: [
{
uri: "docs://api/endpoints",
name: "API Endpoints Documentation",
mimeType: "text/markdown",
},
],
}))
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
const { uri } = request.params
if (uri === "docs://api/endpoints") {
const content = await fs.readFile("docs/api-endpoints.md", "utf-8")
return { contents: [{ uri, mimeType: "text/markdown", text: content }] }
}
throw new Error(`Resource not found: ${uri}`)
})
Guidelines
- Define clear tool descriptions — the AI uses these to decide when to call your tool
- Validate all inputs — never trust tool arguments
- Read-only by default — require explicit confirmation for write operations
- Return structured data — JSON is easier for AI to parse than prose
- Handle errors gracefully — return error messages, don't crash the server
- Use environment variables for secrets — never hardcode
Anti-Patterns
- ❌ Exposing write/delete operations without safeguards
- ❌ Vague tool descriptions (AI won't know when to use them)
- ❌ Returning huge payloads (keep responses under 10KB)
- ❌ Not validating inputs (SQL injection via tool arguments)
- ❌ Synchronous operations that block the server
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.