Skip to content

MCP Tools

Ilya Muromtsev edited this page Jun 16, 2026 · 4 revisions

MCP Tools

Explyt Spring ships Spring-aware MCP tools for the bundled JetBrains MCP Server in IntelliJ IDEA 2025.2+. They let agentic AI clients ask the IDE for structured Spring context instead of relying only on generic file search — which means fewer broad tool calls, lower token usage, and more accurate Spring-specific answers.

Requires IntelliJ IDEA 2025.2+ with the bundled JetBrains MCP Server. Works with AI clients that can connect to the IntelliJ IDEA MCP Server, including Explyt AI.

Looking for AI-augmented editor actions (entity↔DTO, schema→entity, etc.) instead? See Explyt AI Actions.

Why this matters

A generic agent answers "which controller handles GET /api/stores/{storeId}/orders?" by grepping for the URL — which fails when the path is split across annotations:

@RequestMapping("/api/stores/{storeId}/orders")  // on the class
@GetMapping("/{orderId}/items")                   // on the method

No text search matches the composed path, so the agent falls back to guessing file names and reading candidates — typically 3–8 exploratory calls per question. Explyt's MCP tools answer the same questions in one call, using the IDE's real Spring index:

  • Which Spring Boot apps are in this workspace, and which beans do they define?
  • Which endpoint handles this URL, and what is its full request/response contract?
  • Which service/repository methods does a controller call — and which tests reference them?
  • How do JPA entities map to tables, columns, and relationships?

The example I/O below is representative (a neutral orders domain) — exact fields may evolve. Tool behavior is implemented in SpringMcpProvider.kt.


Discovery

explyt_get_spring_boot_applications

Lists Spring Boot applications in the current workspace, including detected Spring Boot versions and starters. Use it when an agent first enters a multi-module workspace and needs the right application context before calling the other tools.

Example output
[
  {
    "fullyQualifiedClassName": "com.example.OrdersApplication",
    "springBootVersion": "3.3.4",
    "springBootStarters": ["spring-boot-starter-web", "spring-boot-starter-data-jpa"],
    "moduleName": "orders-service.main",
    "buildTool": "gradle"
  }
]

explyt_get_project_beans_by_spring_boot_application

Returns the beans for a selected Spring Boot application, filtered by a bean type — CONTROLLER, REPOSITORY, CONFIGURATION, COMPONENT, CONFIGURATION_PROPERTIES, AUTO_CONFIGURATION, ASPECT, or MESSAGE_MAPPING — without searching every source file for stereotypes. Pass the application's fully-qualified class name (from explyt_get_spring_boot_applications) and the beanType.

Example output (beanType = REPOSITORY)
[
  { "beanName": "orderRepository",     "className": "com.example.repo.OrderRepository",     "moduleName": "orders-service.main" },
  { "beanName": "orderItemRepository", "className": "com.example.repo.OrderItemRepository", "moduleName": "orders-service.main" }
]

Endpoints

explyt_find_spring_endpoint

Turn a URL into the exact handler method. This is the most common entry point for backend work: almost every full-stack task starts from a URL (a browser, frontend code, a bug report).

Problem it solves. A plain search for orders/{orderId}/items returns 0 results when the path is composed from a class-level @RequestMapping plus a method-level @GetMapping. The agent then burns several calls guessing controller file names and reading them.

Input: an optional HTTP method, a urlPattern, and the project path. Matching is forgiving — it matches against the composed path, supports substring/fuzzy matching, and ignores path-variable names ({orderId} matches {id} matches any segment).

Matches across all endpoint types: Spring MVC, WebFlux, JAX-RS, HttpExchange, OpenFeign, OpenAPI, message brokers (Kafka/RabbitMQ listeners), and event listeners.

Example output (a bare array of matches)
[
  {
    "httpMethods": ["GET"],
    "fullPath": "/api/stores/{storeId}/orders/{orderId}/items",
    "controllerClass": "com.example.api.OrderItemsController",
    "methodName": "items",
    "filePath": "src/main/kotlin/.../OrderItemsController.kt",
    "line": 23,
    "parameters": [
      { "name": "storeId", "source": "PATH",  "type": "java.lang.String", "required": true },
      { "name": "orderId", "source": "PATH",  "type": "java.lang.String", "required": true },
      { "name": "page",    "source": "QUERY", "type": "java.lang.String", "required": false }
    ],
    "returnType": "com.example.api.dto.OrderItemsResponse",
    "endpointType": "Spring MVC"
  }
]

