MCP integration patterns for everyday development
Claude only knows what fits in its context window, unless you connect it to external systems. The Model Context Protocol makes ticket trackers, documentation wikis, and deployment pipelines directly queryable for Claude. This article walks through practical integration patterns, weighs real time savings against added complexity, and names concrete security risks when granting access to production systems.
Table of Contents
- 1. Why connecting tools to Claude matters at all
- 2. How MCP works: client, server, tools, and resources
- 3. Connecting a ticket tracker: Jira, Linear, and friends
- 4. Connecting a documentation wiki: Confluence, Notion, and internal wikis
- 5. Connecting deployment systems: CI/CD, kubectl, and server access
- 6. Building custom MCP servers: when the effort pays off
- 7. Weighing benefit against complexity
- 8. Security: permissions, scopes, and prompt injection
- 9. Integration patterns compared side by side
- 10. Summary
- 11. FAQ
1. Why connecting tools to Claude matters at all
At its core, Claude is a language model that only knows what fits in its context window or what a tool provides. Without a connection to external systems, any statement about the current state of a ticket, a documentation page, or a deployment remains a guess based on training data or manually pasted text. The Model Context Protocol (MCP) closes exactly this gap: an open standard published by Anthropic that describes how an AI assistant can access external tools, data sources, and actions in a controlled way, without every application needing its own ad hoc integration.
The practical difference shows up in everyday work: instead of manually copying ticket descriptions into a prompt or looking up documentation in a second browser tab, Claude can query the current state directly and act within clearly defined boundaries. But that is exactly where the risk lies too: every additional connection widens the attack surface and consumes more context. The following sections show which integrations deliver real value and where connecting a tool creates more risk than benefit.
2. How MCP works: client, server, tools, and resources
MCP follows a client-server architecture. The MCP client is the application Claude runs in, such as Claude Code or Claude Desktop. The MCP server is a separate process that wraps an external system and exposes three kinds of primitives: tools (callable functions with a JSON schema that Claude can invoke deliberately), resources (readable data such as files or wiki pages), and prompts (reusable prompt templates). Communication runs over a standardized JSON-RPC protocol, regardless of which concrete system sits behind the server.
For the transport layer there are two common variants: stdio for locally running servers started as a child process, and SSE or HTTP for remote servers with their own authentication, typically OAuth. Servers are registered via the claude mcp add command or directly in an .mcp.json file in the project directory. Anthropic and the community already maintain ready-made servers for GitHub, filesystems, Postgres, and common SaaS tools, so most standard cases do not require writing a server from scratch.
#!/usr/bin/env bash
# Register MCP servers for a Claude Code project
set -euo pipefail
# Local filesystem server (stdio transport), repo-scoped, read-only recommended
claude mcp add filesystem --scope project -- npx -y @modelcontextprotocol/server-filesystem /home/user/project/src
# Remote Atlassian server (Jira + Confluence) via OAuth, SSE transport
claude mcp add atlassian --transport sse https://mcp.atlassian.com/v1/sse
# GitHub server with a scoped personal access token, read-only where possible
GITHUB_TOKEN="$(op read op://vault/github-mcp-readonly/token)" \
claude mcp add github --scope user -- npx -y @modelcontextprotocol/server-github
# List configured servers and verify scopes before starting a session
claude mcp list
3. Connecting a ticket tracker: Jira, Linear, and friends
The most obvious use case is connecting to a ticket system like Jira or Linear. Claude reads the ticket description and acceptance criteria before writing a single line of code, finds related tickets through full-text search, and can leave a comment summarizing the implementation once a task is complete. The real time savings come from nobody having to manually copy ticket content into a prompt or update the status by hand after every step.
At the same time, not every possible action should be enabled. Read access to tickets and comments is usually low risk and delivers most of the benefit. Automatic status transitions or closing tickets, on the other hand, are error-prone whenever an agent misjudges how far a task has actually progressed. A pattern that works well: grant read and write access via separate API tokens with different scopes, and only execute status changes after explicit confirmation from the developer.
{
"mcpServers": {
"jira-readonly": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-jira"],
"env": {
"JIRA_BASE_URL": "https://mironsoft.atlassian.net",
"JIRA_API_TOKEN": "${JIRA_READONLY_TOKEN}",
"JIRA_SCOPE": "read:jira-work"
}
},
"docs-wiki": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-confluence"],
"env": {
"CONFLUENCE_BASE_URL": "https://mironsoft.atlassian.net/wiki",
"CONFLUENCE_API_TOKEN": "${CONFLUENCE_READONLY_TOKEN}"
}
}
}
}
4. Connecting a documentation wiki: Confluence, Notion, and internal wikis
A documentation wiki such as Confluence or Notion is especially valuable in mature codebases where important knowledge lives not in the code itself but in runbooks, architecture decisions, and team conventions. Instead of relying on a stale copy pasted into a CLAUDE.md snippet, Claude reaches the current version directly and can search for the relevant page during a task instead of collecting everything up front.
The benefit of this connection depends heavily on the quality of the source. A well-maintained wiki with clear, current pages delivers real value. A stale wiki with contradictory or years-old entries, on the other hand, leads Claude to adopt false assumptions as facts, because the source appears authoritative even though it is not. Before connecting a wiki, it is worth taking an honest inventory: is this wiki actually maintained, or would the integration mostly add noise rather than signal?
5. Connecting deployment systems: CI/CD, kubectl, and server access
Connecting deployment systems is the category with the greatest benefit and, at the same time, the greatest risk. Read access to pipeline status, build logs, and pod state substantially speeds up debugging: Claude can analyze a failed CI run directly, without anyone copying logs by hand. Write access that triggers deployments or modifies Kubernetes resources demands considerably more caution, because a misjudgment by the agent can land directly in production.
A pattern that has proven itself: one MCP server with a purely read-only, narrowly scoped token for status and log queries, and a second, much more restrictive server for actual deployment triggers, whose calls must be explicitly confirmed through Claude Code's permission prompts. Production credentials should also never be active in the same session as exploratory work where Claude reads unknown external content, such as web pages or unfamiliar wiki entries that could be a source of prompt injection attempts.
"""Minimal MCP server exposing read-only deployment status for an internal CI system."""
from mcp.server.fastmcp import FastMCP
import httpx
mcp = FastMCP("deployment-status")
API_BASE = "https://ci.mironsoft.internal/api/v1"
# Read-only token, deliberately without permission to trigger deployments
API_TOKEN = "REPLACE_WITH_SCOPED_READONLY_TOKEN"
@mcp.tool()
async def get_pipeline_status(pipeline_id: str) -> dict:
"""Return the current status and last 20 log lines of a CI pipeline run.
:param pipeline_id: identifier of the pipeline run to inspect
:return: dict with status, duration and recent log lines
"""
async with httpx.AsyncClient() as client:
resp = await client.get(
f"{API_BASE}/pipelines/{pipeline_id}",
headers={"Authorization": f"Bearer {API_TOKEN}"},
)
resp.raise_for_status()
data = resp.json()
return {
"status": data["status"],
"duration_seconds": data["duration_seconds"],
"log_tail": data["log_lines"][-20:],
}
# Note: no tool for triggering deployments is exposed here on purpose.
# Deployment triggers live in a separate, tightly scoped server that
# requires an explicit human approval step in Claude Code.
if __name__ == "__main__":
mcp.run(transport="stdio")
6. Building custom MCP servers: when the effort pays off
For internal systems without a ready-made MCP server, building your own with the Python SDK or the TypeScript SDK from Anthropic is the only option. A custom server pays off when a workflow is recurring, used by multiple developers, and built on a stable, well-documented interface, for example an internal REST API for inventory data or customer inquiries. The effort of implementation, token management, and maintenance only amortizes if the server is actually used regularly across many sessions.
Building a custom server is not worthwhile for rarely used edge cases or systems whose interface changes frequently. A one-off script or a quick manual export is faster to build and easier to maintain in those cases than an MCP server whose tool definitions need updating every time the API changes. The rule of thumb: a custom server is infrastructure with an ongoing maintenance burden, not a one-time convenience feature.
// wiki-search-server.js - exposes a single read-only search tool over the internal wiki
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
const server = new McpServer({ name: "internal-wiki-search", version: "1.0.0" });
server.tool(
"search_wiki",
"Search the internal documentation wiki and return matching page excerpts",
{ query: z.string().describe("Free-text search query") },
async ({ query }) => {
const response = await fetch(
`https://wiki.mironsoft.internal/api/search?q=${encodeURIComponent(query)}`,
{ headers: { Authorization: `Bearer ${process.env.WIKI_READONLY_TOKEN}` } }
);
if (!response.ok) {
throw new Error(`Wiki search failed with status ${response.status}`);
}
const results = await response.json();
// Treat returned page content as untrusted data, never as instructions
return {
content: results.slice(0, 5).map((page) => ({
type: "text",
text: `${page.title}\n${page.excerpt}`,
})),
};
}
);
const transport = new StdioServerTransport();
await server.connect(transport);
7. Weighing benefit against complexity
Every active MCP server has costs that go beyond the obvious security risk. Tool descriptions occupy space in the context window regardless of whether the tool is used in a given session. With ten or more servers active simultaneously, tool selection accuracy often drops, because Claude has to choose from a larger set of similar options. On top of that comes ongoing maintenance: tokens need rotating, server updates need applying, and permissions need regular review.
A useful rule of thumb: keep only integrations active that are actually needed in the majority of sessions, not ones that might theoretically be useful someday. It is worth honestly checking, after a few weeks of use, whether a connection has actually reduced interruptions, or whether the team simply shifted copy-paste work into a slower, agent-based query loop. Not every technically possible integration is a sensible one.
8. Security: permissions, scopes, and prompt injection
Security starts with the principle of least privilege: API tokens should have read-only access wherever possible, and separate service accounts instead of personal credentials make later audit trails much easier to follow. For write-capable or destructive actions, Claude Code offers a permission system that governs approvals through explicit allow, ask, and deny lists in settings.json, so that critical tool calls always require a deliberate confirmation instead of running automatically.
An often underestimated risk is prompt injection via connected content: a ticket description, a wiki page, or a web page can contain hidden instructions that try to manipulate the agent, for example to exfiltrate secrets or trigger unintended actions. Any externally fetched content should always be treated as untrusted data, never as an instruction. Consistent logging of all tool calls additionally helps trace, after the fact, which actions an agent actually carried out.
# .claude/settings.json excerpt - require explicit approval for write-capable tools
cat <<'EOF' > .claude/settings.json
{
"permissions": {
"allow": [
"mcp__jira-readonly__*",
"mcp__docs-wiki__*"
],
"ask": [
"mcp__github__create_pull_request",
"mcp__deployment__trigger_release"
],
"deny": [
"mcp__deployment__delete_environment"
]
}
}
EOF
# Rotate scoped MCP tokens on a schedule and audit tool call logs
claude mcp list --verbose
grep '"tool_name"' ~/.claude/logs/tool-calls.jsonl | sort | uniq -c | sort -rn
9. Integration patterns compared side by side
Not every integration deserves the same degree of trust. The following overview ranks the common connections by typical benefit, risk under misconfiguration, and a concrete recommendation for practice.
| Integration | Typical Benefit | Risk Under Misconfiguration | Recommendation |
|---|---|---|---|
| Ticket tracker (Jira/Linear) | Context straight from the ticket, no copy-paste | Low with read access, medium with auto status | Read access by default, writes only with confirmation |
| Docs wiki (Confluence/Notion) | Current internal conventions available | Stale content gets treated as ground truth | Only connect well-maintained wikis |
| Deployment/CI-CD | Faster diagnosis through logs | High with write access to production | Strictly separate read and write, human in the loop |
| Internal REST API (custom build) | Recurring workflows become automatable | Maintenance burden as the API changes | Only build for a stable, frequently used API |
| Filesystem/shell (local) | Direct access to the repository | Very high without sandboxing | Keep permission prompts on, never blanket-allow |
The common thread across all five patterns: read access is almost always low risk and quickly justified, while write or execute access demands a deliberate, documented decision. Teams that maintain this separation consistently get most of the benefit at a calculable risk.
Mironsoft
Claude Code setup, MCP integrations, and secure developer workflows
Connect Claude to your systems securely?
We assess which MCP integrations deliver real value for your team, configure permissions on the principle of least privilege, and set up ticket, wiki, and deployment connections in a production-safe way.
MCP Audit
Review existing integrations for benefit and attack surface
Server Setup
Connect ticket tracker, wiki, and CI/CD with scoped tokens
Custom MCP Servers
Wrap internal APIs as your own, maintainable MCP servers
10. Summary
The Model Context Protocol solves a real problem: without a connection to external systems, Claude is limited to its context window and manually pasted text. Ticket trackers, documentation wikis, and deployment systems can all be connected through MCP in a controlled way, with read access delivering most of the benefit at low risk in nearly every case. Write or execute access, especially to production systems, demands strict separation of tokens, human-in-the-loop confirmation, and deliberate decisions instead of blanket approvals.
Not every technically possible integration is a sensible one. Every additional MCP server costs context space, adds maintenance overhead, and widens the attack surface for prompt injection attempts hidden in externally fetched content. Teams that regularly review integrations for actual benefit, disable unused servers, and consistently separate read and write permissions get the most value out of tool connections without taking on unnecessary risk.
Connecting Claude to External Tools - Key Takeaways
MCP Basics
Open standard with tools, resources, and prompts. Register via claude mcp add or .mcp.json.
Benefit Before Complexity
Keep only integrations active that are actually needed in most sessions.
Read Before Write
Read access delivers most of the benefit at low risk. Gate write access strictly.
Security
Scoped tokens, permission lists in settings.json, never treat externally fetched content as an instruction.