Skip to content

Commit d3f48a8

Browse files
docs: align README and docs with implementation
Sync YAML keys and defaults, dependency coordinates, completions handlers, structured content, and error-handling guidance with the code. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 40ccf1b commit d3f48a8

3 files changed

Lines changed: 174 additions & 103 deletions

File tree

README.md

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,13 @@ This SDK is a lightweight, annotation-based framework that simplifies MCP server
5050
<dependency>
5151
<groupId>io.github.thought2code</groupId>
5252
<artifactId>mcp-annotated-java-sdk</artifactId>
53-
<version>0.13.0</version>
53+
<version>0.14.0</version>
5454
</dependency>
5555
```
5656

5757
**Gradle:**
5858
```gradle
59-
implementation 'io.github.thought2code:mcp-annotated-java-sdk:0.13.0'
59+
implementation 'io.github.thought2code:mcp-annotated-java-sdk:0.14.0'
6060
```
6161

6262
#### Step 2: Create Configuration File
@@ -138,11 +138,12 @@ public class MyPrompts {
138138
#### Step 7: Run Your Server
139139

140140
```bash
141-
# Compile and run
141+
# Compile your project
142142
./mvnw clean package
143-
java -jar target/your-app.jar
144143
```
145144

145+
Run `MyFirstMcpServer` from your IDE, or use `java -cp ...` with your compiled classes and dependencies on the classpath. Your own project needs an executable JAR setup (for example Spring Boot or the Maven Shade plugin) if you want `java -jar` with a single file.
146+
146147
That's it! Your MCP server is now ready to serve resources, tools, and prompts!
147148

148149
## 📚 Core Concepts
@@ -195,30 +196,38 @@ change-notification:
195196
tool: true
196197
streamable:
197198
mcp-endpoint: /mcp/message
198-
disallow-delete: true
199-
keep-alive-interval: 30000
199+
disallow-delete: false
200+
keep-alive-interval: 20000
200201
port: 8080
201202
```
202203
203204
### Configuration Properties
204205
205-
| Property | Description | Default |
206-
|-----------------------------------|-------------------------------------------|--------------|
207-
| `enabled` | Enable/disable MCP server | `true` |
208-
| `mode` | Server mode: `STDIO`, `SSE`, `STREAMABLE` | `STREAMABLE` |
209-
| `name` | Server name | `mcp-server` |
210-
| `version` | Server version | `1.0.0` |
211-
| `type` | Server type: `SYNC`, `ASYNC` | `SYNC` |
212-
| `instructions` | Instructions for the LLM client | (empty) |
213-
| `request-timeout` | Request timeout in milliseconds | `20000` |
214-
| `capabilities.resource` | Enable resource support | `true` |
215-
| `capabilities.subscribe-resource` | Enable resource subscription | `true` |
216-
| `capabilities.prompt` | Enable prompt support | `true` |
217-
| `capabilities.tool` | Enable tool support | `true` |
218-
| `capabilities.completion` | Enable completion support | `true` |
219-
| `change-notification.resource` | Notify clients on resource change | `true` |
220-
| `change-notification.prompt` | Notify clients on prompt change | `true` |
221-
| `change-notification.tool` | Notify clients on tool change | `true` |
206+
| Property | Description | Default |
207+
|-----------------------------------|-------------------------------------------|----------------|
208+
| `enabled` | Enable/disable MCP server | `true` |
209+
| `mode` | Server mode: `STDIO`, `SSE`, `STREAMABLE` | `STREAMABLE` |
210+
| `name` | Server name | `mcp-server` |
211+
| `version` | Server version | `1.0.0` |
212+
| `type` | Server type: `SYNC`, `ASYNC` | `SYNC` |
213+
| `instructions` | Instructions for the LLM client | (empty) |
214+
| `request-timeout` | Request timeout in milliseconds | `20000` |
215+
| `capabilities.resource` | Enable resource support | `true` |
216+
| `capabilities.subscribe-resource` | Enable resource subscription | `true` |
217+
| `capabilities.prompt` | Enable prompt support | `true` |
218+
| `capabilities.tool` | Enable tool support | `true` |
219+
| `capabilities.completion` | Enable completion support | `true` |
220+
| `change-notification.resource` | Notify clients on resource change | `true` |
221+
| `change-notification.prompt` | Notify clients on prompt change | `true` |
222+
| `change-notification.tool` | Notify clients on tool change | `true` |
223+
| `sse.message-endpoint` | SSE POST message path | `/mcp/message` |
224+
| `sse.endpoint` | SSE stream path | `/sse` |
225+
| `sse.base-url` | Public base URL for the SSE server | *(empty)* |
226+
| `sse.port` | HTTP port for SSE mode | `8080` |
227+
| `streamable.mcp-endpoint` | Streamable HTTP MCP path | `/mcp/message` |
228+
| `streamable.disallow-delete` | Reject HTTP DELETE on session | `false` |
229+
| `streamable.keep-alive-interval` | Keep-alive interval (ms) | `20000` |
230+
| `streamable.port` | HTTP port for STREAMABLE mode | `8080` |
222231

