a4i

a4i

MCP server for the Cisco ACI REST API, enabling LLM clients to query and modify fabric configurations via tools like get, post, diff, and merge using an existing logged-in session.

Category
访问服务器

README

aciapi(a4i)

test PyPI

CLI/MCP/Python Library for the Cisco ACI REST API.

  • The token is never written to disk. login hands it to a small per-user daemon that holds it in memory, behind a Unix domain socket, so it survives across short-lived CLI invocations without touching the filesystem.
  • The ACI object model ships with it. search and describe answer what a class is called and what a body may set on it, without an APIC and without a login.
  • merge and diff compare a fabric against an intended configuration, reporting both what the configuration asks for and the fabric lacks, and what the fabric carries and the configuration never mentions.

Install

pip install a4i

Shell completion is printed to standard output; add one line to your shell's startup file:

eval "$(a4i generate-shell-completion zsh)"    # ~/.zshrc, after compinit
eval "$(a4i generate-shell-completion bash)"   # ~/.bashrc
a4i generate-shell-completion fish | source    # ~/.config/fish/config.fish

Usage

a4i login apic1.example.com -u admin              # prompts for password; -k if self-signed
a4i get class fvTenant                            # class query
a4i get mo uni/tn-common                          # MO query, by DN
a4i get class fvTenant --query-target subtree --rsp-subtree full
a4i get class l1PhysIf --node leaf101.example.com # query a switch with the same token
echo '{"fvTenant":{"attributes":{"name":"demo"}}}' | a4i post mo uni/tn-demo
a4i logout                                        # drop the in-memory session
a4i daemon status                                 # is a token held, and for how long
a4i login apic1.example.com -u admin --read-only  # a session that will refuse every POST
a4i mcp                                           # serve MCP on stdio for an LLM client

get, post and list each take a class or an mo subcommand, so a DN needs no leading / and a class name is never mistaken for one. Every get option is named after the ACI query parameter it sets, so a parameter read in the APIC REST API documentation can be typed as-is -- a4i get class --help lists them.

Reading the model

a4i search 'bridge domain'          # which class is that, by name
a4i describe fvBD                   # what a body may set on it
a4i list class fvT                  # class names starting with fvT
a4i list mo uni/tn-common           # the MOs one level under that DN

search, describe and list class read the bundled dictionary, so they need neither a login nor a daemon. list mo asks the APIC for one level of children, so it needs a session.

$ a4i describe fvCtx
fvCtx  VRF
The private layer 3 network context that belongs to a specific tenant or is
shared.

rn  ctx-{name}
dn  uni/tn-{name}/ctx-{name}
in  fvTenant

properties (13 settable, 14 read-only hidden)
  descr                string:Basic (0-128)            Specifies a descriptio…
  ipDataPlaneLearning  disabled|enabled = enabled
  name*                string:Basic (1-64)             A name for the network…
  pcEnfDir             egress|ingress|mixed = ingress  Policy Control Enforce…
  pcEnfPref            enforced|unenforced = enforced
  …
children (42)  --children to list them

A * marks a naming property -- the one the RN is built from. The middle column is what the property accepts, with the default after =. -a spells out the read-only properties, --children the classes that may hang under this one, and --json prints the underlying record instead of the layout.

Comparing a configuration

merge folds a configuration written across several files into the one body that diff and post each take, later files winning attribute by attribute. diff then compares that configuration against everything the fabric has under uni.

a4i merge ./configs/ -o merged.json               # every *.json, in path order
a4i merge ./configs/ | a4i diff
a4i merge ./configs/ | a4i diff --exclude uni/tn-common --exclude uni/infra
a4i post mo uni/tn-demo --dry-run '{"fvTenant":{"attributes":{"descr":"prod"}}}'
- fvTenant uni/tn-common  (extra: 2 child MOs)
  - descr: ""
  - name: "common"

~ fvBD uni/tn-demo/BD-bd1
  ~ mtu: "1500" -> "9000"

+ fvTenant uni/tn-new  (missing: 2 child MOs)
  + descr: "added"
  + name: "new"

1 missing, 1 modified, 1 extra

+ is an MO the configuration asks for and the fabric does not have, - one the fabric has and the configuration does not mention, and ~ one whose attributes differ. A wholly missing or wholly extra subtree is reported as its top MO with the MOs below it counted; --expand lists every one of them.

The configuration is taken to describe the whole of uni, so everything it leaves out is extra -- including tn-common, tn-infra, tn-mgmt and the policies the APIC creates for itself. --exclude is how the rest is quietened: it takes a DN, or a pattern whose * matches within one RN, and is repeatable.

post --dry-run reads the same way over a single POST: it fetches the subtree the body targets, prints what would change, and sends nothing. Both commands say in their exit code whether anything would change:

Code Meaning
0 the fabric matches / posting this body would change nothing
2 it differs / the body would change something
1 the command itself failed (not logged in, bad JSON, unknown DN)

MCP server

a4i mcp speaks the Model Context Protocol on stdin and stdout, so an LLM client can read and write the fabric through the session you already logged in. Register it with the client, then log in from a terminal as usual -- there is no login tool, because this server never handles a password.

{"mcpServers": {"a4i": {"command": "a4i", "args": ["mcp"]}}}
Tool What it does
search find a class by what it is called
describe one class from the bundled model, as a JSON record
list class names by prefix, or the DNs one level under a DN
get a class or MO query, with every query option under its own name
dry_run what a POST would change, sending nothing
post POST a body
merge several bodies or paths folded into one
diff the fabric compared against one configuration
Resource Contents
a4i://guide/post-body how an ACI body nests, how a child MO gets its DN, what status does
a4i://guide/query class against MO queries, the two subtree controls, keeping a response small
a4i://guide/workflow the order: search or list, describe, get, dry run, post
a4i://guide/limits where the bundled model, the dry run and the diff each stop short

A get whose response would exceed 64 KB is refused, with the total count and the ways to narrow it; A4I_MCP_MAX_BYTES raises or lowers that. On a --read-only session, post is not offered at all.

Python library

A Client holds its own session, so no daemon is involved: it logs in itself and keeps the token in memory for as long as it lives.

import a4i
from a4i.merge import merge

with a4i.Client("apic1.example.com", verify=False) as client:
    client.login("admin", password)

    data = client.get("fvTenant", kind="class", query_target="subtree", rsp_subtree="full")
    client.post("uni/tn-demo", {"fvTenant": {"attributes": {"name": "demo"}}}, kind="mo")
    changes = client.diff(merge(base, override))

kind is the subcommand the CLI takes, and it is required: "class" for a class name, "mo" for a DN. Every other keyword argument is the CLI option of the same name with underscores. verify is what -k/--insecure and --ca express, timeout is login --timeout, and dry_run(), diff() and a4i.merge.merge() are the commands of those names.

AsyncClient is Client awaited: the same arguments, the same return values and the same exceptions, sending the same requests in the same order.

async with a4i.AsyncClient("apic1.example.com", verify=False) as client:
    await client.login("admin", password)
    data = await client.get("fvTenant", kind="class")

A value ACI does not define raises ValueError before anything is sent. A failed request raises a4i.ApicError, a4i.NotLoggedInError or a4i.SessionExpiredError, all of them a4i.A4iError. The token refreshes itself once half its lifetime has elapsed, so a long-running script needs nothing of its own.

推荐服务器

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 模型以安全和受控的方式获取实时的网络信息。

官方
精选