Skip to content

Commit 48f70ab

Browse files
authored
Merge pull request #2770 from simonredfern/develop
Glossary Items for OBP MCP and Opey, tags for Trading endpoints, Idempotency in v7.0.0
2 parents 5eff59f + b1d87ce commit 48f70ab

7 files changed

Lines changed: 678 additions & 21 deletions

File tree

obp-api/src/main/scala/code/api/util/ApiTag.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ object ApiTag {
104104
val apiTagCache = ResourceDocTag("Cache")
105105
val apiTagLogCache = ResourceDocTag("Log-Cache")
106106
val apiTagTrading = ResourceDocTag("Trading")
107+
val apiTagTrade = ResourceDocTag("Trade")
107108
val apiTagMarket = ResourceDocTag("Market")
108109

109110
val apiTagApiCollection = ResourceDocTag("Api-Collection")

obp-api/src/main/scala/code/api/util/Glossary.scala

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5316,6 +5316,138 @@ object Glossary extends MdcLoggable {
53165316
|
53175317
""")
53185318

5319+
glossaryItems += GlossaryItem(
5320+
title = "OBP-MCP",
5321+
description =
5322+
s"""
5323+
|# OBP-MCP
5324+
|
5325+
|**OBP-MCP** is a [Model Context Protocol](https://modelcontextprotocol.io) server for the Open Bank Project API. It lets AI assistants (Claude, Opey, IDE agents, custom LLM tooling) discover and call OBP-API endpoints as MCP *tools*, without hard-coding any knowledge of the 600+ endpoints.
5326+
|
5327+
|Repository: [github.com/OpenBankProject/OBP-MCP](https://github.com/OpenBankProject/OBP-MCP)
5328+
|
5329+
|## What it does
5330+
|
5331+
|OBP-MCP is a thin protocol bridge. AI clients speak **MCP** to it; it speaks **HTTPS / REST** to OBP-API on their behalf, attaching the user's OAuth token or Consent-JWT.
5332+
|
5333+
|```
5334+
|┌──────────────────┐ MCP ┌────────────────────────┐ HTTPS ┌──────────────┐
5335+
|│ AI client │ ───────▶ │ OBP-MCP │ ─────────▶ │ OBP-API │
5336+
|│ (Claude, Opey, │ ◀─────── │ (FastMCP server) │ ◀───────── │ │
5337+
|│ IDE agent) │ tools │ │ JSON │ │
5338+
|└──────────────────┘ └────────────────────────┘ └──────────────┘
5339+
|```
5340+
|
5341+
|## Three-step discovery + call (no RAG, no vector DB)
5342+
|
5343+
|OBP-MCP avoids embedding the 4 MB OpenAPI spec into the LLM's context. Instead it exposes three tools that work together:
5344+
|
5345+
|1. **`list_endpoints_by_tag(tags)`** — returns lightweight summaries (~50–100 tokens each) from a local `endpoint_index.json`. Lets the LLM narrow down to a handful of candidate endpoints by tag (e.g. `Account`, `Transaction-Request`, `Consent`).
5346+
|2. **`get_endpoint_schema(endpoint_id)`** — lazy-loads the full OpenAPI schema for one endpoint from a local `endpoint_schemas.json`.
5347+
|3. **`call_obp_api(endpoint_id, path_params, query_params, body, headers)`** — actually executes the HTTP request against the live OBP-API.
5348+
|
5349+
|Two further tools cover the glossary itself: **`list_glossary_terms(search_query)`** and **`get_glossary_term(term_id)`**, backed by a local `glossary_index.json` of 800+ banking terms.
5350+
|
5351+
|## Three kinds of traffic
5352+
|
5353+
|It is important to understand that OBP-MCP is **not** a documentation lookup tool — it makes real, authenticated business calls:
5354+
|
5355+
|- **Documentation / discovery** — `list_endpoints_by_tag`, `get_endpoint_schema`, glossary tools. Served from local JSON, no network.
5356+
|- **Business calls** — `call_obp_api` proxies whatever the endpoint declares: `GET /banks/{BANK_ID}/accounts`, `POST .../transaction-requests/SEPA`, `PUT /accounts/{ACC}/label`, `DELETE /my/consents/{CONSENT_ID}`, etc. Real money / data moves.
5357+
|- **Index refresh** — at startup and on a timer, OBP-MCP re-fetches OBP's resource-docs and swagger to rebuild the local indexes, so discovery stays fast and offline.
5358+
|
5359+
|## Authentication and authorization
5360+
|
5361+
|OBP-MCP supports several modes via the `AUTH_PROVIDER` environment variable for client-to-MCP auth:
5362+
|
5363+
|| Mode | Use case | Notes |
5364+
||----------------|---------------------------------------|----------------------------------------------------|
5365+
|| `bearer-only` | Internal agents (e.g. Opey) | JWT validation only, multi-issuer |
5366+
|| `obp-oidc` | External MCP clients | Full OAuth 2.1 + Dynamic Client Registration |
5367+
|| `keycloak` | External MCP clients | OAuth 2.1 + minimal DCR proxy workaround |
5368+
|| `none` | Development / testing | No auth required |
5369+
|
5370+
|For onward calls to OBP-API, `OBP_AUTHORIZATION_VIA` selects:
5371+
|
5372+
|- **`oauth`** — pulls the access token from the MCP request context and sends `Authorization: Bearer ...`.
5373+
|- **`consent`** — if the endpoint declares any required roles and no `Consent-JWT` is supplied, the tool returns a `consent_required` payload listing the required roles and bank scope, so the client can elicit user approval and come back with a `Consent-JWT` header. Public / no-role endpoints skip this and call straight through.
5374+
|- **`none`** — calls OBP unauthenticated (only useful for genuinely public endpoints).
5375+
|
5376+
|This means the consent flow is enforced at the MCP layer, not just at OBP-API: an agent cannot accidentally call a privileged endpoint without explicit user consent.
5377+
|
5378+
|## Why it matters
5379+
|
5380+
|OBP-MCP is the canonical way to make Open Bank Project endpoints **agent-callable**. Instead of teaching every LLM about every endpoint up front, the LLM is given five generic tools and lets the indexes and schemas guide it to the right call at runtime. The same server can serve internal agents (Opey) and external clients (Claude Desktop, IDE plugins, third-party agents) by switching auth providers.
5381+
|
5382+
|See also: [Opey](/glossary#Opey), [Consent](/glossary#Consent), [Authentication: OAuth 2.0](/glossary#Authentication:-OAuth-2.0).
5383+
|
5384+
""")
5385+
5386+
5387+
glossaryItems += GlossaryItem(
5388+
title = "Opey",
5389+
description =
5390+
s"""
5391+
|# Opey
5392+
|
5393+
|**Opey** (current generation: **Opey II**) is the Open Bank Project's agentic AI assistant — a chatbot that lets users explore and operate the OBP API in natural language. It is built on [LangGraph](https://www.langchain.com/langgraph), is provider-agnostic across LLMs (Anthropic, OpenAI, Ollama), and is the chat backend used by **OBP-Portal**.
5394+
|
5395+
|Repository: [github.com/OpenBankProject/OBP-Opey-II](https://github.com/OpenBankProject/OBP-Opey-II)
5396+
|
5397+
|## Opey is an agent. OBP-MCP is its tool surface.
5398+
|
5399+
|Since [OBP-MCP](/glossary#OBP-MCP) was introduced, Opey has been refactored from a self-contained chatbot (with its own endpoint search, glossary search, and OBP HTTP client baked in) into a focused **agent** that *consumes* OBP-MCP as its primary tool source.
5400+
|
5401+
|Opey's `mcp_servers.json` typically points at a running OBP-MCP instance:
5402+
|
5403+
|```json
5404+
|{
5405+
| "servers": [
5406+
| {
5407+
| "name": "obp",
5408+
| "url": "http://0.0.0.0:9100/mcp",
5409+
| "transport": "http",
5410+
| "requires_auth": true
5411+
| }
5412+
| ]
5413+
|}
5414+
|```
5415+
|
5416+
|The Opey README puts it bluntly: *"As a minimum, Opey should be connected to OBP-MCP, or it won't know anything about the Open Bank Project except for what you put in the system prompt."*
5417+
|
5418+
|## What OBP-MCP took over
5419+
|
5420+
|Subsystems that used to live in Opey are now generic MCP tools any client can use:
5421+
|
5422+
|| Old Opey responsibility | Now in OBP-MCP |
5423+
||--------------------------------------------------------------------------------------|-------------------------------------------------------------|
5424+
|| Endpoint Retrieval RAG pipeline (vector store of swagger, query reformulation, etc.) | `list_endpoints_by_tag` + `get_endpoint_schema` |
5425+
|| Glossary Retrieval RAG pipeline | `list_glossary_terms` + `get_glossary_term` |
5426+
|| `OBPClient` (aiohttp + OAuth + consent JWT) — the actual HTTP layer to OBP-API | `call_obp_api` (`oauth` / `consent` / `none` modes) |
5427+
|| "Which endpoint should I call?" logic baked into the agent | Externalised — any MCP client can now discover and call |
5428+
|
5429+
|## What Opey still uniquely does
5430+
|
5431+
|OBP-MCP is stateless and has no model — it cannot reason, plan, or hold a conversation. Everything below is what makes Opey *Opey*:
5432+
|
5433+
|- **The LLM loop itself.** Opey runs the actual reasoning via a LangGraph state machine (`START → Opey Agent → Tools → Sanitize → Opey → Summarize → END`), with **task follow-through**: when a tool call fails (e.g. missing entitlement), Opey reuses tools to self-correct instead of bouncing the problem back to the user.
5434+
|- **Human-in-the-loop approval — richer than MCP's `consent_required`.** A `ToolRegistry` classifies operations as **SAFE / MODERATE / DANGEROUS / CRITICAL**. An `ApprovalManager` persists "approve once / session / user / workspace" decisions with TTLs. The human-review node only interrupts when truly needed. OBP-MCP just *says* consent is required; Opey decides **how** to ask, **whether** to ask again, and **remembers** the answer.
5435+
|- **Conversation state.** SQLite-backed LangGraph checkpoints (`checkpoints.db`), token counting, automatic summarisation when approaching the model context limit, and graceful degradation in long sessions.
5436+
|- **The streaming chat service.** FastAPI endpoints (`POST /invoke`, `POST /stream` SSE, `POST /submit_approval`, `GET /user/consent`, `GET /status`) — this is what OBP-Portal's chat UI actually talks to. Streaming events are produced by dedicated processors (token, tool, human-review, metadata, end).
5437+
|- **Session, auth, usage.** OBP user session management, consent-JWT parsing for user identification, rate limiting, usage tracking, and an admin-client singleton for system-level operations.
5438+
|- **Domain-tuned system prompt.** Behavioural guidelines such as *Tool-First / Knowledge-Second*, *No Hallucination*, *Proactive Verification*, and *Transparent Errors*. Configurable via `OPEY_SYSTEM_PROMPT`.
5439+
|- **Model abstraction.** Provider-agnostic via `MODEL_PROVIDER` / `MODEL_NAME` — swap Claude for GPT or a local Ollama model without touching the graph. New models are registered in `MODEL_CONFIGS` (`src/agent/utils/model_factory.py`).
5440+
|- **Evaluation framework.** Parameter-sweep experiments over batch size, k-value, retry thresholds; CSV export of precision / recall / latency P50–P99; combined scoring (e.g. 70% recall + 30% speed) to find sweet spots. Something a tool surface like MCP has no concept of.
5441+
|
5442+
|## One-line summary
5443+
|
5444+
|**OBP-MCP is the *tool surface* over OBP-API. Opey II is the *agent* that drives it.** Before OBP-MCP, Opey had to be both. Now OBP-MCP provides discovery and authenticated calls as a generic, multi-client surface (Claude Desktop, IDE plugins, third-party agents can all use it), and Opey II becomes a thinner, more focused orchestrator: planning, approvals, conversation state, streaming, and the chat UX that OBP-Portal embeds.
5445+
|
5446+
|See also: [OBP-MCP](/glossary#OBP-MCP), [Consent](/glossary#Consent), [Authentication: OAuth 2.0](/glossary#Authentication:-OAuth-2.0).
5447+
|
5448+
""")
5449+
5450+
53195451
///////////////////////////////////////////////////////////////////
53205452
// NOTE! Some glossary items are generated in ExampleValue.scala
53215453
//////////////////////////////////////////////////////////////////

obp-api/src/main/scala/code/api/util/http4s/AppsPage.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ object AppsPage {
1919
// For each app-key, which probe endpoints it exposes. Rendered as JSON fields
2020
// (e.g. "status_url") and HTML links (e.g. [status]) in `probeEndpoints` order.
2121
private val appProbes: Map[String, Set[String]] = Map(
22-
"public_obp_portal_url" -> Set("status"),
23-
"public_obp_api_manager_url" -> Set("status"),
22+
"public_obp_portal_url" -> Set("status", "health"),
23+
"public_obp_api_manager_url" -> Set("status", "health"),
2424
"public_obp_oidc_url" -> Set("status"),
2525
"public_obp_api_url" -> Set("status", "health"),
2626
"public_obp_opey_url" -> Set("status", "health"),

0 commit comments

Comments
 (0)