# Extending the MCP server

## Locate the source of truth

- `artifacts/api-server/src/mcp/catalogue.ts`: core modules and atomic operations.
- `extended-catalogue.ts`, `field-tools.ts`, `file-tools.ts`: additional business tools.
- `tool-schema.ts`: UUID/date/money/file validators and editable-field allowlists.
- `routes.ts`: transport, tool registration, exact approvals, resources and prompts.
- `bridge.ts`, `guards.ts`: real-user delegation and referenced-record tenant checks.
- `security-policy.ts`, `security-runtime.ts`, `security-scope.ts`, `security-store.ts`: permissions, masking, safe scopes and persistent enforcement.
- `outcome-catalogue.ts`, `outcome-server.ts`, `outcome-data.ts`, `detail-data.ts`: higher-level read workflows and view data.
- `lib/mcp-app-ui`: shared host-rendered UI.
- `lib/api-spec/openapi.yaml`: session-management API contracts.

## Add an atomic tool

1. Reuse an existing authorized business API, or implement/test that API first. Never expose arbitrary HTTP/SQL, integration credentials, identity management, platform administration or payment execution.
2. Add one focused catalogue operation with name, outcome-oriented description, module, method, internal path, sensitivity and a strict Zod input schema.
3. Allow only editable business fields. Exclude tenant/user ownership, payment state, approval overrides, audit fields and internal flags. Preserve decimal-string money and ISO date validation.
4. Add tenant checks for every referenced UUID. Reject foreign references before creating an approval, not just during execution.
5. Check `actionOf`: name/method determine action policy. A new POST command is not necessarily a create. Set sensitivity deliberately; do not rely on tool annotations for human approval.
6. If the tool must support narrowed record scopes, implement a safe scope relationship/filter. Unsupported scope relationships must deny; do not return globally authorized but connection-excluded records.
7. Execute through the existing bridge and `runOperation`, never by directly bypassing the business API from a tool callback. This preserves current user checks, quotas, scopes, response limits and audit.
8. Test allowed, denied, foreign-tenant, invalid-input, changed-role, revoked-token, default-approval and configurable-approval paths. Add output masking/size/document tests where applicable.

Descriptions should name the user's outcome, required UUIDs, relevant boundaries and meaningful uncertainty. Do not embed user data in descriptions or suggest that a reported risk certifies readiness. A tool-level `sensitive` flag is a default; current policy determines whether MCP review is required.

## Add a read-only outcome or dashboard

Define module requirements and a strict input schema in the outcome catalogue. Compose existing authorized reads through injected `execute`, not raw database reads that omit connection scopes. Use `before`/`finish` security hooks. Limit scans, disclose incompleteness and keep unknown financial facts unknown.

Register shared UI metadata through `_meta.ui.resourceUri`; serve a self-contained resource with the standard MCP Apps MIME type. Use the existing App bridge for refresh, drill-down and theme/display capabilities. Do not fetch the API directly from the iframe or put bearer/session credentials inside it.

Native views must remain read-only. Human approval belongs in the application, not in a synthetic assistant response or a dashboard button. Validate record text as untrusted; do not let it choose executable tools or unchecked navigation destinations. Preserve structured/text fallback for non-UI hosts.

Optional provider-specific enhancements must be capability-detected. Do not require a provider model SDK to implement MCP or claim that widget support guarantees directory recommendations.

## Contracts and schema changes

When adding/changing a session-management API, update `lib/api-spec/openapi.yaml`, regenerate with `pnpm --filter @workspace/api-spec run codegen`, then typecheck affected packages. Public machine-readable policy schemas come directly from the enforced validators.

Add database structures to the Drizzle schema and use the documented development-side migration workflow in `replit.md`. Only explicitly configured development startup may apply SQL migrations. Production and publish-test startup perform read-only assertions; **Publish owns the development-to-production schema diff**. Do not add build/startup production DDL or manually mark migrations applied to suppress a failure.

## Documentation and publication

Update relevant guides in `docs/mcp` and provider guidance if behavior changed. These files are copied into the API build and served from an allowlisted public documentation registry; there is no separately edited HTML copy.

Adding a guide requires a registry entry in `developer-docs.ts`. Add public-route and link checks before release. Avoid fixed tool-count claims: the runtime catalogue is authoritative.
