How to Implement a Plugin for MCP#
Overview#
Model Context Protocol (MCP) is an open protocol that standardizes how applications provide context to LLMs. MCP servers allow you to connect your assistant to external tools and services (such as web APIs, search engines, or custom data sources) without writing custom adapters for each integration.
In this guide, you will learn how to:
Create a simple MCP Server (in a separate Python file)
Connect an Agent/Flow to an MCP Server
Important
This guide will show you how to integrate with WayFlow, which supports MCP Tools. Note that the steps shown in this guide can be applied on any runtime executor that supports MCP.
Prerequisite: Setup a simple MCP Server#
First, let’s see how to create and start a simple MCP server exposing a couple of tools.
Note
You should copy the following server code and run it in a separate Python process.
from mcp.server.fastmcp import FastMCP
PAYSLIPS = [
{
"Amount": 7612,
"Currency": "USD",
"PeriodStartDate": "2025/05/15",
"PeriodEndDate": "2025/06/15",
"PaymentDate": "",
"DocumentId": 2,
"PersonId": 2,
},
{
"Amount": 5000,
"Currency": "CHF",
"PeriodStartDate": "2024/05/01",
"PeriodEndDate": "2024/06/01",
"PaymentDate": "2024/05/15",
"DocumentId": 1,
"PersonId": 1,
},
{
"Amount": 10000,
"Currency": "EUR",
"PeriodStartDate": "2025/06/15",
"PeriodEndDate": "2025/10/15",
"PaymentDate": "",
"DocumentsId": 3,
"PersonId": 3,
},
]
def create_server(host: str, port: int):
"""Create and configure the MCP server"""
server = FastMCP(
name="Example MCP Server",
instructions="A MCP Server.",
host=host,
port=port,
)
@server.tool(description="Return session details for the current user")
def get_user_session():
print("called get_user_session")
return {
"PersonId": "1",
"Username": "Bob.b",
"DisplayName": "Bob B",
}
@server.tool(description="Return payslip details for a given PersonId")
def get_payslips(PersonId: int):
return [payslip for payslip in PAYSLIPS if payslip["PersonId"] == int(PersonId)]
return server
def start_mcp_server() -> str:
host: str = "localhost"
port: int = 8080
server = create_server(host=host, port=port)
server.run(transport="sse")
return f"http://{host}:{port}/sse"
# mcp_server_url = start_mcp_server() # <--- Move the code above to a separate file then uncomment
This MCP server exposes two example tools: get_user_session
and get_payslips
.
Once started, it will be available at (by default): http://localhost:8080/sse
.
Note
When choosing a transport for MCP:
Use Stdio when launching and communicating with an MCP server as a local subprocess on the same machine as the client.
Use Streamable HTTP when connecting to a remote MCP server.
For more information, visit https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#stdio
Important
This guide does not aim at explaining how to make secure MCP servers, but instead mainly aims at showing how to connect to one. You should ensure that your MCP server configurations are secure, and only connect to trusted external MCP servers.
Connecting an Agent to the MCP Server#
You can now connect an agent to this running MCP server.
Add imports and configure an LLM#
Start by importing the necessary packages for this guide:
from pyagentspec.agent import Agent
from pyagentspec.flows.edges import ControlFlowEdge, DataFlowEdge
from pyagentspec.flows.flow import Flow
from pyagentspec.flows.nodes import EndNode, StartNode, ToolNode
from pyagentspec.mcp import MCPTool, SSETransport
from pyagentspec.property import StringProperty
mcp_server_url = f"http://localhost:8080/sse" # change to your own URL
Agent Spec supports several LLM API providers. Select an LLM from the options below:
from pyagentspec.llms import OciGenAiConfig
from pyagentspec.llms.ociclientconfig import OciClientConfigWithApiKey
client_config = OciClientConfigWithApiKey(
name="Oci Client Config",
service_endpoint="https://url-to-service-endpoint.com",
auth_profile="DEFAULT",
auth_file_location="~/.oci/config"
)
llm_config = OciGenAiConfig(
name="Oci GenAI Config",
model_id="provider.model-id",
compartment_id="compartment-id",
client_config=client_config,
)
from pyagentspec.llms import VllmConfig
llm_config = VllmConfig(
name="Llama 3.1 8B instruct",
url="VLLM_URL",
model_id="model-id",
)
from pyagentspec.llms import OllamaConfig
llm_config = OllamaConfig(
name="Ollama Config",
model_id="model-id",
)
Build the Agent#
Agents can use tools exposed by MCP servers using MCPTool.
mcp_client = SSETransport(name="MCP Client", url=mcp_server_url)
get_user_session_tool = MCPTool(
client_transport=mcp_client,
description="Return session details for the current user",
name="get_user_session",
)
get_payslips_tool = MCPTool(
client_transport=mcp_client,
description="Return payslip details for a given PersonId",
name="get_payslips",
)
agent = Agent(
name="Agent using MCP",
llm_config=llm_config,
system_prompt="Use tools at your disposal to assist the user.",
tools=[get_user_session_tool, get_payslips_tool]
)
Specify the transport to use to handle the connection to the server
as well as the name of the specific tool you want to use. Additionally, you can override the tool
description (exposed by the MCP server) by specifying the description
parameter.
Agent Serialization#
You can export the agent configuration using the AgentSpecSerializer.
from pyagentspec.serialization import AgentSpecSerializer
serialized_assistant = AgentSpecSerializer().to_json(agent)
Here is what the Agent Spec representation will look like ↓
Click here to see the assistant configuration.
{
"component_type": "Agent",
"id": "a98dfe0f-2f36-4c4c-937e-ab4394ef7863",
"name": "Agent using MCP",
"description": null,
"metadata": {},
"inputs": [],
"outputs": [],
"llm_config": {
"component_type": "VllmConfig",
"id": "2242f59e-d803-4413-8473-c807bc5cbf19",
"name": "llm",
"description": null,
"metadata": {},
"default_generation_parameters": null,
"url": "url",
"model_id": "model_id"
},
"system_prompt": "Use tools at your disposal to assist the user.",
"tools": [
{
"component_type": "MCPTool",
"id": "d0b7948c-74e1-4789-a89a-b7a8a11a1651",
"name": "get_user_session",
"description": "Return session details for the current user",
"metadata": {},
"inputs": [],
"outputs": [],
"client_transport": {
"$component_ref": "d083a903-d504-41d4-84db-aabf19344c5c"
}
},
{
"component_type": "MCPTool",
"id": "2f03453b-def7-4515-b02e-b780c92c81ca",
"name": "get_payslips",
"description": "Return payslip details for a given PersonId",
"metadata": {},
"inputs": [],
"outputs": [],
"client_transport": {
"$component_ref": "d083a903-d504-41d4-84db-aabf19344c5c"
}
}
],
"$referenced_components": {
"d083a903-d504-41d4-84db-aabf19344c5c": {
"component_type": "SSETransport",
"id": "d083a903-d504-41d4-84db-aabf19344c5c",
"name": "MCP Client",
"description": null,
"metadata": {},
"session_parameters": {
"read_timeout_seconds": 60
},
"url": "http://localhost:8080/sse",
"headers": null
}
},
"agentspec_version": "25.4.1"
}
component_type: Agent
id: 29eba92b-ae73-4a28-9bc0-ed47d1d6db12
name: Agent using MCP
description: null
metadata: {}
inputs: []
outputs: []
llm_config:
component_type: VllmConfig
id: 82f0e440-792b-4f4a-b2c7-16306a2c0356
name: llm
description: null
metadata: {}
default_generation_parameters: null
url: url
model_id: model_id
system_prompt: Use tools at your disposal to assist the user.
tools:
- component_type: MCPTool
id: 3e16fc6c-4c7c-4cfe-b25b-a4c792d3fbf8
name: get_user_session
description: Return session details for the current user
metadata: {}
inputs: []
outputs: []
client_transport:
$component_ref: 01c52aac-6b67-4ca2-8b43-08b4ac296fc1
- component_type: MCPTool
id: 2f4a1eff-3df5-4688-9267-c24ae0ae9b1f
name: get_payslips
description: Return payslip details for a given PersonId
metadata: {}
inputs: []
outputs: []
client_transport:
$component_ref: 01c52aac-6b67-4ca2-8b43-08b4ac296fc1
$referenced_components:
01c52aac-6b67-4ca2-8b43-08b4ac296fc1:
component_type: SSETransport
id: 01c52aac-6b67-4ca2-8b43-08b4ac296fc1
name: MCP Client
description: null
metadata: {}
session_parameters:
read_timeout_seconds: 60
url: http://localhost:8080/sse
headers: null
agentspec_version: 25.4.1
Connecting a Flow to the MCP Server#
You can also use MCP tools in a Flow by using the MCPTool in a ToolNode.
Build the Flow#
Create the flow using the MCP tool:
start_node = StartNode(name="start")
user_info_property = StringProperty(title="user_info")
get_user_session_tool = MCPTool(
client_transport=mcp_client,
name="get_user_session",
description="Return session details for the current user",
outputs=[user_info_property]
)
mcptool_node = ToolNode(
name="mcp_tool",
tool=get_user_session_tool,
)
end_node = EndNode(name="end", outputs=[user_info_property])
flow = Flow(
name="Flow using MCP",
start_node=start_node,
nodes=[start_node, mcptool_node, end_node],
control_flow_connections=[
ControlFlowEdge(
name="start->mcptool",
from_node=start_node,
to_node=mcptool_node
),
ControlFlowEdge(
name="mcptool->end",
from_node=mcptool_node,
to_node=end_node
),
],
data_flow_connections=[
DataFlowEdge(
name="user_info",
source_node=mcptool_node,
source_output="user_info",
destination_node=end_node,
destination_input="user_info",
)
]
)
Similarly to when equipping Agents with MCP Tools, you should specify the client transport as with the MCP ToolBox, as well as the name of the specific tool you want to use.
Flow Serialization#
You can export the flow configuration using the AgentSpecSerializer.
from pyagentspec.serialization import AgentSpecSerializer
serialized_assistant = AgentSpecSerializer().to_json(flow)
Here is what the Agent Spec representation will look like ↓
Click here to see the assistant configuration.
{
"component_type": "Flow",
"id": "2849ac60-7154-48a8-a4ef-433ffe85b5ef",
"name": "Flow using MCP",
"description": null,
"metadata": {},
"inputs": [],
"outputs": [
{
"title": "user_info",
"type": "string"
}
],
"start_node": {
"$component_ref": "1949f7b0-782e-4856-bfe9-cc58964c175a"
},
"nodes": [
{
"$component_ref": "1949f7b0-782e-4856-bfe9-cc58964c175a"
},
{
"$component_ref": "c4be5127-81a6-4627-8525-bac37214d547"
},
{
"$component_ref": "ab20a178-5658-4c92-bd9a-ce87dd9a1ecd"
}
],
"control_flow_connections": [
{
"component_type": "ControlFlowEdge",
"id": "d4c33b22-4de1-4e36-bc7f-6e48a7dccfb0",
"name": "start->mcptool",
"description": null,
"metadata": {},
"from_node": {
"$component_ref": "1949f7b0-782e-4856-bfe9-cc58964c175a"
},
"from_branch": null,
"to_node": {
"$component_ref": "c4be5127-81a6-4627-8525-bac37214d547"
}
},
{
"component_type": "ControlFlowEdge",
"id": "c6fde850-2bff-45f4-b44b-6cf1c85805c1",
"name": "mcptool->end",
"description": null,
"metadata": {},
"from_node": {
"$component_ref": "c4be5127-81a6-4627-8525-bac37214d547"
},
"from_branch": null,
"to_node": {
"$component_ref": "ab20a178-5658-4c92-bd9a-ce87dd9a1ecd"
}
}
],
"data_flow_connections": [
{
"component_type": "DataFlowEdge",
"id": "62ee2e58-19e1-403d-b6ca-eeabb753c20a",
"name": "user_info",
"description": null,
"metadata": {},
"source_node": {
"$component_ref": "c4be5127-81a6-4627-8525-bac37214d547"
},
"source_output": "user_info",
"destination_node": {
"$component_ref": "ab20a178-5658-4c92-bd9a-ce87dd9a1ecd"
},
"destination_input": "user_info"
}
],
"$referenced_components": {
"c4be5127-81a6-4627-8525-bac37214d547": {
"component_type": "ToolNode",
"id": "c4be5127-81a6-4627-8525-bac37214d547",
"name": "mcp_tool",
"description": null,
"metadata": {},
"inputs": [],
"outputs": [
{
"title": "user_info",
"type": "string"
}
],
"branches": [
"next"
],
"tool": {
"component_type": "MCPTool",
"id": "f1730e08-491b-4348-96e6-8fb18b0db618",
"name": "get_user_session",
"description": "Return session details for the current user",
"metadata": {},
"inputs": [],
"outputs": [
{
"title": "user_info",
"type": "string"
}
],
"client_transport": {
"component_type": "SSETransport",
"id": "96cda25c-5b3e-43cf-97bd-2d1feca83473",
"name": "MCP Client",
"description": null,
"metadata": {},
"session_parameters": {
"read_timeout_seconds": 60
},
"url": "http://localhost:8080/sse",
"headers": null
}
}
},
"ab20a178-5658-4c92-bd9a-ce87dd9a1ecd": {
"component_type": "EndNode",
"id": "ab20a178-5658-4c92-bd9a-ce87dd9a1ecd",
"name": "end",
"description": null,
"metadata": {},
"inputs": [
{
"title": "user_info",
"type": "string"
}
],
"outputs": [
{
"title": "user_info",
"type": "string"
}
],
"branches": [],
"branch_name": "next"
},
"1949f7b0-782e-4856-bfe9-cc58964c175a": {
"component_type": "StartNode",
"id": "1949f7b0-782e-4856-bfe9-cc58964c175a",
"name": "start",
"description": null,
"metadata": {},
"inputs": [],
"outputs": [],
"branches": [
"next"
]
}
},
"agentspec_version": "25.4.1"
}
component_type: Flow
id: baafbae6-c33a-4c1e-afa2-3fd9fccd0b87
name: Flow using MCP
description: null
metadata: {}
inputs: []
outputs:
- title: user_info
type: string
start_node:
$component_ref: bd3c98eb-68ba-4a06-808d-49f0604d7d7e
nodes:
- $component_ref: bd3c98eb-68ba-4a06-808d-49f0604d7d7e
- $component_ref: 4d5d3dd3-e826-41ec-bd19-1f41f61e07dc
- $component_ref: 605773b7-2573-4a4f-8bbe-be03b1760cb6
control_flow_connections:
- component_type: ControlFlowEdge
id: 84c3460e-0940-4e90-a2dc-fab9e7c84a52
name: start->mcptool
description: null
metadata: {}
from_node:
$component_ref: bd3c98eb-68ba-4a06-808d-49f0604d7d7e
from_branch: null
to_node:
$component_ref: 4d5d3dd3-e826-41ec-bd19-1f41f61e07dc
- component_type: ControlFlowEdge
id: 7afbd6be-8644-4a6a-b351-509be10580ab
name: mcptool->end
description: null
metadata: {}
from_node:
$component_ref: 4d5d3dd3-e826-41ec-bd19-1f41f61e07dc
from_branch: null
to_node:
$component_ref: 605773b7-2573-4a4f-8bbe-be03b1760cb6
data_flow_connections:
- component_type: DataFlowEdge
id: 4275b1f6-a79e-4004-97b6-f00c9935e878
name: user_info
description: null
metadata: {}
source_node:
$component_ref: 4d5d3dd3-e826-41ec-bd19-1f41f61e07dc
source_output: user_info
destination_node:
$component_ref: 605773b7-2573-4a4f-8bbe-be03b1760cb6
destination_input: user_info
$referenced_components:
bd3c98eb-68ba-4a06-808d-49f0604d7d7e:
component_type: StartNode
id: bd3c98eb-68ba-4a06-808d-49f0604d7d7e
name: start
description: null
metadata: {}
inputs: []
outputs: []
branches:
- next
4d5d3dd3-e826-41ec-bd19-1f41f61e07dc:
component_type: ToolNode
id: 4d5d3dd3-e826-41ec-bd19-1f41f61e07dc
name: mcp_tool
description: null
metadata: {}
inputs: []
outputs:
- title: user_info
type: string
branches:
- next
tool:
component_type: MCPTool
id: a94d225e-b15f-4fd5-988f-3587f0e31aab
name: get_user_session
description: Return session details for the current user
metadata: {}
inputs: []
outputs:
- title: user_info
type: string
client_transport:
component_type: SSETransport
id: 2f098c44-854d-4ae6-9642-e50f6b0ac595
name: MCP Client
description: null
metadata: {}
session_parameters:
read_timeout_seconds: 60
url: http://localhost:8080/sse
headers: null
605773b7-2573-4a4f-8bbe-be03b1760cb6:
component_type: EndNode
id: 605773b7-2573-4a4f-8bbe-be03b1760cb6
name: end
description: null
metadata: {}
inputs:
- title: user_info
type: string
outputs:
- title: user_info
type: string
branches: []
branch_name: next
agentspec_version: 25.4.1
Next steps#
In this guide, you learned how to connect MCP Tools to Agent Spec Flows and Agents.
Having learned how to configure agent instructions, you may now proceed to: