Claude Code MCP: Wiring External Tools Into Your Engineering Loop
Out of the box, Claude Code reads your filesystem, runs shell commands, and edits files. That is useful. It stops at the repo boundary, though. It cannot query your Jira board for the spec, pull an Azure AD group membership to check who owns a service, or fetch the last N incidents from your Sentinel workspace to inform a detection rule rewrite. MCP closes that gap.
Model Context Protocol is Anthropic's open spec for connecting AI sessions to external tool servers. Claude Code implements it as a sidecar: when you register an MCP server, it starts alongside your session and exposes typed tools that Claude can call. The difference between MCP and a plain bash script is schema. Every tool has a name, a JSON Schema parameter definition, and a typed response. Claude knows what it can call and how to parse the result without you describing it in every prompt. That is the value. For how we use MCP inside larger AI agent pipelines, the protocol is the same but the surface area grows considerably.
Transport Modes and What They Cost You
Three transports exist. Pick based on where your server lives.
stdio is the default and simplest. Claude Code forks your server process and communicates over stdin/stdout. Zero networking, no auth surface, process lifetime tied to the Claude session. Works well for local tools: a database client, a file converter, a custom linter that reads repo-level config.
sse (Server-Sent Events) is an HTTP server that keeps a long-lived connection open. Useful when the server is remote or needs to outlive any single Claude session. Requires a URL and optionally headers for auth.
http is stateless request/response. Best for serverless or proxy-fronted tools where you do not want persistent connections.
In practice, we run most development-time servers over stdio and production-grade tools (Sentinel query server, GitHub Enterprise MCP, internal secret resolver) over SSE behind a private endpoint. Mixing transports in one project is fine.
Registering a Server in Claude Code
The claude mcp subcommand manages the registry. Two scopes matter: --scope user writes to ~/.claude/mcp.json (available in every project you open) and --scope project writes to .claude/mcp.json at the repo root (committed to source control and shared with the team).
# Add a user-scoped stdio server
claude mcp add --scope user my-sentinel-mcp \
, npx -y @kemet-tech/sentinel-mcp-server
# Add a project-scoped SSE server with a bearer token
claude mcp add --scope project github-ent \
--transport sse \
--header "Authorization: Bearer ${GH_PAT}" \
https://mcp.gh.internal.kemet.tech/sse
# Verify what is registered
claude mcp list
# Inspect a specific server and its advertised tools
claude mcp get github-ent
The -- separator matters on stdio servers; everything after it is the command Claude Code forks. Pass env vars via --env KEY=VALUE flags or reference shell variables already exported. The server process inherits a clean environment by default, not your full shell, so be explicit about anything it needs.
If you want the full registration stored declaratively, .claude/settings.json accepts an mcpServers block in the same format the CLI writes. That is the right place to commit shared tooling for a team:
{
"mcpServers": {
"sentinel-kql": {
"command": "npx",
"args": ["-y", "@kemet-tech/sentinel-mcp-server"],
"env": {
"SENTINEL_WORKSPACE": "${SENTINEL_WORKSPACE_ID}",
"AZURE_TENANT_ID": "${AZURE_TENANT_ID}"
}
}
}
}
Variable expansion uses ${VAR} syntax and resolves against the process environment at session start.
Building a Minimal stdio Server
If a vendor does not publish an MCP server for their API, writing one takes roughly an hour. The MCP TypeScript SDK handles the protocol. Here is the shape of a server that wraps a KQL query endpoint:
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import { runKql } from "./sentinel-client.js";
const server = new Server(
{ name: "sentinel-kql", version: "0.1.0" },
{ capabilities: { tools: {} } }
);
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
name: "run_kql",
description: "Execute a KQL query against the Sentinel workspace",
inputSchema: {
type: "object",
properties: {
query: { type: "string", description: "The KQL query text" },
timespan: {
type: "string",
description: "ISO 8601 duration, e.g. PT1H",
default: "PT24H",
},
},
required: ["query"],
},
},
],
}));
server.setRequestHandler(CallToolRequestSchema, async (req) => {
if (req.params.name !== "run_kql") {
throw new Error(`Unknown tool: ${req.params.name}`);
}
const { query, timespan = "PT24H" } = req.params.arguments as {
query: string;
timespan?: string;
};
const rows = await runKql(query, timespan);
return {
content: [{ type: "text", text: JSON.stringify(rows, null, 2) }],
};
});
const transport = new StdioServerTransport();
await server.connect(transport);
Register a ListTools handler so Claude discovers what is available, register a CallTool handler to dispatch, return structured content. Errors thrown from the handler surface to Claude as tool-call failures, which it can report or retry. That pattern covers 95% of what you will need.
Trust, Scope, and What the Source Leak Confirmed
The HN thread about Claude Code's npm source leak surfaced something worth keeping in mind: internal tool definitions and behavioral rules are not always visible to the operator. The "fake tools" discussion pointed at prompt-level guardrails, not MCP. The lesson still carries over.
MCP servers run with the permissions of the process that starts them. A compromised or malicious server can exfiltrate anything Claude sends it, including file contents and environment variables. We treat MCP server registration like dependency pinning: no npx -y in production environments for anything not in a private registry, explicit version pins, and network egress restricted to known endpoints at the infra level.
For teams on Azure, the right pattern is an App Service or Container Apps instance behind Private Endpoint with Managed Identity auth to downstream services. The MCP server itself never holds a secret; it calls the Azure resource using the identity attached to its host. Claude Code's session connects over SSE to the private endpoint. Nothing leaves the tenant boundary.
For AWS, the equivalent is an ECS task on a VPC with an IAM task role and a VPC endpoint to the target service. The shape is the same.
What We Have Wired Up in Practice
The MCP servers that pay back their setup time fastest on client engagements, in our experience:
A GitHub Enterprise MCP that lets Claude list open PRs, read review comments, and create branches removes roughly 30% of context-switching in a normal review-and-fix session. We have seen engineers go from a failing CI description to a proposed fix without leaving the terminal.
A Sentinel workspace connector that accepts KQL, returns rows, and also exposes list_analytics_rules and get_incident lets detection engineers have Claude propose rule refinements against live data, not synthetic samples. The quality difference is measurable. A rule tuned against 7 days of real telemetry suppresses significantly fewer false positives than one tuned against fabricated examples.
A secret resolver MCP that accepts a secret name and returns the current value from Azure Key Vault, with Managed Identity, means the developer never sees the actual credential and Claude never needs it in the prompt. This also satisfies most enterprise secret-in-prompt policies without any workflow change.
An internal service catalog MCP for one client maps service names to ownership, runbooks, and recent deploy history. That one alone cut average incident-response conversation length by around half. Claude stops asking what a service does and starts asking what changed.
Next Steps
If you are wiring Claude Code into an internal API, a private Azure workspace, or a detection pipeline and want the MCP server built and hardened to production standards, reach out to us and we can scope it in a single call.
