Claude Code Plugins

Community-maintained marketplace

Feedback

mcp-2025-patterns

@frankxai/ai-architect
0
0

Current best practices for Model Context Protocol server design, implementation, and integration. Updated patterns for 2025 MCP ecosystem including multi-server orchestration, security, and performance.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name mcp-2025-patterns
description Current best practices for Model Context Protocol server design, implementation, and integration. Updated patterns for 2026 MCP ecosystem including multi-server orchestration, security, and performance.
version 1.1.0
last_updated Tue Jan 06 2026 00:00:00 GMT+0000 (Coordinated Universal Time)
external_version MCP Specification 1.0, Next.js DevTools MCP
changelog - 1.1.0: Updated for MCP 1.0 stable spec, Next.js 16.1 DevTools MCP server - 1.0.0: Initial skill with 2025 MCP patterns and best practices

MCP 2026 Patterns

This skill covers current best practices for Model Context Protocol (MCP) server design, implementation, and integration as of early 2026.


MCP Architecture Fundamentals

Core Concepts

┌─────────────────────────────────────────────────────────────┐
│                    Claude Code (Host)                        │
├─────────────────────────────────────────────────────────────┤
│  MCP Client Layer                                           │
│  ├── Server Discovery & Connection                          │
│  ├── Tool Registration & Invocation                         │
│  ├── Resource Management                                    │
│  └── Prompt Templates                                       │
├─────────────────────────────────────────────────────────────┤
│  MCP Servers (Multiple)                                     │
│  ├── github-mcp (repositories, issues, PRs)                 │
│  ├── notion-mcp (pages, databases, blocks)                  │
│  ├── linear-mcp (issues, projects, cycles)                  │
│  ├── custom-mcp (your domain-specific tools)                │
│  └── ...                                                    │
└─────────────────────────────────────────────────────────────┘

MCP Server Components

  1. Tools: Functions the AI can invoke
  2. Resources: Data the AI can read
  3. Prompts: Template prompts for common tasks
  4. Notifications: Server-to-client events

Server Design Patterns

Pattern 1: Single Responsibility Server

// Good: Focused server for one domain
const server = new MCPServer({
  name: "github-mcp",
  version: "1.0.0"
});

// Tools all relate to GitHub
server.addTool("create_issue", createIssueHandler);
server.addTool("list_pulls", listPullsHandler);
server.addTool("merge_pr", mergePRHandler);

Pattern 2: Resource-First Design

// Define resources before tools
server.addResource({
  uri: "github://repos/{owner}/{repo}",
  name: "Repository",
  description: "GitHub repository data and metadata",
  mimeType: "application/json"
});

// Tools operate on resources
server.addTool({
  name: "get_repo",
  description: "Fetch repository details",
  inputSchema: {
    type: "object",
    properties: {
      owner: { type: "string" },
      repo: { type: "string" }
    },
    required: ["owner", "repo"]
  }
});

Pattern 3: Hierarchical Tool Organization

// Organize tools by domain/action
const tools = {
  // Issues domain
  "issues_create": createIssue,
  "issues_update": updateIssue,
  "issues_list": listIssues,
  "issues_close": closeIssue,

  // PRs domain
  "pulls_create": createPR,
  "pulls_merge": mergePR,
  "pulls_review": reviewPR,

  // Repos domain
  "repos_list": listRepos,
  "repos_create": createRepo
};

Tool Design Best Practices

Clear, Action-Oriented Names

// Good: Clear action + noun
"create_issue"
"list_repositories"
"merge_pull_request"
"search_code"

// Bad: Vague or ambiguous
"do_github"
"handle_request"
"process_data"

Comprehensive Input Schemas

server.addTool({
  name: "create_issue",
  description: "Create a new GitHub issue with title, body, labels, and assignees",
  inputSchema: {
    type: "object",
    properties: {
      owner: {
        type: "string",
        description: "Repository owner (user or org)"
      },
      repo: {
        type: "string",
        description: "Repository name"
      },
      title: {
        type: "string",
        description: "Issue title",
        minLength: 1,
        maxLength: 256
      },
      body: {
        type: "string",
        description: "Issue body (Markdown supported)"
      },
      labels: {
        type: "array",
        items: { type: "string" },
        description: "Labels to apply"
      },
      assignees: {
        type: "array",
        items: { type: "string" },
        description: "GitHub usernames to assign"
      }
    },
    required: ["owner", "repo", "title"]
  }
});

