ahaft
Provides a curated, permission-scoped MCP tool layer for Express apps, allowing AI agents to call app endpoints (routes) with read/write/destructive access controls and audit logging.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@ahaftlist the products"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
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 build1. Start the demo app (keep it running in its own terminal):
npm run demo
# demo-store listening on http://localhost:3000Open 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-storeTOOL 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 — review3. 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: true4. 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:30006. 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.
Related MCP server: mcp-devtools
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: falseAccess rules:
access | meaning | default |
| GET/HEAD | enabled |
| POST/PUT/PATCH | disabled |
| 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 headersDevelopment
npm test # builds, then runs unit + end-to-end tests (vitest)
npm run typecheckFramework 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.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
Alicense-qualityAmaintenanceOpen-source MCP proxy that enforces security policies, content scanning, and audit logging between AI agents and tool serversLast updated25AGPL 3.0- AlicenseBqualityDmaintenanceProduction-grade MCP server that gives AI agents safe access to your local dev environment: filesystem, databases, processes, and OpenAPI specs.Last updated15523MIT
- Alicense-qualityCmaintenanceMCP server for AI agent security guardrails. Provides input validation, prompt injection detection, PII redaction, output filtering, policy enforcement, rate limiting, and comprehensive audit logging.Last updated481MIT
- Flicense-qualityBmaintenanceMCP server for auditing AI agent permissions and access by scanning for the trifecta of credentials, injection, and reach without heavy infrastructure.Last updated
Related MCP Connectors
MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.
Security firewall for AI agents — scans MCP calls for injection, secrets, and risks.
Zero-config MCP security scanner for AI-generated apps. 25K+ vulnerability patterns.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/ahaft/ahaft'
If you have feedback or need assistance with the MCP directory API, please join our Discord server