CtrlK
BlogDocsLog inGet started
Tessl Logo

nitinjain999/platform-skills

Production-grade platform engineering handbook — Kubernetes, Terraform, Flux CD, GitHub Actions, AWS, and more.

67

Quality

84%

Does it follow best practices?

Impact

No eval scenarios have been run

SecuritybySnyk

Passed

No known issues

Overview
Quality
Evals
Security
Files

mcp.mdreferences/

MCP (Model Context Protocol) Reference

AWS Multi-Account Profiles

For managing AWS MCP servers across multiple accounts (SSO, Granted, assumed-role chains, credential_process, team sharing):

→ See references/aws-mcp-profiles.md

Commands: /platform-skills:aws-profile · /platform-skills:mcp configure-aws


Protocol Fundamentals

MCP is a JSON-RPC 2.0 protocol that connects AI hosts (Claude Desktop, Claude Code) with servers exposing tools, resources, and prompts.

Message Lifecycle

Host (client)                    MCP Server
     │                                │
     │──── initialize ───────────────>│  negotiate capabilities
     │<─── initialized ───────────────│
     │                                │
     │──── tools/list ───────────────>│  discover tools
     │<─── { tools: [...] } ──────────│
     │                                │
     │──── tools/call ───────────────>│  invoke tool
     │<─── { content: [...] } ────────│
     │                                │
     │──── resources/list ───────────>│  discover resources
     │<─── { resources: [...] } ──────│
     │                                │
     │──── resources/read ───────────>│  read resource
     │<─── { contents: [...] } ───────│

Transport Options

TransportUse CaseNotes
stdioLocal CLI tools, Claude DesktopProcess-level isolation, simplest
SSE (HTTP)Remote servers, web servicesRequires auth layer
HTTP (Streamable)Production APIsPreferred for new remote servers

TypeScript SDK

Scaffold

npx @modelcontextprotocol/create-server my-server
cd my-server && npm install

Tool Registration with Zod

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.tool(
  "search_docs",
  "Search internal documentation by keyword",
  {
    query: z.string().min(1).describe("Search query"),
    limit: z.number().int().min(1).max(50).default(10),
  },
  async ({ query, limit }) => {
    const results = await searchIndex(query, limit);
    return {
      content: [{ type: "text", text: JSON.stringify(results) }],
    };
  }
);

Resource Provider

server.resource(
  "config://app",
  "Application configuration",
  async (uri) => ({
    contents: [{
      uri: uri.href,
      text: JSON.stringify(getConfig()),
      mimeType: "application/json",
    }],
  })
);

// Parameterised resource template
server.resource(
  "user://{userId}/profile",
  "User profile by ID",
  async (uri, { userId }) => ({
    contents: [{
      uri: uri.href,
      text: JSON.stringify(await getUserProfile(userId)),
      mimeType: "application/json",
    }],
  })
);

Prompt Template

server.prompt(
  "summarise_pr",
  "Summarise a pull request for a code review",
  {
    pr_url: z.string().url(),
    style: z.enum(["brief", "detailed"]).default("brief"),
  },
  async ({ pr_url, style }) => ({
    messages: [{
      role: "user",
      content: {
        type: "text",
        text: `Summarise this PR in ${style} style: ${pr_url}`,
      },
    }],
  })
);

stdio Transport

const transport = new StdioServerTransport();
await server.connect(transport);

HTTP/SSE Transport (remote)

import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
import express from "express";

const app = express();
const transports = new Map<string, SSEServerTransport>();

app.get("/sse", async (req, res) => {
  const transport = new SSEServerTransport("/message", res);
  transports.set(transport.sessionId, transport);
  await server.connect(transport);
});

app.post("/message", async (req, res) => {
  const sessionId = req.query.sessionId as string;
  const transport = transports.get(sessionId);
  await transport?.handlePostMessage(req, res);
});

app.listen(3000);

Python SDK (FastMCP)

Scaffold

pip install mcp

Tool with Pydantic Validation

import json

from mcp.server.fastmcp import FastMCP
from pydantic import BaseModel, Field

mcp = FastMCP("my-server")


class SearchInput(BaseModel):
    query: str = Field(description="Search query string")
    limit: int = Field(default=10, ge=1, le=50, description="Maximum results")