223232
### Profile-based Configuration
224233

docs/components.md

Lines changed: 105 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,13 @@ public class MyResources {
3131

3232
### Annotation Parameters
3333

34-
| Parameter | Description | Required |
35-
|----------------|------------------------------------------------|----------|
36-
| `uri` | Unique identifier of the resource (URI format) | Yes |
37-
| `description` | Resource description for LLM understanding | Yes |
38-
| `name` | Resource name (defaults to method name) | No |
39-
| `mimeType` | MIME type of the resource content | No |
34+
| Parameter | Description | Required |
35+
|---------------|------------------------------------------------|-------------------------------------------|
36+
| `uri` | Unique identifier of the resource (URI format) | Yes |
37+
| `description` | Resource description for LLM understanding | No (defaults to `name`, then method name) |
38+
| `name` | Resource name (defaults to method name) | No |
39+
| `title` | Resource title (defaults to `name`) | No |
40+
| `mimeType` | MIME type of the resource content | No (default `text/plain`) |
4041

4142
## Tools
4243

@@ -74,25 +75,25 @@ public class MyTools {
7475

7576
#### @McpTool
7677

77-
| Parameter | Description | Required |
78-
|---------------|------------------------------------------|----------|
79-
| `description` | Tool description for LLM understanding | Yes |
80-
| `name` | Tool name (defaults to method name) | No |
81-
| `title` | Tool title for display purposes | No |
78+
| Parameter | Description | Required |
79+
|---------------|----------------------------------------|------------------------------------------------|
80+
| `description` | Tool description for LLM understanding | No (defaults to tool `name`, then method name) |
81+
| `name` | Tool name (defaults to method name) | No |
82+
| `title` | Tool title for display purposes | No |
8283

8384
#### @McpToolParam
8485

85-
| Parameter | Description | Required |
86-
|---------------|------------------------------------------|----------|
87-
| `name` | Parameter name | Yes |
88-
| `description` | Parameter description | Yes |
89-
| `required` | Whether the parameter is required | No |
86+
| Parameter | Description | Required |
87+
|---------------|-----------------------------------|-------------------------|
88+
| `name` | Parameter name | Yes |
89+
| `description` | Parameter description | No (defaults to `name`) |
90+
| `required` | Whether the parameter is required | No (default `true`) |
9091

9192
- `@McpTool`: Marks a method as an MCP tool
9293
- `@McpToolParam`: Marks method parameters as tool parameters
9394
- `name`: Parameter name
9495
- `description`: Parameter description
95-
- `required`: Whether the parameter is required
96+
- `required`: Whether the parameter is required (default `true`)
9697

9798
## Prompts
9899

@@ -127,50 +128,82 @@ public class MyPrompts {
127128

128129
#### @McpPrompt
129130

130-
| Parameter | Description | Required |
131-
|---------------|------------------------------------------|----------|
132-
| `description` | Prompt description for LLM understanding | Yes |
133-
| `name` | Prompt name (defaults to method name) | No |
134-
| `title` | Prompt title for display purposes | No |
131+
| Parameter | Description | Required |
132+
|---------------|------------------------------------------|--------------------------------------------------|
133+
| `description` | Prompt description for LLM understanding | No (defaults to prompt `name`, then method name) |
134+
| `name` | Prompt name (defaults to method name) | No |
135+
| `title` | Prompt title for display purposes | No |
135136

136137
#### @McpPromptParam
137138

138-
| Parameter | Description | Required |
139-
|---------------|------------------------------------------|----------|
140-
| `name` | Parameter name | Yes |
141-
| `description` | Parameter description | Yes |
142-
| `required` | Whether the parameter is required | No |
139+
| Parameter | Description | Required |
140+
|---------------|-----------------------------------|-------------------------|
141+
| `name` | Parameter name | Yes |
142+
| `description` | Parameter description | No (defaults to `name`) |
143+
| `required` | Whether the parameter is required | No (default `true`) |
143144

144145
## Completions
145146

146147
Completions provide auto-complete suggestions for resource URIs and prompt arguments.
147148

149+
Handlers must **return** `McpCompleteCompletion` and take **exactly one** parameter of type `McpSchema.CompleteRequest.CompleteArgument` (the argument being completed has `name()` and `value()` from the MCP request).
150+
148151
### Resource Completions
149152

150153
```java
151154
import com.github.thought2code.mcp.annotated.annotation.McpResourceCompletion;
155+
import com.github.thought2code.mcp.annotated.server.component.McpCompleteCompletion;
156+
import io.modelcontextprotocol.spec.McpSchema;
157+
import java.nio.file.Files;
158+
import java.nio.file.Path;
159+
import java.nio.file.Paths;
160+
import java.util.List;
161+
import java.util.stream.Collectors;
152162

153163
public class MyCompletions {
154-
@McpResourceCompletion(uri = "file://")
155-
public List<String> completeFilePath(String uri, String cursorValue) {
156-
// Return matching file paths
157-
return Files.list(Paths.get(cursorValue))
158-
.map(Path::toString)
159-
.collect(Collectors.toList());
164+
@McpResourceCompletion(uri = "file://")
165+
public McpCompleteCompletion completeFileUri(McpSchema.CompleteRequest.CompleteArgument argument) {
166+
String prefix = argument.value() != null ? argument.value() : "";
167+
try {
168+
List<String> paths =
169+
Files.list(Paths.get(prefix.isEmpty() ? "." : prefix))
170+
.map(Path::toString)
171+
.limit(50)
172+
.collect(Collectors.toList());
173+
return McpCompleteCompletion.builder()
174+
.values(paths)
175+
.total(paths.size())
176+
.hasMore(false)
177+
.build();
178+
} catch (Exception e) {
179+
return McpCompleteCompletion.empty();
160180
}
181+
}
161182
}
162183
```
163184

164185
### Prompt Completions
165186

187+
`@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.
188+
166189
```java
167190
import com.github.thought2code.mcp.annotated.annotation.McpPromptCompletion;
168-
169-
public class MyCompletions {
170-
@McpPromptCompletion(promptName = "generateCode", argumentName = "language")
171-
public List<String> completeLanguage(String value) {
172-
return Arrays.asList("Java", "Python", "JavaScript", "Go", "Rust");
191+
import com.github.thought2code.mcp.annotated.server.component.McpCompleteCompletion;
192+
import io.modelcontextprotocol.spec.McpSchema;
193+
import java.util.List;
194+
195+
public class MyPromptCompletions {
196+
@McpPromptCompletion(name = "generateCode")
197+
public McpCompleteCompletion completeGenerateCode(McpSchema.CompleteRequest.CompleteArgument argument) {
198+
if (!"language".equals(argument.name())) {
199+
return McpCompleteCompletion.empty();
173200
}
201+
return McpCompleteCompletion.builder()
202+
.values(List.of("Java", "Python", "JavaScript", "Go", "Rust"))
203+
.total(5)
204+
.hasMore(false)
205+
.build();
206+
}
174207
}
175208
```
176209

@@ -248,31 +281,50 @@ If no package path is specified, the package containing the main method will be
248281

249282
## Structured Content
250283

251-
Tools can return structured content for rich responses:
284+
Tools can return structured content for rich responses by returning a type that **implements** `McpStructuredContent` (often a `record` with `@McpJsonSchemaProperty` on fields). There is no `McpStructuredContent.of(...)` helper in the API.
252285

253286
```java
254-
@McpTool(description = "Get user details")
255-
public McpStructuredContent<User> getUser(
256-
@McpToolParam(name = "id", description = "User ID") String id
257-
) {
258-
User user = userService.findById(id);
259-
return McpStructuredContent.of(user);
287+
import com.github.thought2code.mcp.annotated.annotation.McpJsonSchemaDefinition;
288+
import com.github.thought2code.mcp.annotated.annotation.McpJsonSchemaProperty;
289+
import com.github.thought2code.mcp.annotated.annotation.McpTool;
290+
import com.github.thought2code.mcp.annotated.annotation.McpToolParam;
291+
import com.github.thought2code.mcp.annotated.server.McpStructuredContent;
292+
293+
public class UserTools {
294+
295+
@McpJsonSchemaDefinition
296+
public record User(
297+
@McpJsonSchemaProperty(description = "User id") String id,
298+
@McpJsonSchemaProperty(description = "Display name") String name)
299+
implements McpStructuredContent {
300+
301+
@Override
302+
public String asTextContent() {
303+
return "User " + id + ": " + name;
304+
}
305+
}
306+
307+
@McpTool(description = "Get user details")
308+
public User getUser(@McpToolParam(name = "id", description = "User ID") String id) {
309+
return new User(id, "Ada");
310+
}
260311
}
261312
```
262313

263314
## Error Handling
264315

265-
When a tool encounters an error, you can return an error result:
316+
If a tool method **throws any exception**, the server returns a `CallToolResult` with `isError` set to `true` and a generic method-invocation error message (the exception message is not forwarded to the client today).
317+
318+
For expected failures such as validation, return a normal value (for example a `String`) so the tool call remains a successful result with `isError` false:
266319

267320
```java
268321
@McpTool(description = "Divide two numbers")
269-
public Number divide(
322+
public String divide(
270323
@McpToolParam(name = "a", description = "Dividend") double a,
271-
@McpToolParam(name = "b", description = "Divisor") double b
272-
) {
273-
if (b == 0) {
274-
return McpStructuredContent.error("Division by zero is not allowed");
275-
}
276-
return a / b;
324+
@McpToolParam(name = "b", description = "Divisor") double b) {
325+
if (b == 0) {
326+
return "Cannot divide by zero.";
327+
}
328+
return Double.toString(a / b);
277329
}
278330
```

0 commit comments

Comments
 (0)