Skip to content

Commit 385147b

Browse files
authored
improve: enhance generate-tests command (#425)
1 parent 6259fb0 commit 385147b

182 files changed

Lines changed: 74328 additions & 5201 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

cli-tool/components/skills/development/mcp-builder/SKILL.md

Lines changed: 92 additions & 184 deletions
Large diffs are not rendered by default.

cli-tool/components/skills/development/mcp-builder/reference/mcp_best_practices.md

Lines changed: 93 additions & 759 deletions
Large diffs are not rendered by default.

cli-tool/components/skills/development/mcp-builder/reference/node_mcp_server.md

Lines changed: 124 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@ This document provides Node/TypeScript-specific best practices and examples for
1111
### Key Imports
1212
```typescript
1313
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
14+
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
1415
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
16+
import express from "express";
1517
import { z } from "zod";
16-
import axios, { AxiosError } from "axios";
1718
```
1819

1920
### Server Initialization
@@ -26,9 +27,22 @@ const server = new McpServer({
2627

2728
### Tool Registration Pattern
2829
```typescript
29-
server.registerTool("tool_name", {...config}, async (params) => {
30-
// Implementation
31-
});
30+
server.registerTool(
31+
"tool_name",
32+
{
33+
title: "Tool Display Name",
34+
description: "What the tool does",
35+
inputSchema: { param: z.string() },
36+
outputSchema: { result: z.string() }
37+
},
38+
async ({ param }) => {
39+
const output = { result: `Processed: ${param}` };
40+
return {
41+
content: [{ type: "text", text: JSON.stringify(output) }],
42+
structuredContent: output // Modern pattern for structured data
43+
};
44+
}
45+
);
3246
```
3347

3448
---
@@ -41,6 +55,11 @@ The official MCP TypeScript SDK provides:
4155
- Zod schema integration for runtime input validation
4256
- Type-safe tool handler implementations
4357

58+
**IMPORTANT - Use Modern APIs Only:**
59+
- **DO use**: `server.registerTool()`, `server.registerResource()`, `server.registerPrompt()`
60+
- **DO NOT use**: Old deprecated APIs such as `server.tool()`, `server.setRequestHandler(ListToolsRequestSchema, ...)`, or manual handler registration
61+
- The `register*` methods provide better type safety, automatic schema handling, and are the recommended approach
62+
4463
See the MCP SDK documentation in the references for complete details.
4564

4665
## Server Naming Convention
@@ -204,55 +223,43 @@ Error Handling:
204223
};
205224
}
206225

207-
// Format response based on requested format
208-
let result: string;
226+
// Prepare structured output
227+
const output = {
228+
total,
229+
count: users.length,
230+
offset: params.offset,
231+
users: users.map((user: any) => ({
232+
id: user.id,
233+
name: user.name,
234+
email: user.email,
235+
...(user.team ? { team: user.team } : {}),
236+
active: user.active ?? true
237+
})),
238+
has_more: total > params.offset + users.length,
239+
...(total > params.offset + users.length ? {
240+
next_offset: params.offset + users.length
241+
} : {})
242+
};
209243

244+
// Format text representation based on requested format
245+
let textContent: string;
210246
if (params.response_format === ResponseFormat.MARKDOWN) {
211-
// Human-readable markdown format
212-
const lines: string[] = [`# User Search Results: '${params.query}'`, ""];
213-
lines.push(`Found ${total} users (showing ${users.length})`);
214-
lines.push("");
215-
247+
const lines = [`# User Search Results: '${params.query}'`, "",
248+
`Found ${total} users (showing ${users.length})`, ""];
216249
for (const user of users) {
217250
lines.push(`## ${user.name} (${user.id})`);
218251
lines.push(`- **Email**: ${user.email}`);
219-
if (user.team) {
220-
lines.push(`- **Team**: ${user.team}`);
221-
}
252+
if (user.team) lines.push(`- **Team**: ${user.team}`);
222253
lines.push("");
223254
}
224-
225-
result = lines.join("\n");
226-
255+
textContent = lines.join("\n");
227256
} else {
228-
// Machine-readable JSON format
229-
const response: any = {
230-
total,
231-
count: users.length,
232-
offset: params.offset,
233-
users: users.map((user: any) => ({
234-
id: user.id,
235-
name: user.name,
236-
email: user.email,
237-
...(user.team ? { team: user.team } : {}),
238-
active: user.active ?? true
239-
}))
240-
};
241-
242-
// Add pagination info if there are more results
243-
if (total > params.offset + users.length) {
244-
response.has_more = true;
245-
response.next_offset = params.offset + users.length;
246-
}
247-
248-
result = JSON.stringify(response, null, 2);
257+
textContent = JSON.stringify(output, null, 2);
249258
}
250259

251260
return {
252-
content: [{
253-
type: "text",
254-
text: result
255-
}]
261+
content: [{ type: "text", text: textContent }],
262+
structuredContent: output // Modern pattern for structured data
256263
};
257264
} catch (error) {
258265
return {
@@ -695,27 +702,57 @@ server.registerTool(
695702
);
696703

697704
// Main function
698-
async function main() {
699-
// Verify environment variables if needed
705+
// For stdio (local):
706+
async function runStdio() {
700707
if (!process.env.EXAMPLE_API_KEY) {
701708
console.error("ERROR: EXAMPLE_API_KEY environment variable is required");
702709
process.exit(1);
703710
}
704711

705-
// Create transport
706712
const transport = new StdioServerTransport();
707-
708-
// Connect server to transport
709713
await server.connect(transport);
714+
console.error("MCP server running via stdio");
715+
}
710716

711-
console.error("Example MCP server running via stdio");
717+
// For streamable HTTP (remote):
718+
async function runHTTP() {
719+
if (!process.env.EXAMPLE_API_KEY) {
720+
console.error("ERROR: EXAMPLE_API_KEY environment variable is required");
721+
process.exit(1);
722+
}
723+
724+
const app = express();
725+
app.use(express.json());
726+
727+
app.post('/mcp', async (req, res) => {
728+
const transport = new StreamableHTTPServerTransport({
729+
sessionIdGenerator: undefined,
730+
enableJsonResponse: true
731+
});
732+
res.on('close', () => transport.close());
733+
await server.connect(transport);
734+
await transport.handleRequest(req, res, req.body);
735+
});
736+
737+
const port = parseInt(process.env.PORT || '3000');
738+
app.listen(port, () => {
739+
console.error(`MCP server running on http://localhost:${port}/mcp`);
740+
});
712741
}
713742

714-
// Run the server
715-
main().catch((error) => {
716-
console.error("Server error:", error);
717-
process.exit(1);
718-
});
743+
// Choose transport based on environment
744+
const transport = process.env.TRANSPORT || 'stdio';
745+
if (transport === 'http') {
746+
runHTTP().catch(error => {
747+
console.error("Server error:", error);
748+
process.exit(1);
749+
});
750+
} else {
751+
runStdio().catch(error => {
752+
console.error("Server error:", error);
753+
process.exit(1);
754+
});
755+
}
719756
```
720757

721758
---
@@ -777,30 +814,47 @@ server.registerResourceList(async () => {
777814
- **Resources**: When data is relatively static or template-based
778815
- **Tools**: When operations have side effects or complex workflows
779816

780-
### Multiple Transport Options
817+
### Transport Options
818+
819+
The TypeScript SDK supports two main transport mechanisms:
781820

782-
The TypeScript SDK supports different transport mechanisms:
821+
#### Streamable HTTP (Recommended for Remote Servers)
783822

784823
```typescript
785-
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
786-
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
824+
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
825+
import express from "express";
826+
827+
const app = express();
828+
app.use(express.json());
829+
830+
app.post('/mcp', async (req, res) => {
831+
// Create new transport for each request (stateless, prevents request ID collisions)
832+
const transport = new StreamableHTTPServerTransport({
833+
sessionIdGenerator: undefined,
834+
enableJsonResponse: true
835+
});
787836

788-
// Stdio transport (default - for CLI tools)
789-
const stdioTransport = new StdioServerTransport();
790-
await server.connect(stdioTransport);
837+
res.on('close', () => transport.close());
838+
839+
await server.connect(transport);
840+
await transport.handleRequest(req, res, req.body);
841+
});
791842

792-
// SSE transport (for real-time web updates)
793-
const sseTransport = new SSEServerTransport("/message", response);
794-
await server.connect(sseTransport);
843+
app.listen(3000);
844+
```
845+
846+
#### stdio (For Local Integrations)
847+
848+
```typescript
849+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
795850

796-
// HTTP transport (for web services)
797-
// Configure based on your HTTP framework integration
851+
const transport = new StdioServerTransport();
852+
await server.connect(transport);
798853
```
799854

800-
**Transport selection guide:**
801-
- **Stdio**: Command-line tools, subprocess integration, local development
802-
- **HTTP**: Web services, remote access, multiple simultaneous clients
803-
- **SSE**: Real-time updates, server-push notifications, web dashboards
855+
**Transport selection:**
856+
- **Streamable HTTP**: Web services, remote access, multiple clients
857+
- **stdio**: Command-line tools, local development, subprocess integration
804858

805859
### Notification Support
806860

@@ -889,7 +943,7 @@ Before finalizing your Node/TypeScript MCP server implementation, ensure:
889943

890944
### Advanced Features (where applicable)
891945
- [ ] Resources registered for appropriate data endpoints
892-
- [ ] Appropriate transport configured (stdio, HTTP, SSE)
946+
- [ ] Appropriate transport configured (stdio or streamable HTTP)
893947
- [ ] Notifications implemented for dynamic server capabilities
894948
- [ ] Type-safe with SDK interfaces
895949

cli-tool/components/skills/development/mcp-builder/reference/python_mcp_server.md

Lines changed: 7 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -204,32 +204,6 @@ async def list_items(params: ListInput) -> str:
204204
return json.dumps(response, indent=2)
205205
```
206206

207-
## Character Limits and Truncation
208-
209-
Add a CHARACTER_LIMIT constant to prevent overwhelming responses:
210-
211-
```python
212-
# At module level
213-
CHARACTER_LIMIT = 25000 # Maximum response size in characters
214-
215-
async def search_tool(params: SearchInput) -> str:
216-
result = generate_response(data)
217-
218-
# Check character limit and truncate if needed
219-
if len(result) > CHARACTER_LIMIT:
220-
# Truncate data and add notice
221-
truncated_data = data[:max(1, len(data) // 2)]
222-
response["data"] = truncated_data
223-
response["truncated"] = True
224-
response["truncation_message"] = (
225-
f"Response truncated from {len(data)} to {len(truncated_data)} items. "
226-
f"Use 'offset' parameter or add filters to see more results."
227-
)
228-
result = json.dumps(response, indent=2)
229-
230-
return result
231-
```
232-
233207
## Error Handling
234208

235209
Provide clear, actionable error messages:
@@ -377,7 +351,6 @@ mcp = FastMCP("example_mcp")
377351

378352
# Constants
379353
API_BASE_URL = "https://api.example.com/v1"
380-
CHARACTER_LIMIT = 25000 # Maximum response size in characters
381354

382355
# Enums
383356
class ResponseFormat(str, Enum):
@@ -643,28 +616,23 @@ async def query_data(query: str, ctx: Context) -> str:
643616
return format_results(results)
644617
```
645618

646-
### Multiple Transport Options
619+
### Transport Options
647620

648-
FastMCP supports different transport mechanisms:
621+
FastMCP supports two main transport mechanisms:
649622

650623
```python
651-
# Default: Stdio transport (for CLI tools)
624+
# stdio transport (for local tools) - default
652625
if __name__ == "__main__":
653626
mcp.run()
654627

655-
# HTTP transport (for web services)
628+
# Streamable HTTP transport (for remote servers)
656629
if __name__ == "__main__":
657630
mcp.run(transport="streamable_http", port=8000)
658-
659-
# SSE transport (for real-time updates)
660-
if __name__ == "__main__":
661-
mcp.run(transport="sse", port=8000)
662631
```
663632

664633
**Transport selection:**
665-
- **Stdio**: Command-line tools, subprocess integration
666-
- **HTTP**: Web services, remote access, multiple clients
667-
- **SSE**: Real-time updates, push notifications
634+
- **stdio**: Command-line tools, local integrations, subprocess execution
635+
- **Streamable HTTP**: Web services, remote access, multiple clients
668636

669637
---
670638

@@ -733,12 +701,11 @@ Before finalizing your Python MCP server implementation, ensure:
733701
- [ ] Resources registered for appropriate data endpoints
734702
- [ ] Lifespan management implemented for persistent connections
735703
- [ ] Structured output types used (TypedDict, Pydantic models)
736-
- [ ] Appropriate transport configured (stdio, HTTP, SSE)
704+
- [ ] Appropriate transport configured (stdio or streamable HTTP)
737705

738706
### Code Quality
739707
- [ ] File includes proper imports including Pydantic imports
740708
- [ ] Pagination is properly implemented where applicable
741-
- [ ] Large responses check CHARACTER_LIMIT and truncate with clear messages
742709
- [ ] Filtering options are provided for potentially large result sets
743710
- [ ] All async functions are properly defined with `async def`
744711
- [ ] HTTP client usage follows async patterns with proper context managers

0 commit comments

Comments
 (0)