Cost: ~3–5 exploratory calls today → 1 call.

explyt_get_spring_http_endpoints

Lists all HTTP endpoints in the project (or for a given application), optionally filtered by controller class name or endpoint type (SPRING_MVC, SPRING_WEBFLUX, SPRING_JAX_RS, …). Best for "give me the whole API surface."

Returns endpoints (a per-endpoint summary: HTTP methods, full path, controller, method name, return type, file location, endpoint type), totalCount (how many matched the filters), and truncated (true when matches exceed the result cap, so the list is incomplete — narrow it with the filters).

Example output
{
  "totalCount": 2,
  "truncated": false,
  "endpoints": [
    {
      "httpMethods": ["GET"],
      "fullPath": "/api/stores/{storeId}/orders/{orderId}/items",
      "controllerClass": "com.example.api.OrderItemsController",
      "methodName": "items",
      "filePath": "src/main/kotlin/.../OrderItemsController.kt",
      "line": 23,
      "parameters": [
        { "name": "storeId", "source": "PATH", "type": "java.lang.String", "required": true }
      ],
      "returnType": "com.example.api.dto.OrderItemsResponse",
      "endpointType": "Spring MVC"
    },
    {
      "httpMethods": ["POST"],
      "fullPath": "/api/stores/{storeId}/orders",
      "controllerClass": "com.example.api.OrderController",
      "methodName": "create",
      "filePath": "src/main/kotlin/.../OrderController.kt",
      "line": 41,
      "parameters": [
        { "name": "storeId", "source": "PATH", "type": "java.lang.String", "required": true },
        { "name": "body", "source": "BODY", "type": "com.example.api.dto.CreateOrderRequest", "required": true }
      ],
      "returnType": "com.example.api.dto.OrderResponse",
      "endpointType": "Spring MVC"
    }
  ]
}

explyt_get_spring_endpoint_contract

