The Guitar Tab Problem
I wanted to generate guitar tabs to help me study various guitar techniques. My LLM (Claude by Anthropic) had plenty of suggestions and could create tabs for hammer-ons, walk downs, double stops, and scales. Within minutes, I had pages of practice material that seemed musical and well-explained.
But there were issues. Sometimes the tabs were fine, sometimes there were small alignment issues, sometimes they were completely unusable. Claude would generate tabs where the timing didn’t match the chord names, or where measures had different lengths, or where the fingering instructions made no sense. When I pointed out these errors, Claude would either apologize and repeat the same mistakes, or confidently insist that broken tabs were perfect.

Figure: Claude did a good job aligning the tabs here, but can’t ‘see’ when the fingering is messed up.

Figure: This is Claude’s attempt to instruct me on finger picking. It did not help.
How Can This Happen?
If you’ve read my previous posts on how LLMs actually work, you know the answer: LLMs are prediction machines, not logical reasoning systems. When Claude generates a guitar tab, it’s not following musical theory or carefully aligning notation. It’s predicting what text should come next based on patterns it learned during training.
Claude had seen thousands of guitar tabs in its training data, so it learned that tabs contain certain symbols, follow specific layouts, and use particular terminology. But it cannot learn the underlying rules that make tabs work—the precise alignment requirements, the mathematical relationships between timing and notation, or the constraints that ensure tabs are actually playable.
This is the fundamental limitation with LLMs. The probability-based mechanism can’t guarantee qualities such as accuracy, consistency, truthfulness, correctness. Or, in the case of guitar tablature, consistently structured, readable output.
Enter MCPs
I had recently learned about Model Context Protocols (MCPs), and this seemed like a good opportunity to see if they could provide a solution. MCPs connect LLMs to external tools and systems, bridging the gap between the LLM’s creative capabilities and the accuracy and logic of traditional programming.
MCPs are implemented as applications so they can be programmed to access data, perform calculations, and integrate with systems or applications. Or, in this case, consistently generate proper tab layouts, ensure correct alignment, and validate that the output follows tablature rules. I could let the LLM handle the creative parts, suggesting techniques, explaining theory, creating musical examples, while an MCP handled the precise formatting.
Why MCPs Are Needed
My guitar tab problem illustrates a broader issue with LLMs. There are fundamental limitations that no amount of prompting, fine-tuning, or clever techniques can solve. Again, I go into greater detail on this in my previous post. The issues relevant to tab generation are:
They don’t recognize their own limitations. When I asked Claude to fix alignment issues, it often made them worse while insisting they were better. LLMs generate confident-sounding responses for everything because that’s what they’re trained to do. They can’t recognize when they should say “I’m not equipped for this precise formatting task.”
They can’t perform reliable calculations. Guitar tabs require exact spacing and timing calculations. When an LLM generates things involving math, spacing, and timing it’s simulating patterns learned from training, not applying logic or calculations. Ask it to properly space a complex rhythm, and it might provide wrong spacing because it’s guessing based on what similar tabs looked like.
They struggle with structured formats. LLMs excel at human-readable text but fail when tasks require exact alignment or precise data structures. Claude could describe what a properly formatted tab should look like, but couldn’t reliably generate one.
My guitar tabs were just practice exercises, but companies and individuals are using LLMs for medical and financial decisions, customer service, automated decision-making, and mission-critical applications. They need to consider these fundamental limitations!
MCPs as the Bridge
Rather than hoping LLMs will somehow overcome their probabilistic nature, MCPs provide them with external capabilities that can address some of the deficiencies. The LLM remains the intelligent coordinator, deciding what tools to use and interpreting results. MCPs provide such things as: access to relevant, updated data, reliable information and calculations, structured thinking, fact checking, precise formatting, and access to external systems.
In this post I will go into more detail explaining exactly what MCPs are, and how they provide these capabilities.
What Are MCPs
MCPs (Model Context Protocols) are external applications that are created specifically to provide information to an LLM. Think of them as plugins or APIs specifically designed to work with LLMs.
From a technical perspective, they are callable resources—either local programs on your machine or services running on a server. For example, when Claude needs to generate a properly formatted guitar tab, it can call my MCP, send it the musical information, and get back perfectly aligned tablature that follows all the formatting rules.
The USB Standard for LLMs
One analogy for MCPs is the “USB standard” for LLM integrations. Just as USB created a universal way for computers to talk to keyboards, mice, printers, and storage devices without custom drivers for each combination, MCPs create a universal way for LLMs to interact with databases, APIs, file systems, calculators, and specialized tools.
Without USB, computer manufacturers would need to write custom drivers for every possible device combination—a daunting task. Without MCPs, every LLM would need custom integration code for every external tool, creating the same unsustainable complexity.
Traditional APIs are designed for human programmers who can read documentation, understand error codes, and parse various output styles. Given the nature of LLMs they struggle with both properly calling APIs and understanding how to leverage the results returned from them. MCPs are designed with very simple interfaces and extensive documentation such that an LLM is far more likely to reliably call them, handle issues, and parse the output.
Simple, Standardized, and Self Documenting
Simple: Unlike complex enterprise integration patterns, MCPs have minimal requirements. You need just a few standard methods (a listing of available tools and their interfaces) and some structured documentation. A basic MCP can be implemented in under 100 lines of code. No heavyweight frameworks, complex authentication, or elaborate service discovery are required.
Standard: MCPs define a consistent interface that any compatible LLM can understand. Just as web APIs standardized around HTTP methods and status codes, MCPs standardize around a small set of operations and response formats. This means an MCP I write for Claude could work with other LLM systems that support the protocol.
Self Documenting: The documentation integrated into an MCP isn’t an optional component. This documentation is where the MCP’s creator specifies how to effectively both call the MCP interfaces and process the results. It includes text descriptions of parameters and return results, best practices, examples, warnings, and anything else that might be useful for the LLM. This is prompting (or context) that the LLM processes and (hopefully) follows as it determines when and how to call the MCP.
The key insight is that LLMs need a different kind of interface than humans or software. My guitar tab MCP doesn’t just format tabs—it provides Claude with clear instructions on what musical information it needs, what format to expect back, and examples of proper usage. This bridges the gap between Claude’s probabilistic nature and the deterministic requirements of proper tablature formatting.
@mcp.tool() def generate_tab(tab_data: str) -> TabResponse: """ Generate UTF-8 tablature for stringed instruments from structured JSON input. Converts tab specifications into properly formatted UTF-8 tablature with comprehensive support for musical notation, dynamics, strum patterns, and playing techniques. Provides structured error messages for correction when input is invalid. Args: tab_data: Complete tab specification with title, parts, and structure Returns: TabResponse with generated tab content and any warnings ## Input Format - Parts System The parts system allows definition of reusable song sections with automatic numbering: ```json { "title": "Song Title", "artist": "Artist Name", "instrument": "guitar", "timeSignature": "4/4", "tempo": 120, "key": "G major",
Figure: The endpoint for the tab generation MCP. Note that the python docstring comments, starting with “””, actually continue for 500 lines! I am only showing about 30 of them. This documentation is sent back to the LLM so that it can determine how to use the endpoint.
What Types of Problems MCPs Solve
The algorithm LLMs use is simple, elegant, and incredibly powerful. But it is difficult to add special case logic into this architecture. Within reason, specialized functionality can be integrated into LLM systems—many now include built-in calculators or web search, But it’s not reasonable for LLM creators to add every possible capability users might need.
MCPs solve this by extending LLMs indefinitely, providing the core engine with access to information and capabilities it otherwise couldn’t reach.
Many MCPs are being created every day. Here are some of the broad categories they tend to fall into:
Data Access
LLMs are trained on static datasets with knowledge cutoffs. Claude can’t read your files, query your databases, or access external data sources or your company’s internal systems. MCPs bridge this gap by providing secure, controlled access to data.
Examples: Reading local files, querying SQL databases, accessing cloud storage, scraping web pages, pulling data from CRM systems, retrieving Git repository information.
System Interaction
LLMs cannot directly interact with operating systems, file systems, databases, or external services. MCPs can handle all of this—though be careful what you wish for! An MCP with broad system access could potentially perform damaging operations, leak information, or cause other problems if not properly designed.
Examples: Renaming local files, updating SQL databases, updating web pages, adding data to CRM systems, automating Git processes.
Specialized Computation
While LLMs can generate text that looks like math or code, they’re terrible at precise calculations. I just fed 847 × 329 into Claude and it confidently told me the answer is 278,763 (my calculator says 278,663) because it’s pattern matching, not computing.
Examples: Mathematical calculations, data analysis, image processing, statistical computations, algorithmic problem solving.
Real-Time Information
LLMs know what was true in their training data, but they can’t tell you today’s weather, current stock prices, or breaking news. Their knowledge becomes stale the moment training ends.
Examples: Weather APIs, financial data feeds, news services, system status checks, live sensor data.
Format Conversion and Validation
This is where my guitar tab frustration perfectly illustrates the problem. LLMs excel at generating human-readable text but struggle with precise formatting requirements and structured data validation. Claude could describe what a properly formatted tab should look like, but couldn’t generate one reliably.
Examples: Converting between data formats, validating structured data, generating properly formatted documents, parsing complex file formats, ensuring compliance with specifications.
How MCPs are Used
The interaction between LLMs and MCPs isn’t as straightforward as it might seem. Understanding how they work together—and where things go wrong—is crucial for anyone building or using MCP-enabled systems.
When MCPs Get Called
In order for an LLM to contact an MCP, you first need to configure the MCP connection. Configuration varies by both MCP and LLM types. Any particular MCP you would like to use is likely to have instructions on how to set it so that LLMs can discover it.
For testing I initially created my MCP as a local server running on my computer. Once I felt it was ready, I transferred it to a hosting service that made it generally available. (I will talk about this entire process in a later post.) In addition to testing, you may want to run an MCP locally if it needs to access local services, such as a file system MCP.
Despite proper configuration, Claude did not always know when it should use my tab generator MCP. For quite a while I had to explicitly tell it to call my service. Eventually, this seemed to become part of the conversation context, and Claude would remember to use it more consistently. This leads me to believe that configuration alone is not enough to convince an LLM that it should call a particular type of MCP.
A key point: LLMs make probabilistic decisions about when to use external tools based on patterns they learned during training and the context you provide. There’s no guarantee they’ll recognize when an MCP could solve their problem.
The Discovery and Calling Process
When Claude does decide to use an MCP, it follows a process: it determines what tools (these would be endpoints in API terminology) are exposed by the MCP, retrieves documentation about how to use them, and uses the documentation to determine appropriate data formats and their meaning. Finally, it makes the actual call with properly formatted input JSON, the format of choice for LLMs.
Claude was remarkably good at generating proper JSON for MCP calls—I don’t think I ever saw a formatting error. It also parsed the JSON responses cleanly. I assume that LLMs have been trained on vast quantities of JSON, and this is why they handle the format so reliably.
{ `tab_data`: `{ \"title\": \"Song in Am\", \"key\": \"A minor\", \"timeSignature\": \"4/4\", \"parts\": { \"Verse\": { \"description\": \"Main verse in Am\", \"measures\": [ { \"strumPattern\": [\"D\", \"\", \"D\", \"\", \"D\", \"U\", \"D\", \"U\"], \"events\": [ {\"type\": \"chord\", \"beat\": 1.0, \"chordName\": \"Am\", \"frets\": [ {\"string\": 5, \"fret\": 0}, {\"string\": 4, \"fret\": 2}, {\"string\": 3, \"fret\": 2}, {\"string\": 2, \"fret\": 1} ]}, {\"type\": \"chord\", \"beat\": 3.0, \"chordName\": \"F\", \"frets\": [ {\"string\": 6, \"fret\": 1}, {\"string\": 4, \"fret\": 3}, {\"string\": 3, \"fret\": 2}, {\"string\": 2, \"fret\": 1} ]} ] } ] }, \"Chorus\": { \"description\": \"Chorus section\", \"measures\": [ { \"strumPattern\": [\"D\", \"\", \"D\", \"\", \"D\", \"U\", \"D\", \"U\"], \"events\": [ {\"type\": \"chord\", \"beat\": 1.0, \"chordName\": \"C\", \"frets\": [ {\"string\": 5, \"fret\": 3}, {\"string\": 4, \"fret\": 2}, {\"string\": 3, \"fret\": 0}, {\"string\": 2, \"fret\": 1} ]}, {\"type\": \"chord\", \"beat\": 3.0, \"chordName\": \"G\", \"frets\": [ {\"string\": 6, \"fret\": 3}, {\"string\": 5, \"fret\": 2}, {\"string\": 1, \"fret\": 3} ]} ] } ] } }, \"structure\": [\"Verse\", \"Chorus\", \"Verse\", \"Chorus\", \"Verse\"] }` }
Figure: JSON tab request generated by Claude for the tab generation MCP
{"success":true,"content":"# Song in Am\n
**Time Signature:** 4/4 | **Key:** A minor\n\n
**Song Structure:**\n
Verse 1 → Chorus 1 → Verse 2 → Chorus 2 → Verse 3\n\n
**Parts Defined:**\n
- **Verse**: 1 measure - Main verse in Am\n
- **Chorus**: 1 measure - Chorus section\n\n
## Verse 1\n
*Main verse in Am*\n\n
Am F\n
1 & 2 & 3 & 4 & \n
|-----------------|\n
|-1-------1-------|\n
|-2-------2-------|\n
|-2-------3-------|\n
|-0---------------|\n
|---------1-------|\n
D D D U D U\n\n\n
## Chorus 1\n
*Chorus section*\n\n
C G\n 1 & 2 & 3 & 4 & \n
|---------3-------|\n
|-1---------------|\n
|-0---------------|\n
|-2---------------|\n
|-3-------2-------|\n
|---------3-------|\n
D D D U D U\n\n\n
## Verse 2\n
*Main verse in Am*\n\n
Am F\n 1 & 2 & 3 & 4 & \n
|-----------------|\n
|-1-------1-------|\n
|-2-------2-------|\n
|-2-------3-------|\n
|-0---------------|\n
|---------1-------|\n
D D D U D U\n\n\n
## Chorus 2\n
*Chorus section*\n\n
C G\n 1 & 2 & 3 & 4 & \n
|---------3-------|\n
|-1---------------|\n
|-0---------------|\n
|-2---------------|\n
|-3-------2-------|\n
|---------3-------|\n
D D D U D U\n\n\n
## Verse 3\n
*Main verse in Am*\n\n
Am F\n 1 & 2 & 3 & 4 & \n
|-----------------|\n
|-1-------1-------|\n
|-2-------2-------|\n
|-2-------3-------|\n
|-0---------------|\n
|---------1-------|\n
D D D U D U\n\n
","error":null,"warnings":[]}
Figure: JSON tab response returned from my tab-generator MCP.
Iterative Interactions
MCP calls aren’t one-time events. Claude might call my tab generator, hit an error, then automatically retry with modified parameters—something like “That didn’t work, let me try specifying the timing explicitly.” Sometimes this was based on error codes from the MCP, though Claude didn’t always explain why it was trying a different approach.
This automatic retry behavior was usually helpful, showing that LLMs can learn from MCP responses within a conversation and adjust their approach accordingly.
Where Things Go Wrong
The interaction between LLMs and MCPs creates several failure modes that can be subtle and dangerous. Here are the issues that I encountered:
Forgetting to Call MCPs: Sometimes Claude would generate broken guitar tabs by itself, completely forgetting that the MCP existed. In these cases I would need to explicitly tell it to redo the work, calling the MCP this time.
Ignoring MCP Results: Even when Claude successfully called my MCP, it sometimes failed to show the results—despite that being the only reason to call it! This was particularly frustrating because the MCP was working perfectly, but users would never see the output.

Figure: Despite repeated requests to display the results of the tab generation in both my chat and encoded in the MCP instructions, Claude would often fail to do so.
Reformatting MCP Data: Occasionally, Claude would take the precisely formatted data returned from my MCP and “helpfully” reformat it, destroying the exact alignment and spacing that made the tabs functional.

Figure: Claude reformatted the data returned from the MCP, ruining the layout
Hallucinated Interactions: The most dangerous failure mode occurred when my MCP server wasn’t running. Usually Claude would notice and tell me the MCP was unavailable. But occasionally it would invent entire interactions with my MCP—complete with realistic-looking responses and testing processes—only for me to discover later that the server had never been contacted at all. When I pointed out the data was fabricated, Claude gave the standard apologetic response, but the damage was already done.

Figure: Apologies for the long image.This is (only part of) Claude hallucinating an entire interaction with my MCP server, including JSON requests and response, then claiming success. I realized shortly after I had asked Claude to perform these tests that I had not in fact started the server!

Figure: This is how Claude should (and usually did) respond when the server could not be found.
No Guarantees
Here’s the crucial point: there’s no guarantee that an LLM will use MCP data correctly, even when the MCP works perfectly. Claude occasionally showed me returned data that contained bugs it missed, though usually it was good at noticing problems. Sometimes it would modify or ignore MCP results based on its own “understanding” of what looked right.
This unpredictability means MCPs aren’t a silver bullet. They can help solve the problem of providing LLMs access to reliable external capabilities, but they don’t solve the fundamental issue of LLMs being probabilistic systems that make unpredictable decisions about how to use those capabilities.
For developers building MCP-enabled applications, this means you need monitoring, validation, and fallback strategies—not just working MCPs.
The Reality of MCPs
These failure modes might sound discouraging, but they’re really just the same issues you encounter with LLMs in general – probabilistic systems making unpredictable decisions. The difference is that MCPs give you tools to work around those limitations when they matter most.
Despite the complications, MCPs can provide genuinely useful functionality. The key is understanding both their capabilities and their constraints, then designing your workflow accordingly. In Part 2, I’ll explore concrete examples of popular MCPs, show you where to find them, and share what I learned building my guitar tab generator.