AI Greg: a public MCP server that answers for me
One brain, five channels. Anyone's AI agent can interview me; anything it cannot answer goes to the real Greg with a human approval gate on every write.
- Status
- live
- Stack
- Python, FastMCP, Cloud Run, Gemini File Search, Firestore, Twilio, Slack Events API
- Links
- Web front door: mcp.aigreg.bot · MCP endpoint
The problem
People ask me the same forty questions. What do you teach, can you speak at our event, how do I connect my AI to your stuff, what do you think about AI in the classroom. Answering each one by hand is slow, and the answers already exist in things I have written: over a hundred articles, a hundred-plus podcast episodes, a full graduate course.
At the same time, more and more first contact is going to arrive through someone else’s AI agent rather than a person typing an email. I wanted that agent to have somewhere to go.
The constraint
It has to speak for me without pretending to be me, and it has to be safe to leave running unattended on the public internet with my calendar and email behind it.
What I built
A Model Context Protocol server at mcp.aigreg.bot, running on Cloud Run. Read tools answer from a personal corpus through Gemini File Search. Write tools (leave a message, request a meeting) do not act. They create a ticket in Firestore that I approve or decline.
Five channels share the one brain: the MCP endpoint for agents, a web front door for people with a browser (the ask box on this site is that front door), email, SMS through Twilio, and Slack. Same corpus, same escalation path, same ticket queue.
Three design decisions carry the weight:
Trust tiers, not one big yes. Anonymous callers get public-depth answers. Verifying an email unlocks deeper material. An allowlist unlocks the rest. The filter is applied server-side before the model reads anything, and there is deliberately no retry-without-filter fallback, because by the time you post-filter the model has already read restricted text and put it in the answer.
Fail toward a human, never toward a guess. Every failure path in retrieval returns confidence zero rather than raising. Low confidence means escalate to Greg. The system degrades to a person instead of to a wrong answer.
Least privilege, written down. The OAuth scopes are calendar free-busy, calendar event creation, send-only mail, and one read-only Drive folder. No mail read. No full calendar read. The README says so in capitals, because the scopes are the security model and the next person to touch the code should not have to infer that.
Spam control is email verification rather than a CAPTCHA. A bot can post a thousand addresses and generate zero inbox mail, because it does not control those mailboxes. The same click that proves the address also promotes the sender to the verified tier, so the friction buys something.
What it cost or taught
The filter syntax that reads best (visibility IN [public, verified]) is rejected by the store with a 400. The failure would have been quiet: retrieval fails closed, so a rejected filter escalates every anonymous question to me as a ticket, which looks like thin corpus coverage rather than a syntax bug. Two tests now pin the working string and ban the readable one. Verification scripts report leaks rather than passes, because a filter that silently returns everything looks like it is working.