Skip to content

feat(server): REST routes per tool; API reference generated from the tool registry - #107

Merged
ac12644 merged 1 commit into
mainfrom
rest-tool-routes
Oct 22, 2026
Merged

ac12644 merged 1 commit into
mainfrom
rest-tool-routes

Conversation

@ac12644

@ac12644 ac12644 commented Oct 22, 2026

Copy link
Copy Markdown
Owner

The API Reference had one generic POST /mcp operation with an untyped JSON-RPC body, so no tool's arguments or response were visible. OpenAPI can't describe 32 tools on one path, so this adds real routes.

REST routes (src/vayl/api/rest.py, mounted at /v1 behind the same AuthMiddleware, body cap, rate limit and request IDs as /mcp):

  • POST /v1/tools/<name>: JSON arguments in, {"result": "..."} out
  • GET /v1/tools: the tools with their JSON Schemas (same as MCP tools/list)
  • calls go through FastMCP's call_tool, so validation, _guard capability/scope checks, audit and metrics are identical to MCP
  • 400 non-object body · 401 no key · 403 missing capability or scope · 404 unknown tool · 422 bad arguments (pydantic's message in detail)

Generated reference:

  • openapi/base.yaml: the hand-written parts (/mcp, probes, metrics, shared components)
  • openapi/generate.py: writes openapi/vayl-server.yaml (one typed operation per tool, with its capability from _guard, MCP annotations and example) and docs/api-reference/tools/*.md (one page per group, each tool an openapi-operation block like the MCP endpoint page)
  • openapi/capture_examples.py: drives all 32 tools through the REST routes with a real model and saves the examples; every example is a real 200 response, API keys redacted
  • tests: the spec lists exactly the served routes plus one op per registered tool; generate.py --check must pass
  • the spec validates as OpenAPI 3.1 (openapi-spec-validator 0.7.1)

Docs: API Reference home rewritten for developers (curl quick start with real output, endpoint table, auth, status codes, REST vs MCP); "Calling Vayl from code", the MCP tools overview and HTTP endpoints mention the REST routes.

Found while capturing, not fixed here: in about 1 of 8 runs, "Warfarin stopped today. Started apixaban…" was stored as an ADD of apixaban plus an ARCHIVE of the stop, which skips the approval gate and leaves warfarin active. Tracked separately.

…tool registry

vayl-server serves POST /v1/tools/<name> and GET /v1/tools behind the same
auth as /mcp. Calls go through FastMCP's call_tool, so validation, the
_guard capability and scope checks, audit and metrics match MCP exactly;
errors map to 400/401/403/404/422.

openapi/generate.py builds openapi/vayl-server.yaml (from base.yaml plus
one typed operation per tool: schema, capability, annotations) and the
API Reference tool pages. openapi/capture_examples.py records a real
request/response for all 32 tools (fictional patient, clinical preset,
gpt-6-luna). A test fails if the committed spec or pages are stale.
@ac12644
ac12644 merged commit dd4af87 into main Oct 22, 2026
9 checks passed
@ac12644
ac12644 deleted the rest-tool-routes branch October 22, 2026 05:06
@ac12644 ac12644 mentioned this pull request Oct 22, 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.

1 participant