boxadm-mcp
The boxadm-mcp server is a read-only MCP server for Box administrators to monitor external file sharing risks using Box admin event logs and folder enumeration. All operations are read-only — no Box content is modified.
Health Check: Verify server version, Box API connectivity, authentication status,
admin_logsscope access, and configured internal domain allowlist.Raw Admin Events: Fetch recent enterprise-wide admin log events for diagnostic purposes, with pagination support via
stream_position.External Access Analysis: Aggregate external DOWNLOAD/PREVIEW events — identify top external accessors, top externally-accessed files, and shared-link usage. Supports DLP tracing mode to trace exactly which files a specific external account accessed.
External Collaborators: Enumerate folders visible to the admin and list all outside-org collaborators (accepted or pending), including their role, status, and expiry.
Public Shared Links: Discover all files/folders shared via open (anyone-with-the-link) access — the highest-exposure sharing mode in Box.
Top External Sharers: Rank internal users by total external exposure (external collaborations + public shared links combined) to identify who shares the most outside the org.
Daily DLP Brief: A single combined call summarizing recent external access events and current sharing exposure (collaborators, public links, top sharers) for a morning DLP review.
Supports both OAuth 2.0 (user auth) and Client Credentials Grant (server-to-server) for Box authentication.
Provides tools for monitoring external file sharing and access events from a Box enterprise admin perspective, including enterprise events, external collaborators, public shared links, and DLP tracing.
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., "@boxadm-mcpwho are the top external sharers today?"
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.
boxadm-mcp
English | 日本語
MCP (Model Context Protocol) server that surfaces external file flow from
a Box admin's point of view. It reads Box's enterprise event log
(admin_logs) to highlight "who shares a lot with the outside" and "which
files get accessed from outside" — an early-warning signal for leakage, not a
general-purpose file browser.
Documentation: https://shigechika.github.io/boxadm-mcp/
Read-only: it never revokes shares, deletes files, or otherwise mutates anything — it only surfaces risk. This is a different tool from a general-purpose Box file MCP (the official Box MCP, or the claude.ai Box connector): those operate on a user's own files and cannot see enterprise events, which is exactly what this server is for.
Named after the admin-console viewpoint (boxadm = Box admin), sibling of
gwsadm-mcp.
Features
Tool | Category | Description |
| — | version + auth_mode + Box auth + |
| Diagnostic | Raw recent enterprise events (for checking event types/fields). Supports manual pagination via |
| Access (events, enterprise-wide) | Aggregates external DOWNLOAD/PREVIEW within a window: top external accessors, top externally-accessed files, share-link count. Pass |
| Exposure (enumeration) | Lists external collaborators (outside-org login or external invite email) |
| Exposure (enumeration) | Lists items shared with an |
| Exposure (enumeration) | Ranks internal owners by external exposure (external collabs + public links) |
| One folder ( | Names, upload time, size, who uploaded, and a direct link per item. Filter by uploader or upload-time window. Reads no file content |
| Account state (lookup) | One account by its exact login: |
| Combined | Morning summary combining access (events) and exposure (enumeration) |
Related MCP server: gwsadm-mcp
Auth model
Two modes, selected via BOX_AUTH_MODE:
oauth— OAuth 2.0 (user auth). An admin authorizes once in a browser; the refresh token keeps it running unattended after that.ccg— Client Credentials Grant (server-to-server). Simpler to run unattended if your Box tenant has an available server-authentication app slot.
admin_logs (enterprise events) is readable in either mode, provided the
authorizing/impersonated user is an admin and the app has the Manage
enterprise properties scope.
OAuth setup (one-time, by a Box admin)
Developer Console → Create Platform App → Custom App → User Authentication (OAuth 2.0)
Redirect URI:
http://localhost:8787/callbackApplication Scopes: check Manage enterprise properties (required for
admin_logs). Add Read all files and folders too if you also want collaboration/share-link enumeration, and Manage users if you want theget_userlookup (each scope change requires re-consent viaboxadm-mcp auth)Enable the app in the Admin Console (unpublished apps are disabled by default under most tenant policies)
Note the Client ID / Client Secret
First login: set
BOX_AUTH_MODE=oauthetc., then runboxadm-mcp auth→ authorize in the browser → a token cache is written to~/.config/boxadm-mcp/token.json(chmod 600)
Setup
# uv
uv pip install boxadm-mcp
# pip
pip install boxadm-mcpOr from source:
git clone https://github.com/shigechika/boxadm-mcp.git
cd boxadm-mcp
# uv
uv sync
# pip
pip install -e .Configuration
Variable | Required | Description |
|
| |
| ✓ | App Client ID |
| ✓ | App Client Secret |
| ccg mode | Enterprise ID (CCG subject; not needed for oauth) |
| oauth redirect. Default | |
| oauth token cache path. Default | |
| Default | |
| Parallel per-folder lookups in the enumeration scan. Default | |
| Soft wall-clock budget (seconds) for one enumeration scan. Default | |
| Per-request HTTP timeout (seconds). Default | |
| ✓ | Internal email domains (comma-separated). No default — every address counts as external until you set this |
Keep secrets out of .mcp.json (e.g. in a local env file sourced before
launch); .mcp.json itself can reference ${BOX_CLIENT_ID}-style variables
and be safely committed.
Scope and limits
Access tools (
external_access_events, and the access half ofdaily_brief) read the enterprise-wide events stream. Hittingmax_eventssetscapped: true(oldest-first scan).Exposure (enumeration) tools only see folders visible to the co-admin account (not a guaranteed 100% of the enterprise), plus
max_folders/max_depthlimits (surfaced viacapped). Requires the Read all files and folders scope.The scan fans its per-folder lookups out concurrently (
BOX_SCAN_CONCURRENCY), since Box has no enterprise-wide collaboration listing — this widens how many folders finish inside a tool-call timeout, but coverage is still bounded by the caps. The read path retries429(honoringRetry-After) and transient5xxwith jittered backoff, so a passing throttle recovers instead of degrading coverage; a folder dropped by a per-folder API error that outlasts those retries (e.g. a persistent403) is counted infetch_errors: coverage is complete only whencappedis false andfetch_errorsis 0.Enumeration tools share a short-TTL scan memo across calls;
public_shared_linksskips collaboration calls entirely (optimization).get_userreads the enterprise user directory instead — one request, no paging, and structurally not an enumerator (it answers about the login you pass and nothing else). Itscappedflag discloses a truncated search, so afound: falsefrom a truncated result reads as inconclusive rather than negative.
DLP tracing (reverse-lookup by accessor)
To answer "what did this external account download": pass
created_by_logins (comma-separated logins) to external_access_events. It
keeps only that accessor's events and returns per-file detail
(matched_events: item id/name, owner, size in bytes+GB, timestamp,
event_type, whether it was via a share link).
external_access_events(since_hours=26, created_by_logins="someone@example.com")Since the accessor could appear anywhere in the window, a filtered call auto-extends the scan cap to up to 50,000 events (oldest-first) — but only matching events are kept, so memory stays bounded.
In this mode the response carries
events_matched(match count) instead ofevents_scanned(no running total is kept; usecappedto judge coverage).capped: truemeans the window wasn't fully scanned — raisemax_events.Box's
admin_logsAPI has nocreated_byquery parameter, so this is a client-side filter (fetch_admin_events(created_by_logins=...)).
One folder's contents (list_folder_items)
An ls, not a cat. Written for a help desk answering a submitted enquiry whose
attachments land in a Box folder: instead of a human going to find that folder,
the answer names the attachments and links straight to them. File content is
never read, and no shared link is ever created — an existing one is reported
because it is an exposure finding, not a convenience.
Who uploaded an item is not where you would look for it. For an upload made
through a File Request, Box records no user at all: created_by and
modified_by both read "Anonymous User", and owned_by is the application's
own service account — identical on every row. The only field carrying the
submitter is uploader_display_name, and despite its name the value observed in
practice was an email address. It is therefore matched as an opaque string
(exact, case-insensitive) and never parsed or validated as an address. For a file
uploaded by a signed-in user the reverse holds, so created_by is the fallback.
Ordering and time bounds are computed here rather than by Box:
Box documents
sortas the second sort attribute — items order by type first, so a subfolder precedes every file regardless of date. Measured against a real folder,sort=datealso matched neithercreated_atnormodified_atorder, so it cannot honestly be presented as "newest".since/untilare compared as instants, not text. Box stamps items in its own UTC offset while a caller asks in theirs, so a lexicographic comparison is wrong by that difference at every date boundary and silent about it. Both bounds must carry an offset; a bare date is refused rather than guessed.
limit bounds what is RETURNED, not what is searched — a full page is fetched
first, so an uploader's item is found even when it is not among the newest.
Truncation is disclosed twice over, because they are different truths: returned
vs matched is the caller's own limit, while capped means the folder holds
more than one page and a miss is inconclusive rather than negative.
Per-account lookup (get_user)
Every other tool reads the event stream or walks folders, so an account with no
recent activity cannot be asked about at all. get_user answers directly —
"is this account disabled, and is its quota full?" — in one request:
get_user(login="someone@example.com")login is the account's full Box login (an email address), matched exactly
and case-insensitively. That matching is the point, not an implementation
detail: Box's underlying filter_term is a prefix search over display name
and login, so the endpoint readily returns a colleague whose name starts with
the same letters. Only an exact login match lands in user; everything else is
counted in other_prefix_hits and never identified. A term that is not email-shaped is
refused before the request is made — filter_term has no minimum length, so a
one-character term would otherwise return a page of real accounts.
One drift it cannot find: the same person under a second login at another domain.
filter_term prefix-matches the whole term, so alice@old.example can never return
alice@new.example; that would need a search on the local part alone, which is the
directory-wide prefix search this tool refuses by design.
Field | Meaning |
| The only field that says whether the account exists. |
| The account when |
| Count of further prefix matches. A count only: those are different accounts and are deliberately not identified |
| The search was truncated, so |
| How many entries came back, and a plain-language reading |
Inoauth mode this endpoint's requirement is verified end-to-end: the
app must hold the "Manage users" application scope. Without it
/2.0/users answers 403 even when the authorising user is a co-admin who can
manage users; with it, 200. Two caveats: the effective permission is still
capped by the authorising user's own role, and a scope added in the Developer
Console does not reach tokens minted from an existing refresh token — the
app must be re-authorised interactively (boxadm-mcp auth) before the new
scope takes effect. Under ccg the endpoint remains unverified. A permission
failure returns likely_cause saying all of this rather than a bare HTTP
status.
Usage
Claude Code (plugin)
This repository doubles as a single-plugin marketplace, so Claude Code can install the server for you:
/plugin marketplace add shigechika/boxadm-mcp
/plugin install boxadm-mcp@boxadm-mcpThe plugin launches uvx boxadm-mcp and reads the same environment variables
described in Configuration; export BOX_CLIENT_ID,
BOX_CLIENT_SECRET, BOX_ENTERPRISE_ID (ccg mode), and BOX_ALLOWED_DOMAINS
before starting Claude Code. The plugin ships with BOX_AUTH_MODE=ccg by default —
switch to oauth only after running boxadm-mcp auth once yourself, since the
plugin cannot provision that browser step or the resulting token cache file for
you.
uvx must be on the PATH of the process that runs Claude Code — a login
shell usually has it, but a GUI-launched app may not; install
uv system-wide if the plugin fails to start.
Claude Code (manual)
Add to .mcp.json:
{
"mcpServers": {
"boxadm-mcp": {
"type": "stdio",
"command": "boxadm-mcp",
"env": {
"BOX_AUTH_MODE": "oauth",
"BOX_CLIENT_ID": "${BOX_CLIENT_ID:-}",
"BOX_CLIENT_SECRET": "${BOX_CLIENT_SECRET:-}",
"BOX_ALLOWED_DOMAINS": "example.com"
}
}
}
}CLI Options
boxadm-mcp auth # OAuth first-time login (opens a browser)
boxadm-mcp --version # Print version and exit
boxadm-mcp # Start MCP server (STDIO, default)Development
git clone https://github.com/shigechika/boxadm-mcp.git
cd boxadm-mcp
# uv
uv sync --dev
uv run pytest -v
uv run ruff check .
# pip
python3 -m venv .venv
.venv/bin/pip install -e . && .venv/bin/pip install pytest respx ruff
.venv/bin/pytest -v
.venv/bin/ruff check .Tests never touch Box — respx mocks the CCG/OAuth token endpoint and the
admin_logs/enumeration APIs.
Live smoke test
That isolation is the point of the unit tests, and also their limit: they
cannot tell you that a tool has stopped returning real data.
scripts/smoke_test.py runs every registered tool against the configured
enterprise and fails on empty, malformed or error answers:
# needs the same BOX_* environment variables as the server
uv run python scripts/smoke_test.py
uv run python scripts/smoke_test.py --only shared_links --tracebackRead-only. Every tool here reads; nothing in Box is changed. A future tool that writes must be listed as state-changing and skipped, and a test enforces that.
No payloads in the report. Tool names, statuses and row counts only; server-authored error text is redacted too, since Box errors quote the account or item they were asked about.
Bounded. These tools page the event stream and walk the folder tree, so each probe passes explicit small caps instead of the interactive defaults (5000 events, 150 folders) — enforced by a test that finds the bounding parameters from the source.
Nothing enterprise-specific in the specs. A test bans address shapes (login, URL, hostname, IPv4, IPv6) and the parameters that carry an account name, because this repository is public. Two literals identify nobody and are allowed: folder id
0, the root folder in every enterprise, and the made-up termget_useris probed with — an account that cannot exist, so the probe asserts the not-found path rather than naming a real person.An empty answer passes: no public links and no external collaborators is the desired state, so probes assert the accounting envelope (
count,folders_scanned,window_hours) rather than a row count.CI enforces the cheap half: a tool registered without a probe spec fails the build (
tests/test_smoke_probes.py), so adding a tool forces the question "how would we know it works?".scripts/smoke_harness.pyis the engine and holds no Box knowledge: it is kept identical across the servers that share it, so fix engine bugs once and sync the file rather than patching this copy.
Releasing
Releases are automated with release-please.
Merging Conventional Commits (feat:, fix:, …)
to main keeps a release PR open with the next version and changelog. Merging
that PR tags vX.Y.Z and publishes a GitHub Release, whose release: published
event triggers the release workflow to build and publish to PyPI and the MCP
Registry. release-please owns the version in boxadm_mcp/__init__.py and
server.json (do not bump them by hand).
The release-please workflow should be given a repository secretRELEASE_PLEASE_TOKEN (a PAT with contents: write + pull-requests: write).
The default GITHUB_TOKEN cannot create the Release that triggers the
downstream release workflow (GitHub blocks workflow runs triggered by
GITHUB_TOKEN), so without the PAT nothing gets published. The workflow falls
back to GITHUB_TOKEN when the secret is unset so PR CI keeps working on forks.
Governance
Because this surfaces what users share, run it as authorized information-security monitoring with a clear purpose, a defined set of viewers, and a retention policy. Most external sharing is legitimate (collaborators, vendors), so treat findings as a risk ranking, not an alert queue — build an allowlist of known-OK sharers over time.
License
MIT
Available Tools
9 toolsdaily_briefA
Morning DLP brief: external access (events) + external-sharing state (enumeration).
One call that combines:
access (enterprise-wide, events): external DOWNLOAD/PREVIEW in the last
since_hours, with top external accessors and top externally-accessed files.exposure (co-admin visible folders, enumeration): current external collaborations, open ("anyone with the link") shared links, and the owners most externally exposed.
Reuses the cached folder scan, so calling this alongside the other enumeration
tools doesn't re-walk. Args mirror the underlying tools; top defaults to 5
for a compact summary. Coverage/caps caveats are the same (capped flags +
enumeration limited to the co-admin's visible content). On failure returns
{"error": ...}.
| Name | Required | Description | Default |
|---|---|---|---|
| top | No | ||
| max_depth | No | ||
| max_events | No | ||
| max_folders | No | ||
| since_hours | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Despite no annotations, the description thoroughly discloses behavioral traits: it reuses a cached folder scan, returns an error object on failure, mentions coverage/caps caveats (capped flags, enumeration limited to co-admin visible content), and explains default behavior (top defaults to 5 for compact summary).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with bullet points and clear sections, and the main purpose is front-loaded. It is slightly lengthy but each part adds value (purpose, behavioral notes, caveats).
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema is provided, so the description should explain the return format. It mentions an error object on failure but does not describe the success response structure (e.g., fields, format of 'access' and 'exposure' data). This is a notable gap given the tool's complexity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. It explains 'since_hours' (last N hours) and 'top' (defaults to 5 for compact summary) but only vaguely states 'Args mirror the underlying tools' for other parameters like max_depth, max_events, max_folders, lacking individual explanations.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it provides a combined brief of external access events and external-sharing state (enumeration). It distinguishes from siblings like external_access_events and external_collaborators by explicitly saying it combines two underlying tools into one call.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides clear context on when to use it (e.g., morning DLP brief, reuses cached folder scan alongside other enumeration tools). However, it does not explicitly state when not to use it or mention alternative tools by name, only implying they are the individual underlying tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
external_access_eventsA
Surface external file access (DOWNLOAD / PREVIEW) from enterprise admin_logs.
Enterprise-wide (events stream): over the window, flags each access whose
actor (created_by.login) is outside the org domain allowlist — an
external party, or an anonymous open-link visitor (no login) — and whether it
came via a shared link. Aggregates to the top externally-accessed files and
the top external accessors, so an admin can spot unusual outbound data pulls.
Args:
since_hours: Look-back window in hours (default 24).
max_events: Cap on DOWNLOAD/PREVIEW events scanned (default 5000); the
result's capped flag is true when more existed (never silently
truncated).
top: How many top files / accessors to return (default 20).
created_by_logins: Comma-separated accessor logins to trace (empty = all).
When set, switches to DLP-tracing mode (see below).
Returns window_hours, events_scanned, capped,
external_access_count, via_shared_link, top_external_accessors
(login + count + bytes), and top_externally_accessed_files (item id/name/
owner + external-access count). On failure returns {"error": ...} (incl.
needs-login for an expired OAuth session).
Notes:
via_shared_linkcounts ALL scanned accesses that went through a shared link (internal and external), not just external ones.Events are scanned oldest-first from the window start. When
cappedis true the aggregates reflect only the scanned (earliest) slice, NOT the full window — raisemax_eventsfor a complete picture.DLP tracing (
created_by_loginsset): scans up to the wider ofmax_eventsand 50000 events (the accessor may sit anywhere in the window) but keeps only that accessor's events, so the answer to "which files did this account pull" is exact and bounded. The result reportsevents_matched(notevents_scanned— this mode doesn't track the scanned total; judge coverage bycapped),filtered_loginsandmatched_events(per access: item id/name, owner, size bytes+GB, created_at, event_type, accessor, via_shared_link); the aggregate is scoped to the filtered accessor(s).cappedtrue means the window was not fully scanned (raisemax_events).
| Name | Required | Description | Default |
|---|---|---|---|
| top | No | ||
| max_events | No | ||
| since_hours | No | ||
| created_by_logins | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description fully discloses behaviors: scan window and capping, via_shared_link counting details, oldest-first scanning, DLP mode behavior changes, and error handling (needs-login). This is comprehensive and goes beyond basic annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is verbose but well-structured with sections (Args, Returns, Notes). It is front-loaded with the main purpose. Some redundancy exists (e.g., DLP mode repeated), but the complexity justifies the length. Minor conciseness improvements possible.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (multiple modes, 4 parameters, no output schema), the description is exceptionally complete. It details all return fields, error conditions, and behavioral nuances like capped flag and DLP mode changes. No gaps for an AI agent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description compensates fully by explaining each parameter: since_hours (look-back window), max_events (cap with capped flag), top (number of results), created_by_logins (DLP mode). This adds significant meaning beyond the schema's type and default.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it 'Surface external file access (DOWNLOAD / PREVIEW) from enterprise admin_logs.' It specifies the verb 'surface' and resource 'external file access', distinguishing it from siblings like 'external_collaborators' and 'top_external_sharers' by focusing on admin log events.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides clear context for use: 'so an admin can spot unusual outbound data pulls.' It explains normal mode and DLP tracing mode, but does not explicitly state when not to use this tool or mention alternative tools, leaving some ambiguity.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
external_collaboratorsA
List external collaborators on Box folders (current state, enumeration).
Walks folders the authenticating co-admin user can see (default from the root "All Files") and reports collaborations whose collaborator is outside the org domain allowlist — accepted external users or pending external invites. Useful to review who outside the organization has standing access.
Args:
root_folder_id: Folder to start from ("0" = the user's root). A Box
folder id: decimal digits only, as shown at the end of a Box folder
URL. Anything else is refused with {"error": ...} before any
request is made, rather than being reported as an empty result.
max_folders: Cap on folders visited (default 150); capped discloses
when coverage was cut short.
max_depth: Folder recursion depth (default 1 = top-level folders only).
Externally-owned folders (this org is only a guest, not the owner) are out
of scope and skipped — we cannot govern their collaborations, and their
"external collaborators" are just the owner's own org accounts. They are
reported separately under skipped_externally_owned (never silently
dropped) and do not consume the max_folders budget.
Coverage note: limited to content the co-admin user can access (not provably
100% of the enterprise) and to the depth/folders caps. Returns
folders_scanned, capped, fetch_errors (count of folders whose
lookup hit an API error that outlasted the client's retries, e.g. a persistent
403 or a sustained throttle — coverage is complete only when capped is false
AND fetch_errors is 0), count,
external_collaborators (folder, owner, collaborator, role, status,
expires_at), and skipped_externally_owned (folder_id, folder_name,
owner). On failure returns {"error": ...}.
| Name | Required | Description | Default |
|---|---|---|---|
| max_depth | No | ||
| max_folders | No | ||
| root_folder_id | No | 0 |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description discloses extensive behavior: it refuses invalid root_folder_id with an error, skips externally-owned folders with separate reporting, and explains the max_folders cap via the `capped` field. Error handling for fetch errors is also detailed, covering persistent API errors and retries—all beyond what any annotation could provide.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with a one-sentence summary, followed by structured details organized into coherent paragraphs. Each sentence contributes new information, such as coverage limitations and return fields, justifying its length.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with no output schema and no annotations, the description provides a thorough account of return values, error behavior, and limitations (e.g., coverage only reflects co-admin's accessible folders). It covers all critical aspects an agent needs to invoke and interpret results correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Despite 0% schema description coverage, the Args section richly explains each parameter: root_folder_id's format and validation, max_folders' default and `capped` disclosure, and max_depth's recursion semantics. This fully compensates for the sparse schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first line 'List external collaborators on Box folders (current state, enumeration)' uses a specific verb and resource, clearly distinguishing the tool's purpose. Though siblings like external_access_events exist, the description unambiguously defines what this tool does.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Clear context is provided about walking folders from the root 'All Files' and the tool's usefulness for reviewing external standing access. However, no explicit alternatives or when-not-to-use conditions are given, aside from the out-of-scope externally-owned folders, which is more about tool behavior than usage guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_userA
Look up ONE Box account by its exact login (the account's email address).
Answers "what is this account's state?" — the question behind a ticket that says "my Box account is disabled". Every other tool here reads the event stream or walks folders, so an account with no recent events is invisible to them; this is one request against the user directory and the only tool that answers about an account directly. Use it when a specific account is named. It cannot list, search or enumerate accounts: it takes one login and answers about that login only.
Args:
login: The account's full Box login, i.e. its email address
(someone@example.com) — not a display name, not a user id. Matched
EXACTLY, case-insensitively. A partial login does not match.
This server is downstream of an identity provider, not the master. Read what comes back as "what Box currently believes", and compare it against the IdP's own record (which is authoritative for who the account is). A disagreement is the finding, and is usually drift on the Box side rather than a mistyped address:
enterpriseabsent/null — the account is no longer in the enterprise (it has become a free personal account), so enterprise SSO no longer applies to it even though the IdP still authenticates the person. Box classes such an account as external and returns it only on a COMPLETE login match, which is exactly what this tool asks for — so it is reachable here, and a partial login would silently lose it.statusother thanactive— the IdP authenticates, Box refuses.is_platform_access_onlytrue — an App User, which cannot sign in interactively at all.
One drift this tool cannot find for you: the same person under a second login at
another domain (an alias, or a duplicate left by a migration). filter_term
prefix-matches the WHOLE term, so a search for alice@old.example can never return
alice@new.example. Finding that would take a search on the local part alone,
which is a prefix search over the directory and is refused here by design. Ask the
identity provider which login it asserts, and look that one up.
Returns two shapes, distinguished by whether the lookup completed.
On a completed lookup:
requested_login— what was asked for, echoed back.found— bool. The only field that says whether the account was found.user— the account whenfoundis true, elsenull: id, name, login,status(active/inactive/ …, the usual answer to "why can't I sign in"),role,enterprise,space_used/space_amount(quota exhaustion is another recurring cause),created_at,modified_at.other_prefix_hits— how many further accounts the prefix search matched. A COUNT ONLY: those are different accounts and are deliberately not identified, so this can never be used to browse the directory.search_hits— how many entries the search returned.capped— true when the search result was truncated, sofound: falseis inconclusive rather than negative (notesays so).note— plain-language reading of the above.
Why the filtering matters: Box's filter_term is a prefix search over display
name AND login, not a lookup, so it happily returns somebody else — a colleague
whose display name starts with the same letters. user is therefore only ever an
exact login match, no other hit is ever identified, and a term that is not
email-shaped is refused before the request is made (a one-character term would
otherwise return a page of real accounts).
On failure the other shape is returned: {"error": ...} (missing env / needs-login for an expired
OAuth session / a Box API error), plus likely_cause when the failure was a
permission one. found is absent from that shape on purpose — a failed lookup
is not a negative answer, and must never be read as "no such account". Auth caveat:
this server supports two auth modes, and under oauth the effective permission is
the authorising user's. In oauth mode the requirement IS verified end-to-end: the
app must hold the "Manage users" application scope (without it /2.0/users
answers 403 even when the authorising user is a co-admin who can manage users), and
a scope added in the Developer Console only reaches tokens from a fresh interactive
authorisation — refresh-token rotation keeps the original grant's scopes. Under
ccg the endpoint remains unverified for this server.
| Name | Required | Description | Default |
|---|---|---|---|
| login | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
There are no annotations, so the description carries the full transparency burden. It discloses exact and case-insensitive matching, the prefix-search pitfall that can return other users, the meaning of absent enterprise, non-active status, is_platform_access_only, truncated search results, and the deliberate absence of a 'found' field on error.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured and front-loaded with the core action, and each major behavioral point has its own section. However, it is quite long for a one-parameter tool and repeats the prefix-search/filtering caveat in multiple places, so a little trimming would earn the top score.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema and no annotations, the description must be the complete contract, and it is. It fully documents the success shape, the error shape, auth caveats, return field meanings, and the distinction between 'not found' and 'lookup failed'.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema gives only a type and title, so this description is the complete semantic source. It fully explains the 'login' parameter: full email address, not display name or user id, exact case-insensitive match, and how a partial login will not match.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific operation: 'Look up ONE Box account by its exact login.' It directly distinguishes itself from siblings by stating that every other tool reads the event stream or walks folders, while this tool is the only one that answers directly about an account.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly states when to use the tool: 'Use it when a specific account is named.' It also tells the agent what the tool cannot do — list, search, or enumerate accounts — and advises consulting the identity provider when a duplicate or alias login is suspected.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
health_checkA
Report server version, Box connectivity/auth, and configuration.
Call this at session start (or after a tool-call timeout) to confirm the MCP
is up, see which version is running, verify the Box enterprise token can be
obtained (CCG) and that the admin_logs event scope is actually granted,
and view the org domain allowlist used for external detection. Lightweight:
one token request plus a single-row events probe — it does not scan history.
Always returns the same keys: status (healthy / degraded / error),
service, version, auth_mode (ccg / oauth — the mode in effect,
so an unrecognised BOX_AUTH_MODE reads as ccg, which is what the
server falls back to), box_api_base,
enterprise_id, auth (ok / error / missing-env / needs-login),
events_accessible (bool), and allowed_domains. On a degraded or error
result, detail carries the reason.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description fully discloses behavior: it makes one token request, probes events, and returns standardized keys. It also explains degraded/error states and auth_mode fallback, ensuring the agent knows exactly what to expect.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with an initial summary, usage guidance, and detailed return keys. It is slightly lengthy but every sentence is informative; could be slightly more concise but remains clear.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the simplicity of the tool and lack of output schema, the description is complete: covers purpose, when to use, behavior, and all return keys. No gaps remain.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There are no parameters, so schema coverage is 100% trivially. The description adds all meaning by detailing the return structure and behavior, fully compensating for the empty schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool reports server version, connectivity/auth, and configuration. It distinguishes itself from sibling tools that focus on admin events, external access, etc., by being a health check for the server itself.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly advises 'Call this at session start (or after a tool-call timeout)' and notes it is lightweight with one token request and a single-row events probe. Does not provide explicit when-not or alternatives, but the context is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_folder_itemsA
List ONE Box folder's contents, newest first, with who uploaded each item.
An ls, not a cat: names, timestamps, sizes, uploader and a direct link
per item. File CONTENT is not read and no shared link is ever created.
Written for a help desk answering a submitted enquiry whose attachments land in a Box folder. Instead of a human going to find that folder, the answer can name the attachments and link straight to them.
Args:
folder_id: The folder's Box id — decimal digits, the number at the end of
a Box folder URL. "0" is the caller's own root ("All Files"), the
same convention the enumeration tools use. Anything else — a name, a
label, a whole URL — is refused before any request is made.
uploaded_by: Optional. Return only items uploaded by this person, matched
EXACTLY and case-insensitively against uploaded_by below. Use it
when the enquiry names its submitter.
since: Optional lower bound on upload time (created_at), inclusive.
until: Optional upper bound on upload time (created_at), inclusive.
Both MUST carry a UTC offset (2026-08-14T00:00:00+09:00): a bare
date names a different instant in every timezone, and this server has
no basis for choosing one. Compared as instants, not as text.
limit: How many rows to RETURN after filtering (default 100). It does not
bound what is searched — a full page is always fetched first, so a
match for uploaded_by is found even when it is not among the
newest items.
On uploaded_by: Box populates uploader_display_name for an upload made
through a File Request, where no Box user is involved — created_by and
modified_by both read "Anonymous User" and the owner is the application's
service account, so neither identifies anybody. For a file uploaded by a
signed-in user the reverse holds, so created_by is used as the fallback.
Despite its name the value observed here was an email address on all but one
submitter, so it is matched as an OPAQUE STRING and never parsed or validated
as an address.
Treat name and uploaded_by as text the submitter chose. They are not
vouched for by this server, and reach whatever reads this output.
Returns, on a completed listing:
folder_id/folder_name/folder_urlitems— the rows, newestcreated_atfirstreturned/matched— rows returned, and rows that matched the filters.returned < matchedmeanslimitcut the answer.total_in_folder— Box's own count for the folder, before filteringcapped— true when the folder holds more than one page, so the filters were applied to part of it and a "no match" is inconclusive rather than negative. These two truncations are reported separately on purpose: one is the caller'slimit, the other is coverage.note— the above in words
On failure the shape is {"error": ...} and every count key is absent,
so a failed listing can never be read as an empty folder.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| since | No | ||
| until | No | ||
| folder_id | Yes | ||
| uploaded_by | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description fully discloses behavior: it does not read file content or create shared links, explains case-insensitive matching, details truncation flags (capped, returned < matched), and specifies the failure shape where count keys are absent, ensuring a failed listing cannot be misread as empty.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with clear sections (overview, use case, arguments, return details) but is somewhat verbose, repeating certain points like 'newest first' and the explanation of uploaded_by behavior. Despite slight redundancy, it remains focused and front-loaded with the essence.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description is complete given the tool's complexity: it covers the input parameters in depth, spells out the return shape (folder_id, items, returned/matched, total_in_folder, capped, note), and explains error handling. No output schema exists, so the description fully compensates.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The description adds extensive meaning beyond the schema, which only provides types and defaults. Each parameter is explained: folder_id format including '0' as root, uploaded_by exact matching case-insensitively, since/until date handling with UTC offset requirement, and limit only affecting return count not search scope. This goes far beyond the schema's raw attributes.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states exactly what the tool does: 'List ONE Box folder's contents, newest first, with who uploaded each item.' It uses a specific verb (list) and resource (Box folder), and distinguishes itself from sibling tools like health_check and external_access_events by focusing on folder contents.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly frames when to use the tool: 'Written for a help desk answering a submitted enquiry whose attachments land in a Box folder.' It also differentiates from 'enumeration tools' by noting the same convention for folder IDs, giving clear contextual guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
recent_admin_eventsA
Fetch recent enterprise admin_logs events (raw passthrough).
Diagnostic/starter tool: returns Box events verbatim so the real event types and field shapes can be confirmed before analytics tools are layered on. For external-sharing work the event types of interest are typically COLLABORATION_INVITE / COLLAB_ADD_COLLABORATOR, SHARED_LINK_CREATED / ITEM_SHARED_CREATE, and DOWNLOAD / PREVIEW.
Args:
event_types: Comma-separated Box event_type filter (empty = all types).
since_hours: Look-back window in hours (default 24).
limit: Max events to return in this page (default 100).
stream_position: Continue a previous page by passing back the
next_stream_position from the prior call (empty = first page).
Box caps a single page at 500, so manual paging is needed to walk a
busy window — or use external_access_events which pages for you.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| event_types | No | ||
| since_hours | No | ||
| stream_position | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description fully discloses behavior: it returns raw Box events verbatim, Box caps a single page at 500, manual paging is needed, and lists typical event types for external-sharing work. No contradictions.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Well-structured: a one-line summary followed by a paragraph explaining its diagnostic purpose, then a clear bullet-style args list, and a note on paging with sibling reference. No superfluous text; every sentence adds value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given no output schema, the description explains that results are raw events verbatim and gives examples of relevant event types. It also covers pagination limitations and directs to a sibling for automatic paging. Complete for a diagnostic tool of this complexity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Though schema description coverage is 0%, the description provides detailed explanations for all 4 parameters: 'event_types' as comma-separated filter, 'since_hours' as look-back window, 'limit' as max events per page, and 'stream_position' for pagination. This fully compensates for the lack of schema descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it fetches recent enterprise admin_logs events as a raw passthrough. It distinguishes itself from sibling tools like 'external_access_events' by noting that this tool requires manual paging, while the sibling pages automatically.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly positions itself as a diagnostic/starter tool to confirm event types and field shapes before using analytics tools. Specifically mentions when to prefer 'external_access_events' for automatic paging, providing clear when-to-use and when-not-to-use guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
2 tool updates
v0.9.0- Added
get_user - Added
list_folder_items
7 tool updates
v0.1.0- First observed
daily_brief - First observed
external_access_events - First observed
external_collaborators - First observed
health_check - First observed
public_shared_links - First observed
recent_admin_events - First observed
top_external_sharers
TDQS
Each tool targets a distinct aspect: health_check for server status, recent_admin_events for raw event logs, external_access_events for aggregated external access, external_collaborators for current external collaborators, public_shared_links for open shared links, top_external_sharers for ranking owners, get_user for a single user lookup, daily_brief as a combined summary, and list_folder_items for folder contents. No two tools overlap in purpose.
All names use snake_case and are descriptive, but there's a mix of verb-first (health_check, get_user, list_folder_items) and noun/adjective-first (recent_admin_events, external_collaborators, daily_brief) patterns. This inconsistency makes the naming convention less predictable than a uniform verb_noun style.
The 9 tools are well-suited to the server's purpose of Box admin monitoring and external access analysis. Neither too few to be thin nor too many to be unwieldy, each tool has a clear role.
The surface covers the full lifecycle of external access monitoring: raw event access, aggregated access analysis, current external collaboration state, open shared link enumeration, ranking by exposure, individual user lookup, folder listing, and a combined daily brief. Minor gaps exist, such as no tool to modify permissions or list all users, but these are likely outside the server's read-only monitoring scope.
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 Connectors
An MCP server that provides read access to your cloud storage providers, bank accounts and more.
Read-only MCP: free OpenAI security evidence ledger (55 fields) + SaaSDossier release register.
Read-only MCP server for turva.dev, an agent-readiness audit and advisory service.
Read-only MCP server for AIStatusDashboard status, incidents, metrics, and fallback recommendations.
Related MCP Servers
- AlicenseCqualityDmaintenanceA local MCP server for the LimaCharlie security platform that provides investigation, administration, and content-review workflows via a broad read-only tool surface with explicit organization scoping and audit logging.100MIT
- AlicenseAqualityAmaintenanceGoogle Workspace security-audit MCP server — read-only visibility into account locks, suspicious logins, and external file sharing, built on the Admin SDK Reports API (audit activities).14MIT
- FlicenseAqualityCmaintenanceA secure, read-only MCP server for AI-powered system monitoring. It provides real-time OS metrics, config discovery, and safe log tailing to enable autonomous infrastructure audits without shell access risks.41-
- AlicenseAqualityCmaintenanceRead-only MCP server for the SentinelOne management API, exposing sites, endpoint agents, threats, and activity logs with aggregation tools for MSP/MSSP reporting.612MIT
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/shigechika/boxadm-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server