import { z } from 'zod';
export interface ToolDefinition {
name: string;
description: string;
parameters: z.ZodTypeAny;
execute: (args: z.infer<typeof this.parameters>) => Promise<unknown>;
}
export const provisionServerTool: ToolDefinition = {
name: 'provision_compute_instance',
description: 'Spin up a cloud compute instance with specified region and tier',
parameters: z.object({
region: z.enum(['us-east-1', 'eu-west-1', 'ap-southeast-1']),
tier: z.enum(['standard', 'high-memory', 'gpu-accelerated']),
tags: z.record(z.string()).optional()
}),
async execute(args) {
// Actual cloud provider SDK call would live here
console.log(`Provisioning ${args.tier} instance in ${args.region}`);
return { instanceId: 'i-8f7a2c1d', status: 'pending', region: args.region };
}
};
Architecture Rationale: Using Zod for parameter validation ensures schema contracts are enforced before the model's output reaches execution. The tool knows nothing about when it should be called, what precedes it, or what follows. This isolation prevents business logic from leaking into execution primitives.
Step 2: Expose Capabilities via MCP Server
MCP servers decouple capability exposure from the consuming application. They run over standard I/O for local processes or HTTP with Server-Sent Events for remote deployments, supporting OAuth 2.1 for authentication. The server registers tools, resources, and prompts, allowing any compliant client to discover and invoke them.
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
const server = new McpServer({
name: 'infrastructure-provisioning',
version: '1.0.0'
});
server.tool(
provisionServerTool.name,
provisionServerTool.description,
provisionServerTool.parameters.shape,
async (params) => {
const result = await provisionServerTool.execute(params);
return {
content: [{ type: 'text', text: JSON.stringify(result) }]
};
}
);
// Resource primitive for read-only data
server.resource(
'cloud_regions',
'cloud://regions',
async () => ({
contents: [{
uri: 'cloud://regions',
mimeType: 'application/json',
text: JSON.stringify(['us-east-1', 'eu-west-1', 'ap-southeast-1'])
}]
})
);
const transport = new StdioServerTransport();
await server.connect(transport);
Architecture Rationale: MCP's bidirectional sampling capability allows servers to request model inference from the client, enabling interactive workflows that exceed simple request-response patterns. By standardizing on MCP, you eliminate the need to rebuild integration adapters for every new agent framework or host application. The same server works across Claude Desktop, VS Code extensions, or custom orchestration engines.
Step 3: Orchestrate with Skills
Skills operate at the highest abstraction layer. They combine system instructions, conditional logic, and tool selection strategies to guide agents through complex workflows. Skills do not execute code; they define the decision architecture.
# skills/provision_workflow.yaml
name: infrastructure_provisioning_workflow
description: "Orchestrate cloud resource provisioning with compliance checks"
version: "1.2.0"
system_prompt: |
You are an infrastructure automation agent. You must verify compliance before provisioning.
Never skip validation steps. Always log the final state.
tool_selection:
- provision_compute_instance
- check_compliance_policy
- notify_ops_team
workflow:
- step: validate_request
action: check_compliance_policy
condition: "region in ['us-east-1', 'eu-west-1']"
on_failure: notify_ops_team
- step: execute_provisioning
action: provision_compute_instance
depends_on: [validate_request]
retry_policy:
max_attempts: 2
backoff: exponential
- step: confirm_deployment
action: notify_ops_team
condition: "status == 'pending'"
Architecture Rationale: Skills encode domain knowledge that raw tool access cannot provide. The workflow defines sequence, branching, retry logic, and guardrails. By externalizing this into a structured configuration, you enable version control, peer review, and runtime validation of agent behavior without modifying underlying code.
Pitfall Guide
Explanation: Developers frequently overload tool descriptions and parameters with conditional logic, business rules, or multi-step instructions. This forces the model to parse unnecessary context, increasing token consumption and hallucination risk.
Fix: Keep tool schemas strictly atomic. Move conditional logic, thresholds, and sequencing into the skill layer. Validate inputs at the host level using strict schema enforcement before execution.
Explanation: Some teams assume MCP servers eliminate the need for tool definitions, attempting to route all logic through protocol primitives. MCP standardizes transport and discovery; it does not replace execution contracts.
Fix: Maintain clear separation. Define tools as executable functions, register them on the MCP server, and let the protocol handle routing. Do not embed execution logic inside MCP transport handlers.
3. Hardcoding Business Rules in Prompts
Explanation: Embedding compliance thresholds, approval limits, or routing logic directly into system prompts makes rules unversioned, untestable, and difficult to audit.
Fix: Externalize business rules into skill configurations or policy engines. Use structured YAML/JSON for workflows, and validate them against a schema before deployment. Prompts should define persona and constraints, not decision trees.
4. Ignoring Transport Timeout Constraints
Explanation: MCP servers running over HTTP+SSE introduce network latency and connection management overhead. Developers often assume stdio-like responsiveness, leading to silent failures or dropped sampling requests.
Fix: Implement explicit timeout handling, retry logic, and connection health checks. Use stdio for local development and single-process agents. Reserve HTTP+SSE for distributed deployments, and configure OAuth 2.1 token rotation to prevent authentication drift.
5. Monolithic Skill Configurations
Explanation: Writing skills as single, massive prompt blocks creates maintenance debt. Teams struggle to track changes, debug branching logic, or reuse components across workflows.
Fix: Decompose skills into modular workflow steps. Use dependency graphs to define execution order. Version control skill files separately from application code, and implement a skill registry for runtime loading and hot-swapping.
6. Neglecting Permission Boundaries at the Skill Layer
Explanation: Skills orchestrate tools, but without explicit permission mapping, agents can invoke destructive operations outside intended contexts.
Fix: Define capability scopes within skill configurations. Map each tool to a permission tier, and enforce runtime checks before execution. Implement a consent layer that requires explicit approval for high-risk operations, regardless of skill instructions.
Production Bundle
Action Checklist
Decision Matrix
| Scenario | Recommended Approach | Why | Cost Impact |
|---|
| Single-purpose agent with fixed tools | Direct SDK tool calling | Minimal overhead, simpler deployment | Low infrastructure cost |
| Multi-client ecosystem (IDE, desktop, custom apps) | MCP server exposure | Eliminates duplicate integration code, ensures protocol compliance | Higher initial setup, lower long-term maintenance |
| Complex multi-step workflows with compliance requirements | Skill-based orchestration | Centralizes business logic, enables versioning and auditing | Moderate configuration overhead, high reliability gain |
| High-frequency, low-latency operations | Direct tool execution | Avoids protocol serialization and transport latency | Optimal performance, limited portability |
| Cross-team capability sharing | MCP + standardized skill templates | Enables reusable primitives and consistent orchestration patterns | Higher coordination cost, scalable architecture |
Configuration Template
# mcp-server-config.yaml
server:
name: data-pipeline-orchestrator
version: "2.1.0"
transport:
type: http_sse
port: 8080
auth: oauth2.1
token_rotation_interval: 3600
capabilities:
tools:
- name: extract_dataset
description: "Pull structured data from source warehouse"
schema: ./schemas/extract_dataset.json
- name: transform_records
description: "Apply mapping rules and normalize fields"
schema: ./schemas/transform_records.json
- name: load_to_destination
description: "Write transformed data to target system"
schema: ./schemas/load_to_destination.json
resources:
- uri: pipeline://schemas
type: json_schema_registry
- uri: pipeline://logs
type: structured_event_stream
prompts:
- name: pipeline_diagnosis
template: ./prompts/diagnosis_template.md
security:
consent_required: true
high_risk_tools: ["load_to_destination"]
audit_logging: true
rate_limit:
requests_per_minute: 120
burst_limit: 30
Quick Start Guide
- Initialize the MCP server: Install the SDK, create a server instance, and register your atomic tools using strict schema validation. Configure transport based on deployment target (stdio for local, HTTP+SSE for remote).
- Define skill workflows: Create YAML configurations that map tools to sequential steps, add conditional branching, and enforce guardrails. Validate configurations against a schema before deployment.
- Connect a compliant client: Use any MCP-compatible host (Claude Desktop, VS Code extension, or custom agent framework) to discover and invoke capabilities. Verify bidirectional sampling works if your workflow requires interactive model requests.
- Enforce runtime boundaries: Implement permission mapping, consent prompts for high-risk operations, and audit logging. Monitor transport latency and configure timeout/retry policies to prevent silent failures.
- Iterate and version: Treat skills as infrastructure code. Version control configurations, implement rollback procedures, and establish a review process for workflow changes. Monitor agent behavior against skill specifications and adjust guardrails based on production telemetry.