@musashishao/agent-kit 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of @musashishao/agent-kit might be problematic. Click here for more details.

@@ -1,12 +1,23 @@
1
1
  ---
2
2
  name: mcp-builder
3
- description: MCP (Model Context Protocol) server building principles. Tool design, resource patterns, best practices.
4
- allowed-tools: Read, Write, Edit, Glob, Grep
3
+ description: MCP (Model Context Protocol) server building. Complete guide with TypeScript/Python examples, FastMCP, tool design, deployment patterns.
4
+ allowed-tools: Read, Write, Edit, Glob, Grep, Bash
5
+ skills:
6
+ - typescript-expert
7
+ - python-patterns
5
8
  ---
6
9
 
7
10
  # MCP Builder
8
11
 
9
- > Principles for building MCP servers.
12
+ > Build production-ready MCP servers to extend AI capabilities with external tools and data.
13
+
14
+ ## 🔧 Quick Reference
15
+
16
+ | File | Purpose |
17
+ |------|---------|
18
+ | [typescript-template.md](typescript-template.md) | TypeScript MCP server template |
19
+ | [python-template.md](python-template.md) | FastMCP Python template |
20
+ | [tool-patterns.md](tool-patterns.md) | Tool design patterns & examples |
10
21
 
11
22
  ---
12
23
 
@@ -14,154 +25,628 @@ allowed-tools: Read, Write, Edit, Glob, Grep
14
25
 
15
26
  ### What is MCP?
16
27
 
17
- Model Context Protocol - standard for connecting AI systems with external tools and data sources.
28
+ Model Context Protocol - the open standard for connecting AI systems with external tools, data sources, and services.
29
+
30
+ ```
31
+ ┌─────────────┐ MCP Protocol ┌─────────────────┐
32
+ │ AI Host │◄───────────────────►│ MCP Server │
33
+ │ (Claude) │ Tools/Resources │ (Your Service) │
34
+ └─────────────┘ └─────────────────┘
35
+ ```
18
36
 
19
37
  ### Core Concepts
20
38
 
21
- | Concept | Purpose |
22
- |---------|---------|
23
- | **Tools** | Functions AI can call |
24
- | **Resources** | Data AI can read |
25
- | **Prompts** | Pre-defined prompt templates |
39
+ | Concept | Purpose | Example |
40
+ |---------|---------|---------|
41
+ | **Tools** | Functions AI can call | `get_weather`, `create_issue` |
42
+ | **Resources** | Data AI can read | Files, database records, APIs |
43
+ | **Prompts** | Pre-defined templates | Workflow shortcuts |
44
+
45
+ ### Why Build MCP Servers?
46
+
47
+ | Use Case | Example |
48
+ |----------|---------|
49
+ | **API Integration** | Connect to GitHub, Slack, Notion |
50
+ | **Database Access** | Query PostgreSQL, MongoDB |
51
+ | **File Operations** | Read/write local files |
52
+ | **Custom Tools** | Domain-specific automation |
26
53
 
27
54
  ---
28
55
 
29
- ## 2. Server Architecture
56
+ ## 2. TypeScript MCP Server
30
57
 
31
- ### Project Structure
58
+ ### Quick Start
32
59
 
33
- ```
34
- my-mcp-server/
35
- ├── src/
36
- │ └── index.ts # Main entry
37
- ├── package.json
38
- └── tsconfig.json
60
+ ```bash
61
+ # Create project
62
+ mkdir my-mcp-server && cd my-mcp-server
63
+ npm init -y
64
+ npm install @modelcontextprotocol/sdk zod
65
+ npm install -D typescript @types/node tsx
66
+
67
+ # Create structure
68
+ mkdir src
69
+ touch src/index.ts
39
70
  ```
40
71
 
41
- ### Transport Types
72
+ ### Basic Server Template
73
+
74
+ ```typescript
75
+ // src/index.ts
76
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
77
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
78
+ import { z } from "zod";
79
+
80
+ // Create server instance
81
+ const server = new McpServer({
82
+ name: "my-mcp-server",
83
+ version: "1.0.0",
84
+ });
85
+
86
+ // Define a tool
87
+ server.tool(
88
+ "greet",
89
+ "Greet a user by name",
90
+ {
91
+ name: z.string().describe("The user's name"),
92
+ },
93
+ async ({ name }) => {
94
+ return {
95
+ content: [
96
+ {
97
+ type: "text",
98
+ text: `Hello, ${name}! Welcome to MCP.`,
99
+ },
100
+ ],
101
+ };
102
+ }
103
+ );
104
+
105
+ // Define a resource
106
+ server.resource(
107
+ "status",
108
+ "status://server",
109
+ async (uri) => ({
110
+ contents: [
111
+ {
112
+ uri: uri.href,
113
+ mimeType: "application/json",
114
+ text: JSON.stringify({ status: "running", timestamp: new Date().toISOString() }),
115
+ },
116
+ ],
117
+ })
118
+ );
119
+
120
+ // Start server
121
+ async function main() {
122
+ const transport = new StdioServerTransport();
123
+ await server.connect(transport);
124
+ console.error("MCP Server running on stdio");
125
+ }
126
+
127
+ main().catch(console.error);
128
+ ```
42
129
 
43
- | Type | Use |
44
- |------|-----|
45
- | **Stdio** | Local, CLI-based |
46
- | **SSE** | Web-based, streaming |
47
- | **WebSocket** | Real-time, bidirectional |
130
+ ### Package.json Config
131
+
132
+ ```json
133
+ {
134
+ "name": "my-mcp-server",
135
+ "version": "1.0.0",
136
+ "type": "module",
137
+ "bin": {
138
+ "my-mcp-server": "./dist/index.js"
139
+ },
140
+ "scripts": {
141
+ "build": "tsc",
142
+ "dev": "tsx src/index.ts",
143
+ "start": "node dist/index.js"
144
+ },
145
+ "dependencies": {
146
+ "@modelcontextprotocol/sdk": "^1.0.0",
147
+ "zod": "^3.23.0"
148
+ },
149
+ "devDependencies": {
150
+ "@types/node": "^20.0.0",
151
+ "tsx": "^4.0.0",
152
+ "typescript": "^5.0.0"
153
+ }
154
+ }
155
+ ```
48
156
 
49
157
  ---
50
158
 
51
- ## 3. Tool Design Principles
159
+ ## 3. Python MCP Server (FastMCP)
52
160
 
53
- ### Good Tool Design
161
+ ### Quick Start
54
162
 
55
- | Principle | Description |
56
- |-----------|-------------|
57
- | Clear name | Action-oriented (get_weather, create_user) |
58
- | Single purpose | One thing well |
59
- | Validated input | Schema with types and descriptions |
60
- | Structured output | Predictable response format |
163
+ ```bash
164
+ # Install FastMCP
165
+ pip install fastmcp
61
166
 