Structured Output Formats

// Return structured, predictable data
async function createIssue(params) {
  const issue = await github.issues.create({...});

  return {
    success: true,
    issue: {
      number: issue.number,
      url: issue.html_url,
      title: issue.title,
      state: issue.state,
      created_at: issue.created_at
    },
    // Include actionable next steps
    suggested_actions: [
      `Add labels: /api/issues/${issue.number}/labels`,
      `Assign team: /api/issues/${issue.number}/assignees`
    ]
  };
}

Security Patterns

Pattern 1: Credential Isolation

// Store credentials in environment, not code
const server = new MCPServer({
  name: "secure-server"
});

// Validate env vars at startup
const requiredEnv = ["API_KEY", "API_SECRET"];
for (const key of requiredEnv) {
  if (!process.env[key]) {
    throw new Error(`Missing required env var: ${key}`);
  }
}

// Never log or expose credentials
server.addTool("secure_action", async (params) => {
  // Use env vars directly, never pass as params
  const client = new APIClient({
    key: process.env.API_KEY // Not from params
  });
});

Pattern 2: Input Validation

import { z } from "zod";

const CreateIssueSchema = z.object({
  owner: z.string().regex(/^[a-zA-Z0-9-]+$/),
  repo: z.string().regex(/^[a-zA-Z0-9._-]+$/),
  title: z.string().min(1).max(256),
  body: z.string().max(65536).optional()
});

server.addTool("create_issue", async (params) => {
  // Validate before processing
  const validated = CreateIssueSchema.parse(params);

  // Safe to use validated data
  return await github.issues.create(validated);
});

Pattern 3: Rate Limiting

import { RateLimiter } from "rate-limiter";

const limiter = new RateLimiter({
  tokensPerInterval: 100,
  interval: "minute"
});

server.addTool("api_call", async (params) => {
  // Check rate limit before proceeding
  if (!await limiter.tryRemoveTokens(1)) {
    return {
      success: false,
      error: "Rate limit exceeded. Try again in a minute.",
      retry_after: 60
    };
  }

  return await performAPICall(params);
});

Pattern 4: Audit Logging

server.addTool("sensitive_action", async (params, context) => {
  // Log all sensitive operations
  await auditLog({
    action: "sensitive_action",
    params: sanitize(params), // Remove secrets
    user: context.user,
    timestamp: new Date().toISOString(),
    result: "pending"
  });

  try {
    const result = await performAction(params);
    await auditLog.update({ result: "success" });
    return result;
  } catch (error) {
    await auditLog.update({ result: "error", error: error.message });
    throw error;
  }
});

Multi-Server Orchestration

Pattern 1: Server Composition

// In Claude Code settings, compose servers:
{
  "mcpServers": {
    "github": {
      "command": "mcp-github",
      "env": { "GITHUB_TOKEN": "..." }
    },
    "linear": {
      "command": "mcp-linear",
      "env": { "LINEAR_API_KEY": "..." }
    },
    "notion": {
      "command": "mcp-notion",
      "env": { "NOTION_TOKEN": "..." }
    }
  }
}

Pattern 2: Cross-Server Workflows

When handling complex tasks, coordinate across servers:

1. Get issue from GitHub (github-mcp)
2. Create linked Linear ticket (linear-mcp)
3. Update project doc in Notion (notion-mcp)
4. Comment back on GitHub with links (github-mcp)

Claude orchestrates automatically based on task.

Pattern 3: Server Health Monitoring

// Each server should expose health endpoint
server.addTool("health_check", async () => {
  const checks = await Promise.all([
    checkAPIConnection(),
    checkDatabaseConnection(),
    checkCacheConnection()
  ]);

  return {
    status: checks.every(c => c.ok) ? "healthy" : "degraded",
    checks: checks,
    timestamp: new Date().toISOString()
  };
});

Performance Patterns

Pattern 1: Connection Pooling

