Lesson 13 of 30, Module 2: Your First Server. Your own server edits real documents in your Drive folder.
What you can do after this lesson
A tool that says done has only told you what it meant to do. Check the real thing from outside, vary the input on purpose, and write every error message as a message to the AI that will read it.
The problem we inherited
You install the official Google Drive server and Claude reads every document and changes none of them.
Code in this lesson
Every block the lesson shows on screen, in the order it appears.
uv run prove_it.py
python3 prove_it.py
1. READ draft.md FROM DRIVE
| # My first draft
|
| This is a test. Ths line has a typo in it.
2. FIX THE TYPO
server said:
| Changed 1 spot(s) in draft.md.
3. READ IT BACK FROM DRIVE
| # My first draft
|
| This is a test. This line has a typo in it.
4. ASK FOR WORDS THAT ARE NOT IN THE DRAFT
server said:
| That text is not in draft.md. Nothing changed.
5. ASK FOR A DRAFT THAT IS NOT THERE
server said:
| Error executing tool read_doc
(the server's own log is in server.log)
from mcp.server.mcpserver.exceptions import ToolError
if not found["files"]:
raise ToolError(
f"There is no draft called {name} in your folder.")
5. ASK FOR A DRAFT THAT IS NOT THERE
server said:
| Error executing tool read_doc: There is no draft called
| not-here.md in your folder.
(the server's own log is in server.log)
python3 verify_drive_access.py key.json YOUR_FOLDER_ID
3. CAN I CREATE A NEW FILE?
NO. HTTP 403, storageQuotaExceeded
Google says: Service Accounts do not have storage quota.
claude mcp add scribe \
-e SCRIBE_FOLDER_ID="paste your folder id here" \
-e SCRIBE_KEY="/Users/you/scribe/key.json" \
-- /Users/you/scribe/.venv/bin/python \
/Users/you/scribe/scribe_server.py
Downloads
- Module 2 checkpoint (scribe-checkpoint-m2.zip): working code as the module leaves it, so a broken session costs you nothing
- The course GitHub repo: every checkpoint, the README and the full lesson list
Prefer to read?
The written version of this part of the course is on Substack: https://genaiunplugged.substack.com/p/how-to-build-an-mcp-server-and-connect.
Lesson transcript
Stop taking its word for it
Your server says it changed the document. Today we stop taking its word for it.
Hello, and welcome to lesson 13 of the MCP Masterclass. Last lesson you built Scribe, with a tool that reads and a tool that edits. Today we prove that it works, and then we try to break it. And we start with our map, as always.
9 lit boxes, and no hole. Nothing new lights up today, because today we test what is already there.
Six tests, one fails
Well, last lesson ended with Claude telling you the typo was fixed. And I believe Claude.
But a program that says done has only told you what it meant to do. I want to see what it actually did.
So we run 6 tests today. And I will tell you now that 1 of them fails. That failure is the one I most want you to see.
Test 1: look in Drive
So let us start with test number 1, which needs no code at all. Go and look.
Open Google Drive in your browser, and open your draft.
On screen: draft.md open in Google Drive, with the typo gone. Then the file details panel, showing the service account as the last one to change the file.
The typo is gone, and that is the real file in your real Drive.
Now open the details of that file. Drive records who made the last change. And the name on it is your robot user from lesson 4.
So you did not change that file, and Claude did not change it either. Scribe changed it, with the key you gave it.
Test 2: a proof you can rerun
Test number 2. The same proof, but one you can run as often as you like.
Your module 2 checkpoint has a script called prove_it.py. Run it from your scribe folder.
uv run prove_it.py
Or with pip.
python3 prove_it.py
And here is the first part of what it prints.
1. READ draft.md FROM DRIVE
| # My first draft
|
| This is a test. Ths line has a typo in it.
2. FIX THE TYPO
server said:
| Changed 1 spot(s) in draft.md.
3. READ IT BACK FROM DRIVE
| # My first draft
|
| This is a test. This line has a typo in it.
Let us read that together.
First it reads your draft from Drive, and the typo is there. Then it asks your edit tool to fix it. Then it reads the draft from Drive a second time.
That second read is the whole point. The script does not trust what the tool said, so it goes back to Drive and looks.
And you may have noticed something odd. We fixed that typo last lesson, so why is it back?
Because the script puts it back before it starts. I built it that way on purpose. You can run this proof 100 times, and it always has something to fix.
Tests 3 and 4: bad inputs
Now we start changing the inputs. And I change them on purpose, because a tool that only works on a good day is not finished.
Test number 3. We ask for words that are not in the draft.
4. ASK FOR WORDS THAT ARE NOT IN THE DRAFT
server said:
| That text is not in draft.md. Nothing changed.
The tool says the text is not there, and it says nothing was changed. Then the script reads the draft again, and the draft is the same.
That is an honest tool. It did nothing, and it told us it did nothing.
Test number 4. We ask for a draft that does not exist.
5. ASK FOR A DRAFT THAT IS NOT THERE
server said:
| Error executing tool read_doc
(the server's own log is in server.log)
And this is the one that fails.
Look at what came back. It names the tool, and it tells us nothing else.
Now think back to last lesson. We wrote a plain sentence for exactly this case. There is no draft called that in your folder.
So where did our sentence go?
Why the error went quiet
This one is easy to miss, so let me save you the time. The MCP package hid it, and it hid it on purpose.
When your code crashes, the crash message can carry things you never meant to share. It can hold a path on your disk. It can even hold a piece of a key.
So the package plays it safe. It treats every surprise as a crash. It shows Claude the tool name only, and it keeps the rest in its own log.
That is a good rule. But our missing draft was no surprise, because we saw it coming, and we only have to say so.
The two small changes
It takes 2 small changes. First, one more import at the top of your file.
from mcp.server.mcpserver.exceptions import ToolError
Then go to the first helper, and change 1 word.
if not found["files"]:
raise ToolError(
f"There is no draft called {name} in your folder.")
A ToolError is nothing but a failure you saw coming. The package passes its words on to Claude, exactly as you wrote them.
Save the file, and run the proof again.
5. ASK FOR A DRAFT THAT IS NOT THERE
server said:
| Error executing tool read_doc: There is no draft called
| not-here.md in your folder.
(the server's own log is in server.log)
And there is our sentence.
Now, why does this matter so much?
Because Claude reads that message. With the first one, Claude can only tell you that something went wrong. With the second one, Claude can ask you for the correct name.
So an error message is a message to your AI. Write it the way you wrote your docstring, in plain words, for a colleague.
And notice that I left that failure in the lesson. I could have handed you the finished code last time, and you would never have seen it. But then you would not know what to do when your own tool goes quiet.
One more thing. You changed your server file, so Claude Desktop is still running the old one. Quit it properly, and open it again.
Test 5: Scribe cannot make a file
Test number 5. We test the thing Scribe must never do, which is to make a new file.
Run the setup check from your module 1 checkpoint again.
python3 verify_drive_access.py key.json YOUR_FOLDER_ID
Look at part 3 of what it prints.
3. CAN I CREATE A NEW FILE?
NO. HTTP 403, storageQuotaExceeded
Google says: Service Accounts do not have storage quota.
I told you about this limit in lesson 4. Now you have watched Google say it.
Your robot user owns no storage space, so Google refuses. And Scribe offers no tool that makes a file, so Claude has nothing to reach for.
I want you to remember that refusal, because in module 3 we build a guard. Part of its job is turning an error like this one into a plain sentence.
Test 6: a second app
And test number 6, which is my favourite. We open a second app.
Add Scribe to the second app you picked in lesson 6. In Claude Code it is one command.
claude mcp add scribe \
-e SCRIBE_FOLDER_ID="paste your folder id here" \
-e SCRIBE_KEY="/Users/you/scribe/key.json" \
-- /Users/you/scribe/.venv/bin/python \
/Users/you/scribe/scribe_server.py
Every other app takes the same few lines of settings that Claude Desktop took.
Now ask that second app to fix a typo in your draft.
On screen: a second app, Claude Code, calls edit_doc on the same Scribe server and fixes the typo in draft.md.
It uses the same tool, and the same document changes.
And if you have only Claude Desktop, watch mine and count with me. The arithmetic still lands.
So what did the second app cost you? You wrote 1 server, and 2 apps are using it. You wrote no glue for the second app, and you will write none for the third.
That is M+N from lesson 6. But this time the server in the middle is yours.
What we proved
So let us count what we proved today.
The real document changes, and Drive itself names Scribe as the one who changed it. The proof runs as often as you like. Missing words change nothing. A missing draft now gets a plain sentence. Scribe cannot make a file. And a second app uses your server with no new code.
That is 6 tests. One of them failed, and that one taught us the most.
So where does our map stand at the end of this lesson?
Still 9 lit boxes. Nothing new lit up today, but every box you lit last lesson is now proven.
Next lesson we will let Claude see the whole folder, and we will save your editing job.
Bye now, and I will see you in the next lesson.