Returns the full API contract for one endpoint — ideal for backend/frontend integration work. Includes every parameter (path variables, query params, request body, headers) with types and required flags, the response DTO schema recursively expanded up to 3 levels (each DtoSchemaJson has a className and fields; nested DTOs hang off each field's nested), the produces/consumes media types, and the first service method called from the controller (serviceCall).

Example output (abridged)
{
  "httpMethods": ["POST"],
  "fullPath": "/api/stores/{storeId}/orders",
  "controllerClass": "com.example.api.OrderController",
  "methodName": "create",
  "filePath": "src/main/kotlin/.../OrderController.kt",
  "line": 41,
  "parameters": [
    { "name": "storeId", "source": "PATH", "type": "java.lang.String", "required": true },
    { "name": "body", "source": "BODY", "type": "com.example.api.dto.CreateOrderRequest", "required": true }
  ],
  "returnType": "com.example.api.dto.OrderResponse",
  "responseSchema": {
    "className": "com.example.api.dto.OrderResponse",
    "fields": [
      { "name": "id", "type": "java.lang.Long", "nullable": false, "nested": null },
      { "name": "items", "type": "java.util.List<com.example.api.dto.OrderItemResponse>", "nullable": false,
        "nested": { "className": "com.example.api.dto.OrderItemResponse",
          "fields": [ { "name": "sku", "type": "java.lang.String", "nullable": false, "nested": null } ] } }
    ]
  },
  "produces": ["application/json"],
  "consumes": ["application/json"],
  "serviceCall": { "target": "com.example.service.OrderService.createOrder", "line": 88 },
  "endpointType": "Spring MVC"
}

Call chain

explyt_trace_spring_call_chain

Map a Controller → Service → Repository call chain before you edit it. Given a file path and line, the tool recursively follows method calls via UAST and labels each layer using Spring stereotypes:

Annotation Layer
@Controller / @RestController CONTROLLER
@Service SERVICE
@Repository REPOSITORY
@Component COMPONENT
(none — private method in the same class) INTERNAL

Problem it solves. Threading a new parameter through a stack means tracing each layer by hand (find_usagesread_file, repeated ~8 times) — and the change still fails to compile because test files that mock/verify those methods were missed and only surface in compiler errors.

includeTests: true is the key option: it runs usage search on each discovered method and reports the test files + line numbers that reference them, so the agent updates every mock { on { … } } / verify(repo).…(…) up front and avoids the "edit → compile → fail → fix → repeat" cycle.

Example output (abridged)
{
  "chain": [
    { "layer": "CONTROLLER", "className": "com.example.api.OrderItemsController", "methodName": "items",
      "filePath": "src/main/kotlin/.../OrderItemsController.kt", "line": 23,
      "parameters": ["storeId", "orderId", "page"],
      "callsInto": [{ "target": "com.example.service.OrderItemsService.listItems", "line": 31 }] },
    { "layer": "SERVICE", "className": "com.example.service.OrderItemsService", "methodName": "listItems",
      "filePath": "src/main/kotlin/.../OrderItemsService.kt", "line": 18,
      "parameters": ["storeId", "orderId", "page"],
      "callsInto": [{ "target": "com.example.repo.OrderItemsRepository.fetchItems", "line": 44 }] },
    { "layer": "REPOSITORY", "className": "com.example.repo.OrderItemsRepository", "methodName": "fetchItems",
      "filePath": "src/main/kotlin/.../OrderItemsRepository.kt", "line": 12,
      "parameters": ["storeId", "orderId", "page"],
      "callsInto": [{ "target": "this.buildItemsQuery", "line": 60 }] }
  ],
  "testReferences": [
    { "filePath": "src/test/kotlin/.../OrderItemsServiceTest.kt",
      "referencedMethods": [{ "method": "listItems", "lines": [55, 128] }] }
  ]
}

Each chain node carries layer, className, methodName, filePath, line, parameters, and callsInto (each call target with its line). The traversal follows constructor-injected fields to resolve concrete bean types and stops on circular chains.


Data model

explyt_get_spring_data_entities

Understand the whole domain model in one call. Lists all JPA @Entity classes (detects both jakarta.persistence and javax.persistence), with an optional packageFilter to restrict to a package subtree.

Problem it solves. Building a mental model of a 20-entity data layer otherwise costs 30+ calls: search_for_text("@Entity") returns raw lines, then each file is read to extract the table name, columns, and relationships.

Per entity it returns: class name, file path and line, resolved tableName (from @Table/@Entity(name=…) or JPA default naming), fields (with column, type, primaryKey from @Id/@EmbeddedId, and nullable), JPA relationships (ONE_TO_ONE, ONE_TO_MANY, MANY_TO_ONE, MANY_TO_MANY) with joinColumn/mappedBy wiring, and table indexes (from @Table(indexes=[...]) / @Index).

Example output (a bare array of entities, abridged)
[
  {
    "name": "OrderItem",
    "className": "com.example.domain.OrderItem",
    "filePath": "src/main/kotlin/.../OrderItem.kt",
    "line": 12,
    "tableName": "order_items",
    "fields": [
      { "name": "id",    "type": "java.lang.Long",   "column": "id",      "primaryKey": true,  "nullable": false, "relationship": null,         "joinColumn": null,       "mappedBy": null },
      { "name": "sku",   "type": "java.lang.String", "column": "sku",     "primaryKey": false, "nullable": false, "relationship": null,         "joinColumn": null,       "mappedBy": null },
      { "name": "order", "type": "com.example.domain.Order", "column": null, "primaryKey": false, "nullable": true, "relationship": "MANY_TO_ONE", "joinColumn": "order_id", "mappedBy": null }
    ],
    "indexes": [ { "name": "idx_order_id", "columns": ["order_id"], "unique": false } ]
  }
]

Why it's valuable: column-name mapping bridges Kotlin field names ↔ SQL columns for repository/query work; the relationship graph drives correct JOINs; existing indexes/constraints prevent migration conflicts; and the entity shape is the starting point for DTO design.


How the tools work together

For a full-stack change they form a pipeline — route → logic → data model:

  1. explyt_find_spring_endpoint — find the controller that handles a URL.
  2. explyt_trace_spring_call_chain — trace Controller → Service → Repository (and the tests to update).
  3. explyt_get_spring_data_entities — reveal the entities/tables the repository operates on.

explyt_get_spring_http_endpoints and explyt_get_spring_endpoint_contract add the API-surface and per-endpoint contract views on top.

Implementation

Learn more

See also: Features · Native Context Mode · Explyt AI Actions

Clone this wiki locally