Skip to main content
Glama
sudsho

mcp-server-enterprise-tools

by sudsho

mcp-server-enterprise-tools

An opinionated tool gateway for LLM-driven backends, designed around the MCP tool model but shipped with its own JSON transports. It focuses on the governance layer: per-tool RBAC from a declarative YAML policy, a structured audit row for every invocation, PII redaction on arguments before persistence, and a typed error envelope so clients can branch on codes instead of string-matching messages.

The transport is a small HTTPS API (POST /mcp/call) plus a Prometheus /metrics endpoint. The stdio path that would let a full MCP host discover and call these tools is out of scope in this repo.

The problem

Enterprise backends that want to expose internal APIs to LLM-driven callers hit three gaps that are not addressed at the protocol layer:

  • caller identity is not first-class and needs to be resolved out-of-band

  • tool arguments and results can carry PII (SSNs, PANs, account numbers) and those cannot land in cleartext in logs or audit tables

  • error handling needs to be machine-readable so internal callers can branch on codes without string-matching messages

This repo is an opinionated take on filling those gaps while keeping the tool implementations small and readable.

Related MCP server: MCP Enterprise Tool Gateway

What is exposed

Three bank tools (four operations):

Tool

Verb

Purpose

customer_360.lookup

read

profile, primary account summary, risk flags

statement_search.query

read

full-text with date and amount filters

dispute_resolution.open

mutating

open a dispute against a transaction

dispute_resolution.status

read

dispute state by id

Each has a JSON input schema. Adding a fourth is a single file under src/mcp_server/tools/ plus a line in app.build_registry.

Architecture

              +--------------------+          +------------------+
              |  Internal caller   |          |  Internal agent  |
              |  (any HTTP client) |          |  (http)          |
              +---------+----------+          +---------+--------+
                        |                               |
                        |               X-Bank-Identity |
                        v                               v
                    +---+-------------------------------+---+
                    |          Tool gateway (this repo)      |
                    |  transport -> registry.call -> handler |
                    |                    |                   |
                    |            rbac.check + audit.write    |
                    +----+-----------------+----------+------+
                         |                 |          |
                         v                 v          v
                +------------------+  +---------+  +------------------+
                | internal APIs    |  | Postgres|  | Prometheus       |
                | (customer,       |  | audit   |  | metrics scraped  |
                | statements,      |  | log     |  | at /metrics      |
                | disputes)        |  +---------+  +------------------+
                +------------------+

Longer version with request flow: docs/architecture.md.

Quick start (runs offline, no keys)

No cloud creds, no api keys, no database to stand up. The audit log defaults to a local sqlite file, and the three bank tools default to in-repo synthetic upstreams (MCP_UPSTREAM_MODE=fake). Point AUDIT_DB_URL at postgres and set MCP_UPSTREAM_MODE=http when you have the real services.

pip install -r requirements.txt
python -m examples.smoke     # in-process server + client, exits 0
PYTHONPATH=src pytest -q     # 31 passed

python -m examples.smoke starts the FastAPI gateway in-process, drives it through the full governance path with the http client, and reads the audit table back. Real output (trimmed):

1. client lists tools
  - customer_360.lookup: Look up a customer 360 view: profile, primary account...
  - statement_search.query: Search a customer's statements. Supports date range...
  - dispute_resolution.open: Open a dispute against a specific transaction...
  - dispute_resolution.status: Get the current status of an open dispute by id.

2. customer_360.lookup  (allowed for svc-analyst-01)
{
  "result": {
    "profile": {
      "name": "Jane A. Doe",
      "email": "[REDACTED]<email>",
      "ssn": "[REDACTED]<ssn>",
      "notes": "primary card [REDACTED]<pan>on file; backup acct [REDACTED]<acct>"
    },
    ...
  }
}

5. dispute_resolution.open  (DENIED for svc-analyst-01 by RBAC)
{
  "error": {
    "code": "forbidden",
    "message": "identity 'svc-analyst-01' is not permitted to call 'dispute_resolution.open'",
    ...
  }
}

