# Adopting an MCP-First API Design for the Agentic Era | Beyond REST.

Move beyond traditional RESTful thinking. Learn how to design APIs specifically for MCP (Model Context Protocol) servers. This guide covers the shift in mindset, a practical OpenAPI 3.1 example, and a Spring Boot implementation to make your services AI-native.

# Introduction:

For the last decade, our mantra as architects has been "API-first." We designed beautiful, resource-oriented RESTful interfaces, meticulously documented with OpenAPI, to decouple frontends from backends and enable a rich ecosystem of integrations. We built our digital empires on HTTP verbs and status codes.

But a new client has entered the building. It’s not a mobile app or a single-page application. It’s an AI Agent.

This agent doesn't navigate hypermedia links or care about the fine print of your `application/json` schema in the same way a human developer does. It needs **context** and **capability**. It needs to know: "What can you do for me, and how do I ask you to do it?"

This is where the **Model Context Protocol (MCP)** changes the game. MCP provides a standardized way to expose tools, resources, and prompts to AI models. If you want your enterprise systems to be "AI-native," you must shift from "REST-first" to **"MCP-first" API design.**

### The Shift in Mindset: From Resources to Actions

Traditional REST is about managing *state* (GET, POST, PUT, DELETE on `/users` or `/orders`). MCP is about enabling *action*. An agent doesn't want to just *read* a user; it wants to "Send a notification to user X" or "Calculate the risk for customer Y."

Therefore, an MCP-first design philosophy treats your APIs as a collection of **tools**. While these tools may be backed by REST endpoints, their public face to the agent ecosystem is a list of declarative functions.

**The Golden Rule:** *Design the tool first, then implement the API endpoint that supports it.*

### What is an MCP Tool?

From an API perspective, an MCP server exposes a tool, which is defined by:

1. **Name:** A unique identifier for the function (e.g., `get_weather`).
    
2. **Description:** A natural language explanation of what the tool does. This is crucial for the LLM to decide when to use it.
    
3. **Input Schema:** A JSON Schema describing the parameters the tool accepts.
    

### Practical Example: The Weather Service (A Classic for a Reason)

Let’s say we need to expose an internal weather service to an AI agent so it can answer, "Do I need an umbrella in London tomorrow?"

#### The MCP-First Thought Process

1. **Identify the Tool:** The agent needs a tool called `get_forecast`.
    
2. **Describe it:** "Retrieves the weather forecast for a specific location for a given number of days."
    
3. **Define the Input:**
    
    * `location` (string, required): The city name or coordinates.
        
    * `days` (integer, optional): Number of days for the forecast (default: 1).
        

Now that we know the tool, we design the backing API.

#### 1\. The Backing API (OpenAPI 3.1 & Spring Boot)

The backing API is what your backend team builds. It might be REST, gRPC, or GraphQL. For our example, let's design a simple REST controller in Spring Boot.

**OpenAPI 3.1 Specification Snippet (**`weather-service.yaml`)

```yaml
openapi: 3.1.0
info:
  title: Internal Weather API
  version: 1.0.0
servers:
  - url: https://api.internal.company.com/v1
paths:
  /weather/forecast:
    get:
      summary: Get weather forecast
      operationId: getForecast
      parameters:
        - name: location
          in: query
          required: true
          schema:
            type: string
          description: "City name (e.g., London) or lat,long"
        - name: days
          in: query
          required: false
          schema:
            type: integer
            default: 1
            minimum: 1
            maximum: 7
          description: "Number of forecast days"
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                type: object
                properties:
                  location:
                    type: string
                  forecast:
                    type: array
                    items:
                      type: object
                      properties:
                        date:
                          type: string
                          format: date
                        condition:
                          type: string
                        high:
                          type: number
                        low:
                          type: number
```

**Spring Boot Controller Implementation**

This is the code that fulfills the OpenAPI contract.

```java
@RestController
@RequestMapping("/api/v1/weather")
public class WeatherController {

    @GetMapping("/forecast")
    public ResponseEntity<ForecastResponse> getForecast(
            @RequestParam String location,
            @RequestParam(defaultValue = "1") @Min(1) @Max(7) int days) {

        // In a real app, you'd call a weather service here
        ForecastResponse response = new ForecastResponse(location, days);
        return ResponseEntity.ok(response);
    }

    // Inner class for response structure
    record ForecastResponse(String location, List<DailyForecast> forecast) {
        ForecastResponse(String location, int days) {
            this(location, generateMockForecast(days));
        }
        private static List<DailyForecast> generateMockForecast(int days) {
            // Mock implementation
            return IntStream.range(0, days)
                    .mapToObj(i -> new DailyForecast(
                            LocalDate.now().plusDays(i),
                            "Sunny",
                            22.5 + i,
                            13.0 + i))
                    .toList();
        }
    }

    record DailyForecast(LocalDate date, String condition, Double high, Double low) {}
}
```

