Starting Over: Accepting the AI Revolution through MCP

Starting over is never easy. I’ve had to do it a few times. It’s one of the few things in life that actually gets harder each time you do it. From school to my first failed career in church music, to my short-lived career in commercial photography, to a total reboot into tech as a front-end engineer, to back-end engineer, to managing engineers, to managing managers - some were harder than others to be sure, but with each successive revolution the cognitive load hit me harder.

Despite my ostensible continued growth, I managed to remain set in at least some of my ways. I still primarily work in VIM when I still code, and I have mostly resisted the AI revolution so far. I read the blog posts and tried out a few models, and even wrote a simple (not terribly good) VIM plugin so I could get a little AI flavor in my normal workflow. But, I wasn’t really excited about it.

Until I played with MCP. At work, a friend wrapped some of our APIs in an MCP and hooked it up to our in-house agent (codename goose). After about 5 minutes of playing with our APIs via agent/MCP I never wanted to write another curl command or create another postman collection again. The ease of asking the agent in plain English to do the things, and the peaceful bliss of watching it stumble through all the usual mistakes I would have made to find the right APIs, string together the right calls, and verify the outputs - were both vindication and an epiphany: this is a universal interface that removes the work of writing many interfaces, as well as the collective cognitive load of using so many of them.

Immediately, I started writing MCPs for my own personal projects. I started by just wrapping my one-off scripts and tools in a simple MCP I could provide to goose or Claude. Suddenly, stumbling through remembering all of the magic invocations I wrote however many months or years ago became “hey goose, can you check on my server and restart the things if they need it?” And it just worked. I still have the same scripts. I can read them if I need to go back and understand. But, I don’t have to remember. And moving forward, I don’t have to constantly rebuild the interface - with the agent/MCP combo, documentation is the interface.

Take the following example MCP I wrote to help manage a test server for a personal project:

# server.py
from mcp.server.fastmcp import FastMCP
import subprocess

# Create an MCP server
mcp = FastMCP("oncall")


# check the server tool
@mcp.tool()
def check_server() -> str:
    """
    logs into the test server
    kickstart.js should be listed as a running forever process in the output

    """
    return run_shell_cmd(["ssh", "test", "cd", "server", ";", "forever", "list"])

# restart the server tool
@mcp.tool()
def restart_server() -> str:
    """
    logs into the test server and restarts the main process

    """
    return run_shell_cmd(["ssh", "test", "cd", "server", ";", "forever", "restart", "kickstart.js"])
  
# check the db tool
@mcp.tool()
def check_db() -> str:
    """
    logs into the test server and checks if the db is running

    """
    return run_shell_cmd(["ssh", "test", "service", "mongod", "status"])

# restart the db tool
@mcp.tool()
def restart_db() -> str:
    """
    logs into the test server and restarts the db

    """
    return run_shell_cmd(["ssh", "test", "sudo", "service", "mongod", "restart"])

def run_shell_cmd(cmd):
  result = subprocess.run(cmd, shell=False, capture_output=True, text=True)


  # Print the error (if any)
  if result.stderr:
    return f'Error: {result.stderr}'

  # Print the output
  return f'Result: {result.stdout}'

if __name__ == "__main__":
    mcp.run()

Also, the goose config so the agent knows how to run the mcp:

OLLAMA_HOST: localhost:9000
GOOSE_MODEL: claude-3-5-haiku-latest
GOOSE_PROVIDER: anthropic
extensions:
  developer:
    display_name: Developer
    enabled: true
    name: developer
    timeout: 300
    type: builtin
  oncall:
    args:
    - run
    - /Users/johnfellman/shop/skybot/mcp/oncall/server.py
    cmd: uv
    description: oncall
    enabled: true
    name: oncall
    timeout: 1000
    type: stdio

That’s all it takes for an agent like goose to be able to do some basic maintenance tasks:

goose working with mcp

It’s a trivial example, but it’s easy to see how much time and cognitive load can be saved by using an agent + a simple MCP wrapper as the unified, natural interface for the myriad of tools a programmer may use day to day.