Some months, the AI news is just a trickle of point releases. But this past month was like a firehose. The protocol that connects agents to your tools got its biggest rewrite since inception, and Anthropic, OpenAI, Google, Meta, Moonshot, and a brand-new lab founded by a former OpenAI CTO all shipped new models in a single month.
Besides the models, the rest of the Python ecosystem was equally active. The major scientific libraries dropped support for 3.13t and settled on 3.14t as their free-threaded target. Python 3.15 shipped its final beta, the JIT team responded to the Steering Council’s ultimatum, the PSF opened nominations for its board and the first-ever Packaging Council, and Astral shipped breaking minors of uv and Ruff. The MCP rewrite comes first.
Join Now: Click here to join the Real Python Newsletter and you’ll never miss another Python tutorial, course, or news update.
MCP Drops Sessions and Goes Stateless
Two things landed on July 28, and together they make this the most disruptive month MCP has had since it launched. The 2026-07-28 specification was finalized with a revision that changes how servers are deployed, and the Python SDK shipped a 2.0 the same day, renaming the class most Python servers are built on.
What the New Spec Changes
The main change is that the protocol is now stateless. A client used to open with a handshake and then carry a session ID through the rest of the conversation. Both are gone. Protocol version and client capabilities now ride along on every request, and a new server/discover call fetches what a server can do.
Under the new specification, any request can land on any instance, and a plain round-robin load balancer is enough. If you only call MCP servers, then the stateless switch is what affects you the most.
If you ship an MCP server, then your migration list looks like this:
- Remove the session machinery: The handshake and the session header are both gone, so anything you built to track a client between requests goes with them.
- Validate the
Mcp-MethodandMcp-Nameheaders: Clients now send them so gateways can route without cracking open the request body, and your server has to check that they match the request. - Change your missing-resource error: Use the standard JSON-RPC invalid-params code,
-32602, instead of MCP’s own-32002. - Rework your server-initiated requests: Roots, Sampling, and Elicitation no longer call back to the client. Instead, your server returns a result that the client uses to make a follow-up request, which is the biggest rewrite on this list.
- Move off the experimental Tasks API: Tasks have graduated from the core spec to an extension and have gained a new lifecycle along the way.
Roots, Sampling, and Logging all entered formal deprecation, and all three keep working for now. The spec also adopted a deprecation policy promising at least a year’s notice before anything is removed, with a 90-day floor reserved for active security risks. That’s more warning than this ecosystem has offered before.
Authorization also hardened, picking up issuer validation and issuer-bound credentials on top of its OAuth 2.0 foundation.
Extensions, which existed before without any process around them, finally got one: namespaced identities and independent release cycles. That’s what let Tasks move out of the core without dragging the whole protocol along, and MCP Apps now arrives as an official extension under that process. A server can send interactive HTML that the host renders in a sandboxed iframe, so a tool call returns a real interface instead of a wall of text.
Treat third-party MCP servers with the same scrutiny you’d give any dependency. The official registry verifies who published a server through GitHub or DNS ownership, but there’s still no code-signing requirement and no review of what a server actually does, and a server you install gets to describe its own tools to your agent.
The Python SDK Renames FastMCP
The spec is only part of the story if you write Python. The MCP Python SDK reached 2.0.0 alongside it, and pip install mcp now provides the 2.x line.
The first change you’ll notice is a rename. FastMCP is now MCPServer, with no alias and no deprecation shim:
# Before, on mcp 1.x
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("Demo")
# After, on mcp 2.x
from mcp.server.mcpserver import MCPServer
mcp = MCPServer("Demo")
The rest of 2.0 is broader than the rename suggests:
- Wire types are snake_case now:
result.isErroris nowresult.is_error, andtool.inputSchemais nowtool.input_schema. These types have also moved into a separatemcp-typespackage, althoughmcp.typesstays as a permanent alias. - One
Clientreplaces three layers: The old arrangement of a transport, aClientSession, and aninitialize()call now collapses into a single object that connects to a URL, a stdio subprocess, or an in-memory server object for tests. httpxis nowhttpx2: The SDK moved to the next-generation HTTP client, which is worth knowing if you pinhttpxelsewhere in your dependency tree.- Synchronous handlers run on worker threads: They no longer block the event loop. Your handler code doesn’t change, but
asyncio.get_running_loop()now raises inside them. McpErroris nowMCPError: It’s the same acronym capitalization asMCPServer, so anyexcept McpErrorclause needs the new spelling.
One MCPServer serves both protocol eras, so 2025-era clients keep working against a migrated server with nothing to configure. The 1.x line moves to maintenance mode with security fixes only, so if you’re not ready this month, then pin mcp>=1.28,<2 and come back to it.
One gap remains mid-migration: the Tasks extension isn’t in this release, so Tasks has left the core spec but hasn’t yet arrived in the Python SDK.
And if you reach for the standalone fastmcp package rather than the official SDK, then none of this touches you. That’s a separate project on its own 3.x line, and the rename is partly there to stop the two from being mistaken for each other.
Frontier Models Arrive in Bunches
The common theme in this month’s releases is that near-frontier capability is spreading fast, and the gap between what you can rent and what you can download keeps narrowing. One lab even switched a model back on.
If you’d rather try several of this month’s models than pick from a leaderboard, Accessing Multiple AI Models With the OpenRouter API shows you how to reach them all behind one interface.
Claude Opus 5 Turns Thinking on by Default
Anthropic released Claude Opus 5 on July 24, and the API model string is claude-opus-5. The company’s framing is that it “comes close to the frontier intelligence of Claude Fable 5 at half the price.” The arithmetic checks out: Fable 5 sits at $10 per million input tokens and $50 per million output tokens, compared to Opus 5’s $5 and $25.
The change that’s most likely to surprise you is quieter than the price tag, and you’ll notice it as a bug before you read about it in the release notes. On Opus 5, adaptive thinking is on by default. On Opus 4.8 and 4.7, leaving out the thinking parameter meant no thinking at all:
import anthropic
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-opus-5",
max_tokens=16000,
messages=[{"role": "user", "content": "Refactor this module."}],
)
That request now spends thinking tokens, and max_tokens caps thinking plus response text together. If you set that ceiling tightly around the answer you expect from an older model, then your responses can start truncating mid-sentence with no obvious cause.
Give max_tokens headroom. You can also pass thinking={"type": "disabled"}, although only at an effort of high or lower, which you set through output_config—pairing it with xhigh or max returns a 400. Anthropic’s guidance is to lower the effort level rather than switch thinking off.
If the anthropic package is new to you, then How to Use the Claude API in Python walks through the request shape from the start.
The Rest of the Month’s Releases
Here are the other models worth knowing about:
- Kimi K3 put 2.8 trillion parameters behind what Moonshot AI calls the first open model at that scale. The weights run to well over a terabyte even in MXFP4 quantization, so self-hosting means a cluster rather than a laptop, and every request runs a reasoning pass that bills as output. Simon Willison’s write-up prices a single pelican SVG at 25 cents. Eight days after it landed, Nvidia, Microsoft, Meta, and twenty-two others signed a joint letter, “Open Weights and American AI Leadership,” urging Washington not to restrict open-weight models, with Google and OpenAI adding their names a day later.
- Claude Fable 5 returned on July 1 after export controls suspended it worldwide in June, with a new classifier that Anthropic says blocks the specific technique behind those controls in over 99 percent of cases. It’s still Anthropic’s top capability tier above Opus 5, and thinking can’t be switched off at all.
- GPT-5.6 became generally available on July 9 as three models rather than one: Luna, Terra, and Sol, in order of increasing capability. The Responses API picked up programmatic tool calling, which lets the model write JavaScript to orchestrate your tools in OpenAI’s own sandbox instead of round-tripping every call through the conversation.
- Gemini 3.6 Flash shipped on July 21 alongside two 3.5-class siblings, a Flash-Lite and a cybersecurity-tuned Flash Cyber. The story here is what didn’t ship, since the Gemini 3.5 Pro flagship that developers have been waiting on remains unreleased, leaving Flash a full version ahead of it.
- Meta Muse Spark 1.1 arrived on July 9 with something more surprising than the model: Meta’s first paid hosted API. For a company that built its reputation on open weights, and whose Muse Spark line launched closed-weight back in April, putting a price on hosted access completes Meta’s shift toward closed, paid models. Muse Spark 1.1 itself is aimed at agent orchestration.
- Inkling is the first model from Thinking Machines Lab, the outfit founded by former OpenAI CTO Mira Murati. It’s a mixture-of-experts model under Apache 2.0, and the lab is refreshingly blunt about positioning it as a strong base for fine-tuning rather than a frontier competitor.
Free Threading Becomes the Default Target
Underneath the models and the agents sits a pile of Python libraries, where the free-threaded build stopped being an experiment. Nobody announced it as a milestone because the story is spread across three release notes that few people read together.
PyTorch 2.13 shipped on July 8 and stopped building wheels for CPython 3.13t after upstream manylinux dropped it. The same release added preliminary Linux-only Python 3.15 wheels, including free-threaded 3.15t builds. JAX v0.11.0 followed on July 16 and dropped 3.13t too, with an unusually clear explanation:
Python 3.13 free-threaded was an experimental build needed to bootstrap free threading support. Now that Python 3.14t is stable, it is time to drop the experimental build. Other parts of the Python ecosystem (e.g.
cibuildwheel,scipy) are making similar moves.
NumPy 2.5, out in late June, comes at it from the opposite direction, improving free-threading support while preparing for 3.15.
When you put those together, the picture is clear: 3.13t was scaffolding, 3.14t is the supported target, and 3.15t builds are already appearing. The GIL-free build is now the baseline wherever concurrency matters most.
Two other pieces arrived as well. The free-threaded stable ABI from PEP 803 lands with 3.15 in October, and Quansight published a tour of the CPython ABI explaining what that involves in practice.
Meanwhile, core developer Thomas Wouters gave a talk at PyCon US 2026 tracing GIL-removal attempts back to 1996. LWN’s summary notes his estimate that free threading becomes the default somewhere in the 3.17 to 3.19 range.
With 3.19 due in October 2030, that’s too far out to plan for. If you maintain an extension module, then target 3.14t instead.
Note: If you want to understand what changes when the GIL goes away, then start with Python 3.13: Free Threading and a JIT Compiler and the Thread Safety in Python: Locks and Other Techniques video course.
The Rest of the Python World
July brought the last beta before Python 3.15’s release candidates, a concrete answer to last month’s governance deadline, and the opening of two elections that will shape who decides what happens next. The toolchain you probably run on every commit also shipped a pair of breaking releases.
Python 3.15 Ships Its Final Beta
Python 3.15.0 beta 4 arrived on July 18 carrying around three hundred bugfixes, build improvements, and documentation changes since beta 3, and it’s the last beta. From here the schedule is short: release candidate 1 on August 4, release candidate 2 on September 1, and the final release on October 1.
No new features have landed since the feature freeze back in May, so that article is still the tour of what’s coming.
What has changed is how much time you have left. If you maintain a library, then the window for finding breakage in your own code is closing, and beta 4 is your last low-stakes chance to catch it.
The JIT Team Answers the Steering Council
Last month we covered the Steering Council putting CPython’s JIT on a six-month clock: write a standards-track PEP, or the JIT comes back out of main.
The answer arrived on July 2 as PEP 836, titled “JIT Go Brrr: The Path to a Supported JIT Compiler for CPython” and authored by Savannah Ostrowski, Ken Jin, and Brandt Bucher.
It lays out a roughly two-and-a-half-year plan starting with Python 3.16 and running through 3.17. The JIT would move from today’s trace-based recording to method-based compilation and hit at least a 20 percent improvement over the free-threaded interpreter alone by 3.17. It would also avoid regressing debugger and profiler support, and sort out how packagers distribute the JIT.
The PEP is still a draft, and the Council hasn’t ruled. But turning a governance ultimatum into a concrete public roadmap inside a month is a decent showing, and the discussion thread is worth reading if you want to see the process working as intended.
The Election Dates Get Concrete
Last month we noted that the PSF had set its 2026 election dates, and that the first-ever Packaging Council vote would run alongside the board election. The details are now out, and if you’re thinking of standing, then the window is narrow: nominations for both open on July 28 and close on August 11.
The Packaging Council election has five seats, split into two two-year terms and three one-year terms. The PSF Board election has four.
If you’d rather vote than run, then you need to be a PSF voting member in good standing and affirm your intent by August 25. It takes two minutes, and a surprising number of eligible people forget.
Astral Ships Two Breaking Minors
uv 0.12.0 arrived on July 28, the first minor bump since 0.11.0 in March, with Ruff 0.16.0 five days ahead of it. Both are flagged as breaking, though Astral’s line on uv is that it expects “most users to be able to upgrade without making changes.”
The visible change in uv is that uv init builds a packaged project again. New projects get a src/ layout, a [build-system] using uv_build, and a [project.scripts] entry, so the project can be imported from your tests instead of only run as a loose script. Pass uv init --no-package for the old flat layout. Existing projects are untouched.
The more interesting half of the release got less attention. uv used to warn about a --require-hashes directive inside a requirements.txt and then install without checking hashes at all. That’s now fixed. Hash-checking mode also rejects MD5-only digests, and uv now refuses wheels that could overwrite your interpreter. That includes variants like Python.exe, which slipped past the old check on case-insensitive file systems.
Source distributions must be .tar.gz now, per PEP 625, so a .tar.bz2 or .tar.xz sitting in an existing lockfile will start failing. If you’ve been trying pylock.toml, then uv validates it far more strictly: a missing packages array used to read as an empty lockfile, which meant uv pip sync could quietly uninstall your environment instead of rejecting the file.
Ruff 0.16.0 is the one more likely to fill your terminal. The default rule set jumps from 59 rules to 413, so ruff check will flag far more on an existing project than it did before. Ruff also formats Python code blocks inside your Markdown files by default now.
Conferences and Events
EuroPython 2026 took place in Kraków from July 13 to 19, across five parallel tracks, with more than 1,500 attendees expected.
Of the sessions we previewed last month, the one people kept posting about was Guido van Rossum appearing live on stage as a guest on the core.py podcast, with hosts Łukasz Langa and Pablo Galindo Salgado. pyOpenSci founder Leah Wasser gave a July 16 keynote on building resilience when things feel hard, drawing on ultrarunning as much as on open source.
If you missed it, the talks get recorded and posted. The same goes for PyCon US 2026, whose videos are up, including Thomas Wouters’s free-threading talk.
Real Python Roundup
The Real Python team leaned into AI this month too, right down to a course on testing MCP servers. Here’s what’s new on the site.
You can start with these new tutorials:
- Python 3.15 Preview: Upgraded JIT Compiler
- How to Use GitHub
- LangGraph Tutorial: Build Stateful AI Agents in Python
- How to Write a CLAUDE.md File for Claude Code
- Using NumPy reshape() to Change the Shape of an Array
- Tool-Agnostic Python Lock Files With PEP 751 and pylock.toml
- How to Use Google’s Antigravity CLI for AI Code Assistance
- CrewAI in Python: Coordinating Teams of AI Agents
If you prefer learning by watching, check out these new video courses:
Test your understanding with these new quizzes:
- Python 3.15 Preview: Upgraded JIT Compiler
- Natural Language Processing With Python’s NLTK Package
- Python Interfaces: Object-Oriented Design Principles
- Testing MCP Servers With a Python MCP Client
- How to Use GitHub
- Build Enumerations of Constants With Python’s Enum
- LangGraph: Build Stateful AI Agents in Python
- Understanding Mixin Classes in Python
- How to Write a CLAUDE.md File for Claude Code
- Using NumPy reshape() to Change the Shape of an Array
- Exploring Python’s Built-in Functions
- FastAPI: Python API Development With Light Speed
- Tool-Agnostic Python Lock Files With PEP 751 and pylock.toml
- A Guide to Excel Spreadsheets in Python With openpyxl
- How to Use Google’s Antigravity CLI for AI Code Assistance
- Managing Imports With Python’s
__all__ - NumPy Tutorial: Your First Steps Into Data Science in Python
- 11 Beginner Tips for Learning Python Programming
On The Real Python Podcast, the conversation kept circling back to agents:
- Episode 301: Running Python Locally in a Sandbox
- Episode 302: Constructing and Judging Modern Agentic Workflows
- Episode 303: Free-Threaded Python’s History & uv in Production
- Episode 304: Configuring a Versatile LLM Harness & Scraping the Web With Scrapy
Episode 302 is the one to pick if you only have time for one. Quality engineer Suneet Malhotra explains how to use an LLM as a judge inside an agent system, and how to measure whether those judgments agree with each other using Cohen’s kappa.
What’s Next for Python?
Python 3.15 moves past beta and starts its release-candidate phase this month, with the final release scheduled for the fall. The feature set has been final since spring, so no new features are expected. This makes it the last good opportunity to see if your code still works, and a few hours of testing with a candidate build now can prevent surprises after the official release.
On the AI side, the MCP rewrite stops being a specification and turns into migration work. If you run a server, then you already know what your week looks like. If you only call MCP servers, then you mostly get to enjoy the results. The release everyone is still watching for is Gemini 3.5 Pro, which keeps slipping while Google ships Flash models around it. See you next month!
Join Now: Click here to join the Real Python Newsletter and you’ll never miss another Python tutorial, course, or news update.