Building Your Own MCP Server for AI

Authentication and Secrets

Store API keys and user credentials in the environment, understand OAuth at a high level, and never echo secrets to the model.

Anything you return from a tool can appear in the chat, logs, and the host’s transcript. Treat tool results as public to the human in that session. Secrets stay in the process environment or a secret manager — not in docstrings, not in default arguments.

Environment variables

Read keys at startup or on each call:

import os

import httpx
from mcp.server.mcpserver import MCPServer

mcp = MCPServer("github-lite")


@mcp.tool()
def github_me() -> dict:
    '''Return the authenticated GitHub login. Requires GITHUB_TOKEN in the environment.'''
    token = os.environ.get("GITHUB_TOKEN", "").strip()
    if not token:
        return {"ok": False, "error": "GITHUB_TOKEN is not set on the server"}
    headers = {
        "Authorization": f"Bearer {token}",
        "User-Agent": "geek-university-mcp-course/1.0",
        "Accept": "application/vnd.github+json",
    }
    with httpx.Client(timeout=10.0, headers=headers) as client:
        response = client.get("https://api.github.com/user")
    if response.status_code >= 400:
        return {"ok": False, "status": response.status_code, "error": "GitHub rejected the token"}
    data = response.json()
    return {"ok": True, "login": data.get("login")}

In Cursor MCP config, pass env into the child process:

{
  "mcpServers": {
    "github-lite": {
      "command": "/abs/path/.venv/bin/python",
      "args": ["/abs/path/server.py"],
      "env": { "GITHUB_TOKEN": "ghp_use_a_real_secret_store" }
    }
  }
}

OAuth, briefly

OAuth is for user access (“this person allowed my app to read their calendar”). The MCP server then holds a delegated token, not the user’s password. The dance (redirect, code, refresh token) usually lives in a small web app or the host. Your MCP tools only send Authorization: Bearer …. Do not implement a full OAuth client inside a stdio hello-world.

User credentials versus service credentials

  • Service token — one bot identity for the server (CI, a shared GitHub app). Simple, easy to over-scope.
  • Per-user token — the host or your login flow supplies a token for that person. Harder, safer for “their” data.

Never log the token. Never return it in a tool result. If you must debug, log token[-4:] only. Next: shape a multi-endpoint API into a few tools.