8000 feat(mcp): an MCP server for agents to search, read and cite the archive by adeelahmad · Pull Request #43 · adeelahmad/lense · GitHub
[go: up one dir, main page]

Skip to content

feat(mcp): an MCP server for agents to search, read and cite the archive - #43

Merged
adeelahmad merged 3 commits into
mainfrom
claude/mcp-server-au1poj
Oct 2, 2026
Merged

adeelahmad merged 3 commits into
mainfrom
claude/mcp-server-au1poj

Conversation

@adeelahmad
Copy link
Copy Markdown
Owner

Requested by Adeel · project thread

Description

Before: agents had no way into Lens. MCP clients could sign in through the OAuth provider from #18, but there was no MCP server for them to use.

After: add https://<your Lens>/mcp to Claude, Cursor, VS Code or any other MCP client. The client sends you to Lens's consent page, asks for read access only, and the agent then sees exactly what you see: your namespaces, the collections you were given a role on, and the graphs those open.

The tools are read-only:

  • search: moments that were said, shown on screen or written, each with a link to that moment.
  • list_namespaces, list_recordings, list_speakers.
  • get_recording: summary, chapters, top entities and keywords.
  • get_transcript: paged by line or by time window.
  • fetch: the whole text at once.
  • cite: the quote, who said it, the recording, the date, the time and a link, also as Markdown.
  • list_entities, get_entity, explore_graph, find_path: entities and the knowledge graph.

Links open the recording at that moment in the web app (/resources/<id>?t=), on whatever address the client used. Clients that can't sign in can send an API token instead. See docs/mcp.md.

How it works:

  • app/api/mcp.py implements Streamable HTTP without sessions and serves both protocol eras:
    • the initialize handshake (2024-11-05 to 2025-11-25, including batches);
    • 2026-07-28's per-request envelope: params._meta, the MCP-Protocol-Version/Mcp-Method/Mcp-Name header checks, server/discover, resultType, -32020/-32022 errors with their HTTP statuses.
  • Tools in app/api/mcp_tools.py read only through the API's own route functions and Access checks, so permissions match the REST API. That covers partial (collection-role) users and isolated graphs.
  • A 401 from /mcp points at /.well-known/oauth-protected-resource/mcp, which advertises scopes_supported: ["read"].
  • Requests from a browser must come from Lens's own origin or one listed in CORS_ORIGINS.
  • The web app proxies /mcp (app/mcp/route.ts), and auth middleware skips it.
  • mcp (the official SDK) is a dev dependency only, used to test against. Nothing new at runtime.

Motivation and Context

This is the MCP server item from the backlog. Semantic search isn't on main yet, so search is full-text for now. It can gain a mode once semantic search lands.

Steps to reproduce (if appropriate):

Tested end to end on SurrealDB 3.2.4 (server, surrealkv), with the API under uvicorn and the Next.js web app proxying:

  • The official Python MCP SDK client did the full OAuth flow through http://localhost:3000/mcp: 401, protected-resource metadata, dynamic registration, consent, PKCE token, then tools. This worked in auto mode (which settles on 2026-07-28) and in legacy mode (2025-11-25). The consent page showed scope: read.
  • The MCP Inspector CLI (TypeScript SDK) listed tools and called get_transcript using an API token.
  • tests/api/test_mcp.py also passes against the SurrealDB 3.2.4 server (LENS_TEST_SURREAL_URL).

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change; ! in the title)

Checklist:

  • The title is a Conventional Commit.
  • My code follows the code style of this project (ruff, ruff format, mypy, eslint, tsc clean).
  • I added or updated tests: tests/api/test_mcp.py covers auth, the transport, both eras, every tool, access limits and the official SDK client in both eras.
  • My change requires documentation updates, and I have updated docs/ accordingly (docs/mcp.md, plus api, authentication, README and mkdocs nav).
  • Users need more than the title to understand it, so I wrote it under ## Unreleased in CHANGELOG.md.

🤖 Generated with Claude Code

https://claude.ai/code/session_01TUqMhwUCvF9dsP5JzVvMJf


Generated by Claude Code

/mcp speaks Streamable HTTP without sessions, in both protocol eras (the
initialize handshake and 2026-07-28's per-request envelope). Agents sign
in with Lens's OAuth (the 401 names /.well-known/oauth-protected-resource/mcp,
which asks for read only) or an API token, and read what the person can
through the API's own checks. Read-only tools: search, list_namespaces,
list_recordings, list_speakers, get_recording, get_transcript, fetch,
cite, list_entities, get_entity, explore_graph and find_path; moments
carry links that open the recording there in the web app. The web app
proxies /mcp. Tested with the official MCP SDK client in both eras.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TUqMhwUCvF9dsP5JzVvMJf
@adeelahmad adeelahmad self-assigned this Oct 2, 2026
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TUqMhwUCvF9dsP5JzVvMJf
Copy link
Copy Markdown
Owner Author

CI is red on every check (FastAPI embedded, FastAPI SurrealDB server, Next.js, pre-commit, Conventional Commit title), but the failures don't come from this PR. Each job fails 2 to 3 seconds after it is queued, before checkout, and leaves no log or output. The same thing happens on main (#41's runs at 13:58 UTC) and even on the title check, which runs no code. It looks like GitHub's hosted runners aren't available to this repository right now; a billing or spending limit on Actions is the usual cause. #27, still a draft, moves the jobs to a self-hosted runner, but that only helps once a runner is registered and online. I haven't ported it here because it would widen this PR.

Locally, on this head (93f8a7a), everything the CI jobs run passes:

  • ruff, ruff format and mypy are clean.
  • The OpenAPI schema is unchanged.
  • eslint and tsc are clean.
  • The backend suite passes on embedded SurrealDB. The one exception is test_conversion::test_office_and_text_files_become_documents, which fails because this machine's LibreOffice can't read the minimal docx; CI installs its own LibreOffice.
  • tests/api/test_mcp.py and tests/api/test_oauth.py pass against a SurrealDB 3.2.4 server.

I'll re-check once the runners are back.


Generated by Claude Code

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SNbRrpHTCqLewRKdkmd45X
@adeelahmad
adeelahmad merged commit a853c48 into main Oct 2, 2026
0 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

0