Overview

Connect your AI Colleague to any third-party application that speaks the Model Context Protocol (MCP) — SAP Joule, Microsoft Copilot, IBM watsonx Orchestrate, a custom agent, an internal LLM app, or any MCP-compatible client. Once connected, your application can talk to your Leena AI Colleague in plain natural language and get back grounded, permission-aware answers and actions, exactly as if the user were chatting in the Leena web app.

For deterministic, machine-to-machine automation, Leena also supports A2A (Agent-to-Agent) access — a bot-scoped, OAuth-protected surface that lets an external agent or system trigger a specific AOP by name and poll its execution status, without a human user in the loop. MCP and A2A share the same enablement flow and the same OAuth application, so you configure credentials once and use whichever surface fits your integration.


1. Overview

The Leena MCP Server turns your AI Colleague into a sub-agent that any MCP client can use as a single, intelligent tool.

Instead of exposing dozens of individual tools, forms, and workflows to the connecting application, Leena exposes one conversational surface. Your third-party app sends a natural-language instruction; the AI Colleague decides — on its own — which tools, knowledge sources, approval workflows, case-management actions, or organisation-specific AOPs to run, and returns the result. This is the same "agent brain" that powers the Leena web app, Slack, and Teams — only reachable programmatically.

What you can do once connected:

  • Ask HR, IT, and policy questions and get answers grounded in your knowledge base, complete with clickable, authenticated source links.
  • Trigger approval workflows, case creation, and custom AOPs through conversation.
  • Carry on stateful, multi-turn conversations — the agent remembers the thread, pauses to ask follow-up questions, and resumes paused workflows automatically.

Who it's for: teams who want to embed their Leena AI Colleague inside another assistant or build a custom front-end, rather than using Leena's own channels. The consumer on the other end is typically another AI/LLM application, not a human clicking buttons — so the entire surface is text-in, text-out.

Key idea to keep in mind: every MCP interaction is tied to a specific Leena end-user. The MCP connection authenticates as a person, so the AI Colleague applies that user's permissions, audience rules, and data access — just like any other channel. It is not an anonymous or "service account" firehose into your data. (A2A is the deliberate exception: it authenticates as an application scoped to one AI Colleague — see Section 6.)

MCP or A2A — which one do you need?

Both surfaces are enabled from the same settings page and share one OAuth application, but they serve different integration shapes:

MCPA2A
IdentityA specific, signed-in Leena end-userYour application, scoped to one AI Colleague
Interaction styleConversational — natural language in, the agent decides what to runDeterministic — you name the exact AOP to execute
Best forEmbedding the AI Colleague in another assistant (Joule, Copilot, custom chat)Backend systems, schedulers, and other agents triggering known workflows
Human in the loopYes — supports follow-up questions (input_required)No — runs headless as a System user
Permissions appliedThe signed-in user's permissions and audience rulesBot-level scope enforced by the OAuth token (aic.aop_execute)
StatefulnessMulti-turn threads with memoryOne execution per call; track it via its item ID

Rule of thumb: if a person is on the other end (even indirectly, through another assistant), use MCP. If a system is on the other end and it knows exactly which workflow it wants to run, use A2A.

Why a single orchestrator beats a flat list of tools

There are two ways to expose an enterprise system over MCP. The tool method publishes each capability as its own named tool — one for "search the knowledge base," one for "create a ticket," one per workflow — and expects the connecting app's model to pick and sequence them. The orchestrator method, which Leena uses, publishes a single conversational sub-agent and lets Leena's own orchestrator do the routing. For an enterprise assistant, the orchestrator method is the stronger choice:

  • One stable contract. Your integration depends on three tools that never change. Tools, workflows, and AOPs can be added, renamed, or retired on the Leena side and your connected app keeps working — no re-integration, no broken tool schemas. With a flat tool list, every catalog change is a breaking change for every connected client.
  • The reasoning happens on Leena's side. Choosing the right tool, chaining a multi-step AOP, filling a form, asking a follow-up, and grounding the answer in the knowledge base are all handled by Leena's orchestrator — the model it's tuned for. The connecting app doesn't need to understand dozens of tool schemas or sequence multi-step flows itself.
  • Less for the client's model to get wrong. Exposing many tools bloats the connecting model's tool list, costs tokens, and raises the odds it picks the wrong tool or the wrong arguments. One conversational entry point keeps the client focused and the failure modes simple.
  • Governance stays server-side. Permissions, audience targeting, guardrails (PII detection, moderation, jailbreak detection), citations, and audit logging are enforced once, inside Leena, for every request. A flat tool list would force each client to re-implement or be trusted to respect these — which doesn't scale and isn't safe.
  • Grounding and citations are preserved. Answers come back already grounded, with authenticated source links attached. A raw tool call hands back data that the client then has to assemble, cite, and secure on its own.
  • Statefulness is built in. Threads, multi-turn memory, and automatic resumption of paused workflows live in the orchestrator. A flat tool list is inherently stateless and pushes all of that complexity onto the client.
Orchestrator method (Leena)Flat tool-list method
Integration surface3 stable toolsGrows and shifts with every tool
Who routes and reasonsLeena's orchestratorThe connecting app's model
Adding a new toolWorks automaticallyBreaking change for clients
Governance and guardrailsEnforced server-sideRe-implemented per client
Grounding and citationsBuilt inClient's responsibility
State and multi-turnBuilt inClient's responsibility
Control over the exact toolIndirect (natural-language intent)Direct (named calls)

In short, the tool method gives a client deterministic, low-level control at the cost of a brittle, high-maintenance, governance-heavy integration. The orchestrator method trades that fine-grained control for a single durable surface that stays correct, secure, and grounded as your AI Colleague evolves. And when you do need deterministic "run exactly this workflow" control from a machine, that's precisely what A2A is for (Section 6) — so you're not forced to bend one surface to do the other's job.


2. Authentication

Supported method: OAuth 2.0

Both MCP and A2A use OAuth 2.0, with the access token sent as a Bearer token in the Authorization header on every call. There is no API-key mode and no anonymous access.

The OAuth roles line up like this:

  • Leena MCP/A2A server — the resource server. It validates the bearer token on each request. For MCP, the token resolves to a specific AI Colleague and end-user. For A2A, the token resolves to a specific AI Colleague and a set of granted scopes.
  • Leena's chat/auth service — the authorization server. This is where tokens are issued (and, for MCP, where users sign in). The authorization, token, and refresh URLs on the settings page all point here.
  • Your third-party app — the OAuth client. It holds the Client ID and secret issued from the dashboard and drives the token flow.

MCP and A2A share the same OAuth application for a given AI Colleague. Enabling either one provisions it automatically; you configure credentials once and both surfaces accept them.

Discovery: automatic where supported

Leena publishes standard OAuth discovery metadata, so a compliant MCP client pointed at the MCP URL can find the sign-in endpoints on its own — you don't have to wire them by hand. For clients that need the endpoints spelled out (for example, a "manual OAuth" configuration), the authorization, token, and refresh URLs are all listed on the settings page.

Two identity models — and why it matters

The two surfaces intentionally authenticate different principals:

MCP: identity is per-user. A token represents the person who signed in, not your application in the abstract. On every call, Leena resolves the token to that user and runs the request under their permissions, audience membership, and data scope. In practice:

  • The same connection returns different results for different users — each sees only the data they're entitled to.
  • There is no service-account or machine-to-machine bulk access over MCP; the connecting principal is always a real, provisioned AI Colleague user.
  • Guardrails and audit logging apply exactly as they do on any human channel.

A2A: identity is per-application, scoped to one bot. The token carries the AI Colleague's ID and a set of scopes (the standard execution scope is aic.aop_execute). The bot identity comes from the token itself — it is never supplied by the caller in the request — so a token issued for one AI Colleague can never trigger workflows on another. Executions run as a synthetic System user in a dedicated thread, isolated from any employee's chat history.

Prerequisite

Authentication only succeeds when the corresponding surface is enabled for that AI Colleague (see Section 4): MCP server for MCP connections, A2A for A2A calls. Until the toggle is on, even valid tokens are rejected.


3. The MCP Tools

When your application connects over MCP, the Leena MCP Server advertises exactly three tools. You do not see individual Leena tools as separate MCP tools — you only see these three, and the agent routes everything internally.

send_message

The primary tool. Sends a natural-language instruction to the AI Colleague.

  • Start a new conversation: call send_message with just your message. A new conversation thread is created and its ID is returned.
  • Continue a conversation: pass the thread_id from a previous response along with the new message. The agent picks up where it left off and automatically resumes any paused workflow.

send_message waits for the agent to finish and then returns one of these outcomes:

StatusWhat it meansWhat your app should do
completedThe agent finished and produced a final answer (in response).Show the answer to the user. If it includes a Sources section, include those links verbatim.
input_requiredThe agent paused to ask the user something (prompt in input_required).Relay the prompt to the user, then call send_message again with the same thread_id and the user's reply as the message.
runningThe agent is still working after the wait window elapsed.Poll using request_details(thread_id) until it reaches a final state.
failedSomething went wrong (reason in error).Surface the error.
canceledThe request was stopped.No action needed.

