< Research
December 24, 2025

Agent Communication Protocol (ACP) — How Will These Agents Communicate with Each Other?

The MCP concept holds a very important place in today's artificial intelligence world and is becoming increasingly prevalent. Thanks to MCPs, the ways in which LLMs and Agents use tools have been standardized through a protocol, and we can now quickly integrate tools into our AI solutions using many ready-made MCP servers that are currently available. Similarly, agents are also among the most popular topics in today's artificial intelligence world. New agent frameworks or methods are emerging every day, but many of the agents developed today work in isolation, disconnected from each other. This is the biggest obstacle to these developed agents communicating and working with each other. As a solution to this problem, IBM has introduced a protocol like MCP that enables Agents to communicate with each other in a standardized manner. In this article, we will examine the concept of ACP (Agent Communication Protocol) and discuss what it offers us.

‍

What is Agent Communication Protocol (ACP)?

ACP solves the problem of agents operating as isolated and separate systems by enabling them to communicate via a standard RESTful API. In fact, considering the evolution of language models, OpenAI first established a standard inference server architecture. Subsequently, agents and LLM applications utilizing these inference services emerged. Methods such as RAG or Function Calling began to be used to enable these applications to interact with the outside world and current data. However, this process meant that the same implementations had to be repeated for each application. This is where MCP came in, standardizing the process and providing a standardized approach to tool usage for Agents or LLM applications. This eliminated the need to write similar tools for each application while also enabling access to all shared tools through a common server standard.

Now, a similar situation is occurring with regard to communication between Agents. Today, Agent developers either make their Agents available for use in different structures or use them without making them available at all, which makes developing a compatible system difficult. This is precisely where protocols such as ACP come into play, enabling all agents to communicate using a common language. This not only standardizes the agent server structure but also allows agents created by other organizations or teams to communicate with each other via a protocol.

Let's look at the features ACP provides us:

  • Communication across all modality types: An Agent can communicate not only with written prompts but also with audio and visual data formats.
  • Synchronous and asynchronous communication: Agents can complete fast operations synchronously and also run long-term operations asynchronously in the background, displaying the result later.
  • Streaming interactions: Allows responses to be displayed word by word without waiting for the Agent to generate the entire response (a ChatGPT-like experience).
  • Both stateful and stateless working patterns: Agents can generate results without past state information or generate results using past information.
  • Online and offline agent discovery: With this protocol, you can search for agents online or discover agents in your own systems offline and connect them with each other.
  • Long-running tasks.

It is possible to enable Agents created using any Agent framework with ACP to operate with the features listed above.

‍

Why isn't MCP used instead of ACP?

When you start researching these topics, you'll often come across comparison articles or content shared under titles like MCP vs ACP vs A2A. In reality, MCP and ACP complement each other. When creating an Agent with ACP, utilizing the tools provided by MCP will make the process more effective.

MCP provides us with a server structure that is accepted in the standard and artificial intelligence world, but you may wonder, “Why are we creating a new server structure?” You are right to think this. In fact, MCP servers also provide some of the features offered by ACP servers; however, the reason we need a new protocol is that Agents are defined as tools with MCP, and there is a hierarchical structure between the system using this tool and the tool itself. The application using the MCP server that the Agent is part of is actually directly affected by the use of this Agent. This eliminates what we call peer-to-peer connection, which is direct communication between two Agents.

‍

How to Communicate Between Two Agents Using ACP?

We have sufficiently discussed what ACP is in theory. Now, let's implement ACP with an example application.

As an example, we will create two different Agents: one is the idea_creator_agent, which generates blog post ideas on a given topic, and the other is the blog_writer_agent, which writes blog posts based on a given idea.

In this example, the idea_creator_agent will be created using the CrewAI framework, while the blog_writer_agent will be created using the Huggingface smolagents framework; thus demonstrating that ACP operates independently of the framework used.

Agent concept and implementation may remain at a basic level; the purpose of this article is not to create Agents, but to establish the system that will enable their communication.

‍

First, let's create our ACP project and include acp_sdk in our project.

If UV is not installed on your computer, you must first install UV.

uv init --python '>=3.11' my_acp_project #istediğiniz ismi verebilirsiniz
cd my_acp_project

uv add acp-sdk
uv add crewai
uv add smolagents[openai]

‍

We have created our project. Now let's create our first agent, idea_creator_agent, with the CrewAI framework.

In this example, https://openrouter.ai/ was used as the LLM provider. You can perform this demo with any LLM provider you prefer.

‍

from collections.abc import AsyncGenerator
from acp_sdk.models import Message, MessagePart
from acp_sdk.server import RunYield, RunYieldResume, Server

from crewai import Crew, Task, Agent, LLM

server = Server()

llm = LLM(
    model="openrouter/qwen/qwen3-8b", #İstediğiniz modeli kullanabilirsiniz
    base_url="https://openrouter.ai/api/v1",
    api_key="buraya_kendi_key_bilginizi_giriniz"
)


