pse-mcp 0.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.
@@ -0,0 +1,522 @@
1
+ # Comprehensive Model Context Protocol (MCP) Implementation Guide
2
+
3
+ ## Introduction to MCP
4
+
5
+ The Model Context Protocol (MCP) is an open protocol that standardizes how applications provide context to LLMs. Think of MCP like a USB-C port for AI applications - just as USB-C provides a standardized way to connect your devices to various peripherals and accessories, MCP provides a standardized way to connect AI models to different data sources and tools.
6
+
7
+ ### What is MCP?
8
+
9
+ MCP helps you build agents and complex workflows on top of LLMs. LLMs frequently need to integrate with data and tools, and MCP provides:
10
+ - A standardized way to expose data through Resources
11
+ - Executable functionality through Tools
12
+ - Reusable interaction patterns through Prompts
13
+ - A client-server architecture where a host application can connect to multiple servers
14
+
15
+ ### Core Architecture Components
16
+
17
+ The MCP architecture follows a client-server model with these key components:
18
+
19
+ 1. **Host Applications**: Applications like Claude Desktop, VS Code, or other AI tools that want to access external data and tools
20
+ 2. **MCP Clients**: Protocol clients that establish and maintain connections with MCP servers, handling capabilities discovery and communication
21
+ 3. **MCP Servers**: Lightweight programs that expose three types of capabilities:
22
+ - **Tools**: Functions that can be called by the LLM to perform actions
23
+ - **Resources**: Data sources that provide context to the LLM
24
+ - **Prompts**: Reusable templates for LLM interactions
25
+ 4. **Transport Layer**: Supports two primary mechanisms:
26
+ - **stdio (stdin/stdout)**: For local communication when clients and servers run on the same machine
27
+ - **HTTP with Server-Sent Events (SSE)**: For remote communication over networks
28
+
29
+ ## MCP Protocol Details
30
+
31
+ ### Communication Model
32
+
33
+ MCP uses a client-server architecture with JSON-RPC 2.0 as its messaging format. The protocol supports two primary transport mechanisms:
34
+
35
+ 1. **stdio (stdin/stdout)**: Used for local communication when clients and servers run on the same machine
36
+ 2. **HTTP with Server-Sent Events (SSE)**: Used for remote communication over networks
37
+
38
+ ### Core Capabilities
39
+
40
+ MCP servers can provide three main types of capabilities:
41
+
42
+ 1. **Tools**: Functions that can be called by the LLM (with user approval) to perform actions
43
+ 2. **Resources**: Data sources that can be read by the LLM (like file contents or API responses)
44
+ 3. **Prompts**: Reusable templates for LLM interactions
45
+
46
+ ## Server Implementation
47
+
48
+ The server is the component that exposes tools, resources, and prompts to the client. Let's explore implementation approaches in both Python and TypeScript.
49
+
50
+ ### Python Server Implementation
51
+
52
+ Python offers a high-level SDK called `FastMCP` that simplifies server implementation, as well as a lower-level SDK for more advanced use cases.
53
+
54
+ #### Basic Server Setup with FastMCP
55
+
56
+ ```python
57
+ from fastmcp import FastMCP
58
+
59
+ # Create a named server
60
+ mcp = FastMCP("MyServer")
61
+
62
+ # Define a tool using decorator syntax
63
+ @mcp.tool()
64
+ def add(a: int, b: int) -> int:
65
+ """Add two numbers together"""
66
+ return a + b
67
+
68
+ # Define a resource
69
+ @mcp.resource("example://data")
70
+ def get_data() -> str:
71
+ """Provide example data as a resource"""
72
+ return "Example data content"
73
+
74
+ # Define a prompt
75
+ @mcp.prompt()
76
+ def greeting(name: str) -> str:
77
+ """Return a personalized greeting template"""
78
+ return f"Hello {name}, how can I help you today?"
79
+
80
+ # Run the server with stdio transport
81
+ if __name__ == "__main__":
82
+ mcp.run(transport="stdio")
83
+ ```
84
+
85
+ #### Advanced Python Server with Low-Level API
86
+
87
+ ```python
88
+ import asyncio
89
+ import mcp.server.stdio
90
+ import mcp.types as types
91
+ from mcp.server.lowlevel import NotificationOptions, Server
92
+ from mcp.server.models import InitializationOptions
93
+
94
+ # Create a server instance
95
+ server = Server("advanced-server")
96
+
97
+ # Register handlers for protocol requests
98
+ @server.list_tools()
99
+ async def handle_list_tools() -> list[types.Tool]:
100
+ """List available tools"""
101
+ return [
102
+ types.Tool(
103
+ name="example-tool",
104
+ description="An example tool",
105
+ inputSchema={
106
+ "type": "object",
107
+ "properties": {
108
+ "param1": {"type": "string", "description": "Parameter 1"}
109
+ },
110
+ "required": ["param1"]
111
+ }
112
+ )
113
+ ]
114
+
115
+ @server.call_tool()
116
+ async def handle_call_tool(name: str, arguments: dict) -> any:
117
+ """Handle tool calls"""
118
+ if name == "example-tool":
119
+ return f"Executed tool with argument: {arguments['param1']}"
120
+ raise ValueError(f"Unknown tool: {name}")
121
+
122
+ # Main server execution
123
+ async def main():
124
+ async with mcp.server.stdio.stdio_server() as (read_stream, write_stream):
125
+ await server.run(
126
+ read_stream,
127
+ write_stream,
128
+ InitializationOptions(
129
+ server_name="advanced-server",
130
+ server_version="0.1.0",
131
+ capabilities=server.get_capabilities(
132
+ notification_options=NotificationOptions(),
133
+ experimental_capabilities={},
134
+ ),
135
+ ),
136
+ )
137
+
138
+ if __name__ == "__main__":
139
+ asyncio.run(main())
140
+ ```
141
+
142
+ ### TypeScript Server Implementation
143
+
144
+ TypeScript provides a flexible SDK for MCP server implementation.
145
+
146
+ #### Basic TypeScript Server Setup
147
+
148
+ ```typescript
149
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
150
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
151
+
152
+ // Create a server instance
153
+ const server = new McpServer({
154
+ name: "typescript-server",
155
+ version: "1.0.0"
156
+ });
157
+
158
+ // Define a tool
159
+ server.setRequestHandler(
160
+ { jsonrpc: "2.0", method: "tools/list" },
161
+ async () => ({
162
+ tools: [
163
+ {
164
+ name: "multiply",
165
+ description: "Multiply two numbers",
166
+ inputSchema: {
167
+ type: "object",
168
+ properties: {
169
+ a: { type: "number", description: "First number" },
170
+ b: { type: "number", description: "Second number" }
171
+ },
172
+ required: ["a", "b"]
173
+ }
174
+ }
175
+ ]
176
+ })
177
+ );
178
+
179
+ // Handle tool calls
180
+ server.setRequestHandler(
181
+ { jsonrpc: "2.0", method: "tools/call" },
182
+ async (request) => {
183
+ const { name, arguments: args } = request.params;
184
+
185
+ if (name === "multiply") {
186
+ const result = args.a * args.b;
187
+ return { result };
188
+ }
189
+
190
+ throw new Error(`Unknown tool: ${name}`);
191
+ }
192
+ );
193
+
194
+ // Connect to stdio transport and start the server
195
+ async function main() {
196
+ const transport = new StdioServerTransport();
197
+ await server.connect(transport);
198
+ console.error("Server running on stdio");
199
+ }
200
+
201
+ main().catch((error) => {
202
+ console.error("Fatal error:", error);
203
+ process.exit(1);
204
+ });
205
+ ```
206
+
207
+ ## Client Implementation
208
+
209
+ MCP clients establish connections with servers, discover their capabilities, and relay them to the LLM. Here's how to implement clients in both Python and TypeScript.
210
+
211
+ ### Python Client Implementation
212
+
213
+ #### Basic Python Client
214
+
215
+ ```python
216
+ import asyncio
217
+ from mcp import ClientSession, StdioServerParameters
218
+ from mcp.client.stdio import stdio_client
219
+
220
+ async def main():
221
+ # Define server parameters
222
+ server_params = StdioServerParameters(
223
+ command="python", # Command to run the server
224
+ args=["server.py"] # Arguments to pass to the command
225
+ )
226
+
227
+ # Connect to the server
228
+ async with stdio_client(server_params) as (read, write):
229
+ # Create a client session
230
+ async with ClientSession(read, write) as session:
231
+ # Initialize the session
232
+ await session.initialize()
233
+
234
+ # List available tools
235
+ tools_response = await session.list_tools()
236
+ print(f"Available tools: {[tool.name for tool in tools_response.tools]}")
237
+
238
+ # Call a tool
239
+ result = await session.call_tool("add", {"a": 5, "b": 3})
240
+ print(f"5 + 3 = {result.result}")
241
+
242
+ if __name__ == "__main__":
243
+ asyncio.run(main())
244
+ ```
245
+
246
+ #### Integrating with Claude API
247
+
248
+ ```python
249
+ import asyncio
250
+ import os
251
+ from typing import Optional, List
252
+ from contextlib import AsyncExitStack
253
+
254
+ from mcp import ClientSession, StdioServerParameters
255
+ from mcp.client.stdio import stdio_client
256
+ from anthropic import Anthropic
257
+
258
+ class MCPClaudeClient:
259
+ def __init__(self):
260
+ self.session: Optional[ClientSession] = None
261
+ self.exit_stack = AsyncExitStack()
262
+ self.anthropic = Anthropic(api_key=os.environ.get("ANTHROPIC_API_KEY"))
263
+ self.tools = []
264
+
265
+ async def connect_to_server(self, server_script_path):
266
+ """Connect to an MCP server"""
267
+ server_params = StdioServerParameters(
268
+ command="python",
269
+ args=[server_script_path]
270
+ )
271
+
272
+ read, write = await self.exit_stack.enter_async_context(stdio_client(server_params))
273
+ self.session = await self.exit_stack.enter_async_context(ClientSession(read, write))
274
+
275
+ # Initialize session
276
+ await self.session.initialize()
277
+
278
+ # Discover tools
279
+ tools_response = await self.session.list_tools()
280
+ self.tools = tools_response.tools
281
+
282
+ print(f"Connected to MCP server with {len(self.tools)} tools available")
283
+
284
+ async def process_with_claude(self, user_message):
285
+ """Process user message with Claude using MCP tools"""
286
+ if not self.session:
287
+ raise RuntimeError("No active MCP session")
288
+
289
+ # Convert MCP tools to Claude's tool format
290
+ claude_tools = []
291
+ for tool in self.tools:
292
+ claude_tools.append({
293
+ "name": tool.name,
294
+ "description": tool.description,
295
+ "input_schema": tool.parameters
296
+ })
297
+
298
+ # Send to Claude with tools
299
+ response = self.anthropic.messages.create(
300
+ model="claude-3-5-sonnet-20241022",
301
+ max_tokens=1000,
302
+ messages=[{"role": "user", "content": user_message}],
303
+ tools=claude_tools
304
+ )
305
+
306
+ # Process Claude's response
307
+ for content in response.content:
308
+ if content.type == "tool_use":
309
+ # Claude wants to use a tool
310
+ tool_name = content.name
311
+ tool_args = content.input
312
+
313
+ print(f"Claude is calling tool: {tool_name}")
314
+
315
+ # Call the tool via MCP
316
+ tool_result = await self.session.call_tool(tool_name, tool_args)
317
+
318
+ # Send the result back to Claude
319
+ follow_up = self.anthropic.messages.create(
320
+ model="claude-3-5-sonnet-20241022",
321
+ max_tokens=1000,
322
+ messages=[
323
+ {"role": "user", "content": user_message},
324
+ {"role": "assistant", "content": response.content},
325
+ {"role": "tool", "name": tool_name, "content": str(tool_result.result)}
326
+ ]
327
+ )
328
+
329
+ return follow_up
330
+
331
+ return response
332
+
333
+ async def cleanup(self):
334
+ """Clean up resources"""
335
+ await self.exit_stack.aclose()
336
+
337
+ async def main():
338
+ client = MCPClaudeClient()
339
+ try:
340
+ await client.connect_to_server("path/to/server.py")
341
+ response = await client.process_with_claude("Calculate 5 + 3")
342
+ print(response)
343
+ finally:
344
+ await client.cleanup()
345
+
346
+ if __name__ == "__main__":
347
+ asyncio.run(main())
348
+ ```
349
+
350
+ ### TypeScript Client Implementation
351
+
352
+ #### Basic TypeScript Client
353
+
354
+ ```typescript
355
+ import { McpClient } from "@modelcontextprotocol/sdk/client/mcp.js";
356
+ import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
357
+
358
+ async function main() {
359
+ // Create a transport
360
+ const transport = new StdioClientTransport({
361
+ command: "node",
362
+ args: ["server.js"]
363
+ });
364
+
365
+ // Create client and connect
366
+ const client = new McpClient();
367
+ await client.connect(transport);
368
+
369
+ // Create a session
370
+ const session = await client.createSession();
371
+
372
+ // Initialize session
373
+ await session.initialize();
374
+
375
+ // List available tools
376
+ const { tools } = await session.listTools();
377
+ console.log("Available tools:", tools.map(tool => tool.name));
378
+
379
+ // Call a tool
380
+ const result = await session.callTool("multiply", { a: 5, b: 3 });
381
+ console.log("5 * 3 =", result.result);
382
+
383
+ // Clean up
384
+ await client.disconnect();
385
+ }
386
+
387
+ main().catch(console.error);
388
+ ```
389
+
390
+ ## Python vs TypeScript: A Comparison
391
+
392
+ When choosing between Python and TypeScript for MCP implementation, there are several factors to consider:
393
+
394
+ ### Strengths of Python for MCP
395
+
396
+ 1. **High-Level Abstractions**: Python's `FastMCP` provides a very clean, decorator-based API that makes creating servers intuitive
397
+ 2. **Type Annotations**: Modern Python's type hints work well with MCP's schema requirements
398
+ 3. **Async Support**: Python's asyncio integrates well with the asynchronous nature of MCP
399
+ 4. **AI Ecosystem**: Python has a strong ecosystem for AI/ML, making it easier to integrate with other AI libraries
400
+ 5. **Claude Integration**: The official Anthropic Python SDK integrates well with MCP
401
+
402
+ ### Strengths of TypeScript for MCP
403
+
404
+ 1. **JSON Native**: TypeScript's JavaScript roots make it natural for working with JSON-RPC
405
+ 2. **Web Integration**: Better for building web-based clients or servers (especially with SSE transport)
406
+ 3. **Type System**: More mature type system with interfaces and generics for protocol validation
407
+ 4. **NPX Execution**: TypeScript servers can be easily run with `npx` without installation
408
+ 5. **Most Official Examples**: More official example implementations use TypeScript
409
+
410
+ ### Development Experience Comparison
411
+
412
+ | Aspect | Python | TypeScript |
413
+ |--------|--------|------------|
414
+ | Setup Complexity | Simpler with FastMCP | More boilerplate code |
415
+ | Typing Experience | Good, but less strict | Excellent, more strict |
416
+ | Debugging | Excellent Python tooling | Good browser/Node tooling |
417
+ | Deployment | Requires Python runtime | Requires Node.js runtime |
418
+ | Learning Curve | Gentle with FastMCP | Steeper with lower-level API |
419
+
420
+ ### Performance Considerations
421
+
422
+ For most MCP implementations, performance differences between Python and TypeScript will be negligible, as MCP operations are typically I/O bound rather than CPU bound. The choice should be based more on your team's expertise and integration requirements.
423
+
424
+ ## Windows-Specific Considerations
425
+
426
+ Implementing MCP on Windows platforms requires attention to specific issues, especially when using stdio transport:
427
+
428
+ ### Line Ending Handling
429
+
430
+ Windows uses CRLF (`\r\n`) for line endings while Unix systems use LF (`\n`). This can cause issues with stdio transport if not handled correctly.
431
+
432
+ #### Python Solution
433
+
434
+ ```python
435
+ import sys
436
+ import os
437
+
438
+ # Force binary mode for stdin/stdout on Windows
439
+ if sys.platform == 'win32':
440
+ import msvcrt
441
+ msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)
442
+ msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
443
+ ```
444
+
445
+ #### TypeScript Solution
446
+
447
+ ```typescript
448
+ if (process.platform === 'win32') {
449
+ process.stdin.setEncoding('binary');
450
+ process.stdout.setDefaultEncoding('binary');
451
+ }
452
+ ```
453
+
454
+ ### Path Separators
455
+
456
+ Windows uses backslashes (`\`) in file paths, while MCP server commands often use forward slashes (`/`). Most MCP SDKs handle this automatically, but custom implementations need to be aware of this difference.
457
+
458
+ ### Executable Extensions
459
+
460
+ Windows commands typically require `.exe` extensions, and JavaScript/TypeScript scripts may require `.cmd` or `.bat` wrappers to run properly. The SDKs handle this, but custom implementations should consider it.
461
+
462
+ ## Best Practices for MCP Implementation
463
+
464
+ ### Security Best Practices
465
+
466
+ 1. **User Consent**: Always obtain explicit user consent before executing tools
467
+ 2. **Input Validation**: Validate all inputs at both the client and server levels
468
+ 3. **Least Privilege**: Servers should operate with the minimum required permissions
469
+ 4. **Secure Protocols**: Use HTTPS for remote connections (SSE transport)
470
+ 5. **Authentication**: Implement proper authentication for remote servers
471
+
472
+ ### Error Handling
473
+
474
+ 1. **Graceful Degradation**: Handle server unavailability gracefully
475
+ 2. **Timeouts**: Implement reasonable timeouts for operations
476
+ 3. **Retry Logic**: Add retry mechanisms for transient failures
477
+ 4. **Descriptive Errors**: Provide clear error messages for debugging
478
+
479
+ ### Performance Optimization
480
+
481
+ 1. **Connection Pooling**: Reuse connections where possible
482
+ 2. **Caching**: Cache capabilities and frequently used resources
483
+ 3. **Batching**: Batch multiple requests when appropriate
484
+ 4. **Compression**: Use compression for large resource transfers
485
+
486
+ ## Comprehensive Example: Building a Complete MCP Ecosystem
487
+
488
+ Let's put everything together with a complete example that includes:
489
+ - A Python-based MCP server with multiple tools
490
+ - A TypeScript-based MCP client
491
+ - Integration with Claude via the Anthropic API
492
+
493
+ ### Project Structure
494
+
495
+ ```
496
+ mcp-ecosystem/
497
+ ├── server/
498
+ │ ├── server.py # Python MCP server
499
+ │ └── requirements.txt # Python dependencies
500
+ ├── client/
501
+ │ ├── package.json # Node.js package definition
502
+ │ ├── tsconfig.json # TypeScript configuration
503
+ │ └── src/
504
+ │ └── client.ts # TypeScript MCP client
505
+ └── README.md # Project documentation
506
+ ```
507
+
508
+ ## Conclusion
509
+
510
+ The Model Context Protocol (MCP) provides a powerful standardized way to integrate LLMs with external tools and data sources. Both Python and TypeScript offer robust SDKs for implementing MCP clients and servers.
511
+
512
+ Python's strengths lie in its simplicity, high-level abstractions, and excellent integration with the AI ecosystem. TypeScript shines with its native JSON handling, strong type system, and web integration capabilities.
513
+
514
+ The choice between Python and TypeScript should be based on your specific requirements, team expertise, and the broader ecosystem you're integrating with. For AI-focused teams already working with Python, the Python SDK offers the smoothest experience. For web developers or teams building web-based AI applications, TypeScript might be the better choice.
515
+
516
+ ## Additional Resources
517
+
518
+ - [Official MCP Documentation](https://modelcontextprotocol.io/docs)
519
+ - [MCP Specification](https://spec.modelcontextprotocol.io/specification/2025-03-26/)
520
+ - [TypeScript SDK Repository](https://github.com/modelcontextprotocol/typescript-sdk)
521
+ - [Python SDK Repository](https://github.com/modelcontextprotocol/python-sdk)
522
+ - [Example MCP Servers](https://github.com/modelcontextprotocol/servers)