t

ts-xiaoman-mcp 框架(模型上下文协议工具)

@frankie0736/ts-xiaoman-mcp
0 Stars 14 次浏览 frankie0736 更新于 2026-08-23

一个用于构建Model Context Protocol(MCP)工具的TypeScript框架,该工具允许AI模型调用外部服务,例如发送电子邮件或通知。

该服务暂未提供标准配置,请参考 README 手动接入

服务介绍

MCP Tool Development Scaffold

This is a scaffold project for developing Model Context Protocol (MCP) tools, built on the Bun runtime and Express framework. This project provides the foundational structure and example tools to help developers quickly start building their own MCP tools.

What is MCP?

Model Context Protocol (MCP) is a protocol that allows AI models to call external tools and services. Through MCP, AIs can perform various operations such as sending emails, pushing notifications, querying databases, etc., thereby extending their capabilities.

Scaffold Features

  • Full MCP server implementation supporting streaming responses
  • API key-based authentication mechanism
  • Tool registration and management system
  • Includes 3 example tools (echo, email sending, WeChat notification) for reference

Quick Start

Environment Requirements

  • Bun 1.0.0 or higher

Installation

bash

Clone the scaffold repository

git clone
cd

Install dependencies

bun install

Running

bash

Development mode with hot reloading

bun dev

Production mode

bun start

The server will start on the specified port (default is 3000).

MCP Tool Development Guide

The primary purpose of this scaffold is to help developers quickly get started with building their own MCP tools. Below is a comprehensive guide to developing custom MCP tools.

Basic Structure of an MCP Tool

An MCP tool typically includes the following components:

  1. Parameter Schema: Defines the parameters accepted by the tool and their validation rules.
  2. Implementation Logic: The code that executes the tool's functionality.
  3. Response Formatting: Formats the result of the tool execution into an MCP-compatible response.

Steps to Develop a Custom MCP Tool

1. Create a Tool Definition File

Create a new file under the src/tools/ directory, for example, src/tools/my-tool.ts:

typescript
import { z } from "zod";
import { formatToolResponse } from "../utils/response";

/**

  • Define the schema for tool parameters
    */
    export const myToolSchema = z.object({
    // Define the parameters your tool needs
    param1: z.string().min(1, "param1 cannot be empty"),
    param2: z.number().optional(),
    // Add more parameters...
    });

/**

  • Optional: Define an interface for parameters including context information
    */
    interface MyToolArgs extends z.infer {
    apiKey?: string; // If your tool requires an API key
    // Other context information...
    }

/**

  • Implement the tool functionality
    */
    export async function myTool({ param1, param2, apiKey }: MyToolArgs) {
    try {
    console.log(Executing tool, param1: ${param1});

    // Implement your tool logic
    // For example: calling an external API, processing data, performing calculations, etc.
    const result = await someOperation(param1, param2);

    // Return a successful response
    return formatToolResponse(Operation succeeded: ${result});
    } catch (error) {
    console.error("Tool execution error:", error);
    return formatToolResponse(
    Execution failed: ${error instanceof Error ? error.message : String(error)},
    true // Mark as an error
    );
    }
    }

// Example of a helper function
async function someOperation(param1: string, param2?: number) {
// Implement specific operation...
return "Operation result";
}

2. Register Your Tool in the Tool Registrar

Modify the src/services/tools-registry.ts file to import and register your new tool:

typescript
// Add import
import { myTool, myToolSchema } from "../tools/my-tool";

export function registerTools(server: McpServer, req: Request): void {
const { sendKey, scKey } = extractApiKeys(req);

// Other tool registrations...

// Register your custom tool
server.tool(
"my-tool", // Tool name (AI will use this name to call the tool)
"This is my tool description", // Tool description (helps AI understand the tool's purpose)
myToolSchema.shape, // Parameter schema
async (args: z.infer) => myTool({
...args,
apiKey: sendKey // Or other context information
})
);
}

Best Practices for MCP Tool Development

Tool Design Principles

  1. Single Responsibility: Each tool should focus on completing a specific task.
  2. Simplicity and Clarity: Tool names and descriptions should clearly express their functionality.3. Composability: Tools should be easy to combine with other tools.
  3. Error Handling: Properly handle all possible error scenarios.
  4. Security: Do not expose sensitive information, and handle authentication credentials carefully.

Parameter Validation

  • Use the Zod library to define strict parameter schemas.
  • Validate the type and value of all required parameters.
  • Provide clear error messages for validation errors.
  • Consider boundary conditions and special cases for parameters.

typescript
// Good example of parameter validation
export const userToolSchema = z.object({
userId: z.string().uuid("User ID must be a valid UUID"),
action: z.enum(["create", "update", "delete"], {
errorMap: () => ({ message: "Action must be create, update, or delete" })
}),
data: z.record(z.string(), z.any()).optional(),
limit: z.number().int().positive().optional(),
});

Error Handling

  • Use try/catch blocks to catch all possible errors.
  • Distinguish between different types of errors (validation errors, API errors, network errors, etc.).
  • Log detailed error information for debugging.
  • Return helpful error messages to the user.

