Skip to main content

Getting started

Add the starter for the Model Context Protocol (MCP):

<dependency>
<groupId>io.gatool</groupId>
<artifactId>gatool-mcp-spring-boot-starter</artifactId>
<version>0.1.0</version>
</dependency>

Put the query above in src/main/resources/gatool/mcp/TopRatedMovies.graphql, and point the application at your API:

gatool:
api:
url: https://movies.example.com/graphql
schema:
location: classpath:movies.graphqls
mcp:
security:
unsafe:
allow-mcp-calls-without-authentication: true

GATool validates every operation against the schema file at startup. A query that names a field missing from the schema stops startup. The message names the file and the field. Once the CI check is in place, it fails the build for the same reason. The CI check is the OperationFilesAssert test described under "Checking your tools in CI". A test that starts the context fails the same way.

GATool builds the schema with graphql-java. graphql-java refuses one schema shape that the GraphQL specification allows. In that shape, a type gives an argument a different default from the one its interface declares. An example is memberOf(limit: Int! = 150) under an interface that declares limit: Int! = 100. Startup stops and names each such argument. graphql-java#4480 asks graphql-java to accept such a schema. Until a release does, start the application with a copy of the schema that gives those arguments the default of their interface. GATool then describes the interface default to the model, while the API applies its own.

The YAML above turns on gatool.mcp.security.unsafe.allow-mcp-calls-without-authentication, the unauthenticated switch. Without Spring Security on the classpath, the unauthenticated switch is required, and startup stops while it is off. The application logs a warning at every startup while the switch is on. Keep the endpoint on a loopback address with server.address, or behind a gateway that authenticates for it. The section on securing the endpoint below shows the other way. Add the resource server starter, name the issuer, and leave the unauthenticated switch off.

Start the application. A client that connects to /mcp reads one tool. The entry is shortened here. The one on the wire also carries a title, the $schema and the $id of the input schema, and the hints destructiveHint and idempotentHint.

{
"name": "topRatedMovies",
"description": "Returns the highest-rated movies, best first.",
"inputSchema": {
"type": "object",
"properties": {
"first": {
"anyOf": [{ "type": "integer" }, { "type": "null" }],
"description": "How many movies to return.",
"default": 10
}
},
"required": [],
"additionalProperties": false
},
"annotations": { "readOnlyHint": true }
}