You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs: align README, docs, and llms with current behavior
Fix completion URI matching, base package resolution, and component lifecycle notes. Document mvnw, Spotless validate, and 0.18.0-SNAPSHOT development version.
Co-authored-by: Cursor <cursoragent@cursor.com>
Copy file name to clipboardExpand all lines: README.md
+14-4Lines changed: 14 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -24,7 +24,7 @@ English · [简体中文](README.zh-CN.md)
24
24
25
25
This SDK is a lightweight, annotation-based framework that simplifies MCP server development in Java. Define, develop, and integrate your MCP Resources / Prompts / Tools with minimal code — **no Spring Framework required**.
26
26
27
-
> **Workflow:** Add dependency → Configure `mcp-server.yml` → Annotate Resources / Tools / Prompts → Run with `McpApplication`
27
+
> **Workflow:** Add dependency → Configure `mcp-server.yml` → Annotate Resources / Tools / Prompts / Completions → Run with `McpApplication`
Use the [Maven Central](https://central.sonatype.com/artifact/io.github.thought2code/mcp-annotated-java-sdk) badge above for the latest release. This repository’s development version is `0.18.0-SNAPSHOT`.
79
+
78
80
#### Step 2: Create Configuration File
79
81
80
82
Create `mcp-server.yml` in your `src/main/resources`:
@@ -289,7 +291,9 @@ The SDK creates **one instance per component class** (no-arg constructor) and re
289
291
- Do not store per-request data in instance fields without proper synchronization.
290
292
- Delegate shared mutable state to thread-safe services when needed.
291
293
292
-
`McpApplicationContext.from(...)`currently uses this default singleton-per-class factory. There is no built-in Spring/CDI wiring in the public API today.
294
+
`McpApplicationContext.from(...)`currently uses this default singleton-per-class factory. Component classes must provide a **public no-arg constructor**. There is no built-in Spring/CDI wiring in the public API today.
295
+
296
+
`McpApplication.run(mainClass, args)`loads `mcp-server.yml` by default; pass a third argument to use another classpath config file name.
293
297
294
298
#### MCP Java SDK 2.x (milestone)
295
299
@@ -328,12 +332,18 @@ your-mcp-project/
328
332
329
333
## 🧪 Testing
330
334
331
-
Run the test suite:
335
+
Run the unit test suite (this project requires the Maven Wrapper — do not use a system `mvn` install):
332
336
333
337
```bash
334
338
./mvnw clean test
335
339
```
336
340
341
+
On Windows:
342
+
343
+
```bash
344
+
mvnw.cmd clean test
345
+
```
346
+
337
347
## ❓ FAQ
338
348
339
349
### Q: Do I need Spring Framework?
@@ -389,7 +399,7 @@ We welcome and appreciate contributions! Please follow these steps to contribute
`@McpPromptCompletion.name` must match the **registered prompt name**(by default, the Java method name of the `@McpPrompt` method). Filter by `argument.name()` when one prompt has multiple parameters.
200
+
`@McpPromptCompletion.name` must match the **registered prompt name**— the `@McpPrompt.name` attribute when set, otherwise the `@McpPrompt` method name. Filter by `argument.name()` when one prompt has multiple parameters (the name must match the `@McpPromptParam.name` being completed).
@@ -215,8 +227,9 @@ After defining MCP components, they will be automatically registered to the serv
215
227
216
228
### One instance per component class
217
229
218
-
The SDK creates a single object per component class (via its no-arg constructor) and invokes all annotated methods on that class through the same instance. **Concurrent requests share one object**, so:
230
+
The SDK creates a single object per component class (via its **public no-arg constructor**) and invokes all annotated methods on that class through the same instance. **Concurrent requests share one object**, so:
219
231
232
+
- Component classes must expose an accessible no-arg constructor.
220
233
- Keep component classes stateless when possible.
221
234
- Any mutable instance fields must be thread-safe, or you must synchronize access.
222
235
- Do not treat instance fields as per-request storage.
@@ -235,7 +248,13 @@ If you need to specify a specific package path, you can use the following method
Use the [Maven Central artifact page](https://central.sonatype.com/artifact/io.github.thought2code/mcp-annotated-java-sdk) for the latest release version. This repository’s development version is `0.18.0-SNAPSHOT`.
33
+
32
34
## 5-Minutes Tutorial
33
35
34
36
### Step 1: Create Configuration File
@@ -118,6 +120,8 @@ public class MyPrompts {
118
120
119
121
Run `MyFirstMcpServer` from your IDE, or use `java -cp ...` with your compiled classes and dependencies on the classpath. Use an executable JAR setup in your own project if you need `java -jar` with a single file.
120
122
123
+
To load a non-default configuration file name, use `McpApplication.run(MyFirstMcpServer.class, args, "custom-mcp-server.yml")`.
124
+
121
125
## Server Modes
122
126
123
127
This SDK supports three MCP server modes. If you omit `mode` in `mcp-server.yml`, the server defaults to **STREAMABLE** (see the configuration table below).
@@ -203,7 +207,7 @@ Use **SYNC** by default. Choose **ASYNC** only when your deployment requires the
203
207
204
208
### Component instances and concurrency
205
209
206
-
The SDK creates **one instance per component class** and reuses it for all requests. Concurrent MCP calls share that object. Keep components **stateless** or **thread-safe**; avoid unsynchronized per-request instance fields.
210
+
The SDK creates **one instance per component class** (via a **public no-arg constructor**) and reuses it for all requests. Concurrent MCP calls share that object. Keep components **stateless** or **thread-safe**; avoid unsynchronized per-request instance fields.
Latest release: https://central.sonatype.com/artifact/io.github.thought2code/mcp-annotated-java-sdk (repo development version: 0.18.0-SNAPSHOT).
55
+
54
56
## Quick Start Tutorial
55
57
56
58
### Step 1: Create Configuration File
@@ -159,6 +161,8 @@ public class MyPrompts {
159
161
160
162
Run `MyFirstMcpServer` from your IDE, or use `java -cp ...` with your compiled classes and dependencies on the classpath. Use an executable JAR setup in your own project if you need `java -jar` with a single file.
161
163
164
+
Optional: `McpApplication.run(MyFirstMcpServer.class, args, "custom-mcp-server.yml")` to load a different config file (default `mcp-server.yml`).
165
+
162
166
## Core Components
163
167
164
168
### Resources
@@ -174,6 +178,8 @@ Resource components are used to expose data to LLMs, similar to GET requests in
174
178
| `name` | Resource name (defaults to method name) | No |
175
179
| `title` | Resource title (defaults to `name`) | No |
176
180
| `mimeType` | MIME type of the resource content | No (default `text/plain`) |
181
+
| `roles` | Roles allowed to access the resource | No (default `ASSISTANT`, `USER`) |
182
+
| `priority` | Resource priority | No (default `1.0`) |
177
183
178
184
### Tools
179
185
@@ -223,39 +229,35 @@ Handlers must **return** `CompletionResult` and take **exactly one** parameter o
223
229
224
230
#### Resource Completions
225
231
232
+
`@McpResourceCompletion.uri` must match the paired `@McpResource.uri` exactly (including URI templates).
@McpResource(uri = "file://{path}", description = "Read a file by path")
243
+
public String readFile() {
244
+
return "file content";
245
+
}
246
+
247
+
@McpResourceCompletion(uri = "file://{path}")
248
+
public CompletionResult completeFileUri(McpSchema.CompleteRequest.CompleteArgument argument) {
245
249
return CompletionResult.builder()
246
-
.values(paths)
247
-
.total(paths.size())
250
+
.values(List.of("file://a", "file://b"))
251
+
.total(2)
248
252
.hasMore(false)
249
253
.build();
250
-
} catch (Exception e) {
251
-
return CompletionResult.empty();
252
254
}
253
255
}
254
256
```
255
257
256
258
#### Prompt Completions
257
259
258
-
`@McpPromptCompletion.name` must match the **registered prompt name** (by default, the Java method name of the `@McpPrompt` method). Filter by `argument.name()` when one prompt has multiple parameters.
260
+
`@McpPromptCompletion.name` must match the registered prompt name (`@McpPrompt.name` when set, otherwise the `@McpPrompt` method name). Filter by `argument.name()` when one prompt has multiple parameters (must match `@McpPromptParam.name`).
After defining MCP components, they will be automatically registered to the server. You just need to ensure that the component classes are within the registration scope of the server application.
416
418
419
+
### One instance per component class
420
+
421
+
The SDK creates one object per component class (public no-arg constructor) and reuses it for all requests. Concurrent MCP calls share that object — keep components stateless or thread-safe.
422
+
423
+
### SYNC vs ASYNC server type
424
+
425
+
`type: ASYNC` uses the async MCP server API; handlers wrap blocking Java methods in `Mono.fromCallable(...)`. Annotated methods do not return `Mono`/`Flux`.
426
+
417
427
### Specify Package Path
418
428
419
429
```java
@@ -422,7 +432,7 @@ After defining MCP components, they will be automatically registered to the serv
If no package path is specified, the package of the class passed to `McpApplication.run()` is used as the default registration scope.
435
+
Resolution order: `basePackageClass` (when not `Object.class`) → non-blank `basePackage` → package of `McpApplication.run()` main class. Subpackages under the resolved base package are included.
Latest release: https://central.sonatype.com/artifact/io.github.thought2code/mcp-annotated-java-sdk (repo development version: 0.18.0-SNAPSHOT).
38
+
37
39
### Create MCP Server
38
40
39
41
```java
@@ -95,6 +97,13 @@ public String generateCode(
95
97
| `@McpJsonSchemaDefinition` | Marks a type as a custom JSON Schema definition |
96
98
| `@McpJsonSchemaProperty` | Describes a field in a JSON Schema definition |
97
99
100
+
## Completions
101
+
102
+
When `capabilities.completion: true`, handlers return `CompletionResult` and accept one `McpSchema.CompleteRequest.CompleteArgument` parameter.
103
+
104
+
- `@McpResourceCompletion.uri` must match the paired `@McpResource.uri` exactly (including templates like `file://{path}`).
105
+
- `@McpPromptCompletion.name` must match the registered prompt name (`@McpPrompt.name`, or else the `@McpPrompt` method name). Filter with `argument.name()` for multi-parameter prompts.
106
+
98
107
## Server Modes
99
108
100
109
If `mode` is omitted in `mcp-server.yml`, the server defaults to **STREAMABLE**.
@@ -129,7 +138,8 @@ change-notification:
129
138
130
139
## Important Notes
131
140
132
-
- Use `McpApplication.run()` as the server entry point; component registration scope is resolved through `@McpServerApplication`
141
+
- Use `McpApplication.run()` as the server entry point; optional third argument overrides the config file name (default `mcp-server.yml`)
142
+
- Component registration scope: `basePackageClass` → `basePackage` → main class package; one instance per component class (public no-arg constructor)
133
143
- `instructions` must be a non-blank string in `mcp-server.yml` (validated at startup)
134
144
- SSE mode and related APIs (`ServerMode.SSE`, `McpSseServer`, `ServerSse`, `sse.*` config) are deprecated with `forRemoval = true` since 0.16.0; use STREAMABLE for new HTTP deployments
135
145
- Built on MCP Java SDK **2.0.0-M3** (milestone) — pin versions and retest when upgrading
0 commit comments