Skip to content

Serve an MCP server for AI agents - #686

Merged
vdolek merged 5 commits into
claude/project-thread-fyo2wffrom
claude/project-thread-fyo2wf-mcp
Oct 30, 2026
Merged

vdolek merged 5 commits into
claude/project-thread-fyo2wffrom
claude/project-thread-fyo2wf-mcp

Conversation

@EvilBrainsBot

@EvilBrainsBot EvilBrainsBot commented Oct 30, 2026 •

Copy link
Copy Markdown
Member

Requested by Martin · project thread

Summary

An MCP server on /mcp for AI agents, authenticated by API token only, with one-time links for file bytes. Stacked on #682, whose branch is the base.

Changes

  • Stateless Streamable HTTP through the official SDK; anything but an API token is 401, a foreign Origin 403; a read-only token lists and calls only read tools.
  • Tools for every SDD-005 resource with the contract DTOs, REST paging and filters; errors are tool errors with the Problem Details title and detail.
  • create_file_upload_link / create_file_download_link on anonymous /api/file-links: 256-bit secret stored hashed, 10 minutes, single use, revoked with its token. The secret travels in the query string, which no log records. The download link tool is a read tool.
  • read_file_text: text formats, PDF, DOCX; 50,000-character pages; 30 MB limit.
  • /mcp requests are logged like /api.
  • SDD-023, SDDs 001/002/005/006/018, README, deploy.

Risks

  • The compose stack requires EVILCASE_HOST, which sets AllowedHosts.
  • CLAUDE.md and the API rule still say every other path serves the frontend: [DECISION] Name /mcp in CLAUDE.md and the API rule #685.
  • If a token expires (rather than being revoked) within 10 minutes of creating a file link, the link stays usable until it expires itself, and SDD-023 only says that revoking a token ends its links.
  • dotnet r could not run here (no pwsh, no .NET 8 runtime); format, build and the changed test classes ran directly.

Closes #673


Generated by Claude Code

@EvilBrainsBot
EvilBrainsBot requested a review from vdolek as a code owner October 30, 2026 20:38
@EvilBrainsBot EvilBrainsBot added the agent-in-progress An agent is working on this pull request label Oct 30, 2026 — with Claude
@EvilBrainsBot EvilBrainsBot self-assigned this Oct 30, 2026

Copy link
Copy Markdown
Member Author

Code Review

  • Using a one-time file link returns a FileLinkConsumeOutcome that the controller maps member by member, instead of null.
  • Dropped ConsumedFileLink.ApiTokenId; nothing read it.
  • The MCP convention test also checks that every tool parameter has a description, as SDD-022 requires.

Generated by Claude Code

@EvilBrainsBot EvilBrainsBot removed the agent-in-progress An agent is working on this pull request label Oct 30, 2026
@EvilBrainsBot EvilBrainsBot added the agent-done Waiting for the owner's review and merge label Oct 30, 2026 — with Claude
@vdolek
vdolek added this pull request to stack #689 October 30, 2026 20:54
A file link row holds the SHA-256 of a 256-bit secret, the user, tenant
and API token that created it, its target and its expiry ten minutes
out. It stands outside the tenant like ApiTokens and has no history.
Using a link deletes it with one DELETE ... RETURNING, so two concurrent
uses spend it once; a hosted service removes expired rows every ten
minutes. Revoking the token, or deleting its user or tenant, cascades to
its links.

The text reader returns a file version's text in pages of 50,000
characters: text formats as stored, the PDF text layer through PdfPig
and DOCX paragraphs through OpenXml. A file over 30 MB is not read.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UovdganawgyqDHGsank6jS
/mcp speaks stateless Streamable HTTP through the official SDK. A policy
re-authenticates with the API token scheme alone, so the browser session
and an access token get 401, and a foreign Origin gets 403 as a cross-site
write does. Every MCP message is a POST, so the read-only boundary lets
/mcp through; filters list only the read tools to a read-only token and
refuse it the others.

The tools call the business services in process with the contract DTOs,
paging and filters of REST, and answer a validation, not-found or
conflict outcome with its Problem Details title and detail as a tool
error. File bytes travel only through one-time links on the anonymous
/api/file-links: a PUT of raw bytes under the upload rules, or a GET sent
with Cache-Control: no-store. The secret travels in the query string
because the request log records only the path; hosting diagnostics and
the SDK are pinned to Warning, below which they log the query string and
tool results. The download link tool is a read tool, so a read-only token
can fetch a file.

Production sets AllowedHosts to its public host, since the link URL takes
the scheme and host of the /mcp request.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UovdganawgyqDHGsank6jS
Consuming a link is a business write that can fail, so it answers with an
outcome enum and the action maps every member. The link's token id had no
reader and is dropped from the consumed link.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UovdganawgyqDHGsank6jS
SDD-022 requires an English description on every tool and every parameter;
the convention test covered the tools only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UovdganawgyqDHGsank6jS
@EvilBrainsBot
EvilBrainsBot force-pushed the claude/project-thread-fyo2wf-mcp branch from 729fc64 to a0d268a Compare October 30, 2026 21:03
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UovdganawgyqDHGsank6jS
@vdolek
vdolek merged commit 60386af into master Oct 30, 2026
2 checks passed
@vdolek
vdolek deleted the claude/project-thread-fyo2wf-mcp branch October 30, 2026 21:49
@github-actions github-actions Bot removed the agent-done Waiting for the owner's review and merge label Oct 30, 2026
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.

API tokens and an MCP server for AI agents and integrations

3 participants