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: document runtime model, ASYNC semantics, and MCP SDK milestone
Clarify singleton-per-class concurrency, pseudo-async Mono.fromCallable behavior, and 2.0.0-M3 stability expectations in README, site docs, and llms files.
Co-authored-by: Cursor <cursoragent@cursor.com>
| `SYNC` | Handlers invoke your `@McpTool` / `@McpPrompt` / `@McpResource` methods on the request thread. |
278
+
| `ASYNC` | Handlers return Reactor `Mono` values for MCP SDK compatibility. The SDK wraps each call in `Mono.fromCallable(...)` — your method body is still a normal **blocking** Java invocation. |
279
+
280
+
**ASYNC is not a non-blocking or Project Reactor programming model.** You do not implement `Mono`/`Flux` in annotated methods. Long-running or CPU-heavy work still occupies a Reactor worker thread. Use **SYNC** unless your deployment specifically requires the async MCP server API. For high concurrency, keep handlers short and tune `request-timeout`.
281
+
282
+
#### Component instances and concurrency
283
+
284
+
The SDK creates **one instance per component class** (no-arg constructor) and reuses it for every MCP request to methods on that class. Concurrent calls share the same object.
285
+
286
+
- Prefer **stateless** component classes, or **thread-safe** mutable state only.
287
+
- Do not store per-request data in instance fields without proper synchronization.
288
+
- Delegate shared mutable state to thread-safe services when needed.
289
+
290
+
`McpApplicationContext.from(...)`currently uses this default singleton-per-class factory. There is no built-in Spring/CDI wiring in the public API today.
291
+
292
+
#### MCP Java SDK 2.x (milestone)
293
+
294
+
This project builds on the official [MCP Java SDK](https://github.com/modelcontextprotocol/java-sdk) **2.0.0-M3**, a **pre-release milestone**. APIs may change before 2.0 GA — pin dependency versions and re-run tests when upgrading.
295
+
296
+
- **STREAMABLE** is the recommended HTTP transport for new projects.
297
+
- **SSE** is still supported for compatibility but is **deprecated** in MCP SDK 2.x; avoid new SSE deployments.
298
+
269
299
### Multilingual Support (i18n)
270
300
271
301
Enable i18n for your MCP components:
@@ -353,7 +383,15 @@ Run the test suite:
353
383
354
384
### Q: Can I use this in production?
355
385
356
-
**A:** This project is currently in active development. While it's stable for development and testing, we recommend thorough testing before production use.
386
+
**A:** The annotated layer is stable for development and testing, but it depends on the official MCP Java SDK **2.0.0-M3** (a milestone release). Pin versions, run your own integration tests, and expect possible SDK API changes before 2.0 GA before relying on it in production.
387
+
388
+
### Q: What does `type: ASYNC` mean?
389
+
390
+
**A:** It selects the async MCP server API from the underlying SDK. Your `@McpTool` / `@McpPrompt` / `@McpResource` methods remain ordinary blocking Java code; the framework wraps them in `Mono.fromCallable(...)`. Use SYNC unless you specifically need the async server API.
391
+
392
+
### Q: Are component classes singletons?
393
+
394
+
**A:** Yes. The SDK creates one instance per component class and reuses it for all requests. Keep components stateless or thread-safe; do not keep per-request mutable state on the instance without synchronization.
Copy file name to clipboardExpand all lines: docs/components.md
+12Lines changed: 12 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -267,6 +267,18 @@ public int add(
267
267
268
268
After defining MCP components, they will be automatically registered to the server. You just need to ensure that the component classes are in the package scanning path of the server application.
269
269
270
+
### One instance per component class
271
+
272
+
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:
273
+
274
+
- Keep component classes stateless when possible.
275
+
- Any mutable instance fields must be thread-safe, or you must synchronize access.
276
+
- Do not treat instance fields as per-request storage.
277
+
278
+
### SYNC vs ASYNC server type
279
+
280
+
Setting `type: ASYNC` in `mcp-server.yml` uses the async MCP server API from the underlying SDK. Handlers are implemented with `Mono.fromCallable(...)` around your blocking method — **ASYNC mode is not Project Reactor**. Your `@McpTool`, `@McpPrompt`, and `@McpResource` methods remain ordinary synchronous Java code.
281
+
270
282
### Specify Package Path
271
283
272
284
If you need to specify a specific package path, you can use the following methods:
| `streamable.port` | HTTP port for STREAMABLE mode | `8080` |
190
190
191
+
## Runtime model and stability
192
+
193
+
### SYNC vs ASYNC (`type`)
194
+
195
+
The `type` property selects the MCP Java SDK server API (`SYNC` or `ASYNC`). It does **not** make your annotated methods reactive.
196
+
197
+
- **SYNC** — methods run on the request thread.
198
+
- **ASYNC** — the SDK exposes async handlers that wrap your method in `Mono.fromCallable(...)`. Your code is still **blocking** Java; you do not return `Mono` from `@McpTool` / `@McpPrompt` / `@McpResource` methods.
199
+
200
+
Use **SYNC** by default. Choose **ASYNC** only when your deployment requires the async MCP server API. Long work still blocks a Reactor worker thread under ASYNC.
201
+
202
+
### Component instances and concurrency
203
+
204
+
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.
205
+
206
+
### MCP Java SDK 2.x (milestone)
207
+
208
+
This SDK depends on MCP Java SDK **2.0.0-M3** (pre-release). Pin versions and retest when upgrading. Prefer **STREAMABLE** over deprecated **SSE** for new HTTP deployments.
Copy file name to clipboardExpand all lines: docs/index.md
+6Lines changed: 6 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -55,6 +55,12 @@ This SDK is especially suitable for the following scenarios:
55
55
|**SSE**| Server-Sent Events (HTTP-based) | Real-time web applications (deprecated) |
56
56
|**STREAMABLE**| HTTP streaming | Web applications, recommended for production |
57
57
58
+
## Runtime notes
59
+
60
+
-**ASYNC vs SYNC** — `type: ASYNC` selects the async MCP server API; your annotated methods stay blocking Java wrapped in `Mono.fromCallable(...)`. See [Getting Started — Runtime model](./getting-started.md#runtime-model-and-stability).
61
+
-**Singleton components** — one instance per component class, shared across concurrent requests; keep handlers stateless or thread-safe.
62
+
-**MCP SDK 2.0.0-M3** — built on a pre-release milestone; pin versions and prefer **STREAMABLE** over deprecated **SSE**.
63
+
58
64
## 📖 Getting Started
59
65
60
66
Want to get started quickly? Check out the [Getting Started Guide](./getting-started.md) to learn how to build your first MCP server in 5 minutes.
Copy file name to clipboardExpand all lines: llms-full.txt
+5-2Lines changed: 5 additions & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -517,8 +517,11 @@ public String createUser(
517
517
## Important Notes
518
518
519
519
1. **Deprecated API**: The `McpServers` class is deprecated. Use `McpApplication.run()` instead.
520
-
2. **Deprecated Mode**: SSE mode is deprecated. Use STREAMABLE mode for new projects.
521
-
3. **Default Required**: The default `required` value for `@McpToolParam`, `@McpPromptParam`, and `@McpJsonSchemaProperty` is `true`.
520
+
2. **Deprecated Mode**: SSE mode is deprecated in MCP SDK 2.x. Use STREAMABLE mode for new HTTP projects.
521
+
3. **MCP SDK milestone**: This project depends on MCP Java SDK **2.0.0-M3** (pre-release). Pin versions and retest when upgrading.
522
+
4. **ASYNC is not reactive**: `type: ASYNC` selects the async MCP server API; handlers wrap blocking Java methods in `Mono.fromCallable(...)`. Annotated methods do not return `Mono`/`Flux`.
523
+
5. **Singleton components**: One instance per component class is shared across concurrent requests. Keep components stateless or thread-safe.
524
+
6. **Default Required**: The default `required` value for `@McpToolParam`, `@McpPromptParam`, and `@McpJsonSchemaProperty` is `true`.
Copy file name to clipboardExpand all lines: src/main/java/com/github/thought2code/mcp/annotated/server/component/DefaultMcpComponentInstanceFactory.java
+1-2Lines changed: 1 addition & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -9,8 +9,7 @@
9
9
* Default component instance factory used by the SDK.
10
10
*
11
11
* <p>The factory creates component instances lazily through their no-argument constructor and
12
-
* caches one instance per component class. Callers may also register prebuilt instances to preserve
13
-
* application state or bridge into another object lifecycle.
12
+
* caches one instance per component class for the lifetime of the application context.
0 commit comments