cd /news/developer-tools/build-a-dart-adk-agent-and-mcp-serve… · home topics developer-tools article
[ARTICLE · art-89464] src=dev.to ↗ pub= topic=developer-tools verified=true sentiment=· neutral

Build a Dart ADK Agent and MCP Server

A developer has released an open-source project that enables Dart developers to build AI agents and Model Context Protocol (MCP) servers without relying on Python or Node.js. The project, adk-hello-world-dart, uses the adk_dart library for the agent and Shelf for an HTTP server that exposes an MCP-compatible greeting tool over Server-Sent Events. The developer notes that the Dart library is not an official ADK, as an official Dart ADK has not been released as of July 2026.

read4 min views1 publishedAug 9, 2026

Dart developers do not need a Python or Node.js service just to experiment with agents and Model Context Protocol (MCP) tools. This project uses adk_dart

for the agent and shelf

for a small HTTP server that exposes an MCP-compatible greeting tool over Server-Sent Events (SSE).

The complete code is in the adk-hello-world-dart repository.

Note- the Dart library is not an official ADK. An official Dart ADK has not been released as of July 2026. This approach provides an alternative to start working with agents in Dart without waiting for an official SDK.

The repository has two related examples:

bin/main.dart

creates an LlmAgent

and registers an ADK FunctionTool

.bin/server.dart

starts a Shelf server with an SSE endpoint and a JSON-RPC message endpoint.The server implements the MCP methods needed by this demo: initialize

, notifications/initialized

, ping

, tools/list

, and tools/call

. The transport and JSON-RPC routing are deliberately small and live in SessionService

; they are not a general-purpose MCP server implementation.

flowchart LR
    Client[MCP client] -->|GET /sse| Server[Shelf server]
    Server -->|endpoint event| Client
    Client -->|POST /messages?sessionId=...| Server
    Server --> Session[SessionService]
    Session --> Tool[greet tool]

    CLI[Dart CLI] --> Agent[ADK LlmAgent]
    Agent --> ADKTool[ADK FunctionTool]

The current project targets Dart 3.5 or later and uses these package versions:

environment:
  sdk: ^3.5.0

dependencies:
  adk_dart: ^2026.7.24
  adk_mcp: ^2026.7.24
  logging: ^1.3.0
  shelf: ^1.4.1
  shelf_router: ^1.1.4
  uuid: ^4.5.1

Install them with:

dart pub get

adk_dart

is used directly by the sample agent. The repository also tracks adk_mcp

, while the current server keeps its MCP transport explicit in SessionService

so the protocol flow is easy to inspect.

The project keeps the greeting logic separate from its ADK and MCP wrappers:

class Tools {
  static String formatGreeting(String name) {
    return 'Hello, $name!';
  }

  static final FunctionTool greetFunctionTool = FunctionTool(
    name: Config.toolGreet,
    description: 'Get a greeting from a local HTTPS server.',
    func: ({String? param}) {
      final name = param ?? 'World';
      return formatGreeting(name);
    },
  );
}

Tools

also exposes an MCP tool definition with a JSON Schema input named param

. Keeping formatGreeting

as a plain Dart function makes the domain behavior easy to unit test.

AdkGreetingAgent

attaches the function tool to an LlmAgent

:

class AdkGreetingAgent {
  static LlmAgent createAgent() {
    return LlmAgent(
      name: 'GreetingAgent',
      description: 'An AI Agent built with adk_dart that provides greetings.',
      instruction:
          'You are a friendly greeting assistant. '
          'Use the greet tool to provide personalized greetings.',
      tools: [Tools.greetFunctionTool],
    );
  }
}

Run the CLI example to confirm that the agent and tool can be created:

dart run bin/main.dart

This command initializes the agent and prints a sample tool result. It does not call a hosted model.

The Shelf server registers four routes:

router.get('/', (request) => Response.ok('ADK & MCP Dart Server Running'));
router.get('/health', (request) => Response.ok('OK'));
router.get(Config.sseEndpoint, sessionService.handleSseSession);
router.post(Config.messagesEndpoint, sessionService.handlePostMessage);

When a client opens GET /sse

, SessionService

creates an in-memory session and sends an endpoint

event containing a URL such as:

/messages?sessionId=7c6d...

The client posts JSON-RPC requests to that URL. Responses arrive as message

events on the original SSE connection.

Start the server with:

dart run bin/server.dart

It listens on port 8080

by default. Set the PORT

environment variable to use another port.

For an MCP client that supports remote SSE servers, point it at:

http://localhost:8080/sse

A typical client configuration looks like this:

{
  "mcpServers": {
    "dart-greeting-server": {
      "url": "http://localhost:8080/sse"
    }
  }
}

Configuration keys differ between MCP clients, so check the documentation for the client you use. Once connected, call the greet

tool with:

{
  "param": "Dart developer"
}

The result is Hello, Dart developer!

.

The repository includes unit tests for the greeting behavior and endpoint tests for the Shelf server:

dart test
dart analyze

You can run the complete build, analysis, and test sequence with:

make check

The included multi-stage Dockerfile compiles the server to a native executable and copies it into a small scratch image:

docker build -t adk-hello-world-dart .
docker run --rm -p 8080:8080 adk-hello-world-dart

Check the running container at http://localhost:8080/health

.

cloudbuild.yaml

builds the image, pushes it to Container Registry, and deploys the service in us-central1

:

make deploy

The deployment allows unauthenticated access and sets --max-instances 1

.

That instance limit matters here. Active SSE transports are stored in a process-local map, so a POST request routed to another instance would not find its session. A production service should move session state to shared storage or use a transport and deployment design that does not depend on process-local routing. Authentication, origin restrictions, request validation, timeouts, and rate limiting would also need attention before exposing the service publicly.

This sample is intentionally narrow: one agent, one deterministic tool, and enough MCP handling to show the request flow. Useful next steps include replacing the greeting with real domain logic, using adk_mcp

transport primitives as the Dart package evolves, adding model configuration to execute the agent, and moving session state out of memory before scaling the service.

Resources:

── more in #developer-tools 4 stories · sorted by recency
── more on @adk_dart 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/build-a-dart-adk-age…] indexed:0 read:4min 2026-08-09 ·