62
- ### Input Schema Design
167
+ # Or with uv (recommended)
168
+ uv add fastmcp
169
+ ```
63
170
 
64
- | Field | Required? |
65
- |-------|-----------|
66
- | Type | Yes - object |
67
- | Properties | Define each param |
68
- | Required | List mandatory params |
69
- | Description | Human-readable |
171
+ ### Basic Server Template
172
+
173
+ ```python
174
+ # server.py
175
+ from fastmcp import FastMCP
176
+
177
+ # Create server
178
+ mcp = FastMCP("My MCP Server")
179
+
180
+ # Define a tool
181
+ @mcp.tool()
182
+ def greet(name: str) -> str:
183
+ """Greet a user by name.
184
+
185
+ Args:
186
+ name: The user's name
187
+
188
+ Returns:
189
+ A greeting message
190
+ """
191
+ return f"Hello, {name}! Welcome to MCP."
192
+
193
+ # Define a tool with complex input
194
+ @mcp.tool()
195
+ def calculate(
196
+ operation: str,
197
+ a: float,
198
+ b: float
199
+ ) -> dict:
200
+ """Perform a mathematical calculation.
201
+
202
+ Args:
203
+ operation: One of 'add', 'subtract', 'multiply', 'divide'
204
+ a: First number
205
+ b: Second number
206
+
207
+ Returns:
208
+ Result of the calculation
209
+ """
210
+ ops = {
211
+ "add": lambda: a + b,
212
+ "subtract": lambda: a - b,
213
+ "multiply": lambda: a * b,
214
+ "divide": lambda: a / b if b != 0 else "Error: Division by zero",
215
+ }
216
+
217
+ if operation not in ops:
218
+ return {"error": f"Unknown operation: {operation}"}
219
+
220
+ return {"result": ops[operation](), "operation": operation}
221
+
222
+ # Define a resource
223
+ @mcp.resource("config://settings")
224
+ def get_settings() -> str:
225
+ """Get server configuration."""
226
+ import json
227
+ return json.dumps({
228
+ "version": "1.0.0",
229
+ "features": ["tools", "resources"],
230
+ })
231
+
232
+ # Define a prompt template
233
+ @mcp.prompt()
234
+ def code_review(code: str, language: str = "python") -> str:
235
+ """Generate a code review prompt."""
236
+ return f"""Please review this {language} code:
237
+
238
+ ```{language}
239
+ {code}
240
+ ```
70
241
 
71
- ---
242
+ Focus on:
243
+ 1. Code quality
244
+ 2. Potential bugs
245
+ 3. Performance
246
+ 4. Best practices"""
72
247
 
73
- ## 4. Resource Patterns
248
+ if __name__ == "__main__":
249
+ mcp.run()
250
+ ```
74
251
 
75
- ### Resource Types
252
+ ### Running FastMCP
76
253
 
77
- | Type | Use |
78
- |------|-----|
79
- | Static | Fixed data (config, docs) |
80
- | Dynamic | Generated on request |
81
- | Template | URI with parameters |
254
+ ```bash
255
+ # Development
256
+ fastmcp dev server.py
82
257
 
83
- ### URI Patterns
258
+ # Production
259
+ fastmcp run server.py
84
260
 