This is a standard, well-designed REST endpoint. It's ready for mobile apps and web UIs. But it's not yet ready for an AI Agent.

#### 2\. The MCP Server Wrapper (The "Adapter")

This is the critical piece of the MCP-first architecture. We build a lightweight MCP server that acts as an adapter. Its job is to expose our `getForecast` REST endpoint as an MCP Tool.

Here’s how you might implement that adapter using a Spring Boot MCP abstraction (building on the new Spring AI MCP modules).

**MCP Server Tool Definition (Spring Boot).**

```java
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestClient;
import org.springframework.web.util.UriComponentsBuilder;

@Component
public class WeatherTools {

    private final RestClient restClient;

    public WeatherTools() {
        this.restClient = RestClient.builder()
                .baseUrl("https://api.internal.company.com/v1")
                .build();
    }

    @Tool(description = "Retrieves the weather forecast for a specific location for a given number of days.")
    public String getForecast(
            @ToolParam(description = "The city name (e.g., London) or latitude,longitude") String location,
            @ToolParam(description = "Number of forecast days (1-7, default is 1)") Integer days) {

        // The MCP tool calls the internal REST API
        String url = UriComponentsBuilder.fromPath("/weather/forecast")
                .queryParam("location", location)
                .queryParam("days", days != null ? days : 1)
                .toUriString();

        ForecastResponse response = restClient.get()
                .uri(url)
                .retrieve()
                .body(ForecastResponse.class);

        // The tool returns a simplified string result for the LLM
        return String.format("The forecast for %s is: %s", response.location(), response.forecast());
    }

    // You can reuse the ForecastResponse record from the controller
    // or define a simpler one here.
    private record ForecastResponse(String location, List<DailyForecast> forecast) {}
    private record DailyForecast(String date, String condition, Double high, Double low) {}
}
```

### The MCP Server Configuration

To make this work, you need a main application class that scans for these `@Tool` annotations and starts an MCP server.

```java
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.ai.tool.method.MethodToolCallbackProvider;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class McpWeatherServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(McpWeatherServerApplication.class, args);
    }

    // This crucial bean tells Spring AI to scan your component for @Tool methods
    // and expose them as MCP tools.
    @Bean
    public ToolCallbackProvider weatherTools(WeatherTools weatherTools) {
        return MethodToolCallbackProvider.builder().toolObjects(weatherTools).build();
    }
}
```

When this MCP server runs, it connects to an MCP client (like Claude Desktop, or a custom agent orchestrator) and advertises the `getForecast` tool with its description and input schema.

### Why This Matters for the Enterprise Architect

1. **Separation of Concerns:** The core business logic (the `WeatherController`) remains clean and unaware of AI. It serves all clients. The MCP layer is a specialized adapter.
    
2. **Security and Governance:** The MCP server can be deployed in a DMZ with stricter security controls. It can handle authentication to the internal API, rate limiting for agent requests, and input sanitization specifically tuned for LLM quirks.
    
3. **Evolution:** You can version your MCP tools independently of your REST APIs. You could have an MCP tool that composes multiple backend REST calls into a single, agent-friendly action.
    
4. **Standardization:** By adopting MCP, you stop writing custom, brittle prompts for every new API. The agent discovers capabilities dynamically.
    

### Conclusion: The Future is Multi-Client

Your API consumers will no longer be just humans with browsers or developers with API keys. They will be autonomous agents making decisions in milliseconds.

An MCP-first design philosophy doesn't mean abandoning REST or OpenAPI. It means treating them as implementation details for a higher-level capability contract. By designing the *tool* the agent needs and then building the API to support it, you ensure your enterprise is not just "digitally transformed," but **"intelligence-ready."**

Start small. Pick one legacy API, define the MCP tool it should expose, and build a lightweight server for it. This is the first step toward an architecture that doesn't just serve data, but participates in reasoning.

**More such articles:**

[**https://medium.com/techwasti**](https://techwasti.com/Link)

[**https://www.youtube.com/@maheshwarligade**](https://www.youtube.com/@maheshwarligade)

[**https://techwasti.com/series/spring-boot-tutorials**](https://techwasti.com/series/spring-boot-tutorials)

[**https://techwasti.com/series/go-language**](https://techwasti.com/series/go-language)
