# Kevin Tan > Thoughts on cloud architecture, AWS, and engineering leadership. By Kevin Tan, Cloud Solutions Architect & Engineering Leader. - [About](https://blog.jztan.com/about/): Author background and focus areas - [Archive](https://blog.jztan.com/archive/): All posts by date - [RSS Feed](https://blog.jztan.com/feed.xml): Atom feed ## AI Agents & LLMs - [How to Test and Debug a Python MCP Server](https://blog.jztan.com/how-to-test-and-debug-a-python-mcp-server/): How to test and debug a Python MCP server: the Inspector, in-process pytest, the stdio traps that fail silently, and a CI job that catches regressions. - [Claude Code Can't Read Vertical Japanese PDFs: How I Fixed Tategaki Extraction](https://blog.jztan.com/vertical-japanese-pdf-reading-order/): Vertical Japanese PDFs extract as scrambled glyphs because reading order is not stored. Here is how I rebuilt tategaki order from glyph geometry, no OCR. - [WebMCP in Production: What I Shipped and What I Removed](https://blog.jztan.com/webmcp-on-a-real-website/): I shipped six WebMCP tools on a live site, then removed three. On honeypots vs invited agents, spec gaps, and where agent-ready websites draw the line. - [Cross-Document RAG Without a Vector Database: SQLite + RRF](https://blog.jztan.com/rag-without-vector-database/): Merging search results across 100 PDFs breaks quietly: BM25 scores aren't comparable between documents. How SQLite FTS5 plus RRF fixed it, with benchmarks. - [Redmine MCP Server: Give AI Agents Live Project Data](https://blog.jztan.com/redmine-mcp-server-for-ai-agents/): Redmine holds your project data and your AI agent cannot see it. This open-source MCP server exposes 51 curated tools for issues, time tracking, and wiki. - [Turn a Folder of PDFs Into an AI Agent Knowledge Base](https://blog.jztan.com/ai-agent-pdf-knowledge-base/): Your AI agent does not need a vector database to search your PDFs. Turn any folder into a knowledge base with zero ingestion: warm, catalog, query, read. - [AI Agent Cloudflare 403: Two Libraries That Fix It and Cut Tokens 90%](https://blog.jztan.com/ai-agent-web-fetch-403-and-token-fix/): Your AI agent's web tool returns 403 on Medium and burns tokens on HTML noise. Here's the two-library fix that solves both, with real trace numbers. - [Why Multi-Column PDFs Scramble Reading Order in RAG](https://blog.jztan.com/multi-column-pdf-reading-order/): Multi-column PDFs silently scramble reading order, poisoning the text your RAG pipeline searches and embeds. Here's the bug that renamed a paper's author. - [How to Evaluate LLM Agents: 5 Patterns That Catch Failures](https://blog.jztan.com/how-to-evaluate-llm-agents/): Most LLM agent eval shortcuts break on honesty-trained models. Five assertion patterns that survived production, when to use each, and how to derive your own. - [RAG for AI Agents: 6 Decisions That Make or Break Retrieval](https://blog.jztan.com/rag-for-ai-agents-decision-guide/): Six decisions determine RAG quality for AI agents: search mode, fusion vs routing, chunk granularity, and more. Benchmark-backed defaults for each one. - [How One Search Change Eliminated an Entire Agent Step](https://blog.jztan.com/how-paragraph-excerpts-changed-agent-behavior/): Switching pdf_search from fixed-width snippets to structural paragraph excerpts changed the dominant agent workflow from search-then-read to search-then-done. - [How to Evaluate an MCP Server With an LLM: 17 Bugs Found and Fixed](https://blog.jztan.com/evaluate-mcp-server-with-llm/): I drove my Redmine MCP server like an agent would. Eight rounds of probing found 17 bugs that unit tests, schema tests, and MCP Inspector all missed. - [How AI Agents Should Read PDFs: 5 Patterns That Survived Production](https://blog.jztan.com/ai-agent-pdf-reading-patterns/): Five patterns for AI agents reading PDFs at scale: scout-then-read, tool decomposition, persistent caching, reading-order recovery, and search-mode routing. - [MCP Tool Sprawl: How I Cut 69 Tools to 43 With a Decorator](https://blog.jztan.com/mcp-tool-sprawl-consolidation/): When your MCP server hits 60+ tools, agents start picking the wrong ones. Here's how the Resource-Action Pattern cut redmine-mcp-server from 69 tools to 43 without losing a single capability. - [How to Deploy a Python MCP Server: Remote HTTP, Auth, and Docker](https://blog.jztan.com/how-to-deploy-a-python-mcp-server/): Your MCP server runs locally over STDIO. Here's how to deploy it as a remote HTTP service with bearer-token auth and Docker, ready for any host. - [Section-Level RAG: Why BM25 Beat Hybrid Search in My Benchmark](https://blog.jztan.com/bm25-vs-hybrid-search-section-rag/): Hybrid search lost to BM25 at section grain in my pdf-mcp benchmark: fusion caused a 33% lexical regression. Why granularity flips the verdict in RAG. - [Section Chunking vs Page Chunking for AI Agents: ~6 Fewer Tool Calls Per PDF Query](https://blog.jztan.com/section-chunking-vs-page-chunking-ai-agents/): Section-aware PDF search beats page-mode by 2 to 6 tool calls per query. Benchmarked on GPT-3, an LLM survey, and a GNN review against pdf-mcp v1.12.1. - [Your LLM Is Free QA for Your MCP Server](https://blog.jztan.com/llm-free-qa-mcp-server/): Four schema bugs I found in pdf-mcp because Claude got in their way during real PDF work. The tests passed. The payloads did not. - [I Built CI for My AI Agent (It Catches What You Miss)](https://blog.jztan.com/i-built-ci-for-ai-agents/): Your agent works. Then a prompt change breaks it silently. I built behavioral contract CI for blueclaw and caught 4 regressions before they shipped. - [How I Debug AI Agents Like Code (Not Guesswork)](https://blog.jztan.com/debug-ai-agents-like-code/): Most AI agent debugging is re-run, read output, guess, repeat. I built 10 trace CLI commands that let me inspect agent runs like a developer, not a guesser. - [I Cut My AI Agent's Token Costs 21% Without Changing the Model](https://blog.jztan.com/how-i-cut-ai-agent-token-costs/): My AI agent burned tokens on old tool outputs it never reread. One context strategy change cut costs 21%. Here's what I measured and how to replicate it. - [How I Added Observability to My AI Agent (Without a Hosted Dashboard)](https://blog.jztan.com/ai-agent-observability-without-dashboard/): I kept hitting failures I couldn't reproduce in my AI agent. Here's the observability layer I built into blueclaw: no hosted dashboard, no infra, just traces. - [Hybrid Search vs Query Routing in RAG: Benchmark on Real PDFs](https://blog.jztan.com/hybrid-search-vs-query-routing-ai-agents/): I benchmarked a query router against hybrid RRF search on real PDFs. The router missed exactly when it mattered. Here's the data, the failure pattern, and why fusion wins for AI agents. - [How to Ship an MCP Server to Production (Authentication, Safety, and What Breaks)](https://blog.jztan.com/what-it-actually-takes-to-ship-a-production-mcp-server-for-redmine/): Most MCP tutorials stop at tool integration. In production, the real work is authentication, guardrails, and handling untrusted data. - [Semantic vs Keyword Search for AI Agents: When to Use Each](https://blog.jztan.com/semantic-vs-keyword-search-ai-agents/): Semantic search finds synonyms. Keyword search finds invoice numbers. I benchmarked both in pdf-mcp. Here's exactly when each wins and the pattern production agents actually need. - [How Claude Code Actually Reads PDFs: Lessons from Building an MCP Server](https://blog.jztan.com/how-claude-code-actually-reads-pdfs-lessons-from-building-an-mcp-server/): Most MCP content explains how to build. This is what happens after you ship. Tool boundaries shape agent behavior more than prompts ever will. - [My AI Agent Passed Every Check. 67% of It Was Wrong.](https://blog.jztan.com/the-most-dangerous-llm-is-the-one-that-sounds-confident/): My AI agent's report passed every validation check. 67% of its facts were wrong. Here are 3 detection layers I built to catch confident hallucinations. - [Why AI Agents Hallucinate: Search Returns Headlines, APIs Fix It](https://blog.jztan.com/why-ai-agents-need-apis-not-search/): My AI agent got 10 of 15 financial claims wrong using web search. Switching to structured APIs fixed every one. Here's the architectural fix. - [Why Local LLMs Hallucinate When Your AI Agent Has Search](https://blog.jztan.com/why-local-llms-hallucinate-with-search/): Local models got 10 of 15 financial claims wrong, even with web search. The root cause: search returns headlines, not data. Here's what broke and why. - [The Production AI Agent Playbook: 8 Disciplines for Reliable LLM Systems](https://blog.jztan.com/production-ai-agent-playbook/): A practical playbook for building AI agents in production. Architecture, error handling, monitoring, security, and cost control for reliable LLM systems. - [Monitoring AI Agents in Production: 4 Layers That Actually Catch Failures](https://blog.jztan.com/monitoring-ai-agents-in-production-4-layers/): Four monitoring layers I added to my AI agent after a 709K-character runaway slipped past every health check. Here's what each layer caught. - [How to Test AI Agents Before They Break Production](https://blog.jztan.com/testing-ai-agents-in-production/): Unit tests aren't enough for AI agents. Learn the three testing layers that prevent hallucinations and tool failures before they reach production. - [MCP Server Security: 8 Vulnerabilities I Found and Fixed](https://blog.jztan.com/mcp-server-security-8-vulnerabilities/): SSRF, prompt injection, path traversal: I audited my MCP server (3,000+ downloads) and found 8 vulnerabilities. Every fix included, plus 2026's CVE wave. - [How to Build an MCP Server in Python with FastMCP 3.0 (Full Code)](https://blog.jztan.com/how-to-build-an-mcp-server-in-python-step-by-step/): Notes MCP server in Python with FastMCP 3.0: tools, resources, prompts, SQLite persistence, and in-process testing. Under 100 lines. Full source on GitHub. - [MCP vs Function Calling: Key Differences, Trade-offs, and When to Use Each](https://blog.jztan.com/mcp-vs-function-calling-ai-agents/): Function calling couples tools to your app. MCP decouples them for multi-agent reuse. Key differences, production trade-offs, and when each approach breaks down. - [AI Agent Error Handling: 5 Patterns to Catch Silent Failures](https://blog.jztan.com/ai-agent-error-handling-patterns/): Production AI agents fail silently with 200 OK responses. Five error handling patterns: circuit breakers, validation gates, idempotent sagas, budget guards. - [Copilot SDK Performance: How I Cut 33% Latency](https://blog.jztan.com/i-profiled-the-copilot-sdk-33-percent-latency-avoidable/): I profiled GitHub's Copilot SDK across 27 runs and 9 models. Most latency wasn't in inference. It was in client lifecycle overhead that's avoidable. - [Claude's 100-Page PDF Limit: The Free MCP Tool That Skips It](https://blog.jztan.com/how-i-built-pdf-mcp-solving-claude-large-pdf-limitations/): Claude analyzes PDF visuals for 100 pages, then text only. pdf-mcp is a free, open-source MCP server that searches and reads PDFs of any size in chunks. - [AI Agent API Access: Why Full Permissions Are a Security Risk](https://blog.jztan.com/i-gave-my-ai-agent-full-api-access-it-was-a-mistak/): Three MCP server design patterns that emerged from giving an AI agent unrestricted API access: pagination, intent-level tools, and resource isolation. - [Why AI Agents Fail in Production (And How to Fix Them)](https://blog.jztan.com/why-ai-agents-fail-in-production-and-what-i-learne/): Five lessons from real production failures: structured output, constraints over roles, silent failure modes, memory vs context, and architecture over model. - [Strands Agents SDK: Three Things That Clicked](https://blog.jztan.com/i-built-my-first-ai-agent-with-the-strands-agents/): Tools give agents agency, state gives them memory, and async lets them scale. What I learned building my first agent with the Strands SDK. - [AWS AgentCore Runtime for MCP: Why Local Was Faster for IDE Workflows](https://blog.jztan.com/i-spent-6-hours-on-aws-agentcore-for-mcp-idecli-in/): I tested AWS AgentCore Runtime as a managed host for my MCP server. Auth friction, latency, and cost made local the better choice for IDE workflows. - [How to Connect a Legacy System to AI Agents Using MCP](https://blog.jztan.com/how-i-linked-a-legacy-system-to-a-modern-ai-agent/): How I turned Redmine into an AI-ready platform using MCP, without rewriting or destabilizing the original system. Includes Python code and Docker setup. - [Agentic AI vs Generative AI: A Builder's Framework](https://blog.jztan.com/generative-ai-vs-agentic-ai-whats-the-difference-a/): Most systems called 'AI agents' are just prompts with API calls. A practical framework for what actually makes a system agentic, and when simpler is better. - [What Is MCP? The Universal Connector for AI Agents](https://blog.jztan.com/what-if-ai-agents-had-a-universal-connector-meet-m/): How Model Context Protocol gives AI agents a standard way to connect to tools, APIs, and data sources without custom integrations. - [RAG vs Fine-Tuning vs Prompting: A Decision Framework](https://blog.jztan.com/unlock-the-full-potential-of-your-llms-prompting-r/): A decision framework for choosing between prompt engineering, RAG, and fine-tuning. Real trade-offs on cost, latency, and maintenance in production LLM systems. - [I Tried AWS Bedrock Knowledge Bases: What Worked and What Didn't](https://blog.jztan.com/i-tried-aws-bedrock-knowledge-bases-for-the-first/): A hands-on look at AWS Bedrock Knowledge Bases for RAG, from 20-minute setup to an unexpected OpenSearch Serverless bill ## AWS & Cloud Infrastructure - [How I Built a Serverless Newsletter on AWS (SES + Lambda + DynamoDB)](https://blog.jztan.com/how-i-built-a-serverless-newsletter-on-aws/): Most newsletters run on Mailchimp or Substack. Yours doesn't have to. Here's how I built a fully serverless newsletter on AWS for under $1/month with full data ownership. - [How to Reduce AWS Lambda Costs: 10 Practical Tips](https://blog.jztan.com/aws-lambda-cost-optimization-practical-tips/): 10 practical tips to cut your AWS Lambda bill, from hidden CloudWatch costs to memory right-sizing, Graviton2, and knowing when to move off Lambda entirely. - [Serverless vs Containers: A Decision Framework](https://blog.jztan.com/serverless-vs-containers-decision-framework/): Stop asking 'it depends.' Five questions to decide between AWS Lambda and ECS Fargate, a practical framework for choosing the right compute platform. - [Parallel Processing in AWS Lambda with Python: What Actually Works (And What Doesn't)](https://blog.jztan.com/parallel-processing-in-aws-lambda-with-python-what/): Threads do not parallelize CPU work in Lambda, and standard multiprocessing crashes. The pipe-based fix, plus the memory setting that unlocks real vCPUs. - [The 7 Rs of Cloud Migration: A Decision Guide](https://blog.jztan.com/understanding-the-7-rs-of-cloud-migration-and-how/): Most teams pick the wrong migration strategy and pay for it later. A practical guide to the 7 Rs with real cost numbers and a decision checklist. - [Jekyll CI/CD with GitHub Actions: Production Gates, S3 Staging, and Scheduled Posts](https://blog.jztan.com/goodbye-manual-deployments-how-github-actions-made/): A two-environment CI/CD pipeline for a Jekyll blog: validation gates on prod, branch-path multiplexing on S3 for staging, and a daily cron for scheduled posts. - [AWS Global to China S3 Sync: A Serverless Solution](https://blog.jztan.com/a-serverless-bridge-between-aws-global-and-aws-chi/): A minimal, event-driven serverless architecture to sync S3 data between AWS Global and AWS China regions. No VPN, no persistent infrastructure required. ## Optional - [Welcome to My Blog](https://blog.jztan.com/welcome-to-my-blog/): What this blog covers: AI agents, MCP servers, retrieval, and AWS serverless systems, written from production work and backed by benchmarks.