Skip to main content
creating-mcp-servers
Published by @askskills
Build Model Context Protocol (MCP) servers that extend Claude and other AI assistants with custom tools
Third-Party Content
This skill is created by a third-party developer, not Asterism. While security-scanned, we cannot guarantee safety. By using any skill, you accept our Terms of Service and assume all risk.
Installation
aster install creating-mcp-serversUniversal installation
By installing, you accept the Terms of Service. Skills are third-party content; Asterism is not liable for their use.
README
# Creating MCP Servers
## Viral Potential: ⭐⭐⭐⭐⭐
Build MCP servers that give Claude and other AI assistants new capabilities.
## What This Skill Does
This skill generates complete MCP server implementations:
- Tool definitions with proper schemas
- Resource providers for data access
- Server configuration
- Client integration instructions
- Testing utilities
## MCP Architecture Overview
```
┌─────────────────┐ ┌─────────────────┐
│ Claude/Client │────▶│ MCP Server │
│ │◀────│ │
└─────────────────┘ └────────┬────────┘
│
┌────────────┼────────────┐
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│ Tool │ │Resource │ │ Prompt │
│ Handler │ │Provider │ │Template │
└─────────┘ └─────────┘ └─────────┘
```
## TypeScript MCP Server Template
### Project Structure
```
my-mcp-server/
├── src/
│ ├── index.ts # Server entry point
│ ├── tools/ # Tool implementations
│ │ └── myTool.ts
│ ├── resources/ # Resource providers
│ │ └── myResource.ts
│ └── utils/ # Helper functions
├── package.json
├── tsconfig.json
└── README.md
```
### Basic Server Implementation
```typescript
#!/usr/bin/env node
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
ListResourcesRequestSchema,
ReadResourceRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
// Create server instance
const server = new Server(
{
name: "my-mcp-server",
version: "1.0.0",
},
{
capabilities: {
tools: {},
resources: {},
},
}
);
// Define available tools
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "my_tool",
description: "Description of what this tool does",
inputSchema: {
type: "object",
properties: {
param1: {
type: "string",
description: "Description of parameter",
},
param2: {
type: "number",
description: "Another parameter",
},
},
required: ["param1"],
},
},
],
};
});
// Handle tool calls
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
if (name === "my_tool") {
try {
const result = await myToolFunction(args);
return {
content: [
{
type: "text",
text: JSON.stringify(result, null, 2),
},
],
};
} catch (error) {
return {
content: [
{
type: "text",
text: `Error: ${error.message}`,
},
],
isError: true,
};
}
}
throw new Error(`Unknown tool: ${name}`);
});
// Define available resources
server.setRequestHandler(ListResourcesRequestSchema, async () => {
return {
resources: [
{
uri: "myserver://resource/path",
name: "My Resource",
description: "Description of the resource",
mimeType: "application/json",
},
],
};
});
// Handle resource reads
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
const { uri } = request.params;
if (uri.startsWith("myserver://")) {
const data = await fetchResourceData(uri);
return {
contents: [
{
uri,
mimeType: "application/json",
text: JSON.stringify(data),
},
],
};
}
throw new Error(`Unknown resource: ${uri}`);
});
// Tool implementation
async function myToolFunction(args: any) {
// Your tool logic here
return { success: true, data: args };
}
// Resource fetcher
async function fetchResourceData(uri: string) {
// Your resource fetching logic here
return { uri, fetched: new Date().toISOString() };
}
// Start server
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("MCP server running on stdio");
}
main().catch(console.error);
```
### package.json
```json
{
"name": "my-mcp-server",
"version": "1.0.0",
"description": "MCP server for [purpose]",
"type": "module",
"bin": {
"my-mcp-server": "./dist/index.js"
},
"scripts": {
"build": "tsc",
"start": "node dist/index.js",
"dev": "tsx src/index.ts"
},
"dependencies": {
"@modelcontextprotocol/sdk": "^0.6.0"
},
"devDependencies": {
"@types/node": "^20.0.0",
"typescript": "^5.0.0",
"tsx": "^4.0.0"
}
}
```
## Common Tool Patterns
### API Integration Tool
```typescript
const apiTool = {
name: "fetch_api_data",
description: "Fetches data from external API",
inputSchema: {
type: "object",
properties: {
endpoint: {
type: "string",
description: "API endpoint to call",
},
method: {
type: "string",
enum: ["GET", "POST"],
default: "GET",
},
body: {
type: "object",
description: "Request body for POST",
},
},
required: ["endpoint"],
},
};
async function handleApiTool(args: any) {
const response = await fetch(args.endpoint, {
method: args.method || "GET",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.API_KEY}`,
},
body: args.body ? JSON.stringify(args.body) : undefined,
});
return response.json();
}
```
### Database Query Tool
```typescript
const dbTool = {
name: "query_database",
description: "Runs a read-only SQL query",
inputSchema: {
type: "object",
properties: {
query: {
type: "string",
description: "SQL SELECT query",
},
params: {
type: "array",
description: "Query parameters",
},
},
required: ["query"],
},
};
async function handleDbTool(args: any) {
// Validate query is SELECT only
if (!args.query.trim().toUpperCase().startsWith("SELECT")) {
throw new Error("Only SELECT queries allowed");
}
const result = await db.query(args.query, args.params);
return result.rows;
}
```
### File System Tool
```typescript
const fsTool = {
name: "read_file",
description: "Reads a file from allowed directories",
inputSchema: {
type: "object",
properties: {
path: {
type: "string",
description: "File path (relative to allowed root)",
},
},
required: ["path"],
},
};
async function handleFsTool(args: any) {
const allowedRoot = process.env.ALLOWED_PATH || "./data";
const fullPath = path.join(allowedRoot, args.path);
// Security: Prevent directory traversal
if (!fullPath.startsWith(path.resolve(allowedRoot))) {
throw new Error("Path outside allowed directory");
}
return fs.readFileSync(fullPath, "utf-8");
}
```
## Client Configuration
### Claude Desktop (claude_desktop_config.json)
```json
{
"mcpServers": {
"my-server": {
"command": "node",
"args": ["/path/to/my-mcp-server/dist/index.js"],
"env": {
"API_KEY": "your-api-key"
}
}
}
}
```
### For npm-published servers
```json
{
"mcpServers": {
"my-server": {
"command": "npx",
"args": ["-y", "my-mcp-server"],
"env": {
"API_KEY": "your-api-key"
}
}
}
}
```
## Testing Your MCP Server
### Manual Testing
```bash
# Build the server
npm run build
# Test with echo
echo '{"jsonrpc":"2.0","method":"tools/list","id":1}' | node dist/index.js
# Test a tool call
echo '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"my_tool","arguments":{"param1":"test"}},"id":2}' | node dist/index.js
```
### Integration Test
```typescript
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
async function test() {
const transport = new StdioClientTransport({
command: "node",
args: ["./dist/index.js"],
});
const client = new Client({ name: "test-client", version: "1.0.0" }, {});
await client.connect(transport);
// List tools
const tools = await client.listTools();
console.log("Available tools:", tools);
// Call a tool
const result = await client.callTool("my_tool", { param1: "test" });
console.log("Tool result:", result);
await client.close();
}
```
## Security Best Practices
1. **Validate all inputs** - Never trust tool arguments
2. **Use allowlists** - Restrict file paths, URLs, queries
3. **Sanitize outputs** - Don't leak sensitive data
4. **Rate limit** - Prevent abuse
5. **Log access** - Audit tool usage
6. **Use environment variables** - Never hardcode secrets
## Output Format
When creating MCP servers, provide:
1. **Complete server code** ready to use
2. **package.json** with dependencies
3. **Client configuration** for Claude/other clients
4. **Test commands** for validation
5. **Security considerations** specific to the integration
Sign in to leave a comment