Skip to content

Repository files navigation

mcp-store-build — MCP Server with Runtime Tool Registration and Cisco Backend Fan-out

Python 3.10+ MCP 2.1.1 NETCONF/YANG MIT

An MCP server that lets an AI model register its own tools at runtime and push the resulting configuration to Cisco infrastructure in the same atomic commit.

Normally an MCP server has a fixed tool list defined at startup. This one inverts that: the LLM sends code and a JSON Schema, the server validates and stores it, then notifies the client that the tool list changed. The client re-fetches and the new tool is immediately callable — no restart, no config file edit.

When a tool commits, the server fans out to Cisco backends: DNA Center, Meraki, NSO, IOS XE, or Webex. The AI describes intent; the server builds and deploys it atomically across both the AI context and the network.

The design mirrors NETCONF/YANG: candidate datastore for staging, commit to running, rollback to snapshots, lock/unlock for concurrency, and audit log with content hashes — the same control plane pattern Cisco uses for network device configuration, applied to AI toolchains.

Technology stack: Python 3.10+, MCP 2.1.1 (JSON-RPC 2.0 over stdio/SSE), stdlib urllib for all Cisco API calls. No external HTTP client dependencies.

Status: Beta


Use Case

Network automation and AI toolchain management share a structural problem: both need to maintain a desired state, validate changes before applying them, and roll back safely when something breaks. Cisco solved this at the network layer with NETCONF/YANG. mcp-store-build applies the same pattern to AI agent toolchains.

Problem: AI agents built on MCP have static capability sets. Adding a new tool requires editing server code and restarting the process. There is no staging, no validation, no rollback — and no way to push the resulting configuration to the network layer in the same operation.

Solution: mcp-store-build makes the tool registry a first-class datastore. The LLM stages tool definitions into a candidate datastore, the server validates them against JSON Schema, and a commit operation pushes them to the running registry and fires notifications/tools/list_changed — the MCP protocol's built-in mechanism for telling a client its tool list has changed. The same commit fans out to Cisco DNA Center, Meraki, NSO, IOS XE, or Webex.

Outcomes:

  • AI agents acquire new capabilities at runtime without restarting
  • All tool registrations are schema-validated, sanitized, and audited before going live
  • Configuration intent flows from the AI layer to Cisco infrastructure in a single operation
  • Rollback to any prior registry snapshot is a single tool call

Installation

Clone the repo:

git clone https://github.com/sshpie/mcp-store-build.git
cd mcp-store-build

Set up a Python virtual environment:

python3 -m venv venv
source venv/bin/activate        # Windows: venv\Scripts\activate

Install dependencies:

pip install -r requirements.txt

requirements.txt contains:

mcp>=2.1.1
jsonschema>=4.0.0

Python 3.10 or later is required.


Configuration

Cisco backend credentials are passed through the configure_backend tool at runtime — no credentials in source files or config files.

Webex notifications (optional) use environment variables:

export STORE_BUILD_WEBEX_TOKEN=<your-bot-token>
export STORE_BUILD_WEBEX_ROOM=<your-room-id>

Per-adapter credential format:

Adapter Required fields
dna_center host, token or (username + password), verify (bool, optional)
meraki api_key, org_id (optional, auto-detected if omitted)
nso host, username, password, port (default 8080), https (bool), verify (bool)
ios_xe host, username, password, port (default 443), verify (bool)
webex token, room_id (optional)

Set verify: false for lab or sandbox environments with self-signed certificates.


Usage

Start the server:

# Secure mode — schema sanitization and validation active (recommended)
python server.py

# Insecure mode — disables sanitization, enables inject_schema_poison demo tool
python server.py --insecure

Claude Desktop integration (claude_desktop_config.json):

{
  "mcpServers": {
    "store-build": {
      "command": "/path/to/venv/bin/python",
      "args": ["/path/to/mcp-store-build/server.py"]
    }
  }
}

Workflow

1. validate_tool   — check schema and syntax before staging (optional)
2. configure_backend — register a Cisco backend for commit fan-out
3. build_tool      — stage a Python primitive in the candidate datastore
4. commit_staged   — push to running, fire notifications/tools/list_changed,
                     fan out to all configured Cisco backends
5. <new tool>      — call the registered tool immediately

Example: Register a tool at runtime

# Stage
build_tool({
  "name": "sha256",
  "description": "Returns the SHA256 hash of the input string.",
  "code": "import hashlib\ndef main(args):\n    return hashlib.sha256(args['text'].encode()).hexdigest()",
  "parameters": {
    "type": "object",
    "properties": {"text": {"type": "string"}},
    "required": ["text"]
  }
})
→ [secure] Staged 'sha256' in candidate datastore (hash a3f1c2b4)

# Commit
commit_staged({})
→ Committed 1 tools to running: sha256
→ notifications/tools/list_changed sent

# Use it
sha256({"text": "hello"})
→ "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"

# Idempotency — calling build_tool again with identical args is a no-op
build_tool({...same args...})
→ [no-op] 'sha256' unchanged (idempotent, hash a3f1c2b4)

Example: Fan out to DNA Center

configure_backend({
  "adapter_type": "dna_center",
  "config": {
    "host": "sandboxdnac2.cisco.com",
    "username": "devnetuser",
    "password": "Cisco123!",
    "verify": false
  }
})

commit_staged({
  "backend_config": {
    "targets": [{"id": "device-uuid", "type": "MANAGED_DEVICE", "params": {}}]
  }
})
→ Committed 1 tools to running: sha256
→ [dna_center] DNA Center deployment queued — taskId: abc123

Built-in Tools

Tool NETCONF analog Description
build_tool edit-config (candidate) Stage a Python primitive with validation and idempotency check
configure_backend Register a Cisco backend for commit fan-out
validate_tool <validate> RPC Schema meta-validation + syntax check, no side effects
commit_staged commit Candidate → running, fires notifications/tools/list_changed, fans out to backends
discard_staged discard-changes Clear candidate without modifying running
list_registry get-config Show running or candidate datastore
rollback rollback-N Revert running to previous snapshot
lock_registry <lock> Block concurrent modifications
unlock_registry <unlock> Release lock
get_audit_log Full state-change log with timestamps and content hashes
inject_schema_poison (insecure mode only) Context window hijacking demonstration

Related Sandbox

All five Cisco adapters can be tested against DevNet Always-On sandboxes — no reservation required.

Adapter Sandbox Credentials
DNA Center sandboxdnac2.cisco.com devnetuser / Cisco123!
Meraki DevNet Meraki Sandbox API key in developer portal
NSO NSO on DevNet See sandbox instructions
IOS XE devnetsandboxiosxe.cisco.com developer / C1sco12345
Webex developer.webex.com Personal token

See examples/ for runnable scripts against each sandbox.


Links to DevNet Learning Labs


Prior Art

Parts of this exist in different places; this combination does not.

What exists:

  • notifications/tools/list_changed is in the MCP spec, but almost no servers use it for LLM-driven registration — most use it for static cases like toggling tools on auth state changes.
  • Tool-generating agents (AutoGen, CrewAI, LangChain) have patterns where an LLM generates Python functions and calls them in-process. These run inside the agent loop; they are not registered as MCP tools with schemas, and there is no staging/commit/rollback cycle.
  • Hot-reload MCP servers watch a config file and reload on change. A human edits the file; the LLM does not push registrations.

What is different here:

  • The LLM is the actor pushing tool registrations
  • Candidate/running split with schema meta-validation before anything goes live
  • Content-hash idempotency at the registration layer
  • Rollback to snapshots on demand
  • Commit fan-out to Cisco infrastructure in the same atomic operation
  • NETCONF/YANG semantics applied to MCP tool management

The Architecture

LLM client (Claude, GPT, etc.)
        |
        |  stdio / HTTP SSE (JSON-RPC 2.0)
        |
   ┌────┴────────────────────────────────────────────────┐
   │                  store-build-mcp                    │
   │                                                     │
   │  validate_tool → sanitizer + ast.parse              │
   │                                                     │
   │  build_tool → [SECURE gate]                         │
   │    └─► validate_schema (JSON Schema meta-check)     │
   │    └─► sanitize_description / sanitize_schema       │
   │    └─► idempotency check (SHA-256 content hash)     │
   │    └─► registry.stage() → CANDIDATE datastore       │
   │                                                     │
   │  commit_staged → registry.commit_staged()           │
   │    └─► candidate → RUNNING datastore                │
   │    └─► notifications/tools/list_changed ──────────► │
   │    └─► backend fan-out:                             │
   │         ├─ DNA Center intent API                    │
   │         ├─ Meraki Dashboard API                     │
   │         ├─ NSO RESTCONF                             │
   │         ├─ IOS XE RESTCONF                          │
   │         └─ Webex notifications + webhooks           │
   │                                                     │
   │  primitives/ ◄── subprocess exec (sandboxed, 30s)   │
   └─────────────────────────────────────────────────────┘

Known Issues

  • Primitives execute in a sandboxed subprocess with a 30-second timeout. Long-running computations will be killed. There is no persistent state between primitive invocations.
  • The ios_xe adapter falls back from PATCH to PUT when the device returns 405. Some older IOS XE versions do not support PATCH on all YANG paths.
  • The registry is in-memory only. Restarting the server clears all dynamically registered tools. Persistence to disk is not yet implemented.
  • NSO RESTCONF commit-queue IDs are returned but not polled for completion. For synchronous confirmation, call get_task_status on the DNA Center adapter or check NSO directly.

Getting Help

Open an issue at github.com/sshpie/mcp-store-build/issues.

Include the server startup mode (--insecure or default), the tool call that produced the error, and the full error message from the server's stderr output.


Getting Involved

Key areas for contribution:

  • Persistence — serialize the running registry to disk on commit so restarts preserve dynamically registered tools
  • Additional adapters — Cisco Intersight, Catalyst SD-WAN, SecureX
  • RBAC — per-tool or per-adapter permission gates so different LLM agents have restricted commit scope
  • NSO service model integration — map tool schemas to NSO service YANG models automatically

See CONTRIBUTING.md for development setup and the adapter authoring guide.


Credits and References


License

This code is licensed under the MIT License. See LICENSE for details.

About

Self-extending MCP server for safe, atomic AI orchestration across Cisco networks.

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages