Lesson 16 of 30, Module 3: Make It Trustworthy. It refuses to leave the folder, asks before it overwrites, and remembers your answers.
What you can do after this lesson
A safety prompt that lives in the host is a setting, not a guarantee. A server that can write can write over the wrong thing without any error, so the question that must always be asked has to live inside your own server.
The problem we inherited
A server that can write can write over the wrong document, and there is no undo you can reach from a chat.
Code in this lesson
Every block the lesson shows on screen, in the order it appears.
@mcp.tool()
def edit_doc(name: str, find: str, replace: str) -> str:
"""Replace some text inside one draft in the Scribe folder."""
file_id = _find(name)
text = _text(file_id)
if find not in text:
return f"That text is not in {name}. Nothing changed."
new = text.replace(find, replace).encode()
body = MediaIoBaseUpload(io.BytesIO(new),
mimetype="text/markdown")
drive.files().update(fileId=file_id,
media_body=body).execute()
return f"Changed {text.count(find)} spot(s) in {name}."
Downloads
- Module 3 checkpoint (scribe-checkpoint-m3.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/give-your-ai-agents-memory-mcp-shared.
Lesson transcript
It stopped asking
Last week Claude Desktop stopped and asked me before it changed a file. This week it did not ask. And I had not changed 1 line of Scribe.
Hello, and welcome to lesson 16 of the MCP Masterclass, and welcome to module 3. In module 2 you built Scribe, and you proved that it changes a real document. Today we look at what a server that can write can also do to you. And we start with our map, as always.
11 lit boxes. Your server sits in the middle, with read_doc and edit_doc beside it, the folder Claude can browse, and your saved jobs. And there are 5 dark boxes left.
The one we care about today sits right between edit_doc and your documents. It is called the guard, and it is dark.
Reason 4, corrected
Well, before we build anything, I want to show you the thing that made me build it.
Do you remember reason number 4 from lesson 9? Consent. A script runs with your whole shell, and an MCP tool call is approved one call at a time.
That was true when I said it. And I want to correct it today, because I watched it stop being true on my own machine.
On screen: shot 2 of module 2. Claude Desktop stops on "Claude wants to use Edit doc from scribe", with Deny, Always allow and Allow once.
Here is lesson 12 again. Claude Desktop stops, and it asks me before edit_doc runs.
Now look at my mouse. I meant to click Allow once. I clicked Always allow.
On screen: shot 5 of module 2. Claude reads launch-post.md and makes 3 edits, one after another, and no dialog appears.
And here is lesson 14, recorded 2 hours later. Claude reads my draft and makes 3 changes to it, one after another. It never asks. Not once.
I did not change Scribe between those 2 recordings. I changed 1 setting, by accident, with 1 click.
So here is the correction. The asking in reason number 4 is done by the host. It is a setting inside Claude Desktop, and it is a good one. But it is the host's behaviour, and it is not a promise the protocol makes.
A different app might not ask at all. And your own app will stop asking the moment you tell it to.
So if you want a question that is always asked, it has to live in the 1 place that travels with your server. It has to live inside Scribe.
That is what module 3 is about. Not adding features. Making the features you have safe to trust.
And I want to show you exactly what safe to trust means, because the mistake I am worried about is a quiet one.
The quiet mistake
Here is edit_doc, as you wrote it in lesson 12.
@mcp.tool()
def edit_doc(name: str, find: str, replace: str) -> str:
"""Replace some text inside one draft in the Scribe folder."""
file_id = _find(name)
text = _text(file_id)
if find not in text:
return f"That text is not in {name}. Nothing changed."
new = text.replace(find, replace).encode()
body = MediaIoBaseUpload(io.BytesIO(new),
mimetype="text/markdown")
drive.files().update(fileId=file_id,
media_body=body).execute()
return f"Changed {text.count(find)} spot(s) in {name}."
It finds some text, and it replaces it. It changed 1 typo for you, and it did that job well.
Now think about what happens when Claude gets the find wrong.
Say I ask for the word the to become capital letters, in a draft that uses the word the 40 times. Claude sends the word the. Scribe changes 40 spots, and it says so, cheerfully.
Or say Claude sends nothing at all as the find. An empty find. In Python, an empty string is found everywhere. So Scribe puts the replacement between every single letter of your draft.
And here is the part that matters. There is no undo button in a chat. The file in your Drive is already different. Google Drive keeps old versions, and you can dig one out by hand. But Claude cannot, and Scribe cannot.
A server that can write can write over the wrong thing. That is the quiet mistake.
Nobody warns you about it, because nothing crashes. The tool returns a happy sentence, and the damage is already done.
What the guard does
So what does the guard do about it?
3 things, and we build them in that order over this module.
First, a fence. Scribe only ever touches drafts inside your 1 folder. That was already true in lesson 12, and you built it without noticing. In the next lesson we make Scribe say it out loud.
Second, a question. Before Scribe writes anything, it stops and asks you. And this question is asked by your server, so it travels to every app, and no setting can switch it off.
Third, a memory. Because a guard that asks the same question every single session gets annoying fast, and because you told Scribe your style rules last week and it has already forgotten them.
Checkpoint and next steps
There is 1 more thing you should know before we start, and it is good news.
Module 2 ended with Google refusing to let Scribe make a new file. That refusal came back as a plain sentence, because of the lesson 13 fix. In the next lesson the guard catches every refusal from Google the same way. Not only the one you have already seen.
One thing to do before the next lesson. Grab the module 3 checkpoint.
It holds Scribe exactly as module 2 left it, and 2 small scripts. One tries to break your server 3 ways. The other proves it remembers. Both are safe to run as often as you like.
So where does our map stand at the end of this lesson?
Still 11 boxes lit, and the guard is still dark. But now you know why it has to exist, and why it has to live inside your server and nowhere else.
Next lesson you build it. A fence, and a question before the write.
Bye now, and I will see you in the next lesson.