Skip to content

Commit 954922b

Browse files
committed
first commit
1 parent 6437416 commit 954922b

File tree

43 files changed

+9304
-2
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+9304
-2
lines changed

.gitignore

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,68 @@
2222
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
2323
hs_err_pid*
2424
replay_pid*
25+
26+
### Maven/Gradle Builds ###
27+
target/
28+
!.mvn/wrapper/maven-wrapper.jar
29+
!**/src/main/**/target/
30+
!**/src/test/**/target/
31+
build/
32+
!**/src/main/**/build/
33+
!**/src/test/**/build/
34+
.gradle
35+
out
36+
/.gradletasknamecache
37+
**/*.flattened-pom.xml
38+
39+
### IDE - Eclipse/STS ###
40+
.apt_generated
41+
.classpath
42+
.factorypath
43+
.project
44+
.settings/
45+
.springBeans
46+
.sts4-cache
47+
bin/
48+
com.springsource.sts.config.flow.prefs
49+
50+
### IDE - IntelliJ IDEA ###
51+
.idea/
52+
*.iml
53+
*.ipr
54+
*.iws
55+
56+
### IDE - NetBeans ###
57+
/nbproject/private/
58+
/nbbuild/
59+
/dist/
60+
/nbdist/
61+
/.nb-gradle/
62+
63+
### IDE - VS Code ###
64+
.vscode/
65+
vscode/
66+
settings.json
67+
68+
### Logs and Databases ###
69+
build.log
70+
shell.log
71+
integration-repo
72+
ivy-cache
73+
spring-build
74+
derby-home
75+
derbydb
76+
derby.log
77+
78+
### Node.js ###
79+
node/
80+
node_modules/
81+
package-lock.json
82+
package.json
83+
84+
### Other ###
85+
.antlr/
86+
.profiler/
87+
s3.properties
88+
.*.swp
89+
.DS_Store
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations
16+
# under the License.
17+
wrapperVersion=3.3.2
18+
distributionType=only-script
19+
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip

README.md

Lines changed: 139 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,139 @@
1-
# mcp-annotations
2-
Incubating annotation support for MCP
1+
# MCP Method Module
2+
3+
The MCP Method module is part of the Java MCP SDK, providing annotation-based method handling for Model Context Protocol (MCP) servers. This module enables developers to easily create and register methods for handling MCP operations using simple annotations.
4+
5+
## Overview
6+
7+
The MCP Method module provides a set of annotations and callback implementations for three primary MCP operations:
8+
9+
1. **Complete** - For auto-completion functionality in prompts and URI templates
10+
2. **Prompt** - For generating prompt messages
11+
3. **Resource** - For accessing resources via URI templates
12+
13+
Each operation type has both synchronous and asynchronous implementations, allowing for flexible integration with different application architectures.
14+
15+
## Key Components
16+
17+
### Annotations
18+
19+
- **`@McpComplete`** - Annotates methods that provide completion functionality for prompts or URI templates
20+
- **`@McpPrompt`** - Annotates methods that generate prompt messages
21+
- **`@McpResource`** - Annotates methods that provide access to resources
22+
- **`@McpArg`** - Annotates method parameters as MCP arguments
23+
24+
### Method Callbacks
25+
26+
The module provides callback implementations for each operation type:
27+
28+
#### Complete
29+
- `AbstractMcpCompleteMethodCallback` - Base class for complete method callbacks
30+
- `SyncMcpCompleteMethodCallback` - Synchronous implementation
31+
- `AsyncMcpCompleteMethodCallback` - Asynchronous implementation using Reactor's Mono
32+
33+
#### Prompt
34+
- `AbstractMcpPromptMethodCallback` - Base class for prompt method callbacks
35+
- `SyncMcpPromptMethodCallback` - Synchronous implementation
36+
- `AsyncMcpPromptMethodCallback` - Asynchronous implementation using Reactor's Mono
37+
38+
#### Resource
39+
- `AbstractMcpResourceMethodCallback` - Base class for resource method callbacks
40+
- `SyncMcpResourceMethodCallback` - Synchronous implementation
41+
- `AsyncMcpResourceMethodCallback` - Asynchronous implementation using Reactor's Mono
42+
43+
## Usage Examples
44+
45+
### Complete Example
46+
47+
```java
48+
public class AutocompleteProvider {
49+
private final Map<String, List<String>> cityDatabase = new HashMap<>();
50+
51+
public AutocompleteProvider() {
52+
// Initialize with sample data
53+
cityDatabase.put("l", List.of("Lagos", "Lima", "Lisbon", "London", "Los Angeles"));
54+
// Add more data...
55+
}
56+
57+
@McpComplete(prompt = "travel-planner")
58+
public List<String> completeCityName(CompleteRequest.CompleteArgument argument) {
59+
String prefix = argument.value().toLowerCase();
60+
if (prefix.isEmpty()) {
61+
return List.of("Enter a city name");
62+
}
63+
64+
String firstLetter = prefix.substring(0, 1);
65+
List<String> cities = cityDatabase.getOrDefault(firstLetter, List.of());
66+
67+
return cities.stream()
68+
.filter(city -> city.toLowerCase().startsWith(prefix))
69+
.toList();
70+
}
71+
72+
@McpComplete(uri = "weather-api://{city}")
73+
public List<String> completeCity(CompleteRequest.CompleteArgument argument) {
74+
// Similar implementation for URI template completion
75+
// ...
76+
}
77+
}
78+
```
79+
80+
### Registering Complete Methods
81+
82+
```java
83+
// Create the autocomplete provider
84+
AutocompleteProvider provider = new AutocompleteProvider();
85+
86+
// Register a method with SyncMcpCompleteMethodCallback
87+
Method method = AutocompleteProvider.class.getMethod("completeCityName", CompleteRequest.CompleteArgument.class);
88+
McpComplete annotation = method.getAnnotation(McpComplete.class);
89+
90+
BiFunction<McpSyncServerExchange, CompleteRequest, CompleteResult> callback =
91+
SyncMcpCompleteMethodCallback.builder()
92+
.method(method)
93+
.bean(provider)
94+
.complete(annotation)
95+
.build();
96+
97+
// Use the callback with your MCP server
98+
```
99+
100+
### Async Complete Example
101+
102+
```java
103+
public class AsyncAutocompleteProvider {
104+
// ...
105+
106+
@McpComplete(prompt = "travel-planner")
107+
public Mono<List<String>> completeCityNameAsync(CompleteRequest.CompleteArgument argument) {
108+
return Mono.fromCallable(() -> {
109+
// Implementation similar to sync version
110+
// ...
111+
});
112+
}
113+
}
114+
```
115+
116+
## Installation
117+
118+
To use the MCP Method module in your project, add the following dependency to your Maven POM file:
119+
120+
```xml
121+
<dependency>
122+
<groupId>io.modelcontextprotocol.sdk</groupId>
123+
<artifactId>mcp-method</artifactId>
124+
<version>0.10.0-SNAPSHOT</version>
125+
</dependency>
126+
```
127+
128+
## Features
129+
130+
- **Annotation-based method handling** - Simplifies the creation and registration of MCP methods
131+
- **Support for both synchronous and asynchronous operations** - Flexible integration with different application architectures
132+
- **Builder pattern for callback creation** - Clean and fluent API for creating method callbacks
133+
- **Comprehensive validation** - Ensures method signatures are compatible with MCP operations
134+
- **URI template support** - Powerful URI template handling for resource and completion operations
135+
136+
## Requirements
137+
138+
- Java 17 or higher
139+
- Reactor Core (for async operations)

mcp-annotations-spring/pom.xml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<parent>
8+
<groupId>com.logaritex.mcp</groupId>
9+
<artifactId>mcp-annotations-parent</artifactId>
10+
<version>0.1.0-SNAPSHOT</version>
11+
<relativePath>../pom.xml</relativePath>
12+
</parent>
13+
14+
<artifactId>spring-ai-mcp-annotations</artifactId>
15+
<packaging>jar</packaging>
16+
<name>Spring AI MCP Java SDK - Annotations</name>
17+
<url>https://github.com/spring-ai-community/mcp-annotations</url>
18+
19+
<scm>
20+
<url>https://github.com/spring-ai-community/mcp-annotations</url>
21+
<connection>git://github.com/spring-ai-community/mcp-annotations.git</connection>
22+
<developerConnection>git@github.com/spring-ai-community/mcp-annotations.git</developerConnection>
23+
</scm>
24+
25+
<dependencies>
26+
27+
<dependency>
28+
<groupId>com.logaritex.mcp</groupId>
29+
<artifactId>mcp-annotations</artifactId>
30+
<version>0.1.0-SNAPSHOT</version>
31+
</dependency>
32+
33+
<dependency>
34+
<groupId>org.springframework.ai</groupId>
35+
<artifactId>spring-ai-model</artifactId>
36+
<version>1.0.0-SNAPSHOT</version>
37+
</dependency>
38+
39+
</dependencies>
40+
41+
42+
</project>
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
* Copyright 2025 - 2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.logaritex.mcp.spring;
17+
18+
import java.lang.reflect.Method;
19+
import java.util.List;
20+
21+
import com.logaritex.mcp.provider.SyncMcpCompletionProvider;
22+
import com.logaritex.mcp.provider.SyncMcpPromptProvider;
23+
import com.logaritex.mcp.provider.SyncMcpResourceProvider;
24+
import io.modelcontextprotocol.server.McpServerFeatures.SyncCompletionSpecification;
25+
import io.modelcontextprotocol.server.McpServerFeatures.SyncPromptSpecification;
26+
import io.modelcontextprotocol.server.McpServerFeatures.SyncResourceSpecification;
27+
28+
import org.springframework.aop.support.AopUtils;
29+
import org.springframework.util.ReflectionUtils;
30+
31+
/**
32+
* @author Christian Tzolov
33+
*/
34+
public class SpringAiMcpAnnotationProvider {
35+
36+
private static class SpringAiSyncMcpCompletionProvider extends SyncMcpCompletionProvider {
37+
38+
public SpringAiSyncMcpCompletionProvider(List<Object> completeObjects) {
39+
super(completeObjects);
40+
}
41+
42+
@Override
43+
protected Method[] doGetClassMethods(Object bean) {
44+
return ReflectionUtils
45+
.getDeclaredMethods(AopUtils.isAopProxy(bean) ? AopUtils.getTargetClass(bean) : bean.getClass());
46+
}
47+
48+
};
49+
50+
private static class SpringAiSyncMcpPromptProvider extends SyncMcpPromptProvider {
51+
52+
public SpringAiSyncMcpPromptProvider(List<Object> promptObjects) {
53+
super(promptObjects);
54+
}
55+
56+
@Override
57+
protected Method[] doGetClassMethods(Object bean) {
58+
return ReflectionUtils
59+
.getDeclaredMethods(AopUtils.isAopProxy(bean) ? AopUtils.getTargetClass(bean) : bean.getClass());
60+
}
61+
62+
};
63+
64+
private static class SpringAiSyncMcpResourceProvider extends SyncMcpResourceProvider {
65+
66+
public SpringAiSyncMcpResourceProvider(List<Object> resourceObjects) {
67+
super(resourceObjects);
68+
}
69+
70+
@Override
71+
protected Method[] doGetClassMethods(Object bean) {
72+
return ReflectionUtils
73+
.getDeclaredMethods(AopUtils.isAopProxy(bean) ? AopUtils.getTargetClass(bean) : bean.getClass());
74+
}
75+
76+
}
77+
78+
public static List<SyncCompletionSpecification> createSyncCompleteSpecifications(List<Object> completeObjects) {
79+
return new SpringAiSyncMcpCompletionProvider(completeObjects).getCompleteSpecifications();
80+
}
81+
82+
public static List<SyncPromptSpecification> createSyncPromptSpecifications(List<Object> promptObjects) {
83+
return new SpringAiSyncMcpPromptProvider(promptObjects).getPromptSpecifications();
84+
}
85+
86+
public static List<SyncResourceSpecification> createSyncResourceSpecifications(List<Object> resourceObjects) {
87+
return new SpringAiSyncMcpResourceProvider(resourceObjects).getResourceSpecifications();
88+
}
89+
90+
}

0 commit comments

Comments
 (0)