85
- | Pattern | Example |
86
- |---------|---------|
87
- | Fixed | `docs://readme` |
88
- | Parameterized | `users://{userId}` |
89
- | Collection | `files://project/*` |
261
+ # Install to Claude Desktop
262
+ fastmcp install server.py --name "My Server"
263
+ ```
90
264
 
91
265
  ---
92
266
 
93
- ## 5. Error Handling
267
+ ## 4. Tool Design Patterns
268
+
269
+ ### Pattern 1: CRUD Operations
270
+
271
+ ```python
272
+ @mcp.tool()
273
+ def create_task(title: str, description: str = "", priority: str = "medium") -> dict:
274
+ """Create a new task."""
275
+ task = {
276
+ "id": generate_id(),
277
+ "title": title,
278
+ "description": description,
279
+ "priority": priority,
280
+ "status": "pending",
281
+ "created_at": datetime.now().isoformat(),
282
+ }
283
+ save_task(task)
284
+ return {"success": True, "task": task}
285
+
286
+ @mcp.tool()
287
+ def get_task(task_id: str) -> dict:
288
+ """Get task by ID."""
289
+ task = load_task(task_id)
290
+ if not task:
291
+ return {"error": f"Task {task_id} not found"}
292
+ return task
293
+
294
+ @mcp.tool()
295
+ def update_task(task_id: str, status: str = None, priority: str = None) -> dict:
296
+ """Update task properties."""
297
+ # Implementation...
298
+
299
+ @mcp.tool()
300
+ def delete_task(task_id: str) -> dict:
301
+ """Delete a task."""
302
+ # Implementation...
303
+ ```
304
+
305
+ ### Pattern 2: API Integration
306
+
307
+ ```python
308
+ import httpx
309
+
310
+ @mcp.tool()
311
+ async def github_create_issue(
312
+ repo: str,
313
+ title: str,
314
+ body: str = "",
315
+ labels: list[str] = []
316
+ ) -> dict:
317
+ """Create a GitHub issue.
318
+
319
+ Args:
320
+ repo: Repository in format 'owner/repo'
321
+ title: Issue title
322
+ body: Issue body (markdown)
323
+ labels: List of label names
324
+ """
325
+ token = os.environ.get("GITHUB_TOKEN")
326
+ if not token:
327
+ return {"error": "GITHUB_TOKEN not set"}
328
+
329
+ async with httpx.AsyncClient() as client:
330
+ response = await client.post(
331
+ f"https://api.github.com/repos/{repo}/issues",
332
+ headers={
333
+ "Authorization": f"token {token}",
334
+ "Accept": "application/vnd.github.v3+json",
335
+ },
336
+ json={
337
+ "title": title,
338
+ "body": body,
339
+ "labels": labels,
340
+ }
341
+ )
342
+
343
+ if response.status_code == 201:
344
+ issue = response.json()
345
+ return {
346
+ "success": True,
347
+ "issue_number": issue["number"],
348
+ "url": issue["html_url"],
349
+ }
350
+ else:
351
+ return {"error": response.text}
352
+ ```
94
353
 
95
- ### Error Types
354
+ ### Pattern 3: Database Query
355
+
356
+ ```python
357
+ import sqlite3
358
+
359
+ @mcp.tool()
360
+ def query_database(sql: str, params: list = []) -> dict:
361
+ """Execute a read-only SQL query.
362
+
363
+ Args:
364
+ sql: SQL SELECT query
365
+ params: Query parameters (for safety)
366
+
367
+ Returns:
368
+ Query results as list of dicts
369
+ """
370
+ # Validate read-only
371
+ if not sql.strip().upper().startswith("SELECT"):
372
+ return {"error": "Only SELECT queries allowed"}
373
+
374
+ conn = sqlite3.connect("database.db")
375
+ conn.row_factory = sqlite3.Row
376
+
377
+ try:
378
+ cursor = conn.execute(sql, params)
379
+ rows = [dict(row) for row in cursor.fetchall()]
380
+ return {"rows": rows, "count": len(rows)}
381
+ except Exception as e:
382
+ return {"error": str(e)}
383
+ finally:
384
+ conn.close()
385
+ ```
96
386
 
97
- | Situation | Response |
98
- |-----------|----------|
99
- | Invalid params | Validation error message |
100
- | Not found | Clear "not found" |
101
- | Server error | Generic error, log details |
387
+ ### Pattern 4: File Operations
388
+
389
+ ```python
390
+ from pathlib import Path
391
+
392
+ @mcp.tool()
393
+ def read_file(path: str) -> dict:
394
+ """Read a file's contents.
395
+
396
+ Args:
397
+ path: Relative path to file
398
+ """
399
+ file_path = Path(path).resolve()
400
+
401
+ # Security: validate path
402
+ if not file_path.is_relative_to(ALLOWED_DIR):
403
+ return {"error": "Access denied"}
404
+
405
+ if not file_path.exists():
406
+ return {"error": f"File not found: {path}"}
407
+
408
+ return {
409
+ "content": file_path.read_text(),
410
+ "size": file_path.stat().st_size,
411
+ "modified": file_path.stat().st_mtime,
412
+ }
413
+
414
+ @mcp.tool()
415
+ def write_file(path: str, content: str) -> dict:
416
+ """Write content to a file.
417
+
418
+ Args:
419
+ path: Relative path to file
420
+ content: Content to write
421
+ """
422
+ file_path = Path(path).resolve()
423
+
424
+ if not file_path.is_relative_to(ALLOWED_DIR):
425
+ return {"error": "Access denied"}
426
+
427
+ file_path.parent.mkdir(parents=True, exist_ok=True)
428
+ file_path.write_text(content)
429
+
430
+ return {"success": True, "path": str(file_path)}
431
+ ```
102
432
 
103
- ### Best Practices
433
+ ---
104
434
 
105
- - Return structured errors
106
- - Don't expose internal details
107
- - Log for debugging
108
- - Provide actionable messages
435
+ ## 5. Claude Desktop Configuration
436
+
437
+ ### Config Location
438
+
439
+ | OS | Path |
440
+ |----|------|
441
+ | macOS | `~/Library/Application Support/Claude/claude_desktop_config.json` |
442
+ | Windows | `%APPDATA%\Claude\claude_desktop_config.json` |
443
+
444
+ ### Config Example
445
+
446
+ ```json
447
+ {
448
+ "mcpServers": {
449
+ "my-server": {
450
+ "command": "node",
451
+ "args": ["/path/to/my-mcp-server/dist/index.js"],
452
+ "env": {
453
+ "API_KEY": "your-api-key"
454
+ }
455
+ },
456
+ "python-server": {
457
+ "command": "python",
458
+ "args": ["/path/to/server.py"],
459
+ "env": {
460
+ "DATABASE_URL": "postgresql://..."
461
+ }
462
+ },
463
+ "fastmcp-server": {
464
+ "command": "fastmcp",
465
+ "args": ["run", "/path/to/server.py"]
466
+ }
467
+ }
468
+ }
469
+ ```
109
470
 
110
471
  ---
111
472
 
112
- ## 6. Multimodal Handling
473
+ ## 6. Best Practices
113
474
 
114
- ### Supported Types
475
+ ### Tool Naming
115
476
 
116
- | Type | Encoding |
117
- |------|----------|
118
- | Text | Plain text |
119
- | Images | Base64 + MIME type |
120
- | Files | Base64 + MIME type |
477
+ | Bad | Good | Why |
478
+ |--------|---------|-----|
479
+ | `do_thing` | `create_user` | Specific action |
480
+ | `process` | `parse_csv` | Clear purpose |
481
+ | `handle_request` | `send_email` | Verb + noun |
482
+
483
+ ### Input Validation
484
+
485
+ ```python
486
+ @mcp.tool()
487
+ def send_email(
488
+ to: str,
489
+ subject: str,
490
+ body: str
491
+ ) -> dict:
492
+ """Send an email."""
493
+ # Validate email format
494
+ if not re.match(r"[^@]+@[^@]+\.[^@]+", to):
495
+ return {"error": "Invalid email format"}
496
+
497
+ # Validate subject length
498
+ if len(subject) > 200:
499
+ return {"error": "Subject too long (max 200 chars)"}
500
+
501
+ # ... send email
502
+ ```
503
+
504
+ ### Error Handling
505
+
506
+ ```python
507
+ @mcp.tool()
508
+ def risky_operation(param: str) -> dict:
509
+ """Operation that might fail."""
510
+ try:
511
+ result = do_something(param)
512
+ return {"success": True, "result": result}
513
+ except ValidationError as e:
514
+ return {"error": f"Invalid input: {e.message}"}
515
+ except PermissionError:
516
+ return {"error": "Permission denied"}
517
+ except Exception as e:
518
+ # Log internally, return generic message
519
+ logging.error(f"Unexpected error: {e}")
520
+ return {"error": "An unexpected error occurred"}
521
+ ```
522
+
523
+ ### Security Checklist
524
+
525
+ - [ ] Validate all inputs
526
+ - [ ] Use environment variables for secrets
527
+ - [ ] Limit file system access
528
+ - [ ] Sanitize SQL queries (use parameters)
529
+ - [ ] Rate limit expensive operations
530
+ - [ ] Log operations for audit
121
531
 
122
532
  ---
123
533
 
124
- ## 7. Security Principles
534
+ ## 7. Deployment Options
125
535
 
126
- ### Input Validation
536
+ ### Local (Claude Desktop)
537
+
538
+ ```bash
539
+ # Build and configure
540
+ npm run build
541
+ # Add to claude_desktop_config.json
542
+ ```
127
543
 
128
- - Validate all tool inputs
129
- - Sanitize user-provided data
130
- - Limit resource access
544
+ ### NPX Distribution
131
545
 
132
- ### API Keys
546
+ ```json
547
+ // package.json
548
+ {
549
+ "name": "@myorg/mcp-server",
550
+ "bin": {
551
+ "my-mcp-server": "./dist/index.js"
552
+ }
553
+ }
554
+ ```
133
555
 
134
- - Use environment variables
135
- - Don't log secrets
136
- - Validate permissions
556
+ ```bash
557
+ # Publish
558
+ npm publish --access public
559
+
560
+ # Users can run
561
+ npx @myorg/mcp-server
562
+ ```
563
+
564
+ ### Docker
565
+
566
+ ```dockerfile
567
+ FROM node:20-alpine
568
+ WORKDIR /app
569
+ COPY package*.json ./
570
+ RUN npm ci --production
571
+ COPY dist ./dist
572
+ CMD ["node", "dist/index.js"]
573
+ ```
137
574
 
138
575
  ---
139
576
 
140
- ## 8. Configuration
577
+ ## 8. Testing
578
+
579
+ ### Unit Test Example
580
+
581
+ ```typescript
582
+ import { describe, it, expect } from "vitest";
583
+ import { greetTool } from "./tools/greet";
584
+
585
+ describe("greet tool", () => {
586
+ it("should greet user by name", async () => {
587
+ const result = await greetTool({ name: "Alice" });
588
+ expect(result.content[0].text).toContain("Hello, Alice");
589
+ });
590
+
591
+ it("should handle empty name", async () => {
592
+ const result = await greetTool({ name: "" });
593
+ expect(result.content[0].text).toContain("error");
594
+ });
595
+ });
596
+ ```
141
597
 
142
- ### Claude Desktop Config
598
+ ### Integration Test
143
599
 
144
- | Field | Purpose |
145
- |-------|---------|
146
- | command | Executable to run |
147
- | args | Command arguments |
148
- | env | Environment variables |
600
+ ```bash
601
+ # Test with MCP Inspector
602
+ npx @modelcontextprotocol/inspector node dist/index.js
603
+ ```
149
604
 
150
605
  ---
151
606
 
152
- ## 9. Testing
607
+ ## 9. Common Patterns
608
+
609
+ ### Progress Reporting
610
+
611
+ ```python
612
+ @mcp.tool()
613
+ async def long_running_task(items: list[str]) -> dict:
614
+ """Process items with progress updates."""
615
+ results = []
616
+
617
+ for i, item in enumerate(items):
618
+ # Process item
619
+ result = await process_item(item)
620
+ results.append(result)
621
+
622
+ # Report progress via logging
623
+ progress = (i + 1) / len(items) * 100
624
+ logging.info(f"Progress: {progress:.0f}%")
625
+
626
+ return {"results": results}
627
+ ```
628
+
629
+ ### Caching
153
630
 
154
- ### Test Categories
631
+ ```python
632
+ from functools import lru_cache
155
633
 
