MCP Advanced Features
Composio integration, database MCP clients, Goose interoperability, Stripe payments, testing utilities, and OAuth authentication.
Composio Integration
The com.tnsai.mcp.composio package bridges the Composio platform (500+ tool integrations) with the MCP ecosystem.
ComposioClient
REST client for the Composio API. Provides typed access to apps, tools, and execution.
ComposioClient client = new ComposioClient("your-api-key");
// List available apps
List<ComposioClient.ComposioApp> apps = client.listApps();
// ComposioApp(name, description, logoUrl, connected)
// List tools for an app
List<ComposioClient.ComposioTool> tools = client.listTools("github");
// ComposioTool(name, description, appName, inputSchema)
// Execute a tool
JsonNode result = client.executeTool("github_create_issue",
Map.of("title", "Bug report", "body", "Details..."));
// Check connection status
ComposioClient.ConnectionStatus status = client.getConnectionStatus("github");
// ConnectionStatus(appName, connected, authMethod)Key methods:
| Method | Returns | Description |
|---|---|---|
listApps() | List<ComposioApp> | All available Composio apps |
listTools(String appName) | List<ComposioTool> | Tools for a specific app |
executeTool(String toolName, Map params) | JsonNode | Execute a tool with parameters |
getConnectionStatus(String appName) | ConnectionStatus | OAuth connection status |
ComposioAuthBridge
Bridges Composio's API key authentication to MCP-compatible auth headers.
ComposioAuthBridge bridge = new ComposioAuthBridge("your-api-key");
// Verify API key validity (makes a test API call)
if (bridge.verifyApiKey()) {
Map<String, String> headers = bridge.getAuthHeaders();
// {"X-API-Key": "...", "Accept": "application/json"}
}Key methods:
| Method | Returns | Description |
|---|---|---|
getAuthHeaders() | Map<String, String> | Auth headers for API calls |
verifyApiKey() | boolean | Verify key validity via test call |
getApiKey() | String | The configured API key |
ComposioDiscovery
Converts Composio tools to MCP-compatible McpToolDefinition and McpServerEntry objects for registry integration.
ComposioClient client = new ComposioClient("api-key");
ComposioDiscovery discovery = new ComposioDiscovery(client);
// Discover all tools as MCP definitions
List<McpToolDefinition> allTools = discovery.discoverTools();
// Discover tools for a specific app
List<McpToolDefinition> githubTools = discovery.discoverTools("github");
// Convert to MCP registry entries (one per Composio app)
List<McpServerEntry> entries = discovery.toServerEntries();Key methods:
| Method | Returns | Description |
|---|---|---|
discoverTools() | List<McpToolDefinition> | All tools from all connected apps |
discoverTools(String appName) | List<McpToolDefinition> | Tools for a specific app |
toServerEntries() | List<McpServerEntry> | Apps as MCP server entries |
Database MCP Clients
Convenience wrappers around McpClient for specific database MCP servers.
Neo4jMcpClient
Wraps MCP tool calls to a Neo4j graph database server.
McpClient mcpClient = McpClient.create(transport);
mcpClient.connect();
mcpClient.initialize();
Neo4jMcpClient neo4j = new Neo4jMcpClient(mcpClient);
// Execute Cypher queries
JsonNode result = neo4j.executeCypher("MATCH (n:Person) RETURN n LIMIT 10");
// Explore the schema
JsonNode labels = neo4j.listNodeLabels();
JsonNode schema = neo4j.getSchema();
// Check availability
boolean available = neo4j.isAvailable();
// true when mcpClient.isConnected() && mcpClient.isInitialized()Key methods:
| Method | Returns | Description |
|---|---|---|
executeCypher(String query) | JsonNode | Execute a Cypher query |
listNodeLabels() | JsonNode | List all node labels |
getSchema() | JsonNode | Get graph database schema |
isAvailable() | boolean | Check server availability |
getMcpClient() | McpClient | Underlying MCP client |
PostgresMcpClient
Wraps MCP tool calls to a PostgreSQL database server.
McpClient mcpClient = McpClient.create(transport);
mcpClient.connect();
mcpClient.initialize();
PostgresMcpClient postgres = new PostgresMcpClient(mcpClient);
// Execute SQL queries
JsonNode result = postgres.executeQuery("SELECT * FROM users LIMIT 10");
// Explore schema
JsonNode tables = postgres.listTables();
JsonNode description = postgres.describeTable("users");
boolean available = postgres.isAvailable();Key methods:
| Method | Returns | Description |
|---|---|---|
executeQuery(String sql) | JsonNode | Execute a SQL query |
listTables() | JsonNode | List all tables |
describeTable(String table) | JsonNode | Describe table schema |
isAvailable() | boolean | Check server availability |
getMcpClient() | McpClient | Underlying MCP client |
Goose Interoperability
The com.tnsai.mcp.goose package enables TnsAI and Goose (Block's AI agent framework) to share tools.
TnsAIGooseExtension
Generates a Goose-compatible extension manifest from an MCP server's tool definitions.
McpClient client = McpClient.create(transport);
client.connect();
client.initialize();
// Generate manifest
TnsAIGooseExtension.ExtensionManifest manifest =
TnsAIGooseExtension.generateManifest(client);
// ExtensionManifest(name, version, description, tools)
// ExtensionTool(name, description, inputSchema)
// Export as JSON (place in Goose's extension directory)
String json = TnsAIGooseExtension.toJson(manifest);GooseRecipeParser
Parses Goose recipe files (JSON workflow definitions) into structured objects that can be converted to MCP tool calls.
Recipe JSON format:
{
"name": "deploy-app",
"description": "Deploy an application",
"steps": [
{
"tool": "build_project",
"params": { "target": "production" },
"output": "buildResult"
},
{
"tool": "deploy",
"params": { "artifact": "{{buildResult}}" }
}
]
}// Parse a recipe
GooseRecipeParser.Recipe recipe = GooseRecipeParser.parse(jsonContent);
// Recipe(name, description, steps)
// RecipeStep(tool, params, outputVariable)
// Convert to MCP tool call parameter maps
List<Map<String, Object>> mcpCalls = GooseRecipeParser.toMcpCalls(recipe);
// Each map: {"name": "tool_name", "arguments": {...}}Stripe Integration
The com.tnsai.mcp.stripe package provides Stripe payment operations via MCP.
StripeMcpClient
Wraps MCP tool calls to a Stripe MCP server.
McpClient mcpClient = McpClient.create(transport);
mcpClient.connect();
mcpClient.initialize();
StripeMcpClient stripe = new StripeMcpClient(mcpClient);
// Payments
JsonNode payment = stripe.createPaymentIntent(2000, "usd"); // amount in cents
JsonNode payments = stripe.listPayments(10);
// Account
JsonNode balance = stripe.getBalance();
// Customers
JsonNode customers = stripe.listCustomers(10);
JsonNode newCustomer = stripe.createCustomer("Jane Doe", "jane@example.com");StripePaymentTool
Adapter that wraps StripeMcpClient as a tool-like interface, routing named operations.
StripePaymentTool tool = new StripePaymentTool(stripeMcpClient);
// Execute by operation name
JsonNode result = tool.execute("get_balance", Map.of());
JsonNode payment = tool.execute("create_payment_intent",
Map.of("amount", 2000, "currency", "usd"));
// List supported operations
List<String> ops = tool.listOperations();
// ["create_payment_intent", "list_payments", "get_balance",
// "list_customers", "create_customer"]MCP Testing Utilities
The com.tnsai.mcp.testing package provides tools for testing MCP servers and clients without network I/O.
McpServerTestKit
JUnit 5 extension that sets up a MockMcpServer, MockMcpTransport, and McpClient for each test.
@RegisterExtension
McpServerTestKit testKit = new McpServerTestKit();
@Test
void testToolExecution() throws Exception {
// Configure mock tool responses
testKit.getServer().whenToolReturns("echo",
objectMapper.createObjectNode().put("text", "hello"));
// Assert tool exists
testKit.assertToolExists("echo");
// Assert tool returns expected result
testKit.assertToolReturns("echo", Map.of("msg", "hi"),
result -> result.has("text"));
}Key methods:
| Method | Returns | Description |
|---|---|---|
getServer() | MockMcpServer | The mock server instance |
getTransport() | MockMcpTransport | The mock transport |
getClient() | McpClient | Connected MCP client |
assertToolExists(String) | void | Assert a tool is registered |
assertToolReturns(String, Map, Predicate) | void | Assert tool result matches |
MockMcpServer
In-memory MCP server for unit testing. Handles JSON-RPC messages and routes initialize, tools/list, tools/call, resources/list, resources/read, prompts/list, and prompts/get.
MockMcpServer server = new MockMcpServer("test-server", "1.0.0");
// Register tool handlers
server.whenTool("calculate", args -> {
int a = (int) args.get("a");
int b = (int) args.get("b");
return objectMapper.createObjectNode().put("result", a + b);
});
// Static tool response
server.whenToolReturns("echo", resultNode);
// Tool that simulates an error
server.whenToolThrows("fail", -32000, "Something went wrong");
// Register resources
server.whenResource("file://data.txt", "file contents");
// Register prompts
server.whenPrompt("greeting", promptResultNode);
// Process a raw JSON-RPC message
String response = server.processMessage(jsonRpcRequest);OAuth Authentication
The com.tnsai.mcp.auth package provides OAuth 2.0 support for authenticated MCP connections.
OAuthMcpTransport
Transport decorator that adds OAuth Bearer token authentication to any McpTransport. Manages token lifecycle and ensures tokens are valid before each operation.
McpTokenManager tokenManager = new McpTokenManager();
// ... store tokens after OAuth flow ...
OAuthMcpTransport transport = OAuthMcpTransport.builder()
.delegate(new SSETransport.Builder().sseEndpoint("...").build())
.tokenManager(tokenManager)
.serverUrl("https://mcp.example.com")
.tokenEndpoint("https://auth.example.com/token")
.clientId("my-client")
.build();
McpClient client = new McpClient(transport);
client.connect();
// Query token state
Optional<String> bearerToken = transport.getBearerToken(); // "Bearer eyJ..."
boolean authenticated = transport.isAuthenticated();Builder parameters:
| Parameter | Required | Description |
|---|---|---|
delegate | Yes | Underlying transport to wrap |
tokenManager | Yes | Token storage and refresh manager |
serverUrl | Yes | MCP server URL (token lookup key) |
tokenEndpoint | No | OAuth token endpoint for refresh |
clientId | No | OAuth client ID for refresh |
PkceFlow
PKCE (Proof Key for Code Exchange) flow implementation with S256 challenge method, per RFC 7636.
Step 1: Generate challenge
PkceFlow.PkceChallenge challenge = PkceFlow.generateChallenge();
// PkceChallenge(codeVerifier, codeChallenge, codeChallengeMethod="S256")Step 2: Build authorization URL
String authUrl = PkceFlow.buildAuthorizationUrl(
"https://auth.example.com/authorize",
"my-client-id",
"http://localhost:8080/callback",
"openid profile", // scope
"random-state-for-csrf", // state
challenge
);
// User visits authUrl, authorizes, callback receives codeStep 3: Exchange code for tokens
PkceFlow.TokenResponse token = PkceFlow.exchangeCode(
"https://auth.example.com/token",
"my-client-id",
authCode,
"http://localhost:8080/callback",
challenge.codeVerifier()
);
// TokenResponse(accessToken, refreshToken, tokenType, expiresIn, scope, obtainedAt)Step 4: Refresh tokens
PkceFlow.TokenResponse refreshed = PkceFlow.refreshToken(
"https://auth.example.com/token",
"my-client-id",
token.refreshToken()
);
// Check token state
boolean expired = token.isExpired();
boolean expiringSoon = token.isExpiringSoon(Duration.ofMinutes(5));Cross-References
- MCP Client -- core MCP client and transport
- MCP Server -- building MCP servers
- MCP Registry -- unified registry for MCP servers
- MCP Transports -- stdio, SSE, HTTP, and streamable HTTP
- Tools Advanced -- Composio tool integration in TnsAI.Tools
MCP Registry
The MCP module provides a unified registry that aggregates MCP server entries from 4 public sources, with deduplication, caching, and protocol version filtering. It also includes a testing toolkit for MCP server development.
Channels
The Channels module (TnsAI.Channels) is a multi-channel messaging gateway that connects TnsAI agents to external messaging platforms. It uses an adapter pattern with SPI discovery so new platforms can be added without modifying the core routing logic.