Skip to main content

Exposing a Service as MCP

An MCP service is a WSO2 Integrator artifact that publishes a set of tools over the Model Context Protocol. Any MCP-compatible client (Claude Desktop, GitHub Copilot, or another AI agent) can connect, discover the tools, and call them. This page covers the configuration options for the listener, service, and tools, including how to handle sessions and dynamic tool definitions.

Creating an MCP service

  1. In the design view, select Add Artifact.

  2. Under the AI Integration category, select MCP Service.

    Artifacts page showing the AI Integration category with two artifacts: AI Chat Agent and MCP Service. Above is Automation; below is Integration as API.

  3. Fill in the creation form fields and click Create.

    Create MCP Service form showing Service Name, Version, Port (default 8080), Base Path (/mcp), and an expandable Advanced Configurations section.

FieldDescription
Service NameDisplay name advertised to MCP clients (for example, MCP Service).
VersionService version string (for example, 1.0.0). Sent to clients during initialization.
PortListening port for the MCP listener. Defaults to 8080.
Base PathURL prefix for the MCP service (for example, /mcp).
Advanced ConfigurationsExpand to attach the service to an existing listener instead of creating a new one.

After clicking Create, WSO2 Integrator opens the service in the MCP Service Editor. The header shows the attached listener pill, a Tools section, and Configure / Try It buttons in the top-right.

The MCP Service editor showing the listener chip, the Tools section with 'No tools found. Add a new tool.' and a + Add Tool button.

ElementWhat it does
ListenerThe mcp:Listener the service runs on. Click the chip to swap it or edit its settings.
ToolsThe tools the service exposes. Empty by default; click + Add Tool to add one.
ConfigureService-level settings: base path, server info, session mode, HTTP options.
Try ItSend sample MCP requests to the service from inside the editor.

Service configuration

Service configuration controls the base path, the server identity advertised to clients, the session management mode, and HTTP-level options such as CORS and authentication.

In the MCP Service Editor, click Configure in the header to open the MCP Service Configuration form. The form has two parts: the Base Path field at the top, and a Service Configuration record editor for advanced settings.

FieldDescription
Base PathURL prefix for the MCP endpoint (for example, /mcp). Required.

Click the edit icon on the Service Configuration record to open the record editor.

Service Configuration record editor showing fields: info (with name and version), httpConfig (optional), options (optional), sessionMode (optional, default auto).

FieldDescription
info.nameName of your server implementation (for example, MCP Weather Server). Sent to clients as serverInfo.name during initialization. Required.
info.versionVersion of your server implementation (for example, 1.0.0). Sent as serverInfo.version. This is the version of your service, not the MCP protocol version; the protocol version is negotiated by the runtime. Required.
sessionModeSession management mode. Options: AUTO (default), STATEFUL, STATELESS. See Session modes.
httpConfigHTTP service configuration (CORS, auth, compression, validation, and so on). Same fields as the HTTP service @http:ServiceConfig.
options.capabilitiesCapabilities the server advertises during initialization. Defaults to {tools: {}}.

Listener configuration

The listener binds to a port and handles incoming MCP connections over Streamable HTTP.

In the MCP Service Configuration panel, select the listener under Attached Listeners to configure it.

Listener configuration panel showing Name, Listen To (port), Host, HTTP1 Settings, and Secure Socket fields.

For standard HTTP setups, only Listen To (the port) is required. Configure Secure Socket to enable HTTPS.

FieldDescriptionDefault
NameIdentifier for the listener (for example, mcpListener).
Listen ToListening port (or an existing http:Listener reference). Required.
HostHost name or IP address the listener binds to.0.0.0.0
HTTP1 SettingsHTTP/1.x protocol settings (keep-alive, max pipelined requests).{}
Secure SocketTLS/SSL configuration. Configure this to enable HTTPS.()
HTTP VersionHighest HTTP version the endpoint supports.HTTP/2.0
TimeoutRead/write timeout in seconds. Set to 0 to disable.60
Request LimitsInbound size limits for URI, headers, and request body.{}
Graceful Stop TimeoutGrace period in seconds before the listener force-stops.0

Tools

Tools are the operations the MCP service exposes. Each tool has a name, a description, typed parameters, and a typed return value. The framework derives the JSON Schema sent to clients automatically from the Ballerina types.

Click + Add Tool in the editor to open the Tool Configuration panel.

The Tool Configuration panel showing Tool Name, Tool Description, Parameters, and Return Type fields, with the MCP Service editor visible behind it.

