ahaft

ahaft

Enables AI agents to safely operate Express applications through a permission-scoped MCP server, with static analysis and audit logging.

Category
访问服务器

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 writes ahaft.yaml: one proposed tool per endpoint, classified as read, write, or destructive.
  • 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 init never executes your app, never calls an LLM, never touches the network.
  • No ambient credentials. ahaft never reads .env and never attaches auth headers unless you pass explicit --header "Name: value" flags to serve.
  • 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 / destructiveHint annotations 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

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选