@server.agent()
async def idea_creator_agent(input: list[Message]) -> AsyncGenerator[RunYield,
                                                        RunYieldResume]:
    "This is an agent for blog post idea creator, 
    based on the given topic."

    idea_creator_agent = Agent(
        role="Professional Inovation Team Lead", 
        goal="Find a blog posts idea.",
        backstory="You are an professional innovation team lead.\n
                   You are responsible for finding new ideas for blog posts.",
        verbose=True,
        allow_delegation=False,
        llm=llm,
        max_retry_limit=5
    )
    
    task1 = Task(
         description=input[0].parts[0].content,
         expected_output = "Short blog post idea for given topic",
         agent=idea_creator_agent
    )
    crew = Crew(agents=[idea_creator_agent], tasks=[task1], verbose=True)
    
    task_output = await crew.kickoff_async()
    yield Message(parts=[MessagePart(content=str(task_output))])

if __name__ == "__main__":
    server.run(port=8000)

‍

Above, we created our first Agent and launched it with the ACP server. As you can see, we specified that this function is an Agent using the @server.agent() decorator. The idea_creator_agent function we created is the name of our Agent, and we can search for and connect to this Agent using this name. This function accepts input, representing the task or prompt to be given to this Agent. The rest of the code is just the implementation of the CrewAI Agent structure. As you can see, this service is running on port 8000 on localhost.

Now let's create our second Agent, blog_writer_agent, using the smolagents framework.

‍

from collections.abc import AsyncGenerator
from acp_sdk.models import Message, MessagePart
from acp_sdk.server import Context, RunYield, RunYieldResume, Server
from smolagents import CodeAgent, OpenAIServerModel, FinalAnswerTool
import logging 
from dotenv import load_dotenv

load_dotenv() 

server = Server()

model = OpenAIServerModel(
    model_id="qwen/qwen3-8b", #İstediğiniz modeli kullanabilirsiniz
    api_base="https://openrouter.ai/api/v1",
    api_key="buraya_kendi_key_bilginizi_giriniz"
)

@server.agent()
async def blog_writer_agent(input: list[Message]) -> AsyncGenerator[RunYield, 
                                                              RunYieldResume]:
    "This is a CodeAgent which writes a blog post for given blog post idea."
    agent = CodeAgent(tools=[FinalAnswerTool()], model=model)
    prompt = input[0].parts[0].content
    response = agent.run(prompt)

    yield Message(parts=[MessagePart(content=str(response))])


if __name__ == "__main__":
    server.run(port=8001)

‍

Similarly, we created the blog_writer_agent and launched it on port 8001 of localhost.

Multiple Agents can be launched within the same server. All you need to do is define the Agent under a new @server.agent() decorator.

Now let's connect to these Agent servers we created and enable the relevant Agents to communicate. We can do this as a classic HTTP request because ACP provides us with a standard RESTful API. We can also access these Agents and send requests using the client provided by acp_sdk. In this example, communication will be established using the acp_sdk client.

‍

from acp_sdk.client import Client
import asyncio

async def run_blog_post_workflow() -> None:
    async with Client(base_url="http://localhost:8001") as blog_post_writer,\
               Client(base_url="http://localhost:8000") as idea_creator:
        
        run1 = await idea_creator.run_sync(
            agent="idea_creator_agent", 
            input="Artificial Intelligence"
        )
        content = run1.output[0].parts[0].content
        print(content)

        run2 = await blog_post_writer.run_sync(
            agent="blog_writer_agent", 
            input=f"Context: {content} Write a blog post about the topic."
        )
        print(run2.output[0].parts[0].content)


if __name__ == "__main__":
    asyncio.run(run_blog_post_workflow())

‍

First, we created a function named run_blog_post_workflow. Within this function, we created Client objects for both the idea_creator_agent and the blog_writer_agent because these two Agents run on separate servers, and we will need to communicate between them. In a real-world application, these two Agents could run on the same ACP server and still communicate internally.

After creating the Client objects, we use the run methods of these clients. The critical point here is that the agent parameter must have the same name as the function we gave it. The other parameter is the inputs this Agent will receive. In our example, it only took input, but it is possible to provide different and more inputs.

As seen, the run methods have been called for both agents. The communication between agents here is a sequential type of communication: first, the idea_creator_agent generates an idea on a given topic, then the blog_writer_agent writes a blog post using this idea. Different communication methods can also be used. A routing agent can be used in a flow that automatically determines which agents to use for a given task. I will detail the sources of these examples below.

‍

Conclusion

In conclusion, this article has covered what the Agent Communication Protocol (ACP) is, how it differs from MCP, and whether they can be used together. This article should be considered only an introduction to the concept of ACP; more detailed information can be found in the documentation and videos available in the resources.

💡 If you want to explore how MCP and ACP can be used together and examine different Agent client types in more detail, I highly recommend the short course prepared by DeepLearning.AI listed below.

‍

Sources:

‍

Author: