Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 50 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,17 @@ The MCP (Model Context Protocol) Server Plugin for Jenkins implements the server

- **MCP Server Implementation**: Implements the server-side of the Model Context Protocol.
- **Jenkins Integration**: Exposes Jenkins functionalities as MCP tools and resources.
- **Real-time Communication**: Uses Server-Sent Events (SSE) for efficient, real-time communication with clients.
- **Multiple Transport Options**: Supports both Server-Sent Events (SSE) and Streamable transport for efficient, real-time communication with clients.
- **Backward Compatibility**: Maintains support for legacy SSE transport while providing modern streamable transport.
- **Extensible Architecture**: Allows easy extension of MCP capabilities through the `McpServerExtension` interface.

## Key Components

1. **Endpoint**: The main entry point for MCP communication, handling SSE connections and message routing.
2. **DefaultMcpServer**: Implements `McpServerExtension`, providing default tools for interacting with Jenkins jobs and builds.
3. **McpToolWrapper**: Wraps Java methods as MCP tools, handling parameter parsing and result formatting.
4. **McpServerExtension**: Interface for extending MCP server capabilities.
1. **Endpoint**: The main entry point for legacy SSE-based MCP communication, handling SSE connections and message routing.
2. **StreamableEndpoint**: The modern entry point for streamable MCP communication, providing enhanced transport capabilities with message replay and improved session management.
3. **DefaultMcpServer**: Implements `McpServerExtension`, providing default tools for interacting with Jenkins jobs and builds.
4. **McpToolWrapper**: Wraps Java methods as MCP tools, handling parameter parsing and result formatting.
5. **McpServerExtension**: Interface for extending MCP server capabilities.

## MCP SDK Version

Expand All @@ -34,17 +36,43 @@ The MCP Server plugin automatically sets up necessary endpoints and tools upon i

### Connecting to the MCP Server

MCP clients can connect to the server using:
MCP clients can connect to the server using either transport option:

#### Streamable Transport (Recommended)
- Streamable Endpoint: `<jenkins-url>/mcp-server/streamable`
- Supports message replay and enhanced session management
- Better error handling and connection recovery

#### Legacy SSE Transport
- SSE Endpoint: `<jenkins-url>/mcp-server/sse`
- Message Endpoint: `<jenkins-url>/mcp-server/message`
- Maintained for backward compatibility

### Authentication and Credentials

The MCP Server Plugin requires the same credentials as the Jenkins instance it's running on. To authenticate your MCP queries:

1. **Jenkins API Token**: Generate an API token from your Jenkins user account.
2. **Basic Authentication**: Use the API token in the HTTP Basic Authentication header. Below is an example of VS code settings.xml
2. **Basic Authentication**: Use the API token in the HTTP Basic Authentication header. Below are examples for both transport types:

#### Streamable Transport Configuration (Recommended)
```json
{
"mcp": {
"servers": {
"jenkins": {
"type": "http",
"url": "https://jenkins-host/mcp-server/streamable",

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should be using /mcp url since that's the standard url followed by other MCP servers at large, too. Thanks!

"headers": {
"Authorization": "Basic <user:token base64>"
}
}
}
}
}
```

#### Legacy SSE Transport Configuration
```json
{
"mcp": {
Expand All @@ -60,6 +88,20 @@ The MCP Server Plugin requires the same credentials as the Jenkins instance it's
}
}
```

### Transport Comparison

| Feature | Streamable Transport | Legacy SSE Transport |
|---------|---------------------|---------------------|
| **Message Replay** | ✅ Supports replay from Last-Event-ID | ❌ No replay support |
| **Session Management** | ✅ Enhanced with proper lifecycle handling | ⚠️ Basic session handling |
| **Error Recovery** | ✅ Robust error handling and recovery | ⚠️ Limited error recovery |
| **Connection Stability** | ✅ Better connection management | ⚠️ Basic connection handling |
| **Performance** | ✅ Optimized for modern clients | ⚠️ Legacy performance |
| **Backward Compatibility** | ❌ Requires modern MCP clients | ✅ Works with older clients |

**Recommendation**: Use Streamable Transport for new integrations and modern MCP clients. Legacy SSE Transport is maintained for backward compatibility.

Example of using the token:

### Available Tools
Expand Down Expand Up @@ -98,7 +140,7 @@ The plugin provides the following built-in tools for interacting with Jenkins:

Each tool accepts specific parameters to customize its behavior. For detailed usage instructions and parameter descriptions, refer to the API documentation or use the MCP introspection capabilities.

To use these tools, connect to the MCP server endpoint and make tool calls using your MCP client implementation.
To use these tools, connect to either the streamable endpoint (`/mcp-server/mcp`) or the legacy SSE endpoint (`/mcp-server/sse`) and make tool calls using your MCP client implementation.
### Extending MCP Capabilities

To add new MCP tools or functionalities:
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
<dependency>
<groupId>io.modelcontextprotocol.sdk</groupId>
<artifactId>mcp-bom</artifactId>
<version>0.10.0</version>
<version>0.11.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
Expand Down
16 changes: 14 additions & 2 deletions src/main/java/io/jenkins/plugins/mcp/server/Endpoint.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import hudson.Extension;
import hudson.ExtensionList;
import hudson.model.RootAction;
import hudson.model.User;
import hudson.security.csrf.CrumbExclusion;
Expand Down Expand Up @@ -107,9 +108,11 @@
*/
private McpServerSession.Factory sessionFactory;

public Endpoint() throws ServletException {
private StreamableEndpoint streamableEndpoint;

public Endpoint() throws ServletException {
init();
streamableEndpoint = ExtensionList.lookupSingleton(StreamableEndpoint.class);
}

public static String getRequestedResourcePath(HttpServletRequest httpServletRequest) {
Expand All @@ -132,6 +135,10 @@
response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
return true;
}
if (requestedResource.startsWith("/" + StreamableEndpoint.MCP_SERVER_STREAMABLE)) {

Check warning on line 138 in src/main/java/io/jenkins/plugins/mcp/server/Endpoint.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 138 is only partially covered, one branch is missing
streamableEndpoint.process(request, response, chain);
return true;
}
return false;
}

Expand Down Expand Up @@ -177,6 +184,11 @@
public void doFilter(
ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
if (streamableEndpoint.isStreamableRequest(servletRequest, servletResponse)) {
streamableEndpoint.process(
(HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse, filterChain);
return;
}
if (isSSERequest(servletRequest, servletResponse)) {
handleSSE((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse);
} else {
Expand Down Expand Up @@ -357,7 +369,7 @@
&& jsonrpcRequest.params() instanceof Map params) {
Map arguments = (Map) params.get("arguments");
if (arguments != null) {
arguments.put("userId", sessionObject.userId);
arguments.put(McpToolWrapper.USER_ID_KEY, sessionObject.userId);
}
}
}
Expand Down
Loading
Loading