@mcp.tool()
async def search_docs(input: SearchInput) -> str:
    """Search internal documentation by keyword."""
    results = await search_index(input.query, input.limit)
    return json.dumps(results)

Resource

@mcp.resource("config://app")
async def app_config() -> str:
    """Expose application configuration."""
    return json.dumps(get_config())

@mcp.resource("user://{user_id}/profile")
async def user_profile(user_id: str) -> str:
    """User profile by ID."""
    return json.dumps(await get_user_profile(user_id))

Run

if __name__ == "__main__":
    mcp.run()        # stdio (default)
    # mcp.run(transport="sse")   # SSE

Schema Design

Zod Best Practices (TypeScript)

// Good — narrow, descriptive schemas
const InputSchema = z.object({
  environment: z.enum(["dev", "staging", "prod"]),
  timeout_ms: z.number().int().min(100).max(30_000).default(5_000),
  tags: z.array(z.string().max(64)).max(20).optional(),
});

// Bad — overly permissive
const BadSchema = z.object({
  data: z.any(),        // ❌ no validation
  config: z.object({}), // ❌ empty object
});

Pydantic Best Practices (Python)

from pydantic import BaseModel, Field, validator

class SearchInput(BaseModel):
    query: str = Field(..., min_length=1, max_length=500)
    limit: int = Field(10, ge=1, le=50)
    filters: list[str] = Field(default_factory=list)

    @validator("filters")
    def no_empty_filters(cls, v):
        return [f.strip() for f in v if f.strip()]

Error Handling

// TypeScript — return structured errors, never throw to client
server.tool("risky_op", "...", { id: z.string() }, async ({ id }) => {
  try {
    const result = await performOperation(id);
    return { content: [{ type: "text", text: JSON.stringify(result) }] };
  } catch (err) {
    return {
      content: [{ type: "text", text: `Error: ${err.message}` }],
      isError: true,
    };
  }
});
# Python — return error content, never let exceptions propagate unhandled
@mcp.tool()
async def risky_op(id: str) -> str:
    try:
        return json.dumps(await perform_operation(id))
    except OperationError as e:
        return f"Error: {e}"

Testing and Debugging

MCP Inspector

# Launch interactive protocol debugger
npx @modelcontextprotocol/inspector node dist/index.js

Verify:

  • Tools appear in the tool list
  • Schemas reject invalid inputs with clear messages
  • Successful calls return well-formed content arrays
  • Error calls set isError: true

Protocol Smoke Test (curl)

# List tools via stdio
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' \
  | node dist/index.js

Security

Authentication (HTTP transport)

app.use((req, res, next) => {
  const token = req.headers.authorization?.split(" ")[1];
  if (!verifyToken(token)) return res.status(401).json({ error: "Unauthorized" });
  next();
});

Rate Limiting

import rateLimit from "express-rate-limit";

app.use("/message", rateLimit({
  windowMs: 60 * 1000,
  max: 100,
  message: { error: "Too many requests" },
}));

Secrets — Never in Tool Responses

// ❌ Never expose credentials in tool output
return { content: [{ type: "text", text: JSON.stringify({ apiKey: process.env.SECRET }) }] };

// ✅ Return only what the client needs
return { content: [{ type: "text", text: JSON.stringify({ status: "authenticated" }) }] };

Deployment Checklist

  • All tool inputs validated with Zod or Pydantic schemas
  • Error paths return isError: true, not unhandled exceptions
  • No credentials or secrets in resource content or tool responses
  • Authentication on HTTP/SSE transports
  • Rate limiting configured
  • Protocol compliance verified with MCP Inspector
  • Environment variables used for all secrets (process.env / os.environ)
  • Logging of tool calls (without sensitive param values)

BEFORE_AFTER.md

CHANGELOG.md

CODE_OF_CONDUCT.md

COMMANDS.md

CONTRIBUTING.md

EDITOR_INTEGRATIONS.md

GETTING_STARTED.md

HOW_IT_WORKS.md

install.sh

INSTALLATION.md

LAUNCH.md

PROMPTS.md

QUICKSTART.md

README.md

renovate.json

SECURITY.md

SKILL.md

tessl.json

tile.json