Skip to main content
Glama

Finizi B4B MCP Server

by hqtrung
API_MAPPING.md12.5 kB
# API Mapping Reference This document provides comprehensive mapping between MCP tools and B4B API endpoints, including all 15 implemented tools with their complete specifications. ## Overview The Finizi B4B MCP Server implements 15 tools that map to various B4B API endpoints. All API requests (except login) require JWT authentication via Bearer token in the Authorization header. ## Authentication Flow Diagram ```mermaid sequenceDiagram participant User as User/AI Assistant participant MCP as MCP Server participant Session as Session Store participant B4B as B4B API User->>MCP: login(phone, password) MCP->>B4B: POST /api/v1/auth/login B4B-->>MCP: {access_token, refresh_token, user_info} MCP->>Session: Store tokens in metadata MCP-->>User: {success: true, user_info} User->>MCP: Any authenticated request MCP->>Session: Extract token MCP->>B4B: Request with Bearer token B4B-->>MCP: Response data MCP-->>User: Formatted response ``` ## Complete Tool-to-Endpoint Mapping ### Authentication Tools (3) | MCP Tool | HTTP Method | B4B API Endpoint | Description | Authentication Required | |----------|-------------|------------------|-------------|------------------------| | `login` | POST | `/api/v1/auth/login` | Authenticate user with phone and password | No | | `logout` | N/A | Local session clear | Clear stored tokens from session | No | | `whoami` | GET | `/api/v1/users/me` | Get current authenticated user info | Yes | ### Entity Management Tools (4) | MCP Tool | HTTP Method | B4B API Endpoint | Description | Authentication Required | |----------|-------------|------------------|-------------|------------------------| | `list_entities` | GET | `/api/v1/entities` | List entities with pagination and search | Yes | | `get_entity` | GET | `/api/v1/entities/{entity_id}` | Get detailed entity information | Yes | | `create_entity` | POST | `/api/v1/entities` | Create new business entity | Yes | | `update_entity` | PUT | `/api/v1/entities/{entity_id}` | Update existing entity | Yes | ### Invoice Management Tools (4) | MCP Tool | HTTP Method | B4B API Endpoint | Description | Authentication Required | |----------|-------------|------------------|-------------|------------------------| | `list_invoices` | GET | `/api/v1/entities/{entity_id}/invoices` | List invoices with filtering | Yes | | `get_invoice` | GET | `/api/v1/entities/{entity_id}/invoices/{invoice_id}` | Get detailed invoice | Yes | | `import_invoice_xml` | POST | `/api/v1/entities/{entity_id}/invoices/import/xml` | Import invoice from XML | Yes | | `get_invoice_statistics` | GET | `/api/v1/entities/{entity_id}/invoices/statistics` | Get invoice analytics | Yes | ### Vendor Management Tools (2) | MCP Tool | HTTP Method | B4B API Endpoint | Description | Authentication Required | |----------|-------------|------------------|-------------|------------------------| | `list_vendors` | GET | `/api/v1/entities/{entity_id}/vendors` | List vendors with search | Yes | | `get_vendor` | GET | `/api/v1/entities/{entity_id}/vendors/{vendor_id}` | Get vendor details | Yes | ### Product Management Tools (2) | MCP Tool | HTTP Method | B4B API Endpoint | Description | Authentication Required | |----------|-------------|------------------|-------------|------------------------| | `list_products` | GET | `/api/v1/entities/{entity_id}/products` | List products with filtering | Yes | | `search_similar_products` | POST | `/api/v1/entities/{entity_id}/products/search/similar` | AI-powered similar product search | Yes | ## Detailed Tool Specifications ### Authentication Tools #### login ```python async def login(phone: str, password: str, ctx: Context) -> dict ``` **Request Body:** ```json { "phone": "+84909495665", "password": "SecurePass123@" } ``` **Response:** ```json { "success": true, "message": "Successfully logged in as user@example.com", "user_id": "550e8400-e29b-41d4-a716-446655440000", "email": "user@example.com", "is_super_admin": false } ``` #### logout ```python async def logout(ctx: Context) -> dict ``` **Response:** ```json { "success": true, "message": "Successfully logged out (was: user@example.com)" } ``` #### whoami ```python async def whoami(ctx: Context) -> dict ``` **Response:** ```json { "success": true, "user": { "id": "550e8400-e29b-41d4-a716-446655440000", "email": "user@example.com", "phone": "+84909495665", "is_super_admin": false, "entities": [...] } } ``` ### Entity Management Tools #### list_entities ```python async def list_entities( page: int = 1, per_page: int = 20, search: Optional[str] = None, ctx: Context = None ) -> dict ``` **Query Parameters:** - `page`: Page number (default: 1) - `per_page`: Items per page, max 100 (default: 20) - `search`: Search in entity name or tax code **Response:** ```json { "items": [...], "total": 150, "page": 1, "per_page": 20, "pages": 8 } ``` #### get_entity ```python async def get_entity(entity_id: str, ctx: Context) -> dict ``` **Path Parameters:** - `entity_id`: UUID of the entity **Response:** ```json { "id": "550e8400-e29b-41d4-a716-446655440000", "name": "Tech Corp Ltd", "entity_type": "COMPANY", "tax_code": "1234567890", "address": "123 Tech Street", "city": "San Francisco", "country": "USA", "created_at": "2024-01-01T00:00:00Z" } ``` #### create_entity ```python async def create_entity( name: str, entity_type: str, tax_code: str, address: str, city: str, country: str, ctx: Context ) -> dict ``` **Request Body:** ```json { "name": "New Tech Corp", "entity_type": "COMPANY", "tax_code": "9876543210", "address": "456 Innovation Ave", "city": "San Francisco", "country": "USA" } ``` #### update_entity ```python async def update_entity( entity_id: str, name: Optional[str] = None, address: Optional[str] = None, city: Optional[str] = None, country: Optional[str] = None, ctx: Context = None ) -> dict ``` **Request Body:** (partial update supported) ```json { "name": "Updated Tech Corp", "address": "789 New Street" } ``` ### Invoice Management Tools #### list_invoices ```python async def list_invoices( entity_id: str, page: int = 1, per_page: int = 20, date_from: Optional[str] = None, date_to: Optional[str] = None, status: Optional[int] = None, search: Optional[str] = None, ctx: Context = None ) -> dict ``` **Query Parameters:** - `entity_id`: UUID of the entity (required) - `page`: Page number - `per_page`: Items per page - `date_from`: Start date (ISO format: YYYY-MM-DD) - `date_to`: End date (ISO format: YYYY-MM-DD) - `status`: Invoice status (0=DRAFT, 1=ACTIVE, 2=CANCELLED, 3=ARCHIVED) - `search`: Search in invoice number or vendor name #### get_invoice ```python async def get_invoice( entity_id: str, invoice_id: str, ctx: Context ) -> dict ``` **Path Parameters:** - `entity_id`: UUID of the entity - `invoice_id`: UUID of the invoice #### import_invoice_xml ```python async def import_invoice_xml( entity_id: str, xml_content: str, ctx: Context = None ) -> dict ``` **Request Body:** ```json { "xml_content": "<?xml version='1.0'?><Invoice>...</Invoice>" } ``` #### get_invoice_statistics ```python async def get_invoice_statistics( entity_id: str, date_from: Optional[str] = None, date_to: Optional[str] = None, ctx: Context = None ) -> dict ``` **Response:** ```json { "total_count": 150, "total_amount": 250000.00, "by_status": { "DRAFT": 10, "ACTIVE": 120, "CANCELLED": 5, "ARCHIVED": 15 }, "by_month": [...], "top_vendors": [...] } ``` ### Vendor Management Tools #### list_vendors ```python async def list_vendors( entity_id: str, page: int = 1, per_page: int = 20, search: Optional[str] = None, ctx: Context = None ) -> dict ``` **Query Parameters:** - `entity_id`: UUID of the entity - `page`: Page number - `per_page`: Items per page - `search`: Search in vendor name or tax ID #### get_vendor ```python async def get_vendor( entity_id: str, vendor_id: str, ctx: Context ) -> dict ``` **Path Parameters:** - `entity_id`: UUID of the entity - `vendor_id`: UUID of the vendor ### Product Management Tools #### list_products ```python async def list_products( entity_id: str, page: int = 1, per_page: int = 20, category: Optional[str] = None, search: Optional[str] = None, ctx: Context = None ) -> dict ``` **Query Parameters:** - `entity_id`: UUID of the entity - `page`: Page number - `per_page`: Items per page - `category`: Product category filter - `search`: Search in product name or description #### search_similar_products ```python async def search_similar_products( entity_id: str, query: str, max_results: int = 10, ctx: Context = None ) -> dict ``` **Request Body:** ```json { "query": "15-inch laptop with 16GB RAM", "max_results": 10 } ``` **Response:** ```json { "results": [ { "product_id": "...", "name": "Dell XPS 15", "similarity_score": 0.95, "price": 1500.00, "category": "Electronics" } ] } ``` ## Authorization Model ### Token Types - **Access Token**: Short-lived JWT for API authentication (expires in 1 hour) - **Refresh Token**: Long-lived token for obtaining new access tokens (expires in 30 days) ### Permission Levels 1. **Super Admin**: Full access to all entities and operations 2. **Entity Admin**: Full access to assigned entities 3. **Entity User**: Read/write access to assigned entities 4. **Entity Viewer**: Read-only access to assigned entities ### Token Storage Tokens are stored in MCP session metadata: ```python ctx.session.metadata = { "user_token": "eyJhbGciOiJIUzI1NiIs...", "refresh_token": "refresh_token_here", "user_email": "user@example.com", "user_id": "550e8400-e29b-41d4-a716-446655440000", "is_super_admin": false } ``` ## Error Handling Patterns ### HTTP Status Code Mapping | HTTP Status | MCP Exception | Description | |-------------|---------------|-------------| | 400 | MCPValidationError | Invalid request parameters | | 401 | MCPAuthenticationError | Invalid or expired token | | 403 | MCPAuthorizationError | Insufficient permissions | | 404 | MCPNotFoundError | Resource not found | | 409 | MCPConflictError | Resource conflict (duplicate) | | 422 | MCPValidationError | Unprocessable entity | | 429 | MCPRateLimitError | Too many requests | | 500+ | MCPServerError | Server error | ### Error Response Format ```json { "success": false, "error": "Detailed error message", "error_code": "ERROR_CODE", "details": { "field_errors": {...} } } ``` ## Response Formats ### Paginated Response ```json { "items": [...], "total": 1000, "page": 1, "per_page": 20, "pages": 50, "has_next": true, "has_prev": false } ``` ### Single Resource Response ```json { "id": "uuid", "created_at": "2024-01-01T00:00:00Z", "updated_at": "2024-01-01T00:00:00Z", ...resource_fields } ``` ### Operation Result Response ```json { "success": true, "message": "Operation completed successfully", "data": {...} } ``` ## Rate Limiting The B4B API implements rate limiting per user: - **Default**: 100 requests per minute - **Authenticated**: 1000 requests per minute - **Super Admin**: 5000 requests per minute Rate limit headers: - `X-RateLimit-Limit`: Maximum requests allowed - `X-RateLimit-Remaining`: Requests remaining - `X-RateLimit-Reset`: Unix timestamp for limit reset ## Best Practices 1. **Always authenticate first**: Call `login` before any other operations 2. **Handle token expiration**: Implement token refresh logic 3. **Use pagination**: For large datasets, always use pagination parameters 4. **Implement retry logic**: Handle transient failures with exponential backoff 5. **Validate UUIDs**: Ensure all entity/invoice/vendor IDs are valid UUIDs 6. **Log errors**: Capture error responses for debugging 7. **Clean up sessions**: Always call `logout` when done ## API Versioning The API version is specified in the URL path: - Current version: `v1` - Base URL format: `https://api.finizi.com/api/v1/...` Version compatibility: - Breaking changes require new major version - Minor versions add features without breaking existing ones - Patch versions fix bugs without changing functionality --- **Last Updated**: October 2024 **API Version**: v1 **MCP Server Version**: 1.0.0

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/hqtrung/finizi-mcp'

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