MCP Module Code Standard
Why a code standard matters
Every connector we ship looks the same. That is not an accident — it is a discipline. When a second integration arrives, the agent's capabilities are easier to test, audit, and swap because every MCP module follows the same structure, naming, and error contract.
This document defines the standard for all MCP modules in the IdeaBosque orchestration backbone. It covers directory layout, tool registration, input/output schemas, error handling, rate limiting, audit logging, and PII boundary handling.
Directory structure
Each MCP module lives in its own directory under app/mcp_modules/ with a consistent layout:
app/mcp_modules/<slug>/
__init__.py
module.py # Tool registration + handlers
schemas.py # Input/output Pydantic models
tests/
test_module.py
README.md
Tool registration
Every module registers its tools through a standard interface. The orchestration backbone discovers tools by scanning for the register_tools() entry point — no manual wiring.
def register_tools(registrar):
"""Register all tools provided by this module."""
registrar.tool(
name="search_catalog",
description="Search supplier catalog by SKU or name",
input_schema=SearchCatalogInput,
output_schema=SearchCatalogOutput,
rate_limit=120, # calls per minute
)
Error handling
Modules must raise typed exceptions, not bare strings. The backbone catches MCPToolError subclasses and converts them to structured responses the agent can reason about:
- MCPAuthError — credentials missing or expired
- MCPRateLimitError — upstream rate limit hit
- MCPTimeoutError — upstream call exceeded the configured timeout
- MCPValidationError — input did not pass schema validation
- MCPUpstreamError — upstream returned an error status
Rate limiting
Each tool declares its own rate limit in the registration call. The backbone enforces these per-agent, per-tool, and per-window. When a limit is hit, the agent receives a 429 response with a Retry-After header — it does not crash or retry blindly.
Audit logging
Every tool call is logged with: timestamp, agent ID, tool name, input hash (not raw input — PII boundary), output status, duration, and upstream system. Logs are written to structured JSON and shipped to the observability pipeline.
"Every tool call is logged and auditable" is not a feature we add later. It is the first thing the standard requires.
PII boundary handling
Modules must declare which input fields contain PII. The backbone hashes these fields before logging and never sends raw PII to the audit pipeline. PII fields are marked in the schema:
class SearchCatalogInput(BaseModel):
sku: str
customer_name: str = Field(..., pii=True)
region: str
When pii=True is set, the audit logger replaces the value with a SHA-256 hash. The tool handler still receives the raw value — PII handling is enforced at the logging boundary, not inside the business logic.
Want this built for your systems?
Every document here comes from real production work. If you have a target system and a workflow in mind, we can scope a build in one week.
Request a scoped buildOne-week discovery. You get a system inventory, workflow map, and fixed scope — whether or not you build with us.