typescript
try {
// Operation code...
} catch (error) {
if (error instanceof NetworkError) {
console.error("Network error:", error);
return formatToolResponse("Failed to connect to service, please check your network", true);
} else if (error instanceof ValidationError) {
console.error("Validation error:", error);
return formatToolResponse(Invalid input data: ${error.message}, true);
} else {
console.error("Unknown error:", error);
return formatToolResponse("An unexpected error occurred", true);
}
}

Logging

  • Log the tool's invocation information and parameters (be careful not to log sensitive data).
  • Use different log levels (info, warning, error).
  • Control the verbosity of logs in production environments.
  • Log response times and performance metrics.

typescript
console.info(Starting execution of tool ${toolName}, parameters:, sanitizeParams(args));
const startTime = Date.now();

// Tool logic...

const duration = Date.now() - startTime;
console.info(Execution of tool ${toolName} completed, duration: ${duration}ms);

Response Formatting

  • Use a consistent response format.
  • Provide structured and easily understandable results.
  • For complex data, consider how best to present it to AI and users.
  • Clearly distinguish between success and error responses.

typescript
// Example of a successful response
return {
content: [
{ type: "text", text: "Operation successful" },
{
type: "json",
json: {
id: result.id,
status: result.status,
timestamp: new Date().toISOString()
}
}
],
isError: false
};

// Example of an error response
return {
content: [{ type: "text", text: Operation failed: ${errorMessage} }],
isError: true
};

Advanced Development Techniques

1. Chaining Tool Calls

Design tools considering how they can work together, where the output of one tool can serve as the input for another.

2. Context Sharing

Pass context information (such as API keys, user information, etc.) through request objects.

3. Streaming Responses

For long-running operations, consider using streaming responses to provide progress updates.

4. Caching Strategies

Implement caching for frequently requested data to improve performance and reduce external API calls.

5. Timeout and Retry Logic

Implement timeout and retry logic for external API calls to enhance reliability.

typescript
async function callWithRetry(fn, maxRetries = 3, delay = 1000) {
let lastError;
for (let i = 0; i < maxRetries; i++) {
try {
return await fn();
} catch (error) {
console.warn(Attempt ${i+1}/${maxRetries} failed:, error);
lastError = error;
await new Promise(resolve => setTimeout(resolve, delay));
delay *= 2; // Exponential backoff
}
}
throw lastError;
}

Sample Tool References

This scaffold includes three sample tools. You can refer to their implementations when developing your own tools:

1. Echo Tool (Simple Example)

A simple echo tool that receives a message and returns the same message.

typescript
// src/tools/echo.ts
import { z } from "zod";
import { formatToolResponse } from "../utils/response";

export const echoSchema = z.object({
message: z.string(),
});

export async function echo(args: z.infer) {
return formatToolResponse(Tool echo: ${args.message});
}### 2. Email Sending Tool (API Call Example)

Demonstrates an example of how to call an external API to send an email.

typescript
// src/tools/send-email.ts (simplified version)
import { z } from "zod";
import { formatToolResponse } from "../utils/response";

export const emailSchema = z.object({
to: z.string().email("Must be a valid email address"),
subject: z.string().min(1, "Subject cannot be empty"),
body: z.string().min(1, "Email body cannot be empty"),
});

interface SendEmailArgs extends z.infer {
apiKey: string;
}

export async function sendEmail({ to, subject, body, apiKey }: SendEmailArgs) {
// Implement the logic for sending the email...
return formatToolResponse("Email sent successfully");
}

3. WeChat Notification Tool (Error Handling Example)

Shows an example of how to handle responses and error cases from an external API.

typescript
// src/tools/wechat-push.ts (simplified version)
import { z } from "zod";
import { formatToolResponse } from "../utils/response";

export const wechatPushSchema = z.object({
title: z.string(),
description: z.string(),
});

interface WechatPushArgs extends z.infer {
apiKey: string;
}

export async function sendWechatNotification({ title, description, apiKey }: WechatPushArgs) {
try {
// Call the external API to send the notification...

// Handle the response...
if (success) {
  return formatToolResponse("WeChat notification sent successfully");
} else {
  return formatToolResponse(`Failed to send: ${errorMessage}`, true);
}

} catch (error) {
return formatToolResponse(Error occurred: ${error.message}, true);
}
}

Testing Your Tools

Test your tools by sending requests to the /mcp endpoint using cURL or Postman:

bash
curl -X POST http://localhost:3000/mcp
-H "Content-Type: application/json"
-H "mcp-send-key: sk_your_key"
-H "mcp-sc-key: SC_your_key"
-d {
"jsonrpc": "2.0",
"method": "tool",
"params": {
"tool": "my-tool",
"arguments": {
"param1": "test value",
"param2": 123
}
},
"id": "test-1"
}

Contribution Guidelines

We welcome contributions to this MCP tool scaffolding! Please follow these steps:

  1. Fork this repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

相关 MCP 服务