156
- | Type | Focus |
157
- |------|-------|
158
- | Unit | Tool logic |
159
- | Integration | Full server |
160
- | Contract | Schema validation |
634
+ @lru_cache(maxsize=100)
635
+ def expensive_lookup(key: str) -> dict:
636
+ """Cached database lookup."""
637
+ return db.query(key)
638
+
639
+ @mcp.tool()
640
+ def get_user(user_id: str) -> dict:
641
+ """Get user with caching."""
642
+ return expensive_lookup(user_id)
643
+ ```
161
644
 
162
645
  ---
163
646
 
164
- ## 10. Best Practices Checklist
647
+ ## 10. Checklist
648
+
649
+ ### Before Publishing
165
650
 
166
651
  - [ ] Clear, action-oriented tool names
167
652
  - [ ] Complete input schemas with descriptions
@@ -169,8 +654,9 @@ my-mcp-server/
169
654
  - [ ] Error handling for all cases
170
655
  - [ ] Input validation
171
656
  - [ ] Environment-based configuration
172
- - [ ] Logging for debugging
657
+ - [ ] README with installation instructions
658
+ - [ ] Tests for critical paths
173
659
 
174
660
  ---
175
661
 
176
- > **Remember:** MCP tools should be simple, focused, and well-documented. The AI relies on descriptions to use them correctly.
662
+ > **Remember:** MCP tools should be simple, focused, and well-documented. The AI relies on descriptions to use them correctly. Write tool descriptions as if explaining to a junior developer.