AI-Native Updated 2026-09 9 min read View as Markdown

MCP servers worth wiring into a Python project

MCP lets an agent reach outside your codebase. Most of what gets installed is noise; a few of them change what the agent can actually do.

The Model Context Protocol is a standard way for an agent to call tools it did not ship with — read your database schema, query your error tracker, fetch current library documentation. It solved a real problem: before it, every tool integration was bespoke to one client.

The failure mode now is the opposite one. Installing ten servers puts several hundred tool definitions into every request, which crowds out your code, slows every turn and measurably degrades tool selection. Each server should have to justify itself.

The rule

Install a server when it gives the agent information it genuinely cannot get from your repo or your shell. If the agent could get the same answer by running a command you have already allowlisted, the command is better — it costs no context until it is used.

The ones that earn their place#

Documentation retrieval. The single highest-value category for Python, because library APIs move faster than training data. A model confidently writing the 2023 signature of a fast-moving library is a recurring, expensive failure; a docs server that fetches the version you actually have installed removes it.

Your database, read-only. Letting an agent inspect the real schema — column types, nullability, indexes, foreign keys — rather than inferring it from your models eliminates an entire class of "wrote a query against a column that does not exist" errors. Read-only, against a non-production database.

Error tracking. "Here is the stack trace and the last twenty occurrences" turns a debugging session from a description of a bug into the bug itself. This is where MCP is at its most obviously useful.

Issue tracker. Worth it if your issues are actually written; not worth it if your issues are two-line reminders to yourself.

The ones to think twice about#

Filesystem servers. Your agent already has file access. This duplicates it with a worse interface and a large tool surface.

Git servers. Same argument. git is a CLI, the agent has a shell, and the CLI has better documentation than any wrapper.

Anything with write access to production. The blast radius is not worth the convenience, and it will eventually be exercised by a prompt-injection payload in a page the agent read.

Aggregator servers exposing fifty tools. These are the worst offenders for context bloat. If you only need two of the fifty, the other forty-eight are pure tax.

Configuration#

.mcp.json
{
  "mcpServers": {
    "docs": {
      "command": "uvx",
      "args": ["some-docs-mcp-server@latest"]
    },
    "postgres-dev": {
      "command": "uvx",
      "args": ["some-postgres-mcp-server", "--read-only"],
      "env": { "DATABASE_URL": "postgresql://localhost/myapp_dev" }
    }
  }
}

Commit .mcp.json so the team shares a configuration, and keep credentials in the environment rather than in the file. A DATABASE_URL in a committed config is a credential in your git history.

Writing one in Python#

Worth doing when you have an internal system the agent keeps needing — a feature-flag service, a staging deploy API, an internal search index. It is much less work than people expect.

mcp_server.py
from mcp.server.fastmcp import FastMCP
import httpx

mcp = FastMCP("acme-internal")


@mcp.tool()
async def find_customer(email: str) -> dict:
    """Look up a customer by email in the staging environment.

    Returns id, plan, created_at and feature flags. Staging data only —
    never production. Use this instead of guessing at fixture data.
    """
    async with httpx.AsyncClient() as client:
        r = await client.get(f"{STAGING}/internal/customers", params={"email": email})
        r.raise_for_status()
        return r.json()


@mcp.resource("schema://tables")
def table_list() -> str:
    """The current staging database schema, as CREATE TABLE statements."""
    return introspect_schema()


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

Three things matter more than the code:

  1. The docstring is the interface. It is what the model reads to decide whether and how to call the tool. Write it for a competent colleague who has never seen your systems — say what it returns, what it does not cover, and when not to use it.
  2. Return structured data, not prose. A dict the model can index beats a sentence it has to parse.
  3. Keep the tool count small. Four well-described tools beat twenty thin ones, both for selection accuracy and for context cost.

Measuring the cost#

Before adding a server, look at what it actually adds. In Claude Code, /context shows the breakdown; most clients have an equivalent. If a server is consuming a meaningful share of your window and you have used it twice this month, remove it — you can add it back for the session where you need it.

The shape of a good setup#

For a typical Python service, this is usually enough:

docs server        -> current library APIs
postgres (ro, dev) -> real schema
error tracker      -> real stack traces

Three servers, each answering a question the repo cannot. Everything else the agent can get with a shell command you have already allowlisted, at zero standing cost.

Common questions#

Do I need MCP at all?#

No. A well-configured agent with shell access, a fast test suite and a good AGENTS.md is already most of the value. MCP is worth adding when you notice the agent repeatedly guessing at something that exists in a system it cannot see — a schema, a stack trace, a current API signature.

Is it safe to connect an agent to my database?#

To a development or staging database, read-only, yes. To production, no — and not because the agent is malicious, but because an agent's actions can be influenced by any text that reaches its context, including text written by other people. Read-only against non-production data keeps the worst case boring.

Why does adding servers make the agent worse at choosing tools?#

Because tool selection is a discrimination problem, and every extra tool definition is another near-neighbour to confuse with the right one. It is the same reason a 500-line instructions file works worse than a 50-line one: attention is finite and dilution is real.

Can I write an MCP server without publishing it?#

Yes, and most useful ones are never published. A local script referenced by path in .mcp.json works exactly the same as a published package, and internal systems are precisely where the value is highest.

Get the Python agent pack

A battle-tested AGENTS.md, the review checklist, and the failure-mode cheat sheet for Python. One email, then occasional updates when the tooling shifts. No course pitch.

Unsubscribe in one click. We never sell the list. Or just take the AGENTS.md now — no email needed.

Disclosure: some links on this page are affiliate links. If you buy something through one, we earn a commission at no extra cost to you. We only list tools we would tell a friend to use, and we say so when we have not used something ourselves. This is how the site stays free and ad-light.