// Reuse connections across requests
const pool = new ConnectionPool({
  max: 10,
  idleTimeout: 30000
});

server.addTool("db_query", async (params) => {
  const conn = await pool.acquire();
  try {
    return await conn.query(params.sql);
  } finally {
    pool.release(conn);
  }
});

Pattern 2: Caching

import { LRUCache } from "lru-cache";

const cache = new LRUCache({
  max: 1000,
  ttl: 1000 * 60 * 5 // 5 minutes
});

server.addTool("get_user", async (params) => {
  const cacheKey = `user:${params.id}`;

  // Check cache first
  const cached = cache.get(cacheKey);
  if (cached) return cached;

  // Fetch and cache
  const user = await fetchUser(params.id);
  cache.set(cacheKey, user);
  return user;
});

Pattern 3: Batch Operations

// Support batch operations to reduce round trips
server.addTool("batch_create_issues", async (params) => {
  const { issues } = params;

  // Process in parallel with concurrency limit
  const results = await pMap(
    issues,
    issue => createIssue(issue),
    { concurrency: 5 }
  );

  return {
    created: results.filter(r => r.success).length,
    failed: results.filter(r => !r.success).length,
    results
  };
});

Error Handling

Structured Error Responses

class MCPError extends Error {
  constructor(code, message, details = {}) {
    super(message);
    this.code = code;
    this.details = details;
  }

  toResponse() {
    return {
      success: false,
      error: {
        code: this.code,
        message: this.message,
        details: this.details,
        recoverable: this.isRecoverable(),
        suggested_action: this.getSuggestedAction()
      }
    };
  }
}

// Usage
throw new MCPError(
  "RATE_LIMITED",
  "GitHub API rate limit exceeded",
  {
    limit: 5000,
    remaining: 0,
    reset_at: "2025-12-19T12:00:00Z"
  }
);

Graceful Degradation

server.addTool("enriched_search", async (params) => {
  const results = await primarySearch(params);

  // Try to enrich, but don't fail if enrichment fails
  try {
    return await enrichResults(results);
  } catch (enrichError) {
    console.warn("Enrichment failed, returning basic results", enrichError);
    return {
      ...results,
      enrichment_status: "failed",
      enrichment_error: enrichError.message
    };
  }
});

Testing Patterns

Unit Testing Tools

import { describe, it, expect, vi } from "vitest";

describe("create_issue tool", () => {
  it("creates issue with valid params", async () => {
    const mockGithub = vi.fn().mockResolvedValue({
      number: 123,
      html_url: "https://github.com/..."
    });

    const result = await createIssueTool({
      owner: "test",
      repo: "test-repo",
      title: "Test issue"
    }, { github: mockGithub });

    expect(result.success).toBe(true);
    expect(result.issue.number).toBe(123);
  });

  it("validates required params", async () => {
    await expect(createIssueTool({ owner: "test" }))
      .rejects.toThrow("Missing required: repo, title");
  });
});

Integration Testing

describe("MCP Server Integration", () => {
  let server;
  let client;

  beforeAll(async () => {
    server = await startMCPServer();
    client = await connectMCPClient(server.url);
  });

  it("lists available tools", async () => {
    const tools = await client.listTools();
    expect(tools).toContain("create_issue");
    expect(tools).toContain("list_repositories");
  });

  it("executes tool and returns result", async () => {
    const result = await client.callTool("health_check", {});
    expect(result.status).toBe("healthy");
  });
});

FrankX System Integration

Current MCP Servers in Use

  • github-mcp: Repository management, issues, PRs
  • linear-mcp: Project management, issues, cycles
  • notion-mcp: Documentation, databases, pages
  • nano-banana-mcp: Image generation
  • n8n-mcp: Workflow automation
  • playwright-mcp: Browser automation

Best Practices for FrankX

  1. Server per domain: Keep MCPs focused (GitHub for code, Linear for tasks)
  2. Consistent naming: mcp__<server>__<action> format
  3. Graceful fallbacks: If MCP unavailable, suggest alternative
  4. Context awareness: Use right MCP for right task automatically

MCP servers extend Claude's capabilities with real-world integrations. Design them with clear responsibility, robust error handling, and security in mind.