Skip to main content

Integrating Third-Party MCP (All Approaches)

This page does more than list "a few ways to connect" — it unpacks the integration tiers for third-party MCP in AI4J.

What you are really choosing is not a single API but one of 5 integration depths:

  1. Single-client direct connection
  2. Config-driven multi-service gateway
  3. Runtime dynamic add/remove
  4. User-level isolation
  5. Wiring onto the Agent request chain

Different depths solve different problems. Don't conflate them as "just plugging in an MCP."

Streamable HTTP peer profile

streamable_http defaults to AUTO, and the Gateway JSON supports protocolProfile. AUTO uses only the modern server/discover probe for Streamable HTTP: a successful discovery result takes the stateless 2026-07-28 profile, and only an unrecognized 400, 404, or 405 falls back to the initialization-era profile. It is not omniscient detection, and it will not automatically select the deprecated HTTP+SSE; the latter must be configured explicitly with type: "sse". The STDIO examples on this page still follow the session-era flow, so they use initialize. See Streamable HTTP.

1. Pick the Integration Tier First, Don't Write Code First​

Integration approachProblem it solvesSuitable scenarios
McpClient direct connectionGet one service workingValidation, prototyping, small tools
McpGateway.initialize(...)Unified onboarding of multiple servicesService count starts growing
addMcpClient/removeMcpClientRuntime hot-plugPlatform-style governance
addUserMcpClient(...)Per-user or per-tenant isolationSaaS, multi-account
toolRegistry(..., mcpServices)Let an Agent consume specific servicesWiring into the reasoning path

The recommended order is always:

  1. Validate connectivity with a single client first
  2. Then decide whether to introduce a gateway
  3. Only then wire it into the Agent

2. Approach 1: Single McpClient Direct Connection​

This is the minimal closed loop and the starting point for all troubleshooting.

McpTransport transport = McpTransportFactory.createTransport(
"stdio",
TransportConfig.stdio("npx", Arrays.asList("-y", "@modelcontextprotocol/server-github"))
);

McpClient client = new McpClient("github-client", "1.0.0", transport);
client.connect().join();

List<McpToolDefinition> tools = client.getAvailableTools().join();
String result = client.callTool("search_repositories", Collections.singletonMap("q", "ai4j")).join();

client.disconnect().join();

What this STDIO example actually runs:

  1. transport starts
  2. initialize
  3. notifications/initialized
  4. tools/list
  5. tools/call

As long as this chain isn't stable yet, don't rush to McpGateway.

3. Approach 2: Config-Driven Integration of Multiple Third-Party Services​

Once the service count exceeds one, you shouldn't hand-write multiple McpClient instances in business code.

Config example:

{
"mcpServers": {
"github": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"enabled": true
},
"weather-http": {
"type": "streamable_http",
"url": "http://127.0.0.1:8000/mcp",
"protocolProfile": "AUTO",
"enabled": true
}
}
}

Initialization:

McpGateway gateway = new McpGateway();
gateway.initialize("mcp-servers-config.json").join();

List<Tool.Function> tools = gateway.getAvailableTools().join();

Two real boundaries to understand here:

  • The gateway aggregates multiple third-party services into a single catalog
  • It does not automatically resolve same-name tool conflicts for you

If two third-party servers both export names like search, the current mapping overwrites.

4. Approach 3: Runtime Dynamic Add/Remove​

This is the integration depth only "platform mode" needs.

McpClient githubClient = new McpClient("github", "1.0.0", githubTransport);
gateway.addMcpClient("github", githubClient).join();

gateway.removeMcpClient("github").join();

Suitable for:

  • Console-driven service toggles
  • Dynamically trying out a new MCP
  • Fault isolation / traffic draining

The real semantics are not "a put into a map":

  • add connects the client first, then refreshes the entire tool catalog
  • remove disconnects first, then refreshes the entire catalog

So this kind of integration requires you to plan ahead for catalog-refresh cost and conflict governance.

5. Approach 4: User-Level Isolation Integration​

If the third-party MCP isn't globally shared but rather "each user has their own set of credentials or services," you need user-level integration.

McpClient userClient = new McpClient("user-github", "1.0.0", transport);
gateway.addUserMcpClient("u123", "github", userClient).join();

String result = gateway.callUserTool(
"u123",
"search_repositories",
Collections.singletonMap("q", "ai4j")
).join();

The internal key rules are:

  • User client: user_{userId}_service_{serviceId}
  • User tool: user_{userId}_tool_{toolName}

The current default behavior is:

  • Look up user-level tools first
  • Fall back to global tools if not found
User-level falls back to global tools by default

If your permission model requires "a user with no configuration must never invoke a globally shared service," you must disable the fallback yourself at the business layer.

6. Approach 5: Exposing Third-Party MCP to an Agent​

The key here is not "being able to reach the gateway" but "exposing only the services the current task actually needs to the model."

McpGateway gateway = McpGateway.getInstance();
gateway.initialize("mcp-servers-config.json").join();

Agent agent = Agents.react()
.modelClient(modelClient)
.model("doubao-seed-1-8-251228")
.toolRegistry(Collections.<String>emptyList(), Arrays.asList("github"))
.build();

The core semantics of this chain are:

  • McpGateway is only the service catalog
  • toolRegistry(..., mcpServices) is what decides the services visible to the current request

Currently ToolUtil.getAllTools(functionList, mcpServerIds) merges only:

  • The explicitly passed local function list
  • The explicitly passed MCP service list

It does not automatically expose all remote MCPs to the model.

7. The Complete Runtime Chain of Third-Party MCP in AI4J​

If you draw the whole chain as a single line, it is:

  1. McpServerConfig or a custom config source defines services
  2. McpGatewayClientFactory creates the transport + client based on type
  3. McpClient.connect() completes the lifecycle matching the profile: AUTO discovers a modern peer or enters the legacy initialization handshake
  4. McpGatewayToolRegistry collects the tool inventory
  5. The Agent selects the exposure surface for this call via mcpServices
  6. The model triggers a tool call
  7. ToolUtil.invoke(...) routes the call to the gateway
  8. The gateway locates the corresponding client
  9. The client issues tools/call
  10. The result returns to the model

As long as you know which step the problem is stuck on, troubleshooting won't get tangled.

8. The 4 Most Common Pitfalls When Onboarding Third-Party Services​

8.1 Same-Name Tool Conflicts Across Services​

The current gateway mapping is:

  • Global tool: toolName -> clientKey

Not:

  • serviceId + toolName -> clientKey

So when different services export tools with the same name, the conflict surfaces directly at runtime.

8.2 Treating the Gateway as a Permission System​

The gateway handles connection and routing. It does not handle:

  • Whether a given session is allowed to use a given service
  • Who may connect to a given tenant's third-party credentials

Permission control should still be done at the business layer or session layer.

8.3 Assuming Every Config Field Takes Effect​

The core fields that actually reach the transport/client today are mainly:

  • type
  • command
  • args
  • env
  • url
  • headers
  • protocolProfile (Streamable HTTP only)

Fields like priority, tags, and requiresAuth are closer to governance metadata and do not automatically change invocation behavior.

8.4 Wiring Into the Agent Before Validating Connectivity​

The correct order is:

  1. Get McpClient working standalone
  2. Then enter the gateway
  3. Only then enter the Agent

Small projects​

  • Start with direct McpClient
  • Don't introduce heavy governance too early when services are few

Medium projects​

  • Route everything through McpGateway
  • Lock down serviceId and toolName conventions

Platform projects​

  • McpGateway + McpConfigSource
  • Dynamic add/remove
  • Audit logs
  • User-level isolation
  • Explicit exposure allowlist

10. The Conclusion Most Worth Remembering From This Page​

Third-party MCP integration in AI4J is not a single API — it is a layered chain running from connection, to governance, to isolation, to Agent exposure.

First separate "connectivity problems" from "governance problems," then separate "governance problems" from "model-visibility problems," and your integration plan will become much clearer.