While the agent is working, send_message streams lightweight progress updates roughly every 10 seconds so your client knows it's alive.

Source links are special. When a response contains a Sources section with markdown links, those are authenticated deep links the user can click to open the underlying article (often jumping straight to the highlighted passage). Always pass them through to the user exactly as provided — don't drop or rewrite them.

request_details

Checks the current state of a conversation without sending a new message. You pass a thread_id (and optionally a specific request_id) and get back the same status shape as send_message. This is how you poll a long-running request after send_message returns running.

cancel

Stops a running or paused request in a thread. Pass the thread_id. Returns canceled on success, or tells you the request was already finished.

The conversation model in one line

Threads are stateful. Start without a thread_id, continue with the one you were given, poll with request_details, and stop with cancel. Handle input_required by asking the user and replying on the same thread.


4. How to Enable It and Generate Credentials

Everything is configured in the dashboard. You'll need a Leena admin/dashboard user to do this.

Step 1 — Turn on MCP and/or A2A

  1. Open your AI Colleague's Settings → Orchestrator Settings.
  2. Find the MCP server and A2A toggles (the outbound-exposure options, not the MCP client).
  3. Toggle on the surface(s) you need — MCP for conversational sub-agent access, A2A for deterministic workflow execution. You can enable one or both.

Turning either toggle on does two things: it allows external clients to authenticate against this AI Colleague on that surface, and it automatically provisions an OAuth application behind the scenes. If that provisioning fails for any reason, the toggle is rolled back automatically — so if it stays on, your OAuth app exists.

MCP and A2A share the same OAuth application for a given AI Colleague. Enabling either one provisions it; you don't set up credentials twice. Turning one toggle off while the other stays on keeps the app alive; only when both are off is the OAuth app deleted.

Step 2 — Read your connection details

