← ClaudeAtlas

agent-interfacelisted

Expose an existing route to AI agents as an MCP tool via route `.agent()` metadata. Use when the user asks to "expose this to agents", "make an MCP tool", "agent tool", "agent interface", "let Claude call this endpoint", or asks which of the app's routes agents can already reach.
gurenjs/guren · ★ 30 · AI & Automation · score 77
Install: claude install-skill gurenjs/guren
# Agent Interface Skill Guren derives agent tools from the contracts a route already carries — its schemas, its model bindings, its authorization. Nothing is written twice: **there is no tool class and no second JSON schema to hand-write.** Your whole job is deciding which routes to expose and making sure the contracts they already have are complete. ## Exposing a route Declare `agent` metadata on the route. Either form works: ```typescript import { Router } from '@guren/core' router.post('/posts', { name: 'posts.store', body: CreatePostSchema, output: PostOutputSchema, agent: { description: 'Create a blog post as the authenticated user.' }, }, [PostController, 'store']) router .post('/posts', { body: CreatePostSchema }, [PostController, 'store']) .name('posts.store') .agent({ description: 'Create a blog post as the authenticated user.' }) ``` **Argument order trap:** the options object is the **second** argument and the handler is the **last** — `router.post(path, options, handler)`. Writing `router.post(path, handler, options)` registers the options object as the handler. The router recognizes an options object by its keys, `agent` included, so an object carrying only `agent` is still options and not a handler. **One declaration per route.** Declaring `agent` in the route options *and* chaining `.agent()` throws at registration ("already carries agent metadata"). It is a refusal rather than a merge on purpose: a silent overwrite would drop security-rel