{
  "schemaVersion": "1.0",
  "item": {
    "slug": "afrexai-mcp-engineering",
    "name": "MCP Engineering",
    "source": "tencent",
    "type": "skill",
    "category": "开发工具",
    "sourceUrl": "https://clawhub.ai/1kalin/afrexai-mcp-engineering",
    "canonicalUrl": "https://clawhub.ai/1kalin/afrexai-mcp-engineering",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadMode": "redirect",
    "downloadUrl": "/downloads/afrexai-mcp-engineering",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=afrexai-mcp-engineering",
    "sourcePlatform": "tencent",
    "targetPlatform": "OpenClaw",
    "installMethod": "Manual import",
    "extraction": "Extract archive",
    "prerequisites": [
      "OpenClaw"
    ],
    "packageFormat": "ZIP package",
    "includedAssets": [
      "README.md",
      "SKILL.md"
    ],
    "primaryDoc": "SKILL.md",
    "quickSetup": [
      "Download the package from Yavira.",
      "Extract the archive and review SKILL.md first.",
      "Import or place the package into your OpenClaw setup."
    ],
    "agentAssist": {
      "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
      "steps": [
        "Download the package from Yavira.",
        "Extract it into a folder your agent can access.",
        "Paste one of the prompts below and point your agent at the extracted folder."
      ],
      "prompts": [
        {
          "label": "New install",
          "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Then review README.md for any prerequisites, environment setup, or post-install checks. Tell me what you changed and call out any manual steps you could not complete."
        },
        {
          "label": "Upgrade existing",
          "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Then review README.md for any prerequisites, environment setup, or post-install checks. Summarize what changed and any follow-up checks I should run."
        }
      ]
    },
    "sourceHealth": {
      "source": "tencent",
      "status": "healthy",
      "reason": "direct_download_ok",
      "recommendedAction": "download",
      "checkedAt": "2026-04-30T16:55:25.780Z",
      "expiresAt": "2026-05-07T16:55:25.780Z",
      "httpStatus": 200,
      "finalUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=network",
      "contentType": "application/zip",
      "probeMethod": "head",
      "details": {
        "probeUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=network",
        "contentDisposition": "attachment; filename=\"network-1.0.0.zip\"",
        "redirectLocation": null,
        "bodySnippet": null
      },
      "scope": "source",
      "summary": "Source download looks usable.",
      "detail": "Yavira can redirect you to the upstream package for this source.",
      "primaryActionLabel": "Download for OpenClaw",
      "primaryActionHref": "/downloads/afrexai-mcp-engineering"
    },
    "validation": {
      "installChecklist": [
        "Use the Yavira download entry.",
        "Review SKILL.md after the package is downloaded.",
        "Confirm the extracted package contains the expected setup assets."
      ],
      "postInstallChecks": [
        "Confirm the extracted package includes the expected docs or setup files.",
        "Validate the skill or prompts are available in your target agent workspace.",
        "Capture any manual follow-up steps the agent could not complete."
      ]
    },
    "downloadPageUrl": "https://openagent3.xyz/downloads/afrexai-mcp-engineering",
    "agentPageUrl": "https://openagent3.xyz/skills/afrexai-mcp-engineering/agent",
    "manifestUrl": "https://openagent3.xyz/skills/afrexai-mcp-engineering/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/afrexai-mcp-engineering/agent.md"
  },
  "agentAssist": {
    "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
    "steps": [
      "Download the package from Yavira.",
      "Extract it into a folder your agent can access.",
      "Paste one of the prompts below and point your agent at the extracted folder."
    ],
    "prompts": [
      {
        "label": "New install",
        "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Then review README.md for any prerequisites, environment setup, or post-install checks. Tell me what you changed and call out any manual steps you could not complete."
      },
      {
        "label": "Upgrade existing",
        "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Then review README.md for any prerequisites, environment setup, or post-install checks. Summarize what changed and any follow-up checks I should run."
      }
    ]
  },
  "documentation": {
    "source": "clawhub",
    "primaryDoc": "SKILL.md",
    "sections": [
      {
        "title": "MCP Engineering — Complete Model Context Protocol System",
        "body": "Build, integrate, secure, and scale MCP servers and clients. From first server to production multi-tool architecture."
      },
      {
        "title": "When to Use",
        "body": "Building an MCP server (any language)\nIntegrating MCP tools into an AI agent\nDebugging MCP connection/auth issues\nDesigning multi-server architectures\nSecuring MCP endpoints for production\nEvaluating which MCP servers to use"
      },
      {
        "title": "What MCP Is",
        "body": "Model Context Protocol = standardized way for AI agents to call external tools. Think of it as \"USB for AI\" — one protocol, any tool."
      },
      {
        "title": "Architecture",
        "body": "Agent (Client) ←→ MCP Transport ←→ MCP Server ←→ External Service\n                   (stdio/HTTP)      (your code)    (API, DB, file system)"
      },
      {
        "title": "Core Concepts",
        "body": "ConceptWhat It DoesExampleServerExposes tools, resources, promptsA server wrapping the GitHub APIClientDiscovers and calls server capabilitiesOpenClaw, Claude Desktop, CursorToolA callable function with typed paramscreate_issue(title, body, labels)ResourceRead-only data the agent can accessfile://workspace/config.jsonPromptReusable prompt templatessummarize_pr(pr_url)TransportHow client↔server communicatestdio (local) or HTTP+SSE (remote)"
      },
      {
        "title": "Transport Decision",
        "body": "FactorstdioHTTP/SSEStreamable HTTPSetup complexityLowMediumMediumMulti-clientNoYesYesRemote accessNoYesYesStreamingVia stdioSSENativeAuth neededNo (local)YesYesBest forLocal dev, single agentProduction, sharedModern production\n\nRule: Start with stdio for development. Move to HTTP for production or multi-agent."
      },
      {
        "title": "Server Brief YAML",
        "body": "server_name: \"[service]-mcp\"\ndescription: \"[What this server does in one sentence]\"\ntransport: stdio | http\ntools:\n  - name: \"[verb_noun]\"\n    description: \"[What it does — be specific for LLM tool selection]\"\n    params:\n      - name: \"[param]\"\n        type: \"string | number | boolean | object | array\"\n        required: true | false\n        description: \"[What this param controls]\"\n    returns: \"[What the tool returns]\"\n    error_cases:\n      - \"[When/how it fails]\"\nresources:\n  - uri: \"[protocol://path]\"\n    description: \"[What data this exposes]\"\nexternal_dependencies:\n  - \"[API/service this wraps]\"\nauth_required: true | false\nauth_method: \"api_key | oauth2 | none\""
      },
      {
        "title": "TypeScript Server Template (stdio)",
        "body": "// server.ts — minimal MCP server\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { z } from \"zod\";\n\nconst server = new McpServer({\n  name: \"my-service\",\n  version: \"1.0.0\",\n});\n\n// Define a tool\nserver.tool(\n  \"get_item\",                          // tool name (verb_noun)\n  \"Fetch an item by ID\",               // description (LLM reads this)\n  { id: z.string().describe(\"Item ID\") }, // params with descriptions\n  async ({ id }) => {\n    try {\n      const result = await fetchItem(id);\n      return {\n        content: [{ type: \"text\", text: JSON.stringify(result, null, 2) }],\n      };\n    } catch (error) {\n      return {\n        content: [{ type: \"text\", text: `Error: ${error.message}` }],\n        isError: true,\n      };\n    }\n  }\n);\n\n// Define a resource\nserver.resource(\n  \"config\",\n  \"config://app\",\n  async (uri) => ({\n    contents: [{ uri: uri.href, mimeType: \"application/json\", text: JSON.stringify(config) }],\n  })\n);\n\n// Start\nconst transport = new StdioServerTransport();\nawait server.connect(transport);"
      },
      {
        "title": "Python Server Template (stdio)",
        "body": "# server.py — minimal MCP server\nfrom mcp.server import Server\nfrom mcp.server.stdio import stdio_server\nfrom mcp.types import Tool, TextContent\nimport json\n\nserver = Server(\"my-service\")\n\n@server.list_tools()\nasync def list_tools():\n    return [\n        Tool(\n            name=\"get_item\",\n            description=\"Fetch an item by ID\",\n            inputSchema={\n                \"type\": \"object\",\n                \"properties\": {\n                    \"id\": {\"type\": \"string\", \"description\": \"Item ID\"}\n                },\n                \"required\": [\"id\"]\n            }\n        )\n    ]\n\n@server.call_tool()\nasync def call_tool(name: str, arguments: dict):\n    if name == \"get_item\":\n        result = await fetch_item(arguments[\"id\"])\n        return [TextContent(type=\"text\", text=json.dumps(result, indent=2))]\n    raise ValueError(f\"Unknown tool: {name}\")\n\nasync def main():\n    async with stdio_server() as (read, write):\n        await server.run(read, write, server.create_initialization_options())\n\nif __name__ == \"__main__\":\n    import asyncio\n    asyncio.run(main())"
      },
      {
        "title": "Tool Design Rules",
        "body": "Verb-noun naming: create_issue, search_docs, update_config — never issue or doStuff\nDescriptions are critical: The LLM picks tools based on descriptions. Be specific. Include when NOT to use.\nGranular over god-tools: search_issues + get_issue + create_issue beats manage_issues\nReturn structured data: JSON over prose. Let the LLM format for the user.\nError messages for LLMs: Include what went wrong AND what to try next\nIdempotent where possible: create_or_update > create (prevents duplicates from retries)\nLimit output size: Paginate or truncate. A 10MB response kills the context window.\nInclude examples in descriptions: \"Search issues. Example: search_issues(query='bug label:critical')\""
      },
      {
        "title": "Tool Description Quality Checklist",
        "body": "Says what the tool DOES (not just the name restated)\n Mentions when to use vs. when NOT to use\n Each param has a description with format hints\n Return format is documented\n Edge cases mentioned (empty results, not found, etc.)"
      },
      {
        "title": "HTTP Server Template (TypeScript)",
        "body": "import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StreamableHTTPServerTransport } from \"@modelcontextprotocol/sdk/server/streamableHttp.js\";\nimport express from \"express\";\n\nconst app = express();\napp.use(express.json());\n\nconst server = new McpServer({ name: \"my-service\", version: \"1.0.0\" });\n// ... register tools ...\n\napp.post(\"/mcp\", async (req, res) => {\n  const transport = new StreamableHTTPServerTransport(\"/mcp\", res);\n  await server.connect(transport);\n  await transport.handleRequest(req, res);\n});\n\napp.listen(3001, () => console.log(\"MCP server on :3001\"));"
      },
      {
        "title": "Auth Patterns",
        "body": "API Key (simplest)\n\n// Middleware\nfunction authMiddleware(req, res, next) {\n  const key = req.headers[\"x-api-key\"] || req.headers.authorization?.replace(\"Bearer \", \"\");\n  if (!key || !validKeys.has(key)) {\n    return res.status(401).json({ error: \"Invalid API key\" });\n  }\n  req.userId = keyToUser.get(key);\n  next();\n}\n\nOAuth 2.0 (for user-scoped access)\n\n# MCP OAuth flow\n1. Client requests tool → server returns 401 with auth URL\n2. User completes OAuth in browser → gets access token\n3. Client stores token, includes in subsequent requests\n4. Server validates token, calls external API on user's behalf"
      },
      {
        "title": "Production Checklist",
        "body": "Rate limiting per client/key\n Request validation (schema check before execution)\n Structured logging (request ID, tool name, latency, status)\n Health check endpoint (/health)\n Graceful shutdown (finish in-flight requests)\n Timeout on external calls (don't let tools hang forever)\n Output size limits (truncate large responses)\n Error categorization (4xx client vs 5xx server)\n CORS if browser clients connect\n TLS in production (always HTTPS)"
      },
      {
        "title": "OpenClaw Configuration",
        "body": "# In openclaw config — stdio server\nmcpServers:\n  my-service:\n    command: \"node\"\n    args: [\"path/to/server.js\"]\n    env:\n      API_KEY: \"{{env.MY_SERVICE_API_KEY}}\"\n\n# HTTP server\nmcpServers:\n  my-service:\n    url: \"https://mcp.myservice.com/mcp\"\n    headers:\n      Authorization: \"Bearer {{env.MY_SERVICE_TOKEN}}\""
      },
      {
        "title": "Claude Desktop Configuration",
        "body": "{\n  \"mcpServers\": {\n    \"my-service\": {\n      \"command\": \"node\",\n      \"args\": [\"/path/to/server.js\"],\n      \"env\": { \"API_KEY\": \"your-key\" }\n    }\n  }\n}"
      },
      {
        "title": "Client-Side Tool Selection",
        "body": "When multiple MCP servers are connected, the agent sees ALL tools. Help the agent pick correctly:\n\nUnique tool names: Prefix if needed (github_search vs jira_search)\nClear descriptions: Disambiguate similar tools across servers\nDon't overload: 20-30 tools max across all servers. Beyond that, agents get confused."
      },
      {
        "title": "Multi-Server Architecture",
        "body": "Agent\n├── github-mcp (code: create_pr, search_code, list_issues)\n├── slack-mcp (comms: send_message, search_messages)\n├── postgres-mcp (data: query, list_tables)\n└── internal-mcp (business: get_customer, update_pipeline)\n\nPrinciple: One server per domain. Don't build a mega-server."
      },
      {
        "title": "Test Pyramid",
        "body": "/  E2E  \\        Agent actually uses the tool\n       / Integration \\    Tool calls real API (sandbox)\n      /    Unit       \\   Business logic without MCP layer"
      },
      {
        "title": "Unit Test Pattern",
        "body": "// Test the tool handler directly, no MCP transport\ndescribe(\"get_item\", () => {\n  it(\"returns item when found\", async () => {\n    mockDb.findById.mockResolvedValue({ id: \"123\", name: \"Test\" });\n    const result = await getItemHandler({ id: \"123\" });\n    expect(result.content[0].text).toContain(\"Test\");\n  });\n\n  it(\"returns error for missing item\", async () => {\n    mockDb.findById.mockResolvedValue(null);\n    const result = await getItemHandler({ id: \"missing\" });\n    expect(result.isError).toBe(true);\n  });\n\n  it(\"handles API timeout gracefully\", async () => {\n    mockDb.findById.mockRejectedValue(new Error(\"timeout\"));\n    const result = await getItemHandler({ id: \"123\" });\n    expect(result.isError).toBe(true);\n    expect(result.content[0].text).toContain(\"try again\");\n  });\n});"
      },
      {
        "title": "Integration Test with MCP Inspector",
        "body": "# Use the MCP Inspector to manually test\nnpx @modelcontextprotocol/inspector node server.js\n\n# Or use mcporter for CLI testing\nmcporter call my-service.get_item id=123\nmcporter list my-service --schema  # verify tool schemas"
      },
      {
        "title": "Test Checklist Per Tool",
        "body": "Happy path returns expected format\n Missing required params returns clear error\n Invalid param types return clear error\n Not-found cases handled (don't throw, return error content)\n Rate limit / quota exceeded handled\n Auth failure handled (expired token, invalid key)\n Large response truncated appropriately\n Timeout handled (external API slow)\n Concurrent calls don't interfere"
      },
      {
        "title": "1. API Wrapper (most common)",
        "body": "Wrap an existing REST/GraphQL API as MCP tools.\n\nExternal API → MCP Server → Agent\n\nKey decisions:\n\nMap 1 API endpoint → 1 MCP tool (usually)\nSimplify params (agent doesn't need every API option)\nAggregate related calls (e.g., get user + get user's repos = 1 tool)\nCache where safe (reduce API calls)"
      },
      {
        "title": "2. Database Query",
        "body": "Database → MCP Server → Agent\n\nSafety rules:\n\nRead-only by default. Write tools require explicit opt-in.\nParameterized queries only. NEVER interpolate agent input into SQL.\nRow limit on all queries (agent can ask for more if needed).\nSchema as a resource (let agent discover tables/columns)."
      },
      {
        "title": "3. File System",
        "body": "File System → MCP Server → Agent\n\nSafety rules:\n\nSandbox to specific directories. Never allow ../ traversal.\nRead-only by default. Write requires allowlist.\nSize limits on reads. Don't send 1GB files through MCP."
      },
      {
        "title": "4. Multi-Step Workflow",
        "body": "Some tools need to orchestrate multiple steps:\n\nserver.tool(\"deploy_service\", \"Build, test, and deploy a service\", {\n  service: z.string(),\n  environment: z.enum([\"staging\", \"production\"]),\n}, async ({ service, environment }) => {\n  // Step 1: Build\n  const buildResult = await build(service);\n  if (!buildResult.success) return error(`Build failed: ${buildResult.error}`);\n\n  // Step 2: Test\n  const testResult = await runTests(service);\n  if (!testResult.success) return error(`Tests failed: ${testResult.summary}`);\n\n  // Step 3: Deploy (only if build + tests pass)\n  if (environment === \"production\") {\n    // Extra safety: require confirmation resource\n    return {\n      content: [{\n        type: \"text\",\n        text: `Ready to deploy ${service} to production. Tests: ${testResult.passed}/${testResult.total} passed. Call confirm_deploy to proceed.`\n      }]\n    };\n  }\n  const deployResult = await deploy(service, environment);\n  return success(`Deployed ${service} to ${environment}: ${deployResult.url}`);\n});"
      },
      {
        "title": "5. Aggregator Server",
        "body": "Combine multiple data sources into unified tools:\n\nGitHub + Jira + PagerDuty → DevOps MCP Server → Agent\n\nOne get_service_status tool that queries all three and returns a unified view."
      },
      {
        "title": "Threat Model",
        "body": "ThreatRiskMitigationPrompt injection via tool outputAgent executes malicious instructions in API responseSanitize output, strip HTML/scriptsExcessive permissionsTool has write access it shouldn'tPrinciple of least privilege per toolData exfiltrationAgent sends sensitive data to wrong toolTool allowlists, audit loggingDenial of serviceAgent calls tool in infinite loopRate limiting, circuit breakersCredential leakageAPI keys in tool responsesStrip sensitive fields from outputSSRFAgent provides URL that hits internal networkURL allowlisting, no private IPs"
      },
      {
        "title": "Security Checklist",
        "body": "Every tool has minimum required permissions\n Write operations require explicit confirmation or are behind feature flags\n API keys/secrets NEVER appear in tool responses\n Output sanitized (no HTML, no executable content)\n Rate limits per tool AND per client\n Audit log: who called what tool, when, with what params\n Input validation before any external call\n URL parameters validated against allowlist (prevent SSRF)\n Timeout on every external call (max 30s default)\n Circuit breaker: disable tool if error rate > 50% for 5 min"
      },
      {
        "title": "Dangerous Tool Patterns (Avoid)",
        "body": "❌ server.tool(\"execute_sql\", ..., async ({ query }) => db.raw(query))\n❌ server.tool(\"run_command\", ..., async ({ cmd }) => exec(cmd))\n❌ server.tool(\"fetch_url\", ..., async ({ url }) => fetch(url))  // SSRF\n❌ server.tool(\"write_file\", ..., async ({ path, content }) => fs.writeFile(path, content))"
      },
      {
        "title": "Safe Alternatives",
        "body": "✅ Parameterized queries with allowlisted tables\n✅ Predefined commands with argument validation\n✅ URL allowlist + no private IP ranges\n✅ Write to specific directory + filename validation"
      },
      {
        "title": "Common Issues",
        "body": "SymptomLikely CauseFixTool not appearing in agentSchema error / server not connectedCheck mcporter list or client logs\"Connection refused\"Server not running or wrong portVerify process, check portTool times outExternal API slow or hangingAdd timeout, check API health\"Invalid params\"Schema mismatch between client/serverVerify schema with --schema flagAgent picks wrong toolAmbiguous descriptionsRewrite descriptions, add \"Use this when...\"Agent calls tool in loopTool returning confusing errorReturn clearer error with \"do NOT retry\"Large response crashesNo output truncationAdd pagination or character limitAuth errors intermittentToken expiryImplement token refresh"
      },
      {
        "title": "Debug Workflow",
        "body": "Verify server starts: node server.js — does it start without errors?\nList tools: mcporter list my-server --schema — are all tools registered?\nCall directly: mcporter call my-server.tool_name param=value — does it return expected output?\nCheck client config: Is the server path/URL correct? Are env vars set?\nRead client logs: Most clients log MCP connection errors\nTest with Inspector: npx @modelcontextprotocol/inspector for interactive debugging"
      },
      {
        "title": "Logging Template",
        "body": "server.tool(\"my_tool\", description, schema, async (params) => {\n  const requestId = crypto.randomUUID().slice(0, 8);\n  console.error(`[${requestId}] my_tool called:`, JSON.stringify(params));\n  const start = Date.now();\n  try {\n    const result = await doWork(params);\n    console.error(`[${requestId}] my_tool success: ${Date.now() - start}ms`);\n    return success(result);\n  } catch (error) {\n    console.error(`[${requestId}] my_tool error: ${error.message} (${Date.now() - start}ms)`);\n    return errorResponse(error.message);\n  }\n});\n\nNote: Use console.error for logs in stdio transport (stdout is reserved for MCP protocol)."
      },
      {
        "title": "Evaluating Existing MCP Servers",
        "body": "Score 0-5 per dimension:\n\nDimensionWhat to CheckMaintainedLast commit < 3 months? Issues addressed? Version > 1.0?SecureNo raw SQL/exec? Auth implemented? Input validated?Well-typedFull JSON Schema for all tools? Descriptions useful?TestedHas tests? CI passing?DocumentedSetup instructions? Tool descriptions? Examples?LightweightMinimal dependencies? Fast startup?\n\nScore < 15/30: Build your own. Score 15-24: Use with caution. Score 25+: Good to use."
      },
      {
        "title": "Popular MCP Server Categories",
        "body": "CategoryUse CaseExamplesCodeGitHub, GitLab, code searchgithub-mcp, gitlab-mcpDataPostgreSQL, SQLite, Snowflakepostgres-mcp, sqlite-mcpCommsSlack, Discord, emailslack-mcp, gmail-mcpDocsNotion, Confluence, Google Docsnotion-mcp, gdocs-mcpDevOpsAWS, GCP, Kubernetes, Terraformaws-mcp, k8s-mcpSearchBrave, Google, vector storesbrave-search, rag-mcpFilesLocal FS, S3, Google Drivefilesystem-mcp, s3-mcpCRMHubSpot, Salesforcehubspot-mcp, sfdc-mcp"
      },
      {
        "title": "Single Agent + Multiple Servers",
        "body": "Agent ──┬── github-mcp\n        ├── slack-mcp\n        ├── postgres-mcp\n        └── custom-mcp\n\nBest for: Most use cases. Simple, effective."
      },
      {
        "title": "Gateway Pattern",
        "body": "Agent ── MCP Gateway ──┬── server-1\n                       ├── server-2\n                       └── server-3\n\nGateway handles: auth, rate limiting, logging, routing.\nBest for: Enterprise, multi-tenant, compliance requirements."
      },
      {
        "title": "Agent-per-Domain",
        "body": "Orchestrator Agent\n├── Code Agent (github-mcp, gitlab-mcp)\n├── Data Agent (postgres-mcp, analytics-mcp)\n└── Comms Agent (slack-mcp, email-mcp)\n\nBest for: Complex workflows, specialized agents."
      },
      {
        "title": "Tool Count Guidelines",
        "body": "Total ToolsRecommendation1-10Great. Agent handles well.10-20Good. Ensure distinct descriptions.20-30Caution. Group by server, review descriptions.30-50Risk. Consider agent-per-domain pattern.50+Dangerous. Agent WILL pick wrong tools. Split or use gateway."
      },
      {
        "title": "Package Structure",
        "body": "my-mcp-server/\n├── src/\n│   ├── server.ts        # MCP server entry\n│   ├── tools/           # Tool handlers\n│   │   ├── search.ts\n│   │   └── create.ts\n│   ├── auth.ts          # Auth middleware\n│   └── config.ts        # Configuration\n├── tests/\n│   ├── tools.test.ts\n│   └── integration.test.ts\n├── package.json\n├── tsconfig.json\n├── README.md            # Setup + tool docs\n└── LICENSE"
      },
      {
        "title": "README Template for MCP Servers",
        "body": "# [Service] MCP Server\n\n[One sentence: what this enables]\n\n## Quick Start\n[3 steps max to get running]\n\n## Tools\n| Tool | Description | Params |\n|------|-------------|--------|\n[Table of all tools]\n\n## Configuration\n[Env vars, auth setup]\n\n## Examples\n[2-3 real usage examples with agent conversation]"
      },
      {
        "title": "npm Publishing",
        "body": "# package.json\n{\n  \"name\": \"@myorg/service-mcp\",\n  \"version\": \"1.0.0\",\n  \"bin\": { \"service-mcp\": \"./dist/server.js\" },\n  \"files\": [\"dist\"],\n  \"keywords\": [\"mcp\", \"model-context-protocol\", \"ai-tools\"]\n}\n\nnpm publish"
      },
      {
        "title": "Quality Rubric (0-100)",
        "body": "DimensionWeightWhat to ScoreTool design20%Names, descriptions, granularity, paramsSecurity20%Auth, input validation, output sanitization, least privilegeReliability15%Error handling, timeouts, circuit breakersTesting15%Unit + integration coverage, edge casesDocumentation10%Setup, tool docs, examplesPerformance10%Response time, output size, cachingMaintainability10%Code structure, types, logging\n\nScore 0-40: Not production ready. 40-70: Usable with caveats. 70-90: Solid. 90+: Excellent."
      },
      {
        "title": "Common Mistakes",
        "body": "MistakeFixGod-tool that does everythingSplit into focused toolsVague tool descriptionsWrite descriptions as if explaining to a new hireNo error handlingEvery external call wrapped in try/catchReturning raw API responsesShape output for agent consumptionNo rate limitingAdd per-tool and per-client limitsIgnoring output sizePaginate or truncate responsesHardcoded credentialsUse env vars or secret managerNo loggingCan't debug what you can't seeTesting only happy pathTest errors, timeouts, edge casesBuilding before checkingSearch for existing MCP server first"
      },
      {
        "title": "Natural Language Commands",
        "body": "\"Build an MCP server for [service]\" → Use Phase 2 templates\n\"Add a tool to my MCP server\" → Follow tool design rules\n\"Secure my MCP server\" → Phase 7 checklist\n\"Debug MCP connection issue\" → Phase 8 workflow\n\"Evaluate this MCP server\" → Phase 9 scoring\n\"Design multi-server architecture\" → Phase 10 patterns\n\"Publish my MCP server\" → Phase 11 structure\n\"Convert REST API to MCP\" → Phase 6 Pattern 1\n\"Add auth to my MCP server\" → Phase 3 auth patterns\n\"Test my MCP server\" → Phase 5 checklist\n\"How many tools is too many?\" → Phase 10 tool count table\n\"Review my tool descriptions\" → Phase 2 quality checklist"
      }
    ],
    "body": "MCP Engineering — Complete Model Context Protocol System\n\nBuild, integrate, secure, and scale MCP servers and clients. From first server to production multi-tool architecture.\n\nWhen to Use\nBuilding an MCP server (any language)\nIntegrating MCP tools into an AI agent\nDebugging MCP connection/auth issues\nDesigning multi-server architectures\nSecuring MCP endpoints for production\nEvaluating which MCP servers to use\nPhase 1: MCP Fundamentals\nWhat MCP Is\n\nModel Context Protocol = standardized way for AI agents to call external tools. Think of it as \"USB for AI\" — one protocol, any tool.\n\nArchitecture\nAgent (Client) ←→ MCP Transport ←→ MCP Server ←→ External Service\n                   (stdio/HTTP)      (your code)    (API, DB, file system)\n\nCore Concepts\nConcept\tWhat It Does\tExample\nServer\tExposes tools, resources, prompts\tA server wrapping the GitHub API\nClient\tDiscovers and calls server capabilities\tOpenClaw, Claude Desktop, Cursor\nTool\tA callable function with typed params\tcreate_issue(title, body, labels)\nResource\tRead-only data the agent can access\tfile://workspace/config.json\nPrompt\tReusable prompt templates\tsummarize_pr(pr_url)\nTransport\tHow client↔server communicate\tstdio (local) or HTTP+SSE (remote)\nTransport Decision\nFactor\tstdio\tHTTP/SSE\tStreamable HTTP\nSetup complexity\tLow\tMedium\tMedium\nMulti-client\tNo\tYes\tYes\nRemote access\tNo\tYes\tYes\nStreaming\tVia stdio\tSSE\tNative\nAuth needed\tNo (local)\tYes\tYes\nBest for\tLocal dev, single agent\tProduction, shared\tModern production\n\nRule: Start with stdio for development. Move to HTTP for production or multi-agent.\n\nPhase 2: Building Your First MCP Server\nServer Brief YAML\nserver_name: \"[service]-mcp\"\ndescription: \"[What this server does in one sentence]\"\ntransport: stdio | http\ntools:\n  - name: \"[verb_noun]\"\n    description: \"[What it does — be specific for LLM tool selection]\"\n    params:\n      - name: \"[param]\"\n        type: \"string | number | boolean | object | array\"\n        required: true | false\n        description: \"[What this param controls]\"\n    returns: \"[What the tool returns]\"\n    error_cases:\n      - \"[When/how it fails]\"\nresources:\n  - uri: \"[protocol://path]\"\n    description: \"[What data this exposes]\"\nexternal_dependencies:\n  - \"[API/service this wraps]\"\nauth_required: true | false\nauth_method: \"api_key | oauth2 | none\"\n\nTypeScript Server Template (stdio)\n// server.ts — minimal MCP server\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { z } from \"zod\";\n\nconst server = new McpServer({\n  name: \"my-service\",\n  version: \"1.0.0\",\n});\n\n// Define a tool\nserver.tool(\n  \"get_item\",                          // tool name (verb_noun)\n  \"Fetch an item by ID\",               // description (LLM reads this)\n  { id: z.string().describe(\"Item ID\") }, // params with descriptions\n  async ({ id }) => {\n    try {\n      const result = await fetchItem(id);\n      return {\n        content: [{ type: \"text\", text: JSON.stringify(result, null, 2) }],\n      };\n    } catch (error) {\n      return {\n        content: [{ type: \"text\", text: `Error: ${error.message}` }],\n        isError: true,\n      };\n    }\n  }\n);\n\n// Define a resource\nserver.resource(\n  \"config\",\n  \"config://app\",\n  async (uri) => ({\n    contents: [{ uri: uri.href, mimeType: \"application/json\", text: JSON.stringify(config) }],\n  })\n);\n\n// Start\nconst transport = new StdioServerTransport();\nawait server.connect(transport);\n\nPython Server Template (stdio)\n# server.py — minimal MCP server\nfrom mcp.server import Server\nfrom mcp.server.stdio import stdio_server\nfrom mcp.types import Tool, TextContent\nimport json\n\nserver = Server(\"my-service\")\n\n@server.list_tools()\nasync def list_tools():\n    return [\n        Tool(\n            name=\"get_item\",\n            description=\"Fetch an item by ID\",\n            inputSchema={\n                \"type\": \"object\",\n                \"properties\": {\n                    \"id\": {\"type\": \"string\", \"description\": \"Item ID\"}\n                },\n                \"required\": [\"id\"]\n            }\n        )\n    ]\n\n@server.call_tool()\nasync def call_tool(name: str, arguments: dict):\n    if name == \"get_item\":\n        result = await fetch_item(arguments[\"id\"])\n        return [TextContent(type=\"text\", text=json.dumps(result, indent=2))]\n    raise ValueError(f\"Unknown tool: {name}\")\n\nasync def main():\n    async with stdio_server() as (read, write):\n        await server.run(read, write, server.create_initialization_options())\n\nif __name__ == \"__main__\":\n    import asyncio\n    asyncio.run(main())\n\nTool Design Rules\nVerb-noun naming: create_issue, search_docs, update_config — never issue or doStuff\nDescriptions are critical: The LLM picks tools based on descriptions. Be specific. Include when NOT to use.\nGranular over god-tools: search_issues + get_issue + create_issue beats manage_issues\nReturn structured data: JSON over prose. Let the LLM format for the user.\nError messages for LLMs: Include what went wrong AND what to try next\nIdempotent where possible: create_or_update > create (prevents duplicates from retries)\nLimit output size: Paginate or truncate. A 10MB response kills the context window.\nInclude examples in descriptions: \"Search issues. Example: search_issues(query='bug label:critical')\"\nTool Description Quality Checklist\n Says what the tool DOES (not just the name restated)\n Mentions when to use vs. when NOT to use\n Each param has a description with format hints\n Return format is documented\n Edge cases mentioned (empty results, not found, etc.)\nPhase 3: HTTP Transport & Production Server\nHTTP Server Template (TypeScript)\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StreamableHTTPServerTransport } from \"@modelcontextprotocol/sdk/server/streamableHttp.js\";\nimport express from \"express\";\n\nconst app = express();\napp.use(express.json());\n\nconst server = new McpServer({ name: \"my-service\", version: \"1.0.0\" });\n// ... register tools ...\n\napp.post(\"/mcp\", async (req, res) => {\n  const transport = new StreamableHTTPServerTransport(\"/mcp\", res);\n  await server.connect(transport);\n  await transport.handleRequest(req, res);\n});\n\napp.listen(3001, () => console.log(\"MCP server on :3001\"));\n\nAuth Patterns\nAPI Key (simplest)\n// Middleware\nfunction authMiddleware(req, res, next) {\n  const key = req.headers[\"x-api-key\"] || req.headers.authorization?.replace(\"Bearer \", \"\");\n  if (!key || !validKeys.has(key)) {\n    return res.status(401).json({ error: \"Invalid API key\" });\n  }\n  req.userId = keyToUser.get(key);\n  next();\n}\n\nOAuth 2.0 (for user-scoped access)\n# MCP OAuth flow\n1. Client requests tool → server returns 401 with auth URL\n2. User completes OAuth in browser → gets access token\n3. Client stores token, includes in subsequent requests\n4. Server validates token, calls external API on user's behalf\n\nProduction Checklist\n Rate limiting per client/key\n Request validation (schema check before execution)\n Structured logging (request ID, tool name, latency, status)\n Health check endpoint (/health)\n Graceful shutdown (finish in-flight requests)\n Timeout on external calls (don't let tools hang forever)\n Output size limits (truncate large responses)\n Error categorization (4xx client vs 5xx server)\n CORS if browser clients connect\n TLS in production (always HTTPS)\nPhase 4: Client Integration\nOpenClaw Configuration\n# In openclaw config — stdio server\nmcpServers:\n  my-service:\n    command: \"node\"\n    args: [\"path/to/server.js\"]\n    env:\n      API_KEY: \"{{env.MY_SERVICE_API_KEY}}\"\n\n# HTTP server\nmcpServers:\n  my-service:\n    url: \"https://mcp.myservice.com/mcp\"\n    headers:\n      Authorization: \"Bearer {{env.MY_SERVICE_TOKEN}}\"\n\nClaude Desktop Configuration\n{\n  \"mcpServers\": {\n    \"my-service\": {\n      \"command\": \"node\",\n      \"args\": [\"/path/to/server.js\"],\n      \"env\": { \"API_KEY\": \"your-key\" }\n    }\n  }\n}\n\nClient-Side Tool Selection\n\nWhen multiple MCP servers are connected, the agent sees ALL tools. Help the agent pick correctly:\n\nUnique tool names: Prefix if needed (github_search vs jira_search)\nClear descriptions: Disambiguate similar tools across servers\nDon't overload: 20-30 tools max across all servers. Beyond that, agents get confused.\nMulti-Server Architecture\nAgent\n├── github-mcp (code: create_pr, search_code, list_issues)\n├── slack-mcp (comms: send_message, search_messages)\n├── postgres-mcp (data: query, list_tables)\n└── internal-mcp (business: get_customer, update_pipeline)\n\n\nPrinciple: One server per domain. Don't build a mega-server.\n\nPhase 5: Testing MCP Servers\nTest Pyramid\n        /  E2E  \\        Agent actually uses the tool\n       / Integration \\    Tool calls real API (sandbox)\n      /    Unit       \\   Business logic without MCP layer\n\nUnit Test Pattern\n// Test the tool handler directly, no MCP transport\ndescribe(\"get_item\", () => {\n  it(\"returns item when found\", async () => {\n    mockDb.findById.mockResolvedValue({ id: \"123\", name: \"Test\" });\n    const result = await getItemHandler({ id: \"123\" });\n    expect(result.content[0].text).toContain(\"Test\");\n  });\n\n  it(\"returns error for missing item\", async () => {\n    mockDb.findById.mockResolvedValue(null);\n    const result = await getItemHandler({ id: \"missing\" });\n    expect(result.isError).toBe(true);\n  });\n\n  it(\"handles API timeout gracefully\", async () => {\n    mockDb.findById.mockRejectedValue(new Error(\"timeout\"));\n    const result = await getItemHandler({ id: \"123\" });\n    expect(result.isError).toBe(true);\n    expect(result.content[0].text).toContain(\"try again\");\n  });\n});\n\nIntegration Test with MCP Inspector\n# Use the MCP Inspector to manually test\nnpx @modelcontextprotocol/inspector node server.js\n\n# Or use mcporter for CLI testing\nmcporter call my-service.get_item id=123\nmcporter list my-service --schema  # verify tool schemas\n\nTest Checklist Per Tool\n Happy path returns expected format\n Missing required params returns clear error\n Invalid param types return clear error\n Not-found cases handled (don't throw, return error content)\n Rate limit / quota exceeded handled\n Auth failure handled (expired token, invalid key)\n Large response truncated appropriately\n Timeout handled (external API slow)\n Concurrent calls don't interfere\nPhase 6: Common MCP Server Patterns\n1. API Wrapper (most common)\n\nWrap an existing REST/GraphQL API as MCP tools.\n\nExternal API → MCP Server → Agent\n\n\nKey decisions:\n\nMap 1 API endpoint → 1 MCP tool (usually)\nSimplify params (agent doesn't need every API option)\nAggregate related calls (e.g., get user + get user's repos = 1 tool)\nCache where safe (reduce API calls)\n2. Database Query\nDatabase → MCP Server → Agent\n\n\nSafety rules:\n\nRead-only by default. Write tools require explicit opt-in.\nParameterized queries only. NEVER interpolate agent input into SQL.\nRow limit on all queries (agent can ask for more if needed).\nSchema as a resource (let agent discover tables/columns).\n3. File System\nFile System → MCP Server → Agent\n\n\nSafety rules:\n\nSandbox to specific directories. Never allow ../ traversal.\nRead-only by default. Write requires allowlist.\nSize limits on reads. Don't send 1GB files through MCP.\n4. Multi-Step Workflow\n\nSome tools need to orchestrate multiple steps:\n\nserver.tool(\"deploy_service\", \"Build, test, and deploy a service\", {\n  service: z.string(),\n  environment: z.enum([\"staging\", \"production\"]),\n}, async ({ service, environment }) => {\n  // Step 1: Build\n  const buildResult = await build(service);\n  if (!buildResult.success) return error(`Build failed: ${buildResult.error}`);\n\n  // Step 2: Test\n  const testResult = await runTests(service);\n  if (!testResult.success) return error(`Tests failed: ${testResult.summary}`);\n\n  // Step 3: Deploy (only if build + tests pass)\n  if (environment === \"production\") {\n    // Extra safety: require confirmation resource\n    return {\n      content: [{\n        type: \"text\",\n        text: `Ready to deploy ${service} to production. Tests: ${testResult.passed}/${testResult.total} passed. Call confirm_deploy to proceed.`\n      }]\n    };\n  }\n  const deployResult = await deploy(service, environment);\n  return success(`Deployed ${service} to ${environment}: ${deployResult.url}`);\n});\n\n5. Aggregator Server\n\nCombine multiple data sources into unified tools:\n\nGitHub + Jira + PagerDuty → DevOps MCP Server → Agent\n\n\nOne get_service_status tool that queries all three and returns a unified view.\n\nPhase 7: Security & Hardening\nThreat Model\nThreat\tRisk\tMitigation\nPrompt injection via tool output\tAgent executes malicious instructions in API response\tSanitize output, strip HTML/scripts\nExcessive permissions\tTool has write access it shouldn't\tPrinciple of least privilege per tool\nData exfiltration\tAgent sends sensitive data to wrong tool\tTool allowlists, audit logging\nDenial of service\tAgent calls tool in infinite loop\tRate limiting, circuit breakers\nCredential leakage\tAPI keys in tool responses\tStrip sensitive fields from output\nSSRF\tAgent provides URL that hits internal network\tURL allowlisting, no private IPs\nSecurity Checklist\n Every tool has minimum required permissions\n Write operations require explicit confirmation or are behind feature flags\n API keys/secrets NEVER appear in tool responses\n Output sanitized (no HTML, no executable content)\n Rate limits per tool AND per client\n Audit log: who called what tool, when, with what params\n Input validation before any external call\n URL parameters validated against allowlist (prevent SSRF)\n Timeout on every external call (max 30s default)\n Circuit breaker: disable tool if error rate > 50% for 5 min\nDangerous Tool Patterns (Avoid)\n❌ server.tool(\"execute_sql\", ..., async ({ query }) => db.raw(query))\n❌ server.tool(\"run_command\", ..., async ({ cmd }) => exec(cmd))\n❌ server.tool(\"fetch_url\", ..., async ({ url }) => fetch(url))  // SSRF\n❌ server.tool(\"write_file\", ..., async ({ path, content }) => fs.writeFile(path, content))\n\nSafe Alternatives\n✅ Parameterized queries with allowlisted tables\n✅ Predefined commands with argument validation\n✅ URL allowlist + no private IP ranges\n✅ Write to specific directory + filename validation\n\nPhase 8: Debugging & Troubleshooting\nCommon Issues\nSymptom\tLikely Cause\tFix\nTool not appearing in agent\tSchema error / server not connected\tCheck mcporter list or client logs\n\"Connection refused\"\tServer not running or wrong port\tVerify process, check port\nTool times out\tExternal API slow or hanging\tAdd timeout, check API health\n\"Invalid params\"\tSchema mismatch between client/server\tVerify schema with --schema flag\nAgent picks wrong tool\tAmbiguous descriptions\tRewrite descriptions, add \"Use this when...\"\nAgent calls tool in loop\tTool returning confusing error\tReturn clearer error with \"do NOT retry\"\nLarge response crashes\tNo output truncation\tAdd pagination or character limit\nAuth errors intermittent\tToken expiry\tImplement token refresh\nDebug Workflow\nVerify server starts: node server.js — does it start without errors?\nList tools: mcporter list my-server --schema — are all tools registered?\nCall directly: mcporter call my-server.tool_name param=value — does it return expected output?\nCheck client config: Is the server path/URL correct? Are env vars set?\nRead client logs: Most clients log MCP connection errors\nTest with Inspector: npx @modelcontextprotocol/inspector for interactive debugging\nLogging Template\nserver.tool(\"my_tool\", description, schema, async (params) => {\n  const requestId = crypto.randomUUID().slice(0, 8);\n  console.error(`[${requestId}] my_tool called:`, JSON.stringify(params));\n  const start = Date.now();\n  try {\n    const result = await doWork(params);\n    console.error(`[${requestId}] my_tool success: ${Date.now() - start}ms`);\n    return success(result);\n  } catch (error) {\n    console.error(`[${requestId}] my_tool error: ${error.message} (${Date.now() - start}ms)`);\n    return errorResponse(error.message);\n  }\n});\n\n\nNote: Use console.error for logs in stdio transport (stdout is reserved for MCP protocol).\n\nPhase 9: MCP Server Selection Guide\nEvaluating Existing MCP Servers\n\nScore 0-5 per dimension:\n\nDimension\tWhat to Check\nMaintained\tLast commit < 3 months? Issues addressed? Version > 1.0?\nSecure\tNo raw SQL/exec? Auth implemented? Input validated?\nWell-typed\tFull JSON Schema for all tools? Descriptions useful?\nTested\tHas tests? CI passing?\nDocumented\tSetup instructions? Tool descriptions? Examples?\nLightweight\tMinimal dependencies? Fast startup?\n\nScore < 15/30: Build your own. Score 15-24: Use with caution. Score 25+: Good to use.\n\nPopular MCP Server Categories\nCategory\tUse Case\tExamples\nCode\tGitHub, GitLab, code search\tgithub-mcp, gitlab-mcp\nData\tPostgreSQL, SQLite, Snowflake\tpostgres-mcp, sqlite-mcp\nComms\tSlack, Discord, email\tslack-mcp, gmail-mcp\nDocs\tNotion, Confluence, Google Docs\tnotion-mcp, gdocs-mcp\nDevOps\tAWS, GCP, Kubernetes, Terraform\taws-mcp, k8s-mcp\nSearch\tBrave, Google, vector stores\tbrave-search, rag-mcp\nFiles\tLocal FS, S3, Google Drive\tfilesystem-mcp, s3-mcp\nCRM\tHubSpot, Salesforce\thubspot-mcp, sfdc-mcp\nPhase 10: Architecture Patterns\nSingle Agent + Multiple Servers\nAgent ──┬── github-mcp\n        ├── slack-mcp\n        ├── postgres-mcp\n        └── custom-mcp\n\n\nBest for: Most use cases. Simple, effective.\n\nGateway Pattern\nAgent ── MCP Gateway ──┬── server-1\n                       ├── server-2\n                       └── server-3\n\n\nGateway handles: auth, rate limiting, logging, routing. Best for: Enterprise, multi-tenant, compliance requirements.\n\nAgent-per-Domain\nOrchestrator Agent\n├── Code Agent (github-mcp, gitlab-mcp)\n├── Data Agent (postgres-mcp, analytics-mcp)\n└── Comms Agent (slack-mcp, email-mcp)\n\n\nBest for: Complex workflows, specialized agents.\n\nTool Count Guidelines\nTotal Tools\tRecommendation\n1-10\tGreat. Agent handles well.\n10-20\tGood. Ensure distinct descriptions.\n20-30\tCaution. Group by server, review descriptions.\n30-50\tRisk. Consider agent-per-domain pattern.\n50+\tDangerous. Agent WILL pick wrong tools. Split or use gateway.\nPhase 11: Publishing MCP Servers\nPackage Structure\nmy-mcp-server/\n├── src/\n│   ├── server.ts        # MCP server entry\n│   ├── tools/           # Tool handlers\n│   │   ├── search.ts\n│   │   └── create.ts\n│   ├── auth.ts          # Auth middleware\n│   └── config.ts        # Configuration\n├── tests/\n│   ├── tools.test.ts\n│   └── integration.test.ts\n├── package.json\n├── tsconfig.json\n├── README.md            # Setup + tool docs\n└── LICENSE\n\nREADME Template for MCP Servers\n# [Service] MCP Server\n\n[One sentence: what this enables]\n\n## Quick Start\n[3 steps max to get running]\n\n## Tools\n| Tool | Description | Params |\n|------|-------------|--------|\n[Table of all tools]\n\n## Configuration\n[Env vars, auth setup]\n\n## Examples\n[2-3 real usage examples with agent conversation]\n\nnpm Publishing\n# package.json\n{\n  \"name\": \"@myorg/service-mcp\",\n  \"version\": \"1.0.0\",\n  \"bin\": { \"service-mcp\": \"./dist/server.js\" },\n  \"files\": [\"dist\"],\n  \"keywords\": [\"mcp\", \"model-context-protocol\", \"ai-tools\"]\n}\n\nnpm publish\n\nQuality Rubric (0-100)\nDimension\tWeight\tWhat to Score\nTool design\t20%\tNames, descriptions, granularity, params\nSecurity\t20%\tAuth, input validation, output sanitization, least privilege\nReliability\t15%\tError handling, timeouts, circuit breakers\nTesting\t15%\tUnit + integration coverage, edge cases\nDocumentation\t10%\tSetup, tool docs, examples\nPerformance\t10%\tResponse time, output size, caching\nMaintainability\t10%\tCode structure, types, logging\n\nScore 0-40: Not production ready. 40-70: Usable with caveats. 70-90: Solid. 90+: Excellent.\n\nCommon Mistakes\nMistake\tFix\nGod-tool that does everything\tSplit into focused tools\nVague tool descriptions\tWrite descriptions as if explaining to a new hire\nNo error handling\tEvery external call wrapped in try/catch\nReturning raw API responses\tShape output for agent consumption\nNo rate limiting\tAdd per-tool and per-client limits\nIgnoring output size\tPaginate or truncate responses\nHardcoded credentials\tUse env vars or secret manager\nNo logging\tCan't debug what you can't see\nTesting only happy path\tTest errors, timeouts, edge cases\nBuilding before checking\tSearch for existing MCP server first\nNatural Language Commands\n\"Build an MCP server for [service]\" → Use Phase 2 templates\n\"Add a tool to my MCP server\" → Follow tool design rules\n\"Secure my MCP server\" → Phase 7 checklist\n\"Debug MCP connection issue\" → Phase 8 workflow\n\"Evaluate this MCP server\" → Phase 9 scoring\n\"Design multi-server architecture\" → Phase 10 patterns\n\"Publish my MCP server\" → Phase 11 structure\n\"Convert REST API to MCP\" → Phase 6 Pattern 1\n\"Add auth to my MCP server\" → Phase 3 auth patterns\n\"Test my MCP server\" → Phase 5 checklist\n\"How many tools is too many?\" → Phase 10 tool count table\n\"Review my tool descriptions\" → Phase 2 quality checklist"
  },
  "trust": {
    "sourceLabel": "tencent",
    "provenanceUrl": "https://clawhub.ai/1kalin/afrexai-mcp-engineering",
    "publisherUrl": "https://clawhub.ai/1kalin/afrexai-mcp-engineering",
    "owner": "1kalin",
    "version": "1.0.0",
    "license": null,
    "verificationStatus": "Indexed source record"
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/afrexai-mcp-engineering",
    "downloadUrl": "https://openagent3.xyz/downloads/afrexai-mcp-engineering",
    "agentUrl": "https://openagent3.xyz/skills/afrexai-mcp-engineering/agent",
    "manifestUrl": "https://openagent3.xyz/skills/afrexai-mcp-engineering/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/afrexai-mcp-engineering/agent.md"
  }
}