Once enabled, the settings page shows everything your third-party app needs:

  • MCP URL — the endpoint your MCP client points at (ends in /mcp/). Shown when MCP is enabled.
  • A2A endpoint URL — the endpoint for A2A calls, unique to this AI Colleague (of the form .../a2a/bots/{bot_id}/rpc). Shown when A2A is enabled.
  • Client ID — the OAuth client identifier for your AI Colleague (shared by both surfaces).
  • OAuth endpoints — the authorization URL, token URL, and refresh URL. (These point to Leena's chat/auth service, which acts as the OAuth authorization server.)
  • Redirect URIs — currently registered (empty until you add one).
  • Client secret status — whether a secret exists and when it expires.

Step 3 — Register your redirect URI(s)

If your MCP client uses the interactive OAuth login flow (most do), you must register the redirect URI(s) it will use. (Pure A2A integrations that use a non-interactive token flow don't need this step.)

  • Redirect URIs must use HTTPS.
  • The only exception is loopback addresses (localhost, 127.0.0.1, [::1]) over plain HTTP — useful for local development and desktop MCP clients.
  • Any other plain-HTTP URI is rejected.

Add your app's callback URL(s) in the redirect-URI field and save.

Step 4 — Generate a client secret

Click Generate secret on the settings page.

  • The full secret is shown exactly once, at generation time. Copy it immediately and store it securely — Leena keeps only a hint/reference afterward, never the full value.
  • The secret has an expiry date (shown on the settings page). Plan to rotate it before it lapses; generating a new secret replaces the old one.
  • The same secret authenticates both MCP and A2A.

Step 5 — Connect from your third-party app

For MCP: in your MCP client, configure a new MCP server using:

  • Server URL: the MCP URL from Step 2.
  • Authentication: OAuth, using the Client ID, client secret, and the authorization/token URLs from the dashboard.

Leena follows standard OAuth discovery: a well-behaved MCP client pointed at the MCP URL can discover the authorization server automatically and walk the user through login. After the user logs in, the client receives a token and is connected. The connection is bound to that user's identity — the AI Colleague will only ever see and do what that user is allowed to.

For A2A: obtain an OAuth access token from the token URL using your Client ID and secret, then call the A2A execution APIs (Section 6) with the token as a bearer header. The token is bound to this AI Colleague and must carry the aic.aop_execute scope.

Turning it off

Toggling a surface off disables external access on that surface. When both MCP and A2A are off, the associated OAuth application is deleted and all credentials are invalidated. Re-enabling provisions a fresh app — you'll need to generate a new secret and update your clients.


5. MCP Limitations and How It Differs from Other Leena Channels

The MCP server runs your request through the same orchestration engine as the Leena web app — same tools, same AOPs, same knowledge base, same case management, same guardrails, and the same audience/permission enforcement. Functionally, the capabilities are identical. What differs is the surface: MCP is a text-only, programmatic channel meant to be driven by another application, whereas web, Slack, and Teams are rich, human-facing channels.

Here's what that means in practice.

Everything comes back as text

Leena's human channels render rich interactive elements natively — forms, tables, charts, carousels, auth cards, and confirmation cards. Over MCP there is no UI to render these, so the agent returns plain text / markdown. Your consuming application is responsible for presenting it.

Forms and file uploads fall back to web links

The MCP channel has no composer, so a user cannot attach files inline the way they can in the web or Slack chat box. When a tool needs a file upload or a structured form, the agent returns a pre-filled webview link instead — the user opens that link in a browser to complete the form or attach the file, then the conversation continues. This is the same fallback used for phone voice calls. (Web, Slack, and Teams support inline attachments directly.)

Long-running work needs polling

For quick answers, send_message returns the final result in a single call. But the agent only waits a bounded amount of time (around 5 minutes) before returning running. Long workflows and AOPs will exceed that, so your app must poll with request_details until the request reaches a terminal state. Human channels handle this invisibly with live UI updates; over MCP you orchestrate the polling.

Follow-up questions are your app's responsibility

When the agent needs more information it returns input_required with a prompt. In the web app, the user just sees the question and types back. Over MCP, your application must relay that prompt to the user and send the answer back on the same thread. Nothing happens automatically until you do.

It's per-user, not a service connection

Every MCP call is authenticated as a specific Leena end-user via their bearer token. There is no anonymous or shared "machine" access over MCP. The connecting user must be a valid, provisioned user of that AI Colleague, and they will only get the data and actions their permissions and audience rules allow. This is a deliberate safety property, but it means you can't use MCP as a generic bulk-data API. (If your integration genuinely has no human on the other end, use A2A — Section 6.)

The agent decides; you don't pick tools

Unlike a traditional tool API where you call a named endpoint, MCP gives you one conversational entry point. You describe what you want in natural language and the AI Colleague chooses the tool/workflow. You gain the agent's reasoning, but you give up direct, deterministic "call exactly this function" control. When you need that control from a machine, A2A's named-AOP execution is the right surface.

Credential hygiene

The client secret is shown once and expires. If you lose it you must generate a new one (which invalidates the old), and you must rotate before expiry to avoid an outage. Redirect URIs are restricted to HTTPS (plus loopback for local dev).

Quick comparison

AspectMCP serverWeb / Slack / Teams
Primary consumerAnother app / AI clientA human
OutputPlain text / markdownRich rendered UI elements
Forms & attachmentsWebview-link fallbackInline in the chat composer
Long-running requestsYour app polls for statusLive UI updates, no polling
Follow-up promptsYour app relays themHandled in the chat UI
IdentityPer-user OAuth bearer tokenThe signed-in channel user
Tools exposedOne sub-agent (3 tools)One conversational surface
Underlying engineSame orchestration brainSame orchestration brain

6. A2A (Agent-to-Agent) Support

A2A is the surface for headless, deterministic automation: an external system — a scheduler, a backend service, or another AI agent — triggers a specific, named AOP on your AI Colleague and tracks its execution to completion. There is no conversation, no human sign-in, and no natural-language routing: your system says exactly which workflow to run, and Leena runs it.

How it fits together

  1. Enable A2A in Orchestrator Settings (Section 4). This provisions (or reuses) the shared OAuth application and exposes your AI Colleague's A2A endpoint URL on the settings page.
  2. Obtain a token from the token URL using your Client ID and secret. The token is issued for this specific AI Colleague and must carry the aic.aop_execute scope.
  3. Trigger an execution with a single API call, naming the AOP and optionally passing context.
  4. Poll for status using the item ID returned at initiation, until the execution reaches a terminal state.

Triggering an execution

POST /v1/external/aop/execute
Authorization: Bearer <OAUTH_TOKEN>
Content-Type: application/json

{
  "aop_id": "invoice_processor_v1",
  "message_to_start": "Process the attached invoice",
  "context": {
    "invoice_id": "INV-2026-001",
    "callback_url": "https://your-system.example.com/webhook"
  }
}
  • aop_id (required): the AOP to run — either its ID or its human-readable identifier. It must belong to the AI Colleague the token was issued for.
  • message_to_start (optional): the initial instruction or trigger message for the run.
  • context (optional): any JSON-serializable object. Leena threads this into the execution as additional instructions, so the AOP's agent logic can read your external data (record IDs, callback URLs, parameters) with a clear audit trail of where it came from.

The call returns immediately with tracking identifiers — the execution itself runs asynchronously in the background:

{
  "aop_item_id": "65b8f1...",
  "request_id": "65b8f2...",
  "run_id": "123",
  "status": "accepted"
}

Polling for status

GET /v1/external/aop/items/{aop_item_id}/status
Authorization: Bearer <OAUTH_TOKEN>
{
  "aop_item_id": "65b8f1...",
  "reference_id": "EXE000042",
  "status": "completed",
  "initiated_at": "2026-07-02T10:00:00Z",
  "completed_at": "2026-07-02T10:05:00Z"
}
StatusWhat it means
in_progressThe agent is currently executing the AOP.
completedThe execution finished successfully.
failedAn error occurred during execution.
pausedThe execution is waiting on an external trigger, callback, or approval.
abortedThe execution was stopped manually.

Poll until the status is terminal (completed, failed, or aborted). The reference_id (e.g. EXE000042) is the same human-readable execution reference visible in the Leena dashboard, so support and audit conversations can refer to the same run.

Error responses

CodeMeaning
400Malformed request — invalid ID format or a context that isn't JSON-serializable.
401Missing, expired, or invalid token.
403Token is valid but lacks the aic.aop_execute scope.
404The AOP or execution item doesn't exist within this AI Colleague's scope.

Security properties worth knowing

  • Bot scoping is enforced by the token, not the request. The AI Colleague's identity is read from the validated token — the caller never supplies it. A token for Colleague A can never see or trigger anything on Colleague B, even if the caller knows B's AOP IDs.
  • Scope minimization. Tokens carry explicit scopes; the execution surface only accepts aic.aop_execute. Request no more scope than you need.
  • System-user isolation. A2A executions run as a synthetic System user in a dedicated thread — they never mix with, read from, or write into any employee's conversation history.
  • Durable execution. Executions are queued for background processing and survive service restarts; an in-flight run interrupted by a graceful shutdown is re-queued rather than lost.
  • Same credential hygiene as MCP. The shared client secret is shown once, expires, and should be rotated proactively.

A2A limitations

  • One execution per call. There is no multi-turn thread. If a run pauses (paused), it resumes via the workflow's own callbacks/approvals — not via a follow-up A2A message.
  • You must know the AOP. A2A does not do natural-language intent routing. If your caller only has a fuzzy natural-language request, use MCP instead and let the orchestrator route it.
  • Status, not transcript. The status API tells you the lifecycle state and timestamps of the run. Rich intermediate output and grounded conversational answers are an MCP-surface feature.
  • No end-user permissions. Because the run is bot-scoped rather than user-scoped, the AOP executes with the access configured for it — design your AOPs accordingly and don't route user-specific, permission-sensitive queries through A2A.

MCP vs A2A quick comparison

AspectMCPA2A
Entry pointMCP URL (.../mcp/), 3 toolsA2A endpoint per bot + execution APIs
You provideNatural-language messageExact AOP identifier (+ optional context)
Who decides what runsLeena's orchestratorYour calling system
IdentitySigned-in end-userYour app, scoped to one AI Colleague (aic.aop_execute)
Runs asThe end-user, with their permissionsSynthetic System user, isolated thread
ConversationStateful, multi-turn, input_required supportedSingle fire-and-poll execution
ResponseGrounded answer with source linksExecution status + reference ID
OAuth app & secretSharedShared

7. Quick Start Checklist

Common (both surfaces)

  1. Enable MCP and/or A2A in Orchestrator Settings.
  2. Copy the Client ID and OAuth endpoints from the settings page.
  3. Generate a client secret and store it securely (shown only once).
  4. Rotate your client secret before it expires.

MCP

  1. Copy the MCP URL and add your app's redirect URI (HTTPS, or loopback for local dev).
  2. Configure your MCP client with the URL + OAuth credentials and log in as a valid AI Colleague user.
  3. Send a send_message with no thread_id to start; reuse the returned thread_id to continue.
  4. Handle input_required (relay to user) and running (poll with request_details).
  5. Pass through any Sources links to the user verbatim.

A2A

  1. Copy the A2A endpoint URL for your AI Colleague.
  2. Obtain a token with the aic.aop_execute scope using your Client ID + secret.
  3. Trigger the AOP with POST /v1/external/aop/execute, passing your aop_id and any context.
  4. Poll GET /v1/external/aop/items/{aop_item_id}/status until the run reaches completed, failed, or aborted.


Did this page help you?