- Preface i
-
1 The MCP Landscape: Why Protocol Beats Integration 3
- 1.1 The N-by-M Integration Problem 3
- 1.2 What a Protocol Buys You 5
- 1.3 The Three Primitives at a Glance 5
- 1.4 Where MCP Fits in the Stack 6
- 1.5 MCP, Function Calling, and Framework Tools 7
- 1.6 The MCP Client Ecosystem 8
- 1.7 The Four Servers You Will Build 9
- 1.8 Should You Use MCP at All? 9
- 1.9 Hands-On: Connect Your First Server 11
- 1.10 What You Will Be Able to Do 12
-
2 Protocol Internals: JSON-RPC, Transports, and the Handshake 13
- 2.1 Why the Wire Format Matters 13
- 2.2 JSON-RPC 2.0: The Foundation 14
- 2.3 MCP: JSON-RPC With Domain Methods 16
- 2.4 Transports: Changing the Pipe, Not the Message 17
- 2.5 The Initialization Handshake 20
- 2.6 Capability Negotiation 22
- 2.7 MCP Method Reference 23
- 2.8 Tools on the Wire 24
- 2.9 Resources on the Wire 27
- 2.10 Prompt Templates on the Wire 28
- 2.11 Error Handling: Four Layers of Failure 30
- 2.12 Hands-On Lab: Talk to a Server by Hand 31
- 2.13 A Debugging Checklist by Symptom 35
- 2.14 Summary and What Comes Next 36
-
3 The Three Primitives: Tools, Resources, and Prompts 38
- 3.1 Why Primitive Selection Is a Design Decision 38
- 3.2 Discovery Before Use 40
- 3.3 Tools: Callable Actions 40
- 3.4 Tool Return Values 44
- 3.5 Tool Design Boundaries 46
- 3.6 Resources: Readable Context 47
- 3.7 Resource Content Types 50
- 3.8 Resource Design Boundaries 50
- 3.9 Prompts: Reusable Message Workflows 51
- 3.10 Prompt Design Boundaries 53
- 3.11 Comparing the Three Primitives 54
- 3.12 Combining Primitives in One Server 56
- 3.13 Anti-Patterns 57
- 3.14 Hands-On Lab: Classify the Capabilities 59
- 3.15 Beyond the Three Primitives: What This Book Leaves Out 62
- 3.16 A Note on Versions 63
- 3.17 Summary and What Comes Next 63
-
4 Your First MCP Server in Python 66
- 4.1 Setting Up the Project 66
- 4.2 The Smallest Useful Server 68
- 4.3 A Second Tool: Optional Arguments and Bounded Output 69
- 4.4 How FastMCP Builds the Schema 70
- 4.5 Adding a Resource 71
- 4.6 Adding a Prompt Template 73
- 4.7 Running Over Stdio 74
- 4.8 A Preview of Client Configuration 76
- 4.9 Error Handling Done Right 77
- 4.10 Logging Without Breaking Stdio 78
- 4.11 The Complete Server 80
- 4.12 Hands-On Lab: Build, Run, and Break It 82
- 4.13 Mapping the Implementation Back to the Protocol 83
- 4.14 Common Beginner Mistakes 84
- 4.15 Summary and What Comes Next 85
-
5 Your First MCP Server in TypeScript 86
- 5.1 Setting Up the Project 87
- 5.2 The Project Files 87
- 5.3 The Smallest Useful Server 88
- 5.4 A Second Tool: Optional Arguments and Bounded Output 90
- 5.5 How Zod Maps to the Input Schema 91
- 5.6 Adding a Resource 91
- 5.7 Adding a Prompt Template 93
- 5.8 Running Over Stdio 94
- 5.9 A Preview of Client Configuration 96
- 5.10 Error Handling in TypeScript 97
- 5.11 Logging Without Breaking Stdio 98
- 5.12 The Complete Server 99
- 5.13 Python and TypeScript, Side by Side 101
- 5.14 Mapping the Implementation Back to the Protocol 102
- 5.15 Hands-On Lab: Build, Run, Break, and Compare 102
- 5.16 Common Beginner Mistakes 103
- 5.17 Summary and What Comes Next 104
-
6 Designing Tool Surfaces That Models Actually Use 107
- 6.1 Valid Is Not the Same as Usable 107
- 6.2 How Models See Tools 109
- 6.3 Tool Names: Specific, Action-Oriented, Boring 110
- 6.4 Descriptions: When to Use, Preconditions, Side Effects, Result 112
- 6.5 Schema Design: Arguments Are Model Instructions 113
- 6.6 Field Descriptions Decide Argument Quality 115
- 6.7 Enums and Constrained Values 116
- 6.8 Single Rich Tool vs. Multiple Narrow Tools 117
- 6.9 Idempotency and Retry Safety 120
- 6.10 Output Design: What the Model Sees After the Call 122
- 6.11 Error Design: Protocol Error vs. Domain Failure 123
- 6.12 Testing Tool Surface Quality 124
- 6.13 Versioning Tool Definitions 126
- 6.14 Security-Aware Tool Design 127
- 6.15 Applying the Checklist to the notes-server 128
- 6.16 Hands-On Lab: Redesign a Bad Tool Surface 130
- 6.17 The Tool Surface Checklist 132
- 6.18 Summary and What Comes Next 134
-
7 Resources: Serving Live Data to Agents 135
- 7.1 Resources Are the Read Path 136
- 7.2 Discovery and the Read Flow 137
- 7.3 The Anatomy of a Resource 138
- 7.4 URI Design Principles 139
- 7.5 Static Resources 142
- 7.6 Templated Resources 143
- 7.7 Text Resources 145
- 7.8 Binary and Blob Resources 146
- 7.9 Live Data Versus Cached Data 147
- 7.10 Context Efficiency: Return the Slice, Not the World 148
- 7.11 File-Backed Resources and Path Safety 150
- 7.12 Resources Versus Tools: Drawing the Line 152
- 7.13 Resources and Prompt Injection 153
- 7.14 Resources in the Four Reference Servers 154
- 7.15 Implementing Resources: Python and TypeScript 155
- 7.16 Hands-On Lab: Resources for the notes-server 157
- 7.17 Common Mistakes 159
- 7.18 The Resource Design Checklist 160
- 7.19 Summary and What Comes Next 161
-
8 Prompt Templates: Reusable Context Injection 163
- 8.1 Prompt Templates Are Workflow Starters 164
- 8.2 Discovery and Rendering Flow 165
- 8.3 The Anatomy of a Prompt Template 167
- 8.4 Prompt Names and Descriptions 168
- 8.5 Argument Design for Prompts 169
- 8.6 Rendered Message Sequences 171
- 8.7 Single-Turn vs. Multi-Turn Templates 172
- 8.8 Prompt Templates vs. Tools 173
- 8.9 Prompt Templates vs. Resources 174
- 8.10 Combining Prompts with Resources and Tools 175
- 8.11 Prompt Output Structure 177
- 8.12 Safety and Prompt Injection 177
- 8.13 Prompt Versioning and Compatibility 179
- 8.14 Implementing Prompts: Python and TypeScript 179
- 8.15 Prompt Templates in the Four Reference Servers 183
- 8.16 Hands-On Lab: Prompts for the notes-server 185
- 8.17 Common Mistakes 187
- 8.18 The Prompt Template Design Checklist 187
- 8.19 Summary and What Comes Next 189
-
9 Security and Sandboxing 190
- 9.1 MCP Servers Run With Real Permissions 191
- 9.2 The Threat Model for MCP Servers 192
- 9.3 The Defense-in-Depth Model 193
- 9.4 Capability Minimization 194
- 9.5 Token and Credential Scoping 197
- 9.6 Schema Validation Is Necessary but Not Sufficient 198
- 9.7 Path Allowlists and Filesystem Safety 199
- 9.8 Shell and Subprocess Safety 202
- 9.9 SQL and API Injection Prevention 204
- 9.10 Prompt Injection Through Resource and Tool Output 205
- 9.11 Output Sanitization and Framing 207
- 9.12 Dry-Run and Confirmation Workflows 208
- 9.13 Authentication and Authorization for SSE Servers 209
- 9.14 Logging and Audit Trails 211
- 9.15 Process and Container Isolation 212
- 9.16 Security Review of the notes-server 212
- 9.17 Security Review of the Four Reference Servers 213
- 9.18 Hands-On Lab: Harden an Insecure Server 214
- 9.19 The MCP Security Checklist 217
- 9.20 Summary and What Comes Next 218
-
10 Connecting to Claude Code and Other Clients 222
- 10.1 A Server Is Not Useful Until a Client Can See It 223
- 10.2 The Client Integration Mental Model 223
- 10.3 Configuration Anatomy 224
- 10.4 Connecting to Claude Code 225
- 10.5 Claude Code Config Examples 226
- 10.6 Managing and Inspecting Servers in Claude Code 228
- 10.7 Connecting to Claude Desktop 229
- 10.8 Cursor and Editor Clients 230
- 10.9 Zed and Other MCP-Aware Clients 231
- 10.10 Environment Variables and Secrets 232
- 10.11 Working Directory and Relative Paths 233
- 10.12 Python Server Connection Workflow 234
- 10.13 TypeScript Server Connection Workflow 235
- 10.14 SSE Server Connection Preview 236
- 10.15 How to Verify the Connection 237
- 10.16 Finding the Server's Logs 237
- 10.17 Troubleshooting by Symptom 238
- 10.18 Client Differences and Portability 240
- 10.19 Project-Shared Configuration Policy 241
- 10.20 Hands-On Lab: Connect Both Servers and Break Them 241
- 10.21 The Connection Checklist 243
- 10.22 Summary and What Comes Next 244
-
11 Building a WordPress MCP Server 245
- 11.1 Why WordPress Is a Good First Reference Server 246
- 11.2 Server Capability Overview 246
- 11.3 WordPress REST API Basics 247
- 11.4 Authentication with Application Passwords 248
- 11.5 Project Structure 249
- 11.6 The WordPress API Client 250
- 11.7 Tool Surface Design 252
- 11.8 Implementing the Tools 253
- 11.9 Resources for WordPress Content 257
- 11.10 Prompt Templates for Content Workflows 260
- 11.11 Error Handling and WordPress API Failures 261
- 11.12 Pagination and Result Limits 262
- 11.13 Security Review 263
- 11.14 Local WordPress Test Environment 264
- 11.15 Client Configuration 265
- 11.16 Hands-On Lab: Draft, Review, and Revise 266
- 11.17 Testing Strategy 268
- 11.18 Extending the Server 269
- 11.19 Common Mistakes 270
- 11.20 The WordPress MCP Checklist 270
- 11.21 Summary and What Comes Next 272
-
12 Building a GitLab MCP Server 274
- 12.1 Why GitLab Is the Developer-Workflow Reference Server 275
- 12.2 Server Capability Overview 276
- 12.3 GitLab REST API Basics 276
- 12.4 Authentication with Personal Access Tokens 277
- 12.5 Project Structure 278
- 12.6 The GitLab API Client 279
- 12.7 Tool Surface Design 281
- 12.8 Implementing the Issue Tools 282
- 12.9 Implementing the Merge-Request Tools 285
- 12.10 Implementing the CI/CD Tools 286
- 12.11 Resources for GitLab Data 289
- 12.12 Prompt Templates for Developer Workflows 291
- 12.13 Pagination and Result Limits 293
- 12.14 Error Handling and GitLab API Failures 294
- 12.15 Security Review 295
- 12.16 A Safe Test Setup 297
- 12.17 Client Configuration 298
- 12.18 Hands-On Lab: Triage, Diagnose, and Trigger Safely 299
- 12.19 Testing Strategy 300
- 12.20 Extending the Server 302
- 12.21 Common Mistakes 302
- 12.22 The GitLab MCP Checklist 303
- 12.23 Summary and What Comes Next 305
-
13 Building a DevOps Infrastructure MCP Server 306
- 13.1 The Wrong Way Is a Remote Shell 307
- 13.2 Server Capability Overview 308
- 13.3 Threat Model and Safety Boundary 309
- 13.4 Project Structure 310
- 13.5 Allowlist Configuration 311
- 13.6 Command Dispatcher Design 313
- 13.7 Safe Subprocess Execution in Python 315
- 13.8 Output Sanitization 317
- 13.9 Tool Surface Design 318
- 13.10 Implementing the Tools 319
- 13.11 Resources for DevOps Context 322
- 13.12 Prompt Templates for Incident Workflows 323
- 13.13 Audit Logging 325
- 13.14 Dry-Run and State-Changing Operations 326
- 13.15 Local Test Environment 327
- 13.16 Client Configuration 327
- 13.17 Hands-On Lab: Inspect Safely and Try to Break It 328
- 13.18 Testing Strategy 330
- 13.19 Extending the Server Safely 331
- 13.20 Common Mistakes 332
- 13.21 The DevOps MCP Checklist 332
- 13.22 Summary and What Comes Next 334
-
14 Building a Memory and Knowledge MCP Server 335
- 14.1 Memory Turns Sessions into Continuity 336
- 14.2 Server Capability Overview 336
- 14.3 Memory Design Principles 337
- 14.4 SQLite as the Default Backend 338
- 14.5 Project Structure 339
- 14.6 The SQLite Schema 340
- 14.7 The Database Access Layer 341
- 14.8 Tool Surface Design 343
- 14.9 Implementing the Tools 344
- 14.10 Memory Resources 346
- 14.11 Prompt Templates for Memory Workflows 348
- 14.12 Memory Hygiene 350
- 14.13 Privacy and Sensitive Data 351
- 14.14 Full-Text Search 352
- 14.15 Semantic Search and pgvector (Preview) 354
- 14.16 Error Handling 355
- 14.17 Security Review 356
- 14.18 Client Configuration 358
- 14.19 Hands-On Lab: Build a Memory and Use It 359
- 14.20 Testing Strategy 360
- 14.21 Extending the Server 362
- 14.22 Common Mistakes 362
- 14.23 The Memory MCP Checklist 363
- 14.24 Summary and What Comes Next 364
-
15 Testing, Debugging, and the MCP Inspector 368
- 15.1 If You Cannot Test It, You Cannot Ship It 369
- 15.2 The MCP Testing Pyramid 369
- 15.3 Debugging by Lifecycle Phase 370
- 15.4 The MCP Inspector 372
- 15.5 Connecting a Stdio Server to the Inspector 373
- 15.6 Debugging Failed Startup 374
- 15.7 Debugging Handshake Failures 375
- 15.8 Debugging Tool Failures 375
- 15.9 Debugging Resources and Prompts 376
- 15.10 Python Testing Strategy 377
- 15.11 TypeScript Testing Strategy 381
- 15.12 Protocol-Level Tests 383
- 15.13 Stdio Integration Tests 385
- 15.14 Security Test Cases 386
- 15.15 Testing the Four Reference Servers 387
- 15.16 CI Integration 388
- 15.17 Test Data and Fixtures 390
- 15.18 The Manual Debugging Checklist 391
- 15.19 Hands-On Lab: Probing the notes-server 392
- 15.20 Summary and What Comes Next 393
-
16 Packaging, Publishing, and SSE Deployment 394
- 16.1 Local Server vs. Production Service 395
- 16.2 The Deployment Decision Framework 395
- 16.3 Packaging Goals 396
- 16.4 Python Docker Packaging 397
- 16.5 TypeScript Docker Packaging 399
- 16.6 Docker Compose for Local Deployment 400
- 16.7 From Stdio to SSE 401
- 16.8 SSE Server Structure in TypeScript 402
- 16.9 SSE Server Structure in Python 403
- 16.10 Authentication and Authorization for SSE 404
- 16.11 Reverse Proxy Deployment 405
- 16.12 Scaling an SSE Deployment 407
- 16.13 Rate Limiting at the Network Edge 408
- 16.14 Health Checks and Readiness 408
- 16.15 Logging and Observability 410
- 16.16 Environment Variables and Secrets 411
- 16.17 Versioning Server Capabilities 412
- 16.18 Publishing Server Artifacts 413
- 16.19 Upgrade and Maintenance Strategy 415
- 16.20 Deployment for the Four Reference Servers 416
- 16.21 Hands-On Lab: Containerize and Deploy the GitLab Server 417
- 16.22 Common Mistakes 418
- 16.23 The Production Deployment Checklist 419
- 16.24 Summary, and the End of the Road 420
- Conclusion 422
The Model Context Protocol (MCP) in Practice
Building, Integrating, and Scaling Custom Tool Servers for AI Agents
A hands-on guide to designing, building, testing, and deploying secure stdio and SSE MCP servers in Python and TypeScript (437 manuscript pages).
Minimum price
$19.99
$29.99
You pay
Author earns
About
About the Book
The Model Context Protocol (MCP) in Practice is a hands-on guide to building custom MCP servers: the programs that let a language model use real tools, read live data, and work with organizational systems through one open protocol instead of one bespoke integration per client. It has sixteen chapters in five parts, follows the real arc of building a server from protocol to production, and is written for engineers who build things. It covers the server side of MCP only, and it does not teach how to write a client or host.
The first part explains what crosses the wire: the JSON-RPC 2.0 message shapes, the stdio and SSE transports, the initialization handshake and capability negotiation, and the three primitives every server is built from, which are tools, resources, and prompt templates. The second part builds the same small server twice, once in Python and once in TypeScript, so readers can separate what belongs to the protocol from what belongs to one SDK. The code uses pinned versions of both SDKs, and fast-moving details are gathered into clearly marked version-sensitive callouts.
The third part is the craft of design and security. It shows how to name and describe tools, write schemas, and shape results so that a model uses them correctly, how to serve live data as bounded resources, and how to package workflows as prompts. It then treats security as defense in depth, with capability minimization, scoped credentials, path and subprocess safety, injection defenses, and dry-run gates, all built on the premise that a model can be steered by the content it reads. The fourth part connects servers to Claude Code, Claude Desktop, Cursor, and Zed, and builds four reference servers: a WordPress content server in Python that can draft but never publish, a GitLab server in TypeScript that previews before it acts, a DevOps server in Python that runs only allowlisted operations, and a project-scoped memory server in Python backed by SQLite.
The final part proves and ships the work. It covers layered testing with the MCP Inspector, pytest, and vitest, protocol probes and stdio integration tests, Docker packaging for both languages, deployment over SSE behind a reverse proxy with authentication and health checks, versioning, and a decision framework for when a server should stay local. The SSE transport it demonstrates is now a legacy option in the SDKs, and the book explains the Streamable HTTP direction. Each chapter includes a hands-on lab, and from the design chapters onward each provides a reusable checklist. The safety helpers and storage layers of the reference servers have tests that were executed, while running each full server against a live system is left to the reader in the labs and the release checklist.
Readers come away able to choose the right primitive for a capability, design tool surfaces a model can use, secure a server against manipulation, connect it to real clients, test it in layers, and decide whether and how to deploy it. It suits backend, platform, DevOps, and AI engineers who are comfortable with HTTP APIs, JSON, and the command line, and it requires no machine-learning background.
Author
About the Author
Yohan is a Senior Full-Stack Software Engineer with extensive experience delivering scalable, end-to-end software solutions across web, enterprise, and cloud-based environments. He specializes in architecting robust platforms, modernizing legacy systems, driving cloud transformation efforts, and building integration-heavy applications that support critical business workflows. He is recognized for translating complex requirements into reliable, maintainable, and high-value solutions across industries such as insurance, cybersecurity, and professional services.
Known for combining strong technical execution with a practical business mindset, he has contributed to projects from concept and design through production delivery and long-term support. His experience includes collaborating with cross-functional teams, improving development workflows, solving complex technical challenges, and helping organizations deliver dependable software products that adapt to changing business needs. He brings a balanced approach to engineering that values quality, efficiency, and continuous improvement.
Contents
Table of Contents
Get the free sample chapters
Click the buttons to get the free sample in PDF or EPUB, or read the sample online here
The Leanpub 60 Day 100% Happiness Guarantee
Within 60 days of purchase you can get a 100% refund on any Leanpub purchase, in two clicks.
See full terms...
Earn $8 on a $10 Purchase, and $16 on a $20 Purchase
We pay 80% royalties on purchases of $7.99 or more, and 80% royalties minus a 50 cent flat fee on purchases between $0.99 and $7.98. You earn $8 on a $10 sale, and $16 on a $20 sale. So, if we sell 5000 non-refunded copies of your book for $20, you'll earn $80,000.
(Yes, some authors have already earned much more than that on Leanpub.)
In fact, authors have earned over $15 million writing, publishing and selling on Leanpub.
Learn more about writing on Leanpub
Free Updates. DRM Free.
If you buy a Leanpub book, you get free updates for as long as the author updates the book! Many authors use Leanpub to publish their books in-progress, while they are writing them. All readers get free updates, regardless of when they bought the book or how much they paid (including free).
Most Leanpub books are available in PDF (for computers) and EPUB (for phones, tablets and Kindle). The formats that a book includes are shown at the top right corner of this page.
Finally, Leanpub books don't have any DRM copy-protection nonsense, so you can easily read them on any supported device.
Learn more about Leanpub's ebook formats and where to read them
Write and Publish on Leanpub
You can use Leanpub to easily write, publish and sell in-progress and completed ebooks and online courses!
Leanpub is a powerful platform for serious authors, combining a simple, elegant writing and publishing workflow with a store focused on selling in-progress ebooks.
Leanpub is a magical typewriter for authors: just write in plain text, and to publish your ebook, just click a button. (Or, if you are producing your ebook your own way, you can even upload your own PDF and/or EPUB files and then publish with one click!) It really is that easy.