| name | mcp-builder |
| description | Build MCP servers for LLM tool integration in Python (FastMCP), Node/TypeScript (MCP SDK), or C#/.NET (Microsoft MCP SDK). Use when authoring a new MCP server, evaluating a candidate MCP for the Plugin Mall, or diagnosing an MCP issue raised by a heir. |
MCP Builder
Build MCP servers for LLM tool integration in Python (FastMCP), Node/TypeScript
(MCP SDK), or C#/.NET (Microsoft MCP SDK).
When to Build vs Use Existing
Microsoft MCP Servers
Before building custom, check if Microsoft already provides one:
| Server | Type | Description |
|---|
| Azure MCP | Local | 48+ Azure services (Storage, KeyVault, Cosmos, SQL, etc.) |
| Foundry MCP | Remote | https://mcp.ai.azure.com - Models, deployments, evals, agents |
| Fabric MCP | Local | Microsoft Fabric APIs, OneLake, item definitions |
| Playwright MCP | Local | Browser automation and testing |
| GitHub MCP | Remote | https://api.githubcopilot.com/mcp |
Decision Matrix
| Scenario | Recommendation |
|---|
| Azure service integration | Use Azure MCP Server (48 services covered) |
| AI Foundry agents/evals | Use Foundry MCP remote server |
| Custom internal APIs | Build custom server (this guide) |
| Third-party SaaS integration | Build custom server (this guide) |
Shared Knowledge Gate
Before planning, evaluating, or designing a non-trivial MCP integration, consult
scout-knowledge-base for relevant prior
decisions, failure modes, procedures, and gotchas. Read only records whose
signals or preconditions match the integration, and treat them as context rather
than authority. If unavailable, state that once and continue with current
evidence; do not create a local fallback while designing.
Server Types
| Type | Transport | Use Case | Example |
|---|
| Local | stdio | Desktop apps, single-user, local dev | Azure MCP Server via NPM/Docker |
| Remote | Streamable HTTP | Cloud services, multi-tenant, Agent Service | https://mcp.ai.azure.com (Foundry) |
Phase 1: Research and Planning
1.1 Understand Modern MCP Design
API Coverage vs. Workflow Tools:
Balance comprehensive API endpoint coverage with specialized workflow tools. When uncertain, prioritize comprehensive API coverage.
Tool Naming and Discoverability:
Clear, descriptive tool names help agents find the right tools quickly. Use consistent prefixes (e.g., github_create_issue, github_list_repos) and action-oriented naming.
Context Management:
Design tools that return focused, relevant data. Agents benefit from concise tool descriptions and the ability to filter/paginate results.
Actionable Error Messages:
Error messages should guide agents toward solutions with specific suggestions and next steps.
1.2 Study MCP Protocol Documentation
Start with the sitemap: https://modelcontextprotocol.io/sitemap.xml
Key pages to review:
- Specification overview and architecture
- Transport mechanisms (streamable HTTP, stdio)
- Tool, resource, and prompt definitions
1.3 Select Language and Transport
Language Selection:
| Language | Best For | SDK |
|---|
| TypeScript (recommended) | General MCP servers, broad compatibility | @modelcontextprotocol/sdk |
| Python | Data/ML pipelines, FastAPI integration | mcp (FastMCP) |
| C#/.NET | Azure/Microsoft ecosystem, enterprise | Microsoft.Mcp.Core |
Transport Selection:
| Transport | Use Case | Characteristics |
|---|
| Streamable HTTP | Remote servers, multi-tenant, Agent Service | Stateless, scalable, requires auth |
| stdio | Local servers, desktop apps | Simple, single-user, no network |
Phase 2: Implementation
TypeScript Server (Recommended)
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-mcp-server",
version: "1.0.0",
});
server.tool(
"get_weather",
"Get current weather for a city",
{ city: z.string().describe("City name") },
async ({ city }) => ({
content: [{ type: "text", text: JSON.stringify({ city, temp: "72°F" }) }],
})
);
const transport = new StdioServerTransport();
await server.connect(transport);
Python Server (FastMCP)
from mcp.server.fastmcp import FastMCP
from pydantic import BaseModel, Field
mcp = FastMCP("my-mcp-server")
class WeatherParams(BaseModel):
city: str = Field(description="City name")
@mcp.tool(description="Get current weather for a city")
async def get_weather(params: WeatherParams) -> dict:
return {"city": params.city, "temp": "72°F"}
if __name__ == "__main__":
mcp.run()
C#/.NET Server
using Microsoft.Mcp.Core;
var server = new McpServerBuilder()
.WithName("my-mcp-server")
.WithVersion("1.0.0")
.AddTool("get_weather", "Get current weather", async (string city) =>
new { city, temp = "72°F" })
.Build();
await server.RunAsync();
Tool Design Best Practices
Input Schema
- Use Zod (TypeScript) or Pydantic (Python) for validation
- Include constraints and clear descriptions
- Add examples in field descriptions
Output Schema
- Define
outputSchema where possible for structured data
- Use
structuredContent in tool responses (TypeScript SDK feature)
- Helps clients understand and process tool outputs
Annotations
| Annotation | Purpose |
|---|
readOnlyHint: true | Tool doesn't modify state |
destructiveHint: true | Tool makes irreversible changes |
idempotentHint: true | Safe to retry |
openWorldHint: true | Tool accesses external systems |
Implementation Patterns
server.tool(
"list_items",
"List items with pagination",
{
page: z.number().default(1),
limit: z.number().max(100).default(20),
},
async ({ page, limit }) => {
try {
const items = await api.listItems({ page, limit });
return {
content: [{
type: "text",
text: JSON.stringify({ items, page, hasMore: items.length === limit }),
}],
};
} catch (error) {
return {
content: [{
type: "text",
text: `Error: ${error.message}. Try: check API key, verify endpoint, reduce page size.`,
}],
isError: true,
};
}
}
);
Phase 3: Testing
Build and Verify
TypeScript:
npm run build
npx @modelcontextprotocol/inspector ./dist/server.js
Python:
python -m py_compile your_server.py
npx @modelcontextprotocol/inspector -- python your_server.py
MCP Inspector
Use the MCP Inspector for interactive debugging:
npx @modelcontextprotocol/inspector /path/to/your/mcp-server
Code Quality Checklist
Phase 4: Create Evaluations
Evaluation Purpose
Test whether LLMs can effectively use your MCP server to answer realistic,
complex questions. Create 10 evaluation questions:
- Tool Inspection: List available tools and understand capabilities
- Content Exploration: Use READ-ONLY operations to explore data
- Question Generation: Create 10 complex, realistic questions
- Answer Verification: Solve each question yourself to verify answers
Evaluation Requirements
Each question must be:
- Independent: Not dependent on other questions
- Read-only: Only non-destructive operations required
- Complex: Requiring multiple tool calls and deep exploration
- Realistic: Based on real use cases humans would care about
- Verifiable: Single, clear answer that can be verified by string comparison
- Stable: Answer won't change over time
Output Format
<evaluation>
<qa_pair>
<question>Find discussions about AI model launches with animal codenames. One model needed a specific safety designation that uses the format ASL-X. What number X was being determined?</question>
<answer>3</answer>
</qa_pair>
</evaluation>
Common Issues
| Issue | Cause | Solution |
|---|
| Tools not appearing | Server not responding to tools/list | Verify tool registration, check server startup |
| Stdout pollution | Debug output on stdout | Move debug output to stderr |
| Connection refused | Port conflict or server crash | Check port availability, review logs |
| Timeout | Slow API calls | Add timeout handling, implement pagination |
| Schema validation | Invalid input schema | Use Zod/Pydantic with proper constraints |
References
Would Revise If
Revise if the quality bar (license, auth, agent-readable descriptions, README example, actionable errors, test path) admits an MCP that later fails in production use by a heir, or if the Build-vs-Use-Existing decision matrix recommends building when an Azure/Foundry/Fabric/GitHub MCP would have covered the case.