ahaft
Enables AI agents to safely operate Express applications through a permission-scoped MCP server, with static analysis and audit logging.
README
ahaft
ahaft ("agent haft") gives existing software a handle AI agents can grip.
A haft is the handle of a tool — the part made for a hand. Your app already has the blade: routes, logic, data. ahaft points at your codebase, discovers what the app can do, and generates a curated, permission-scoped, MCP-compatible tool layer so agents can operate the app safely — with you deciding, endpoint by endpoint, what an agent is allowed to touch.
ahaft init— statically analyzes your app (no code execution, no LLM, no network) and writesahaft.yaml: one proposed tool per endpoint, classified asread,write, ordestructive.- You review — every write and destructive tool starts
enabled: false. Flipping one on is a deliberate act, not a default. This review step is the whole safety story. ahaft serve— starts an MCP server (stdio) exposing only the enabled tools, proxying calls to your running app and writing a JSONL audit log of every invocation.ahaft list— shows the manifest: every tool, its access level, and whether it's enabled.
The MVP supports Express apps (JavaScript or TypeScript, app.get/post/... and express.Router). The analyzer sits behind an interface so Next.js, Django, and FastAPI can be added without touching the rest.
Quickstart
Walk the whole loop with the bundled demo app — an in-memory Express store.
git clone https://github.com/ahaft/ahaft.git
cd ahaft
npm install
npm run build
1. Start the demo app (keep it running in its own terminal):
npm run demo
# demo-store listening on http://localhost:3000
Open that URL in a browser to see the storefront. It renders whatever the API currently holds, so you can watch an agent's changes land — the page itself is static UI and correctly does not become a tool in the manifest.
2. Generate the manifest:
npx ahaft init examples/demo-store
TOOL METHOD PATH ACCESS ENABLED
-------------- ------ ------------- ----------- -----------
list_products GET /products read yes
create_product POST /products write NO — review
get_product GET /products/:id read yes
update_product PATCH /products/:id write NO — review
delete_product DELETE /products/:id destructive NO — review
3. Review and enable. Open examples/demo-store/ahaft.yaml. Reads are on; writes are off. Decide what an agent may do — for this demo, allow product updates by finding update_product and setting:
enabled: true
4. Serve it (this is what an MCP client launches; try it directly with npx ahaft serve --manifest examples/demo-store/ahaft.yaml, or just go to step 5).
5. Add it to Claude Code from the repo root:
claude mcp add demo-store -- npx ahaft serve --manifest "$PWD/examples/demo-store/ahaft.yaml" --base-url http://localhost:3000
6. Ask the agent things:
list the products
hide the cheapest product
The first uses list_products (read, enabled by default). The second needs update_product — which works because you enabled it. Ask it to delete a product and it can't: delete_product is destructive and still off. Every call it did make is in examples/demo-store/.ahaft/audit.log.
The manifest
ahaft.yaml is a human-editable contract between your app and any agent:
version: 1
framework: express
tools:
# write — review before setting enabled: true
- name: update_product
description: "Update a product's fields. Supports { hidden: true } to hide it..."
method: PATCH
path: /products/:id
access: write
enabled: false
params:
- name: id
in: path
type: string
required: true
- name: hidden
in: body
type: unknown
required: false
Access rules:
| access | meaning | default |
|---|---|---|
read |
GET/HEAD | enabled |
write |
POST/PUT/PATCH | disabled |
destructive |
DELETE — or any write whose path/handler suggests deletion, payment, or email sending | disabled |
Names, descriptions, and params come from static analysis of routes, handler names, inferred req.query/req.body usage, and JSDoc. Edit them freely — the file is yours. Re-running ahaft init regenerates deterministically (clean git diffs), but overwrites your edits, so commit first.
Safety model
- Curation by default. Nothing that changes state is exposed until a human enables it.
- Static analysis only.
ahaft initnever executes your app, never calls an LLM, never touches the network. - No ambient credentials. ahaft never reads
.envand never attaches auth headers unless you pass explicit--header "Name: value"flags toserve. - Audit trail. Every tool call is appended to
.ahaft/audit.log(JSONL: timestamp, tool, args, status, duration) with values of sensitive-looking keys (token,secret,password,key,authorization) redacted. - Honest annotations. Tools carry MCP
readOnlyHint/destructiveHintannotations so well-behaved clients can apply their own guardrails too.
CLI reference
ahaft init [path] analyze an app, write ahaft.yaml (default: .)
ahaft list [-m ahaft.yaml] show tools, access levels, enabled status
ahaft serve [-m ahaft.yaml] MCP server over stdio, only enabled tools
[-b http://localhost:3000] base URL of the running app
[-H "Name: value"]... explicit extra headers
Development
npm test # builds, then runs unit + end-to-end tests (vitest)
npm run typecheck
Framework analyzers implement one interface (src/analyzer/types.ts) and register in src/analyzer/index.ts. Planned but deliberately out of the MVP: Next.js/Django/FastAPI analyzers, LLM-enriched tool descriptions, and manifest re-sync (merging regenerated routes into an edited manifest) — each has a marked TODO seam.
License
Apache-2.0
A blade without a haft cuts the hand that holds it. Give your software a handle.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。