The Night I Stopped Copy-Pasting Logs
I spent 20 minutes pasting Syslog excerpts into Claude to diagnose a routing issue before I realized MCP could do this automatically. The incident started as a quiet second-shift complaint: two CNC controller workstations on our machining VLAN could reach the MES app, but they were intermittently losing their route to a historian collector. Our FortiGate running FortiOS 7.4.3 showed clean policy hits, Ubuntu 22.04 collectors were healthy, and the switch stack looked boring at first glance.
I grabbed Syslog chunks, copied FortiAnalyzer event lines, trimmed timestamps, removed internal hostnames, and pasted the mess into a chat window. Then I did it again after finding NetFlow samples. Then again after pulling BGP neighbor state from our core. The AI was useful, but my workflow was ridiculous because I had turned a machine-speed diagnostic assistant into a clipboard-powered intern.
That was the wrong bottleneck.
MCP, or Model Context Protocol, clicked for me when I stopped thinking about it as another API wrapper and started treating it as a controlled context plane. The model does not need every credential, every file, or every dashboard. It needs a narrow set of tools and resources that answer operational questions from source systems without me laundering the evidence through screenshots and pasted text.
The practical win was immediate. We reduced time to context-load for AI-assisted diagnostics from 15 minutes to under 2 minutes by letting the AI query approved log slices, interface counters, and change records directly. I still make the decision, and my team still owns the blast radius, but the tedious gathering phase no longer dominates the work. In my environment, MCP is not hype; it is plumbing we should have had earlier.
What MCP Is When I Strip Away the Hype
I describe MCP to other engineers as a standard way for an AI client to discover and use capabilities exposed by a local or remote server. Those capabilities usually fall into three buckets: tools, resources, and prompts. Tools perform actions or queries, resources expose readable context, and prompts provide reusable task patterns. Under the hood, the protocol uses JSON-RPC, which makes the interaction explicit enough for logging, review, and defensive controls.
That explicitness matters.
Traditional API integrations usually start with an application deciding exactly what to call. MCP flips part of that experience. The client can ask what capabilities exist, inspect schemas, and call only the approved operations. In a plant network, that means I can expose a read-only tool for recent firewall denies without handing an AI assistant broad SSH access to the firewall or unrestricted access to our log archive.
Here is the mental model that helped my team keep the design sane:
- Resources are context the model can read, such as a saved incident note or a sanitized Syslog window.
- Tools are bounded actions, such as querying interface errors for one switch and one time range.
- Prompts are repeatable workflows, such as “triage routing instability using approved evidence.”
- Transports are delivery paths, commonly local stdio or HTTP-based communication.
- Schemas are guardrails because every parameter should have a shape, type, and limit.
I do not want MCP servers that feel magical. I want boring contracts, boring logs, boring authentication, and boring failure modes. Boring is what survives a maintenance window.
Build My First Python MCP Server
My first useful MCP server was small: Python 3.11 on Ubuntu 22.04, reading from a sanitized log directory and exposing a tool called search_syslog. I kept it local at first because I wanted to see every call before letting it touch anything near production. The point was not to build a chatbot. The point was to remove the copy-paste tax from diagnostics.
The skeleton looked like this:
from mcp.server.fastmcp import FastMCP
from pathlib import Path
mcp = FastMCP("plant-diagnostics")
LOG_ROOT = Path("/srv/ai-context/syslog-readonly").resolve()
@mcp.tool()
def search_syslog(host: str, minutes: int, contains: str) -> list[str]:
if minutes < 1 or minutes > 120:
raise ValueError("minutes must be between 1 and 120")
results = []
for path in LOG_ROOT.glob(f"{host}.log"):
for line in path.read_text(errors="ignore").splitlines():
if contains.lower() in line.lower():
results.append(line[:500])
if len(results) >= 50:
return results
return results
@mcp.resource("runbook://routing-triage")
def routing_triage_runbook() -> str:
return "Check recent denies, interface errors, routing changes, and ARP churn."
if __name__ == "__main__":
mcp.run()
Small beats clever here.
I also added a prompt that forced the assistant to separate evidence from guesses. That sounds minor, but it changed the quality of the output. Instead of “this might be a firewall issue,” I got a tighter response: “I see no denies for the source and destination during the window; interface errors increased on uplink Gi1/0/48; check physical path before policy.” That is the kind of answer I can use while a production supervisor is asking when the cell will be stable again.
My opinion after building the first server is blunt: a useful MCP server should start narrow enough that it feels almost underpowered. Expansion is easy. Cleaning up an overexposed integration after trust is lost is much harder.
Connect Claude Desktop to Our Monitoring Stack
For my lab rollout, I connected Claude Desktop to the MCP server over a local stdio configuration and pointed the server at exported data from our monitoring stack rather than live administrative endpoints. The sources included LibreNMS interface counters, FortiAnalyzer Syslog exports, a Git-backed change log, and selected Zabbix event history. I wanted the AI to correlate context, not become another privileged operator.
What I didn’t expect was how much better the AI became when the context had structure instead of volume. When I pasted 300 log lines, the model sometimes followed the loudest error. When the MCP tool returned 20 scoped lines plus interface deltas and the matching change ticket, the answer became calmer and more useful.
Less context won.
You may also find this useful: Check out our guide on Python Network Config Backup: Automating Multi-Vendor Device Snapshots for more practical tips.
The routing incident that started this shift turned out to be an upstream switchport problem, not a FortiGate policy issue. My first assumption was wrong because I anchored on the firewall after seeing session resets near the same minute as the operator complaint. MCP did not magically solve the incident, but it forced a better evidence path: firewall denies, route table changes, interface errors, ARP movement, then application logs.
That order now lives in a prompt exposed by our MCP server. I like that because the workflow is no longer trapped in my head or in an old incident ticket. In manufacturing IT, repeatability is not bureaucracy; it is how night shift gets the same quality of triage as day shift.
Lock Down MCP Before It Touches Production
My first MCP server exposed too much filesystem access — I had not scoped the tools narrowly enough, which is a real security risk. I let the server read a parent directory because it was convenient during testing. That shortcut would have allowed accidental exposure of unrelated logs and configuration exports if I had moved it unchanged into a shared environment.
I fixed it before deployment.
My production pattern is simple. Every tool gets an allowlist. Every path resolves under a dedicated read-only root. Every query has limits for time range, result count, and output length. Any tool that could mutate infrastructure is excluded until we have a review trail, approval flow, and a reason stronger than convenience. I also run the service account with the least access I can tolerate, behind host firewall rules, with logs forwarded back into our SIEM.
Authentication deserves the same seriousness as any other integration. If an MCP server can query firewall logs, asset inventory, vulnerability data, or ticket history, then it sits inside the security boundary. I treat it like middleware with audit requirements, not like a helper script. That means version pinning, dependency review, secrets outside the codebase, and an owner who gets paged when it breaks.
My opinion is that MCP security failures will mostly come from enthusiasm, not malice. Engineers will expose “just one more” directory, “just one more” command, and “just one more” credential until the assistant can see more than any analyst should see at once.
Deploy the MCP Servers That Already Earn Their Keep
I am not waiting for a perfect ecosystem before using MCP. The servers that matter today are the boring ones: filesystem with strict roots, Git, PostgreSQL, SQLite, browser automation for internal web tools, Slack or Teams history where policy allows it, and ticketing integrations. In our environment, I care most about read-only access to logs, runbooks, change records, asset metadata, and monitoring state.
The best deployments start beside existing controls. I would rather wrap a read-only SQL view that already filters sensitive columns than let a new MCP server talk to the raw database. I would rather expose approved runbooks than scrape a shared drive full of stale documents. MCP does not remove the need for data hygiene; it makes poor hygiene obvious faster.
That is a feature.
For manufacturing security teams, the missing layer has always been operational context. The AI model can reason, but it cannot inspect our switch counters, parse our FortiOS 7.4.3 logs, or compare a failed connection against last night’s approved maintenance unless we give it a safe path to do so. MCP is that path when we build it with restraint.
I still do not want an AI assistant making unsupervised infrastructure changes in my plant. I do want it reading the same evidence I would read, in the same order, with the same boundaries, while I stay responsible for the call. That is the version of MCP I trust: narrow tools, clear schemas, audited access, and context pulled from the source instead of dragged through a clipboard.

