{"id":47791077,"url":"https://github.com/spring-ai-community/spring-ai-a2a","last_synced_at":"2026-04-03T15:38:49.141Z","repository":{"id":334275325,"uuid":"1140545115","full_name":"spring-ai-community/spring-ai-a2a","owner":"spring-ai-community","description":"Spring Boot and Spring integration for building AI agent servers using the A2A Protocol.","archived":false,"fork":false,"pushed_at":"2026-01-23T20:39:46.000Z","size":339,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-24T09:22:53.321Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/spring-ai-community.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-23T12:30:52.000Z","updated_at":"2026-01-23T20:39:50.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/spring-ai-community/spring-ai-a2a","commit_stats":null,"previous_names":["spring-ai-community/spring-ai-a2a"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/spring-ai-community/spring-ai-a2a","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spring-ai-community%2Fspring-ai-a2a","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spring-ai-community%2Fspring-ai-a2a/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spring-ai-community%2Fspring-ai-a2a/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spring-ai-community%2Fspring-ai-a2a/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/spring-ai-community","download_url":"https://codeload.github.com/spring-ai-community/spring-ai-a2a/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spring-ai-community%2Fspring-ai-a2a/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31360807,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-03T15:19:21.178Z","status":"ssl_error","status_checked_at":"2026-04-03T15:19:20.670Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-04-03T15:38:48.597Z","updated_at":"2026-04-03T15:38:49.136Z","avatar_url":"https://github.com/spring-ai-community.png","language":"Java","funding_links":[],"categories":["人工智能","⚙️ Implementations \u0026 Libraries"],"sub_categories":["A2A"],"readme":"# Spring AI A2A\n\n[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)\n[![Maven Central](https://img.shields.io/maven-central/v/org.springaicommunity/spring-ai-a2a-server-autoconfigure.svg?label=Maven%20Central)](https://central.sonatype.com/artifact/org.springaicommunity/spring-ai-a2a-server-autoconfigure)\n[![Java Version](https://img.shields.io/badge/Java-17%2B-orange)](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html)\n\nSpring Boot integration for building AI agent servers using the [A2A Protocol](https://a2a.anthropic.com/).\n\n## Overview\n\nSpring AI A2A provides **server-side** support for exposing Spring AI agents via the A2A protocol. Add the dependency, provide `ChatClient`, `AgentCard`, and `AgentExecutor` beans, and your agent is automatically exposed.\n\n**Key Features**: A2A Protocol Server • Spring AI ChatClient Integration • Full `@Tool` Support • Auto-Configuration\n\n## Quick Start\n\n### 1. Add Dependencies\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.springaicommunity\u003c/groupId\u003e\n    \u003cartifactId\u003espring-ai-a2a-server-autoconfigure\u003c/artifactId\u003e\n    \u003cversion\u003e0.2.0\u003c/version\u003e\n\u003c/dependency\u003e\n\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.springframework.ai\u003c/groupId\u003e\n    \u003cartifactId\u003espring-ai-starter-model-openai\u003c/artifactId\u003e\n\u003c/dependency\u003e\n```\n\n### 2. Create Your Agent\n\n```java\n@SpringBootApplication\npublic class WeatherAgentApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(WeatherAgentApplication.class, args);\n    }\n\n    @Bean\n    public AgentCard agentCard(@Value(\"${server.port:8080}\") int port) {\n        return new AgentCard.Builder()\n            .name(\"Weather Agent\")\n            .description(\"Provides weather forecasts\")\n            .url(\"http://localhost:\" + port + \"/a2a/\")\n            .version(\"1.0.0\")\n            .capabilities(new AgentCapabilities.Builder().streaming(false).build())\n            .defaultInputModes(List.of(\"text\"))\n            .defaultOutputModes(List.of(\"text\"))\n            .skills(List.of(new AgentSkill.Builder()\n                .id(\"weather_search\").name(\"Weather Search\")\n                .description(\"Provides current weather and forecasts\")\n                .tags(List.of(\"weather\")).build()))\n            .protocolVersion(\"0.3.0\")\n            .build();\n    }\n\n    @Bean\n    public AgentExecutor agentExecutor(ChatClient.Builder chatClientBuilder, WeatherTools tools) {\n        ChatClient chatClient = chatClientBuilder.clone()\n            .defaultSystem(\"You are a weather assistant. Use tools to get weather data.\")\n            .defaultTools(tools)\n            .build();\n\n        return new DefaultAgentExecutor(chatClient, (chat, ctx) -\u003e {\n            String userMessage = DefaultAgentExecutor.extractTextFromMessage(ctx.getMessage());\n            return chat.prompt().user(userMessage).call().content();\n        });\n    }\n}\n```\n\n### 3. Define Tools\n\n```java\n@Service\npublic class WeatherTools {\n\n    @Tool(description = \"Get current weather for a location\")\n    public String getCurrentWeather(\n            @ToolParam(description = \"City and state, e.g. San Francisco, CA\") String location) {\n        return \"Current weather in \" + location + \": Sunny, 72°F\";\n    }\n}\n```\n\n### 4. Configure \u0026 Run\n\n```yaml\nserver:\n  port: 8080\n  servlet:\n    context-path: /a2a\n\nspring:\n  ai:\n    a2a.server.enabled: true\n    openai.api-key: ${OPENAI_API_KEY}\n```\n\n```bash\nexport OPENAI_API_KEY=your-key \u0026\u0026 mvn spring-boot:run\n```\n\nYour agent is available at `http://localhost:8080/a2a` (card at `/a2a/card`).\n\n## Calling Your Agent\n\n**Using curl:**\n```bash\ncurl -X POST http://localhost:8080/a2a -H 'Content-Type: application/json' -d '{\n  \"jsonrpc\": \"2.0\", \"method\": \"sendMessage\", \"id\": \"1\",\n  \"params\": {\"message\": {\"role\": \"user\", \"parts\": [{\"type\": \"text\", \"text\": \"Weather in London?\"}]}}\n}'\n```\n\n**Using A2A SDK:**\n```java\nA2ACardResolver resolver = new A2ACardResolver(new JdkA2AHttpClient(), \"http://localhost:8080\", \"/a2a/card\", null);\nClient client = Client.builder(resolver.getAgentCard())\n    .withTransport(JSONRPCTransport.class, new JSONRPCTransportConfig()).build();\nclient.sendMessage(new Message.Builder().role(Message.Role.USER)\n    .parts(List.of(new TextPart(\"Weather in Paris?\"))).build());\n```\n\n## Architecture\n\n```\nYour Spring Boot App\n├── ChatClient, AgentCard, AgentExecutor (your beans)\n├── DefaultAgentExecutor (bridges A2A ↔ ChatClient)\n└── A2A Controllers (auto-configured)\n    ├── POST /      → MessageController (sendMessage)\n    ├── GET  /card  → AgentCardController (discovery)\n    └── GET  /tasks/{id} → TaskController (status)\n```\n\n**Request Flow:**\n1. `MessageController` receives JSON-RPC request\n2. A2A SDK `RequestHandler` creates task\n3. `DefaultAgentExecutor` invokes your `ChatClientExecutorHandler`\n4. `ChatClient` calls LLM and executes tools\n5. Response wrapped as task artifact → returned to client\n\n**You provide:** `AgentExecutor`, `AgentCard`, `ChatClient` beans\n**Framework handles:** Endpoints, task lifecycle, JSON-RPC, error handling\n\n## Implementation Patterns\n\n### Pattern 1: Simple Agent (Recommended)\n\nUse `DefaultAgentExecutor` with a lambda:\n\n```java\n@Bean\npublic AgentExecutor agentExecutor(ChatClient.Builder builder, MyTools tools) {\n    ChatClient chatClient = builder.clone().defaultSystem(\"...\").defaultTools(tools).build();\n    return new DefaultAgentExecutor(chatClient, (chat, ctx) -\u003e {\n        String msg = DefaultAgentExecutor.extractTextFromMessage(ctx.getMessage());\n        return chat.prompt().user(msg).call().content();\n    });\n}\n```\n\n### Pattern 2: Custom AgentExecutor\n\nFor custom task lifecycle or progress updates:\n\n```java\n@Component\npublic class MyAgent implements AgentExecutor {\n    @Override\n    public void execute(RequestContext ctx, EventQueue queue) throws JSONRPCError {\n        TaskUpdater updater = new TaskUpdater(ctx, queue);\n        if (ctx.getTask() == null) updater.submit();\n        updater.startWork();\n        updater.addMessage(List.of(new TextPart(\"Processing...\")), \"assistant\");\n        String response = chatClient.prompt().user(extractText(ctx.getMessage())).call().content();\n        updater.addArtifact(List.of(new TextPart(response)), null, null, null);\n        updater.complete();\n    }\n}\n```\n\n### Pattern 3: Multi-Agent Orchestration\n\nCreate tools that call remote A2A agents:\n\n```java\n@Service\npublic class RemoteAgentTools {\n    private final Map\u003cString, AgentCard\u003e agents;\n\n    @Tool(description = \"Delegate task to remote agent\")\n    public String sendMessage(@ToolParam(description = \"Agent name\") String name,\n                              @ToolParam(description = \"Task\") String task) {\n        CompletableFuture\u003cString\u003e future = new CompletableFuture\u003c\u003e();\n        Client client = Client.builder(agents.get(name))\n            .withTransport(JSONRPCTransport.class, new JSONRPCTransportConfig())\n            .addConsumers(List.of((event, card) -\u003e {\n                if (event instanceof TaskEvent te \u0026\u0026 te.getTask().getArtifacts() != null)\n                    future.complete(extractText(te.getTask().getArtifacts()));\n            })).build();\n        client.sendMessage(new Message.Builder().role(Message.Role.USER)\n            .parts(List.of(new TextPart(task))).build());\n        return future.get(60, TimeUnit.SECONDS);\n    }\n}\n```\n\nSee [airbnb-planner example](spring-ai-a2a-examples/airbnb-planner/) for complete multi-agent implementation.\n\n## Project Structure\n\n```\nspring-ai-a2a/\n├── spring-ai-a2a-server/              # Core: executor/, controller/\n├── spring-ai-a2a-server-autoconfigure/ # Auto-configuration\n└── spring-ai-a2a-examples/airbnb-planner/\n    ├── weather-agent/   (Port 10001)\n    ├── airbnb-agent/    (Port 10002)\n    └── host-agent/      (Port 10000) - orchestrator\n```\n\n## Configuration\n\n**Spring Boot** (`application.properties` or `application.yml`):\n```yaml\nspring:\n  ai:\n    a2a:\n      server:\n        enabled: true\n\nserver:\n  servlet:\n    context-path: /a2a\n```\n\n**A2A SDK properties** can be configured directly in Spring's Environment (application.properties, environment variables, etc.):\n```properties\n# Blocking call timeouts\na2a.blocking.agent.timeout.seconds=30\na2a.blocking.consumption.timeout.seconds=5\n\n# Thread pool configuration\na2a.executor.core-pool-size=5\na2a.executor.max-pool-size=50\na2a.executor.keep-alive-seconds=60\n```\n\nThe `SpringA2AConfigProvider` first checks Spring's `Environment` for property values and falls back to the SDK's `DefaultValuesConfigProvider` for any missing keys. This follows the [custom config provider pattern](https://github.com/a2aproject/a2a-java/blob/main/integrations/microprofile-config/README.md#custom-config-providers) recommended by the A2A Java SDK.\n\n## Building \u0026 Testing\n\n```bash\nmvn clean install           # Build all\nmvn test                    # Run tests\ncd spring-ai-a2a-examples/airbnb-planner/weather-agent \u0026\u0026 mvn spring-boot:run\n```\n\n## Requirements\n\nJava 17+ • Maven 3.8+ • Spring Boot 4.0+ • Spring AI 2.0.0-M2+ • A2A SDK 0.3.3.Final\n\n## Troubleshooting\n\n| Issue | Solution |\n|-------|----------|\n| Requests timeout | Check `AgentExecutor` bean, API key, increase timeout |\n| 404 on endpoint | Verify `spring.ai.a2a.server.enabled=true` and context-path |\n| Tools not called | Ensure tools are `@Service`/`@Component` and registered via `.defaultTools()` |\n\n## Resources\n\n- [A2A Protocol](https://a2a.anthropic.com/) • [A2A Java SDK](https://github.com/anthropics/a2a-java-sdk)\n- [Spring AI Docs](https://docs.spring.io/spring-ai/reference/) • [Spring Boot](https://docs.spring.io/spring-boot/reference/)\n\n## License\n\nApache License 2.0\n\n## Support\n\n[GitHub Issues](https://github.com/spring-ai-community/spring-ai-a2a/issues) • [Spring AI Community](https://github.com/spring-ai-community)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspring-ai-community%2Fspring-ai-a2a","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fspring-ai-community%2Fspring-ai-a2a","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspring-ai-community%2Fspring-ai-a2a/lists"}