FieldRequiredDescription
Tool NameYesName MCP clients will see. Use camel-case and be descriptive: getOrderStatus, searchProducts.
Tool DescriptionYesWhat the tool does and when the assistant should use it. The single most important field for tool discoverability. See Writing a good tool description.
ParametersNoEach parameter has a name, type, and description. Descriptions are included in the schema sent to the client.
Return TypeYesBallerina type returned. The output schema is generated from this.

After clicking Save, the tool appears as a row under Tools in the editor and WSO2 Integrator generates a remote function within the service.

The MCP Service Editor with a single tool 'add' listed under Tools.

Writing a good tool description

The tool description is what the AI client reads to decide whether and when to call the tool. Two patterns matter most:

Be explicit about scope

"Search the product catalog by keyword. Returns up to 10 matching products with name, price, and availability. Use for general product discovery questions."

"Retrieves a single product by its exact SKU. Use only when the user provides a SKU."

These two are clearly distinct, and the AI will not confuse them.

Bake in safety rules

"Cancel a customer order. IMPORTANT: Always confirm with the customer before calling this tool. This action cannot be undone."

The AI client will follow it most of the time. For deterministic enforcement, also keep server-side checks.

Don't leave it generic

"Customer endpoint."

A generic description leads to bad tool selection downstream. If you can't write a useful one-liner, the tool is probably too vague to be useful.

Advanced: mcp:AdvancedService

When tool definitions need to come from configuration, a database, or some runtime source (not from compile-time remote functions), use mcp:AdvancedService. You implement two callbacks:

  • onListTools(): return the list of tools advertised to clients.
  • onCallTool(params, session): dispatch a tool call by name.
import ballerina/mcp;

listener mcp:Listener mcpListener = check new (9090);

@mcp:ServiceConfig {
info: {
name: "MCP Crypto Server",
version: "1.0.0"
},
sessionMode: mcp:STATELESS
}
service mcp:AdvancedService /mcp on mcpListener {

remote isolated function onListTools()
returns mcp:ListToolsResult|mcp:ServerError {
return {
tools: [
{
name: "hashText",
description: "Generate a hash for the given text.",
inputSchema: {
"type": "object",
"properties": {
"text": {"type": "string", "description": "Text to hash"},
"algorithm": {
"type": "string",
"enum": ["md5", "sha1", "sha256"],
"default": "sha256"
}
},
"required": ["text"]
}
}
]
};
}

remote isolated function onCallTool(mcp:CallToolParams params, mcp:Session? session)
returns mcp:CallToolResult|mcp:ServerError {
match params.name {
"hashText" => {
return self.handleHashText(params.arguments ?: {});
}
_ => {
return error mcp:ServerError(string `Unknown tool: ${params.name}`);
}
}
}

private isolated function handleHashText(record {} arguments)
returns mcp:CallToolResult|mcp:ServerError {
// Implementation…
return {content: [{'type: "text", text: "..."}]};
}
}
Use mcp:Service when…Use mcp:AdvancedService when…
Tools map cleanly to compile-time remote functions.Tools are dynamic (defined in configuration, a database, or another service).
You want WSO2 Integrator to derive schemas automatically.You want hand-crafted JSON schemas or extra validation.
You want the simplest possible MCP server.You want a dispatch-table architecture.
info

In onCallTool, content items use the field name 'type (with a leading quote) because type is a reserved keyword in Ballerina.

Error handling

Tools should return informative errors so AI clients can recover or suggest alternatives. The framework propagates the error message back to the client as a tool-call error.

When you build a tool flow in the visual designer, errors returned or propagated with check from the flow are sent back to the client automatically. To return a custom error message, use a Return node with an error value:

return error(string `Invalid invoice ID '${invoiceId}'. Expected format INV-XXXXX.`);

The error message is what the AI client will read, so make it actionable. Avoid bare error() with no message; the assistant has nothing to reason about.

Configuring an MCP client

Once your service is running, MCP clients connect by URL.

Claude Desktop

{
"mcpServers": {
"wso2-integrator": {
"url": "http://localhost:9090/mcp"
}
}
}

Another agent inside WSO2 Integrator — see Consuming MCP from an Agent.

Operational notes

  • Keep the tool list small. Fewer, better-described tools beat dozens of overlapping ones.
  • Authenticate. Anything you expose over MCP is, by default, accessible to whoever connects. Configure auth on httpConfig.auth (JWT, OAuth2, basic).
  • Log tool calls. Just like any other API surface; knowing who called what is essential for debugging and audit.
  • Version explicitly. When tool shapes change, prefer adding a new tool over silently changing an existing one. AI clients depend on stable schemas.

What's next