Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Are APIs Still Relevant in the AI Era?

Are APIs Still Relevant in the AI Era?

Are APIs still relevant in the AI era? Interfaces are changing, but APIs remain the foundation for data, permissions, and business rules—for applications and AI agents alike.

This talk explores how to connect AI agents to your APIs through MCP, comparing three approaches: OpenAPI, a Hydra hypermedia gateway, and manually defined tools. Topics include progressive discovery with Hydra-MCP, real-time notifications with SSE and Mercure, and a look at new features and migrations in API Platform 4.4 and 5.0.

Presented by Antoine Bluchet (soyuka) at API Platform Con 2026.

Avatar for Antoine Bluchet

Antoine Bluchet

September 17, 2026

More Decks by Antoine Bluchet

Other Decks in Programming

Transcript

  1. SEPTEMBER 17 -18, 2026 - LILLE, FRANCE & ONLINE Are

    APIs Still Relevant in the AI Era? Antoine Bluchet
  2. Antoine Bluchet aka soyuka ✔ API Platform release manager ✔

    Developer, biker, builder ✔ Father of 2 ✔ Free software advocate ✔ CTO at Les-Tilleuls.coop https://github.com/soyuka
  3. POWERED BY LES-TILLEULS.COOP What we do? Automation & AI Workflows

    Connectivity & MCP AI-Accelerated Development Product Design & Ownership Connect AI to the system you run. [email protected] AI Architecture & Sovereignty Cloud, AIOps & Kubernetes
  4. Behind the interface MCP Agent API Platform Vehicle plate lookup

    (SIV) TecDoc / PartsAPI Motul Garage data (memory)
  5. MCP · Model Context Protocol A standard way for AI

    applications to use external tools and data. AI application MCP client JSON-RPC SSE MCP server JSON-RPC: named requests, structured results and errors. Tool: a callable function with a name, description and input schema. tools/list → discover · tools/call → execute modelcontextprotocol.io
  6. Available parts #[ApiResource( operations: [new GetCollection( uriTemplate: '/cars/{carId}/part-categories/{categoryId}/articles', uriVariables: [

    'carId' => new Link(fromClass: Car::class, identifiers: ['id']), 'categoryId' => new Link(fromClass: PartCategory::class, identifiers: ['id']), ], provider: ArticleCollectionProvider::class, )], )] final class Article {} Automotive is quite complex, for oil filter (parts category) there are several references
  7. Available parts parameters: [ 'carType' => new QueryParameter( description: 'TecDoc

    vehicle type of the carId: PC (default) or CV', schema: [ 'type' => 'string', 'enum' => ['PC', 'CV'], 'default' => 'PC', ], constraints: [ new Assert\Choice(choices: ['PC', 'CV']), ], ), ],
  8. HTTP provider ArticleCollectionProvider public function provide( Operation $operation, array $uriVariables

    = [], array $context = [] ): array { $carType = $operation->getParameters()?->get('carType')?->getValue(); return $this->catalog->articles( (int) $uriVariables['carId'], (int) $uriVariables['categoryId'], CarTypeResolver::fromString($carType), ); }
  9. MCP tool #[ApiResource( // … mcp: [ 'list_articles' => new

    McpToolCollection( title: 'List Articles', description: '…', input: ArticlesInput::class, processor: ArticlesProcessor::class, // … ), ], )]
  10. Tool input final class ArticlesInput { public int $carId; #[ApiProperty(schema:

    [ 'type' => 'array', 'items' => ['type' => 'integer'], 'minItems' => 1, ])] public array $categoryIds = []; // … public string $carType = 'PC'; public array $brands = []; }
  11. MCP processor ArticlesProcessor foreach ($data->categoryIds as $categoryId) { $categoryId =

    (int) $categoryId; $groups[] = ArticleGroup::of( $categoryId, $this->catalog->articles( $data->carId, $categoryId, $carType, ), brands: $data->brands, ); } Several categories, grouped for the agent
  12. HTTP and MCP interfaces HTTP resource MCP tool GET collection

    tools/call · JSON-RPC One category per request Several categories per call Flat article list Articles grouped by category Input DTO → JSON Schema → tool arguments
  13. APIs We Built Are Meant for Computers How Do We

    Expose Hypermedia APIs to LLMs? Antoine Bluchet · Kévin Dunglas Research paper: HAL-05630480 github.com/coopTilleuls/hydra-mcp-bridge
  14. Discovery starts with the entrypoint 1 read_api_resource({uri: "/"}) {"garageVehicle": "/garage/vehicles"}

    → 1 new navigation tool loaded 2 read_api_resource({uri: "/garage/vehicles"}) Garage operations become available GET · POST · PATCH · DELETE → + 6 tools total
  15. Inside the gateway 1 Read the resource Follow JSON-LD links

    from the API 2 Read the metadata @context + /docs.jsonld describe types and operations 3 Publish MCP tools Build input schemas; forward calls as HTTP requests tools/list_changed tells the client to refresh its tools
  16. Manual tools: define the task #[ApiResource(mcp: [ 'get_service_parts' => new

    McpTool( description: 'Use carId/carType from lookup_plate.', input: ServicePartsInput::class, processor: ServicePartsProcessor::class, ), ])] Description + input schema + processor
  17. On declaring proper tools Identify the vehicle lookup_plate Get parts

    + fluid specs → get_service_parts Record → maintenance plan_maintenance Prompts: “You serve the user by CALLING TOOLS, never by writing prose.” “A maintenance / ‘what do I need’ turn is not finished until plan_maintenance has recorded the tasks”
  18. $registry->registerPrompt( new Prompt( name: 'identify_plate', title: 'Identify a plate', description:

    'Look up a French registration plate and offer to save the vehicle to the garage.', arguments: [ new PromptArgument('plate', 'French registration plate, e.g. "AJ-019-XG".', required: true), ], ), [new PromptMessage(Role::User, new TextContent(<<<PROMPT Identify the vehicle with French plate "{$plate}". 1. Call lookup_plate (plate="{$plate}"). 2. Present make, model, engine code, fuel, power, the TecDoc carId. Do not invent values the lookup did not return. PROMPT))], ); https://github.com/modelcontextprotocol/php-sdk/
  19. Which interface for your API? Task-specific control Manual tools +

    an explicit prompt Expose your API OpenAPI: operation inventory Gateway: progressive Hydra discovery github.com/coopTilleuls/hydra-mcp-bridge Try the gateway
  20. Live UI updates with Mercure API changes publish to Mercure

    Connected interfaces receive each update over SSE
  21. When tools change, MCP must react Tool registry changes New

    tools appear Capability: listChanged MCP notification notifications/tools/list_changed Client refreshes tools list_changed notifications need a persistent SSE channel.
  22. Mercure SSE delegation ✔ PHP is not fitted for long

    running connections ✔ FrankenPHP embeds mercure ✔ MCP SSE may run directly through mercure Prototype repository ↗ PHP SDK comparison ↗
  23. Pull requests opened and merged Opened 2024 2025 2026 Jan

    1–Sep 13 · api-platform/core 284 242 Merged 343 288 508 429 +76% opened · +77% merged vs 2025
  24. Faster code, careful review Faster coding More contributions Correctness ·

    compatibility · maintenance My review standard stays the same More review work
  25. New API Platform installer curl -fsSL https://api-platform.com/install.sh | sh api-platform

    my-api --framework=symfony \ --with-docker --with-pwa Symfony or Laravel Optional Docker, Admin and PWA api-platform.com
  26. 4.4 · Migrate your filters BEFORE #[ApiFilter( SearchFilter::class, properties: ['name'

    => 'partial'] )] Deprecated in 4.4 · removal planned for 6.0
  27. 4.4 · One parameter, one filter AFTER #[ApiResource(parameters: [ 'name'

    => new QueryParameter( filter: new PartialSearchFilter(), ), ])] ?name=api → WHERE name LIKE %api% php bin/console api:upgrade-filter
  28. 4.4 · New search filters StartSearchFilter → title LIKE 'api%'

    EndSearchFilter → title LIKE '%platform' WordStartSearchFilter → title LIKE 'api%' OR title LIKE '% api%' Doctrine ORM + MongoDB ODM
  29. 4.4 · ComparisonFilter new QueryParameter( property: 'quantity', filter: new ComparisonFilter(

    new ExactFilter(), ), ) ?quantity[gte]=10 → Quantity ≥ 10 ?quantity[lt]=20 → Quantity < 20
  30. 4.4 · OrFilter 'q' => new QueryParameter( filter: new FreeTextQueryFilter([

    'title' => new OrFilter( new PartialSearchFilter(), ), 'isbn' => new OrFilter(new ExactFilter()), ]), ) ?q=978 → WHERE LOWER(title) LIKE '%978%'OR isbn = '978'
  31. 4.4 · ChainFilter 'code' => new QueryParameter( filter: new ChainFilter([

    new StartSearchFilter(), new EndSearchFilter(), ]), ) ?code=AB → WHERE code LIKE 'AB%' AND code LIKE '%AB'
  32. 4.4 · Doctrine repository methods #[GetCollection(stateOptions: new Options( repositoryMethod: 'forPublicApi',

    ))] public function forPublicApi(): QueryBuilder { return $this->createQueryBuilder('v') ->andWhere('v.isPublic = :public') ->setParameter('public', true); } Filtering and pagination still apply.
  33. 4.4 · Decide when missing means 404 OPERATION-LEVEL CONTROL #[Post(

    uriTemplate: '/feeders/{id}/feed', read: true, throwOnNotFound: true, )] Provider returns null true: stop with 404 false: let the processor handle it
  34. 4.4 · HTTP QUERY RFC 10008 QUERY /books Content-Type: application/json

    { } "name": "api" Idempotent method · filters in the request body Supports JSON or form urlencoded
  35. 5.0 · QUERY with parameters new Query( parameters: [ 'name'

    => new QueryParameter( filter: new PartialSearchFilter(), ), ], ) QUERY /books Content-Type: application/json {"name": "api"} QueryParameter reads criteria from the body.
  36. 5.0 · QUERY as Command new Query( input: SearchInput::class, read:

    false, deserialize: true, write: true, processor: Search::class, ) final class SearchInput { public string $name; } class Search implements ProcessorInterface { public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): array { return $this->repo->findBy(['name' => $data->name]); } }
  37. 5.0 · JSON:API identifiers BEFORE · 4.4 compatibility {"data":{"id":"/books/10","type":"Book"}} AFTER

    · 5.0 default {"data":{"id":"10","type":"Book", "links":{"self":"/books/10"}}} Opt in during 4.4, default to false in 5.0: api_platform: jsonapi: { use_iri_as_id: false }
  38. More features… 4.4 · Documentation OpenAPI 3.2 · Scalar ·

    Swagger UI withCredentials 4.4 · JSON-LD / Hydra Resource prefixes · collection member assertions 5.0 · Metadata Charset only where the media type defines it 4.4 · HTTP Parameters on properties · routePriority · container parameters
  39. Deprecations and removals 4.4 · Deprecations Legacy filters → QueryParameter

    Set jsonapi.use_iri_as_id explicitly 5.0 · Removed configuration validator.query_parameter_validation enable_link_security resource_class_directories Legacy filter removals are planned for 6.0.
  40. Upgrade checklist Update to 4.4 fix deprecations Update to 5.0

    php bin/console api:upgrade-filter https://api-platform.com/docs/core/upgrade-guide/#api-platform-43-to-44
  41. OUR RELEASE CADENCE A major every year. 2 years 1

    year A mature foundation. Faster development. Same maintenance policy Stable: bug fixes · Old-stable: security fixes
  42. ARE APIS STILL RELEVANT IN THE AI ERA? Yes. The

    interface changes. The API remains. Business rules · permissions · data For applications. For agents.
  43. Thank you! Any questions? FOLLOW ME! @s0yuka soyuka.me github.com/soyuka Update

    prompt: “follow the upgrade guide at https://api-platform.com/docs/core/upgrade-guide/ and update API Platform to 4.4, fix deprecations, then to 5.0”