6. audit log rows (read back from sqlite; args redacted)
  [ok   ] identity=svc-analyst-01         tool=customer_360.lookup        error=-
          args_redacted={"customer_id": "C-[REDACTED]<acct>"}
  [ok   ] identity=svc-dispute-agent-07   tool=dispute_resolution.open    error=-
          args_redacted={... "notes": "caller gave card [REDACTED]<pan>and ssn [REDACTED]<ssn>"}
  [deny ] identity=svc-analyst-01         tool=dispute_resolution.open    error=forbidden

  4 audit rows written, no raw PAN/SSN present.

SMOKE OK

And pytest:

31 passed in 1.21s

Quick start (production shape)

Local (http + postgres via compose):

docker compose up --build
# server on :8080, prometheus on :9090, postgres on :5432
curl -s -X POST http://localhost:8080/mcp/call \
  -H "X-Bank-Identity: svc-analyst-01" \
  -H "Content-Type: application/json" \
  -d '{"tool":"customer_360.lookup","args":{"customer_id":"C-01234567"}}'

Bare local run against the http transport:

pip install -e '.[dev]'
export AUDIT_DB_URL=sqlite:///./audit.db   # or a postgres url
make run-http                              # serves on :8080

RBAC model

Deny by default. Policies in configs/rbac.yaml map identities to allowed tool names, with a trailing .* wildcard for grouping. Every call, allowed or denied, writes an audit row. Full spec in docs/rbac_model.md.

Audit log design

One row per tool call. It defaults to a local sqlite file so the server runs offline, and swaps to Postgres for a real deploy by setting AUDIT_DB_URL (the store is plain SQLAlchemy, so nothing else changes). Columns: request_id, identity, tool, outcome, args_redacted, error_code, created_at.

Arguments are passed through Redactor before persistence: SSNs, PANs (Luhn-checked), email addresses, and 8-17 digit account-shaped numbers are replaced with marked tokens. The two read tools also apply the same redactor to their upstream response as defense-in-depth. Details in src/mcp_server/redaction.py and the tests.

Structured errors

Every failure comes back as an ErrorEnvelope:

{
  "error": {
    "code": "forbidden",
    "message": "identity 'svc-analyst-01' is not permitted to call 'dispute_resolution.open'",
    "request_id": "0d3f4a...",
    "tool": "dispute_resolution.open",
    "retryable": false,
    "details": {}
  }
}

Codes: unauthenticated, forbidden, not_found, invalid_argument, upstream_unavailable, rate_limited, internal. Clients can branch on code without string-matching messages.

Deploy

Terraform under terraform/ is a sketch of an internal ALB, ECS Fargate service, and RDS Postgres for the audit log. It has not been applied against a live account; treat it as a reference layout.

Prod checklist for a real rollout:

  1. Populate a real configs/rbac.yaml. Prefer many narrow identities over a few broad ones.

  2. Wire the X-Bank-Identity header to be set by a trusted upstream (mTLS terminator, OIDC proxy). The server does not authenticate; it only reads the resolved identity.

  3. Ship the audit table to your SIEM nightly. The table is the source of truth.

  4. Rotate the break-glass credential regularly and alert on every use.

Repo layout

src/
  mcp_server/       server, registry, rbac, audit, redaction, tools/
  mcp_client/       http client used for testing and examples
configs/            default.yaml, rbac.yaml, prometheus.yml
terraform/          aws vpc + ecs + rds reference layout
tests/              rbac, audit, redaction, tools, registry
examples/           request/response transcripts
docs/               architecture, rbac model

License

MIT. See LICENSE.

Maintenance

ActivityMaintained
ResponsivenessSyncing

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    B
    maintenance
    A production-grade MCP server for a fictional digital bank, exposing tools for an AI copilot to service customers across the full risk spectrum from read-only lookups to money movement and destructive admin actions, with OAuth 2.1 security and a realistic dataset.
    12
    1
  • F
    license
    Not graded
    quality
    C
    maintenance
    A universal MCP server for registering internal, external, and OpenAPI-based APIs as MCP tools. It exposes them to MCP clients via Streamable HTTP and provides admin portal, RBAC/session auth, credential injection, and audit logging.
  • A
    license
    Not graded
    quality
    C
    maintenance
    An enterprise MCP server scaffold that provides secure, governed access to internal tools through RBAC, audit logging, rate limiting, and prompt-injection boundaries, with a FastAPI control plane and OpenTelemetry observability.
    MIT

Latest Blog Posts

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/sudsho/mcp-server-enterprise-tools'

If you have feedback or need assistance with the MCP directory API, please join our Discord server