OpenAI Responses API in Spring AI 2.1: Hosted Web Search, Code Interpreter and Remote MCP
Spring AI 2.1.0-M1 can talk to OpenAI’s Responses API. One property switches the model bean, and new options add hosted web search, code interpreter and remote MCP. What I verified, what I could not measure.
OpenAI has two ways to talk to a chat model: the older Chat Completions API and the newer Responses API. Spring AI has always used the first. Spring AI 2.1.0-M1 adds the second, and with it three tools that OpenAI runs for you on its own servers: web search, a code interpreter, and calls to a remote MCP server. This post shows the one property that switches APIs, the options that turn the hosted tools on, and what I could and could not check without an OpenAI account.
Versions and limits. Spring AI 2.1.0-M1 (milestone; GA line is 2.0.1), JDK 25 (Temurin 25.0.4.1). I had no OpenAI key and no outbound access to the API, so nothing here was sent to OpenAI. What I verified: which bean Spring creates for each property value, and that the options compile and hold their values. What I did not measure: response quality, latency, or cost. The table further down says so cell by cell, and I did not invent numbers. The code is one downloadable file: ResponsesDemo.java.
The failure first: setting hosted tools on the default model does nothing useful
The Responses options are a separate class, OpenAiResponsesChatOptions, in the package org.springframework.ai.openai.responses. They belong to a separate model, OpenAiResponsesChatModel. Which model Spring gives you is decided by one property, and the default is the old one. I started a context with the dummy key sk-dummy-never-called and three values of spring.ai.openai.chat.api:
So if you copy the options below into an application and forget the property, you are still on OpenAiChatModel, the Chat Completions model. Hosted tools are a Responses feature. I did not run a request to see exactly how the old model reacts to those options, so I cannot say whether it errors or ignores them; the safe reading is that you must set the property. This output is from ResponsesDemo.java, using Spring Boot’s ApplicationContextRunner with the two OpenAI auto-configurations.
The property is bound to an enum with two values, CHAT_COMPLETIONS and RESPONSES. Nothing else in your code changes if you only use ChatClient; the model bean behind it is different.
The picture is only the property-to-bean mapping from the console output above. The default stays on the left.
Reasoning and output options
OpenAiResponsesChatOptions.builder() in 2.1.0-M1 has, among others, reasoningEffort, reasoningSummary, maxOutputTokens, maxToolCalls, parallelToolCalls, include, serviceTier, promptCacheKey, truncation, verbosity and hostedTools. I listed them from the compiled class, not from documentation. Building one:
== Responses options with hosted tools
model = gpt-5.1
reasoningEffort = medium
reasoningSummary = auto
hostedTools = [WebSearch, CodeInterpreter, Mcp]
The model name gpt-5.1 is just a string I typed; I did not check what models your account can use. https://example.com/mcp is a placeholder, not a real server.
The three hosted tools
The sealed type HostedTool has these members in 2.1.0-M1:
WebSearch(searchContextSize, allowedDomains). OpenAI searches the web and cites it. You choose how much context and which domains.
CodeInterpreter(containerId). OpenAI runs code in a sandbox it manages. You may pass an existing container id.
Mcp(serverLabel, serverUrl, connectorId, allowedTools, headers, requireApproval). OpenAI calls an MCP server on your behalf.
Also present: FileSearch, ImageGeneration and Raw for anything the typed ones do not cover.
The contrast with Spring’s usual @Tool methods matters. Your own tools run inside your JVM; Spring sees each call and result (see Tool Calling in Spring AI 2.0). A hosted tool runs at OpenAI, and the loop happens inside one API call, so your code does not execute it and your observability only sees what comes back.
Remote MCP, and why it is different from your MCP client
Spring AI already has an MCP client, covered in Spring AI MCP Client, where your application connects to an MCP server. The hosted Mcp tool reverses who connects. OpenAI’s servers connect to the URL you give, so it has to be reachable from the public internet (my reading of how a hosted MCP connector works; I did not test it). The fields that matter for safety are allowedTools (expose only some tools), headers (for the credential you send to that server) and requireApproval. To protect the server itself, see Securing an MCP Server with Spring Security 7 and the server post.
Responses versus OpenAiChatModel
Cost and latency are the interesting columns and the ones I cannot fill with numbers. Rather than guess, the table records what I verified, what is structural, and what you must measure:
Dimension
OpenAiChatModel
OpenAiResponsesChatModel
Selected by
unset or chat-completions (verified)
responses (verified)
Hosted web search, code interpreter, remote MCP
Not in its options class
Yes, via hostedTools (verified compiles)
Reasoning options
Not measured here
reasoningEffort, reasoningSummary (verified)
Who runs a tool call
Your JVM, loop in Spring
OpenAI for hosted tools, inside one call
Latency per request
Not measured
Not measured
Cost per request
Not measured
Not measured
How to fill the last two rows yourself
Pick 20 representative prompts, and run each against both models with the same model and a fixed seed of questions.
Record wall time per call and, for the Responses model, which hosted tools fired. A web search adds a per-call tool charge on top of tokens, so a search-triggering prompt is not comparable to one that never searched.
Take token counts from the response usage, and price them from OpenAI’s current price sheet at the time you run it. I did not fetch the price sheet, so I give no prices. The method for tokens and cost in Micrometer is in Observability for Spring AI.
Report median and the slowest run, not the mean.
The classes I inspected, so you can check them
Beans: OpenAiResponsesChatAutoConfiguration alongside OpenAiChatAutoConfiguration. Types in org.springframework.ai.openai.responses: OpenAiResponsesChatModel, OpenAiResponsesChatOptions, HostedTool, ResponsesStreamAssembler. I read these with javap on the 2.1.0-M1 jars and then compiled the demo against them.
Should you even do this? Only if you want OpenAI’s hosted tools or reasoning controls. If you just want chat, OpenAiChatModel is the stable path and works on a GA release. Hosted tools also tie you to one vendor: your search and sandbox now live on their side, which cuts against the provider-switching idea in the provider comparison. And since this is a milestone with no measured numbers behind it, do a proper trial before you commit.
No Comments yet!