Recommend which MCP servers to connect for a loop, workflow or task, stage by stage, with the narrowest access that works — what outside context or action each stage needs, the server that provides it (only ones the user named or the vendor officially publishes), the scopes to grant (read-only by default, never write on a review or gate stage), what it must not be able to do, the export-file fallback that keeps the stage running without it, and which stages need no server at all. Use when the user asks "which MCP servers should we hook up for this loop", "what should our agent connect to", "what token scopes does this stage need", "is this MCP setup too broad", or wants to wire GitHub, GitLab, Jira, Linear, Slack, Sentry, Grafana or a database into an agent workflow.
Pack ai-engineeringTier standardJob Design the systemv0.1.0
In Claude Code, with the ai-engineering plugin installed, invoke it as:
/ai-engineering:mcp-pairing
Try it
A realistic prompt from the skill's acceptance evals:
Which MCP servers should we hook up for our release loop? We use GitLab, Linear and Grafana. The loop is plan the rollout, check launch readiness, write the release notes, then a go/no-go call. We release about every two weeks.
What a good result looks like
Every stage has a row, including the ones that get None. A plan that lists only servers hides which stages hold nothing.
No verify or gate stage holds a write scope. Not comment, not approve, not label.
Every write grant names the stage whose output it is and sits on its own credential.
No invented names. Every server, package, URL and scope in the plan came from the user or is a vendor's own server with the confirm step written beside it.
Every grant is narrower than "read-only": a scope, a project or repository, a role.
Every stage that reads untrusted content is checked against write, exec and network tools in the same session, and the combination is split or dropped.
Every stage has an export-file fallback a person can produce today.
At least one server is argued against or the plan says why each one earns its place.
No token value appears anywhere, and the config placement keeps tokens out of git.
Example output
the build loop on GitHub, Jira and Datadog · the skill's own worked example, source
Input
We're adopting the build loop for the orders-api repo. We use GitHub for code and PRs, Jira (project ORD) for stories and bugs, and Datadog for logs and APM. Which MCP servers should we connect, and with what access? We'd like the agent to open the PR itself if that's sensible. About one bug a week needs logs; stories come in daily. Outside contractors open PRs too.
Output
MCP pairing — build loop for orders-api
Tools in use: GitHub, Jira (project ORD), Datadog · Assumptions: the developer's checkout is local, so implement needs no repo server [assumption]; Jira issues in ORD are written by staff and by people raising bugs from support [assumption].
The plan
Connect two servers, both read-only: Jira for the shape stage and GitHub for the verify stage. Implement and decide need none. Datadog is cut: one bug a week is a saved log query, not a live server. Opening the PR is the one write worth granting, on its own GitHub credential used only at the end of implement, and only if the team wants it; otherwise the developer opens the PR.
Pairing by stage
Stage (type, cadence)
Needs
Server
Grant
Must not
Fallback without it
Risk
shape (generate, daily)
Tracker issue: the story or bug, its comments and links
Atlassian's own server — confirm Atlassian publishes it in Atlassian's docs before connecting
A Jira account with Browse on project ORD only; the server acts with that account's permissions
Create, transition, comment, assign, edit fields; see any project but ORD
The issue exported from Jira to a text file, or the filter exported as CSV
Issue text and comments are untrusted (support-raised bugs). Shape holds no write or exec tool, so reading them is safe here; it writes the story file and nothing else
shape, bugs only (generate, ~weekly)
Logs and traces for the failing request
Cut — see below
—
—
The Datadog log query result saved as JSON, and the trace's spans exported, for the bug's time window
Log lines carry request fields an attacker writes; a file a person picked keeps that bounded
implement (generate, per story)
None — works from the story file shape wrote and the local checkout
None
—
—
—
Implement runs tests (exec) and edits files (write), so it gets no tracker or GitHub server: live issue text next to a shell is the dangerous combination. A person skims the story file before implement starts
implement → open PR (generate, per story, optional)
Action: open a draft PR from the pushed branch
GitHub's own server, write configuration — confirm GitHub publishes it (GitHub's own organization, docs on GitHub's domain)
A separate fine-grained token, orders-api only: Pull requests read and write, Contents read and write; branch protection on main requires review
Merge, approve, push to main, change settings or branch protection, touch other repositories
The developer runs the push and opens the PR by hand
Write and exec in one stage, so this stage reads nothing untrusted: no issue comments, no PR comments
verify (verify, per PR)
Repo: the PR diff, description, CI status
GitHub's own server in its read-only mode, limited to the repositories, pull requests and Actions toolsets
A separate fine-grained token, orders-api only: Contents read, Pull requests read, Actions read
Merge, approve, comment, request changes, label, re-run CI
The diff saved as a .diff file and the PR description copied to a file; the CI summary saved
Contractor PRs and comments are untrusted, and the gate script is exec. Allow only the gate script command in this session; the verdict goes to a person, never posted by the agent
decide (gate, per PR)
None — reads verify's verdict and any design disagreement
None
—
—
—
The merge stays a person's action in GitHub's own UI under their own login
Pull requests and Contents: read and write; orders-api
implement → open PR (optional)
Write, separate token
Tokens live in environment variables or the client's secret store. The project's committed MCP config holds variable names only. The write server is a separate server entry, enabled only in the session that opens the PR, so the verify session never loads it.
Servers cut
Datadog — needed for about one bug a week. A saved log query and exported trace cover it, with no standing token to the team's logs and no live attacker-written log lines in context. Revisit if bugs needing logs reach several a week.
Check before installing
Atlassian's own server — confirm publisher; it acts with the account's own permissions, so the account must have nothing beyond Browse on ORD.
GitHub's own server — confirm publisher, use its read-only mode for verify, and turn off every toolset verify doesn't use.
To confirm
Whether the team wants the agent to open PRs at all; if not, drop GH_ORDERS_PR_WRITE.
That branch protection on main requires an approving review, so even the write token cannot land code alone.
Next step: review the finished setup for any path where issue or PR text could make the agent send private data out, before the first real story runs through it.
How it's checked
Measured against plain Claude Code (2026-10-23): it met 92% of its checks, against 39% without it, and a blind judge preferred it. How skills are checked
39 assertions across 5 acceptance evals, and 10 trigger queries. Every skill's checks
What the output must do
It opens with the plan in plain words — how many servers, which ones, read or write, and which stages need none — before any table
Every one of the four stages (plan, readiness, release notes, go/no-go) has its own row, including any that get no server
No write scope is granted to the readiness check or the go/no-go stage; the go/no-go decision stays with a person
Every grant is narrower than 'read-only': a named scope such as GitLab read_api, one project or team, or a Grafana Viewer role, with no admin or api-wide scope
Any write (publishing the release or notes) sits on a separate credential used only by the release-notes stage, or is handed to a person
It does not invent server names, packages, install commands or URLs the user didn't give; vendor servers are named only as the vendor's own, with how to confirm the publisher
Merge request text, comments or Linear issue text are called untrusted, and no stage that reads them is left holding write, exec or network tools
Every stage gets an export-file fallback, and at least one server is cut or argued for against the fortnightly cadence
It flags the token values written into the config file and says to move them to environment variables or the tool's secret store, with the committed file holding variable names only
It drops the admin scopes (admin:org, Slack admin) and the broad repo and workflow scopes, naming the narrower scope each step needs
It flags the unpinned community packages (@harbourline/jira-mcp, @harbourline/pg-mcp@latest, @harbourline/slack-mcp) and gives the vetting checks: publisher, source available, pinned version, tools exposed, code or network reach
It replaces the app_owner connection to the primary database with a read-only role on a replica, scoped to what the postmortem needs, or with an exported query result
It says the Slack posting is the one write the incident-update step's output justifies, on a separate credential from history reading, or hands posting to a person, and the postmortem step gets no write
It calls Slack messages and Jira ticket text untrusted and does not leave a step that reads them holding the write or database tools it doesn't need
It does not invent replacement package names, URLs or install commands the user didn't give
Each step has an export-file fallback, such as the incident channel's thread exported to a file or the query result saved as CSV
It answers the question directly in the opening lines, with a clear verdict on the setup as proposed
Web pages are called untrusted input, and the stage that browses is not given Notion write or any other write or exec tool in the same session
The weigh-the-explanations stage is treated as a verify stage and gets read-only access or none
Notion write, if kept at all, goes only to the stage whose output is filing the summary, scoped to the one research space on its own credential; otherwise a person files it
Google Drive access is narrowed to the folder of past reports, read-only, or replaced by exported files
Given the monthly cadence, at least one server is cut in favour of an export file or saved pages, with the reason stated
It does not invent server names, packages or URLs the user didn't give, and names Notion's or Google's server only with how to confirm the publisher
Flags the GitHub token (and the Jira/Slack/DB secrets) pasted in plain text in a committed .mcp.json as an immediate problem: says to treat the tokens as exposed and rotate them, and to move secrets out of the file (environment variables or a secret store, referenced instead of stored inline).
Flags the classic PAT with admin:org and delete_repo (and workflow) as far too broad, and recommends a narrowly scoped token instead (e.g. a fine-grained token or app limited to example-org/orders-service with only the repository permissions the implement stage needs: contents and pull requests write, plus read for actions/checks).
Says the review stage must be read-only: the 'github-reviewer' entry with all toolsets and the ability to approve/merge contradicts the loop's own rule that only a human merges, and should become a read-only connection (diff, CI results, ticket) with no merge, approve, push or write tools.
Identifies the Jira server 'jira-mcp-plus-unofficial@latest' and the community Slack/Postgres packages as unknown-origin, unpinned third-party code that gets credentials, and recommends replacing them with the vendor's official server or the user's vetted one (or at minimum pinning and reviewing them), not trusting them as-is.
Recommends removing the Postgres connection entirely (or replacing it with a schema-only/read-only path such as a schema dump or migration files), since no stage in the loop needs a database and the current config gives the agent the prod owner role on the orders database.
Narrows Slack to what the announce stage actually needs: posting to the single #team-orders-dev channel (chat:write, invited to that channel), dropping history-reading scopes, users:read.email, chat:write.public and admin; and notes that the merge gate stage needs no MCP server at all.
Gives a per-stage breakdown (pick up, implement, review, merge gate, announce) stating for each what access it needs, what it must not be able to do, and a fallback if the server is unavailable (e.g. pasted or exported ticket text for pick-up, gh CLI or a saved diff/CI log for review, a human posting the Slack line).
Does not invent server package names, registry URLs, image names or MCP tool names that weren't in the user's files; where it recommends an official server it either names one the user already referenced (ghcr.io/github/github-mcp-server) or describes it generically and tells the user to confirm the vendor-published source.
Organises the answer by the five stages (gather, correlate, check data, ticket, postmortem draft) and, for each, states what outside data or action the stage needs and which of the user's named systems supplies it.
Recommends read-only access for Sentry, Grafana and GitLab: e.g. Sentry token limited to reading events/issues/projects for payments-api (no project write/admin, no resolving issues), a Grafana service account with Viewer role, and a GitLab token with read-only scopes (read_api / read_repository) rather than the full 'api' scope.
For the database stage, recommends connecting only to the read replica (never the primary) with a dedicated read-only role, and calls out that the PCI card-data columns (pan_last4, card_token, billing_address) must be excluded, e.g. via a restricted view or column-level grants, rather than trusting the agent to avoid them; may also suggest statement timeouts/row limits.
Treats the ticket stage as the only stage that genuinely needs write access, and limits it to creating/updating issues in the PAY team in Linear (no admin, no access to other teams, no deletion), possibly noting a human could approve or the ticket could be created by a person from the agent's draft.
States that the postmortem draft stage needs no MCP server, since it writes markdown from what earlier stages already gathered.
Gives a no-server fallback per stage that keeps the loop working, e.g. exported Sentry event JSON, Grafana panel CSV/screenshot, a pasted git log or MR diff, psql output pasted by the on-call, and a markdown ticket draft the on-call files by hand.
Explicitly lists what each connection must not be able to do (e.g. no deploys, rollbacks or pipeline triggers from GitLab, no alert silencing or dashboard edits in Grafana, no writes or DDL on Postgres, no reading card data), in a form a security reviewer could check.
Does not invent MCP server package names, repository URLs or tool names for Sentry, Grafana, GitLab, Linear or Postgres; it either says to use the vendor's officially published server (to be confirmed by the user) or describes the capability generically, and notes that self-hosted Sentry may need verification that the official server supports a custom host.
When it should and shouldn't activate
Should activate:
Which MCP servers should we hook up for our release loop? We use GitLab, Linear and Grafana
What token scopes does each stage of our build loop need for the GitHub MCP server?
Here's our .mcp.json — is this too much access for a weekly status report?
We want the on-call agent to read Sentry and Slack. What should we connect and with what permissions?
Should our research workflow get a web browsing server and write access to Notion?
Should leave to another skill:
Threat-model this agent: it reads support tickets, queries our customer DB and can send email
Design an agent loop that keeps our runbooks up to date, with exit criteria and a human gate
How should I split this code migration across parallel subagents?
Write our company's policy on which AI tools staff may use with client data
Walk me through connecting Jira to Claude Code step by step
Hands off to
agent-threat-model — when the pairing still puts private data, untrusted content and any way to send data out in one session, or before the setup is connected at work. Attack the finished capability surface path by path and break a leg on every path that can leak data.