Version: 1.0.0 Protocol Version: 2025-11-25 flAPI Version: >= 1.0.0
This document provides a comprehensive reference for flAPI's MCP (Model Context Protocol) implementation, covering protocol details, configuration, and usage.
- Overview
- Getting Started
- Protocol Reference
- MCP Methods
- Tools
- Resources
- Prompts
- Authentication
- Content Types
- Testing & Examples
MCP (Model Context Protocol) is a JSON-RPC 2.0 based protocol designed for AI model integration. It provides a standardized way for AI assistants and agents to interact with data sources, execute tools, and access resources.
flAPI implements MCP as a first-class protocol alongside REST, allowing the same YAML configurations to expose both REST endpoints and MCP tools/resources.
Key Benefits:
| Benefit | Description |
|---|---|
| Unified Configuration | Same YAML defines both REST and MCP interfaces |
| AI-Optimized | Structured tool definitions with input schemas for LLM consumption |
| Session-Based | Persistent sessions with authentication context |
| Type-Safe | JSON Schema validation for tool inputs |
┌─────────────────────────────────────────────────────────────┐
│ MCP Client │
│ (Claude, GPT, Custom Agent) │
└─────────────────────┬───────────────────────────────────────┘
│ JSON-RPC 2.0 / HTTP
▼
┌─────────────────────────────────────────────────────────────┐
│ flAPI Server │
├─────────────────────────────────────────────────────────────┤
│ POST /mcp/jsonrpc ─────────► MCPRouteHandlers │
│ │ │
│ ┌─────────────────────────────────────┴──────────────────┐ │
│ │ MCP Session Manager │ │
│ │ - Session lifecycle │ │
│ │ - Auth context tracking │ │
│ │ - Protocol version negotiation │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────────────────┼─────────────────────────────┐ │
│ │ Tools │ Resources │ Prompts │ │
│ │ ───── │ ───────── │ ─────── │ │
│ │ mcp-tool: │ mcp-resource:│ mcp-prompt: │ │
│ │ configs │ configs │ configs │ │
│ └──────────────┴───────────────┴────────────────────────┘ │
│ │ │
│ ┌──────┴──────┐ │
│ │ DuckDB │ │
│ │ Engine │ │
│ └─────────────┘ │
└─────────────────────────────────────────────────────────────┘
flAPI supports multiple MCP protocol versions for backward compatibility:
| Version | Release | Status | Notes |
|---|---|---|---|
2025-11-25 |
Latest | Default | Full feature support |
2025-06-18 |
Q2 2025 | Supported | - |
2025-03-26 |
Q1 2025 | Supported | - |
2024-11-05 |
Q4 2024 | Supported | Initial MCP specification |
The server negotiates the highest mutually supported version during initialize.
Implementation:
src/mcp_server.cpp,src/mcp_route_handlers.cpp| Tests:test/cpp/mcp_server_test.cpp,test/integration/test_mcp_methods.py
MCP is enabled in flapi.yaml under the mcp section:
# flapi.yaml
mcp:
enabled: true
port: 8080 # Same port as REST (shared)
host: localhost
allow-list-changed-notifications: true
# Instructions for LLM clients (optional)
instructions-file: ./mcp_instructions.md
# Or inline:
# instructions: |
# # flapi MCP Server
# Use tools for customer lookups.| Property | Type | Default | Description |
|---|---|---|---|
enabled |
boolean | true |
Enable/disable MCP server |
port |
integer | 8080 |
HTTP port (shared with REST) |
host |
string | localhost |
Bind address |
allow-list-changed-notifications |
boolean | true |
Enable listChanged capability |
instructions-file |
string | - | Path to instructions markdown file |
instructions |
string | - | Inline instructions for LLM clients |
The MCP server exposes two categories of tools:
-
Declarative Tools (Always available when MCP enabled)
- Tools defined in YAML configuration files via
mcp-toolsections - Endpoint-based tools from REST API definitions
- Tools defined in YAML configuration files via
-
Configuration Management Tools (Only when
--config-serviceflag is used)flapi_*tools for runtime management of endpoints, templates, caches- 18 tools organized in 4 categories: Discovery, Template, Endpoint, Cache
- See MCP Configuration Tools API Reference
To enable configuration tools:
./flapi --config-service
# or with custom token
./flapi --config-service --config-service-token "your-token"Note: Without the --config-service flag, only declarative tools are available in tools/list responses.
MCP Endpoint: POST /mcp/jsonrpc
To establish a session, send an initialize request:
curl -X POST http://localhost:8080/mcp/jsonrpc \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-11-25",
"clientInfo": {
"name": "my-client",
"version": "1.0.0"
}
}
}'Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2025-11-25",
"capabilities": {
"tools": { "listChanged": true },
"resources": { "subscribe": false, "listChanged": true },
"prompts": { "listChanged": true },
"logging": {}
},
"serverInfo": {
"name": "flapi-mcp-server",
"version": "0.3.0"
},
"instructions": "# flapi MCP Server\n..."
}
}The response includes an Mcp-Session-Id header that must be included in subsequent requests.
Check MCP server status without JSON-RPC:
curl http://localhost:8080/mcp/healthResponse:
{
"status": "healthy",
"server": "flapi-mcp-server",
"version": "0.3.0",
"protocol_version": "2025-11-25",
"mcp_available": true,
"tools_available": true,
"resources_available": true,
"tools_count": 5,
"resources_count": 2
}All MCP requests use JSON-RPC 2.0 over HTTP POST.
Request Format:
{
"jsonrpc": "2.0",
"id": "<string|number>",
"method": "<method_name>",
"params": { ... }
}| Field | Type | Required | Description |
|---|---|---|---|
jsonrpc |
string | Yes | Must be "2.0" |
id |
string/number | Yes | Request identifier (returned in response) |
method |
string | Yes | MCP method name |
params |
object | No | Method-specific parameters |
Response Format (Success):
{
"jsonrpc": "2.0",
"id": "<matching_id>",
"result": { ... }
}Response Format (Error):
{
"jsonrpc": "2.0",
"id": "<matching_id>",
"error": {
"code": -32600,
"message": "Invalid Request"
}
}MCP uses HTTP headers for session tracking:
| Header | Direction | Description |
|---|---|---|
Mcp-Session-Id |
Response → Request | Session identifier |
Content-Type |
Both | Must be application/json |
Authorization |
Request | Authentication credentials (if required) |
Session Lifecycle:
- Creation: New session created on first
initializerequest - Maintenance: Session ID returned in
Mcp-Session-Idheader - Usage: Include session ID header in all subsequent requests
- Cleanup: Send
DELETE /mcp/jsonrpcwith session ID to close - Timeout: Sessions expire after 30 minutes of inactivity (configurable)
Close Session:
curl -X DELETE http://localhost:8080/mcp/jsonrpc \
-H "Mcp-Session-Id: <session_id>"Implementation:
src/mcp_session_manager.cpp| Tests:test/integration/test_mcp_sessions.py
flAPI uses standard JSON-RPC error codes plus MCP-specific codes:
| Code | Name | Description |
|---|---|---|
-32700 |
Parse Error | Invalid JSON |
-32600 |
Invalid Request | Not a valid JSON-RPC request |
-32601 |
Method Not Found | Unknown method name |
-32602 |
Invalid Params | Invalid method parameters |
-32603 |
Internal Error | Internal server error |
-32001 |
Authentication Required | Method requires authentication |
-32000 |
Session Error | Session-related errors |
During initialize, client and server negotiate the protocol version:
Client sends: "protocolVersion": "2025-11-25"
Server supports: ["2024-11-05", "2025-03-26", "2025-06-18", "2025-11-25"]
Negotiated: "2025-11-25" (highest mutually supported)
If the client requests an unknown version, the server uses its latest supported version and logs a warning.
Establishes a new MCP session and negotiates capabilities.
Request:
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-11-25",
"clientInfo": {
"name": "my-client",
"version": "1.0.0"
},
"capabilities": {
"sampling": {},
"roots": {}
}
}
}| Parameter | Type | Required | Description |
|---|---|---|---|
protocolVersion |
string | Yes | Desired protocol version |
clientInfo.name |
string | No | Client name |
clientInfo.version |
string | No | Client version |
capabilities |
object | No | Client capabilities |
Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2025-11-25",
"capabilities": {
"tools": { "listChanged": true },
"resources": { "subscribe": false, "listChanged": true },
"prompts": { "listChanged": true },
"logging": {}
},
"serverInfo": {
"name": "flapi-mcp-server",
"version": "0.3.0"
},
"instructions": "..."
}
}| Field | Type | Description |
|---|---|---|
protocolVersion |
string | Negotiated protocol version |
capabilities.tools |
object | Tool capabilities |
capabilities.resources |
object | Resource capabilities |
capabilities.prompts |
object | Prompt capabilities |
capabilities.logging |
object | Logging capabilities |
serverInfo |
object | Server identification |
instructions |
string | Usage instructions for LLM clients |
Implementation:
src/mcp_route_handlers.cpp| Tests:test/cpp/mcp_server_test.cpp,test/integration/test_mcp_methods.py
Health check for active sessions.
Request:
{
"jsonrpc": "2.0",
"id": 2,
"method": "ping",
"params": {}
}Response:
{
"jsonrpc": "2.0",
"id": 2,
"result": {}
}Returns an empty object on success.
Implementation:
src/mcp_route_handlers.cpp| Tests: None - see TEST_TODO.md
Lists all available MCP tools.
Request:
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/list",
"params": {}
}Response:
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"tools": [
{
"name": "customer_lookup",
"description": "Retrieve customer information by ID",
"inputSchema": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "Customer ID"
}
},
"required": ["id"]
}
}
]
}
}| Field | Type | Description |
|---|---|---|
tools[].name |
string | Unique tool identifier |
tools[].description |
string | Human-readable description |
tools[].inputSchema |
object | JSON Schema for tool inputs |
Implementation:
src/mcp_route_handlers.cpp| Tests:test/integration/test_mcp_methods.py,test/integration/test_mcp_integration.py
Executes an MCP tool with provided arguments.
Request:
{
"jsonrpc": "2.0",
"id": 4,
"method": "tools/call",
"params": {
"name": "customer_lookup",
"arguments": {
"id": "12345"
}
}
}| Parameter | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Tool name to execute |
arguments |
object | No | Tool input arguments |
arguments._dryRun |
boolean | No | Reserved flag. When true, flAPI renders the SQL (with ? placeholders for typed params), validates inputs, and returns the rendered SQL + execution plan as a JSON payload without executing the query. Use for shadow-mode auditing and pre-production batch validation. See § 4.4.1 Dry-run mode |
Response:
{
"jsonrpc": "2.0",
"id": 4,
"result": {
"content": [
{
"type": "text",
"text": "[{\"id\":12345,\"name\":\"John Doe\",\"email\":\"john@example.com\"}]"
}
]
}
}Tool results are returned as content blocks (see Content Types).
Authorization: when mcp.auth.enabled: true, every tool MUST declare mcp-tool.allowed-roles in its YAML. Calls from a JWT/OIDC principal whose roles claim doesn't intersect the allowed list return:
{"jsonrpc":"2.0","id":4,"error":{"code":-32603,"message":"Permission denied: Tool 'X' requires one of [analyst]; caller has [reader]."}}Tools without allowed-roles are denied — this is the secure-by-default stance.
Per-tool rate limit: if mcp-tool.rate-limit.enabled: true, requests over the configured budget receive a JSON-RPC error similar to the RBAC denial. Rate limits are keyed on the authenticated principal (with an anonymous fallback bucket per tool).
Response shaping: the tool's mcp-tool.response block (see CONFIG_REFERENCE § 2.6) applies redaction, row-count caps, or summary-only sampling to the result before it enters the content block.
Set arguments._dryRun: true to run the validate → render → plan pipeline without executing the query. Useful for:
- Pre-production audit: have every tool definition exercised by a smoke-test harness before promoting the endpoint.
- Operator debugging: see exactly what SQL would have been built for a given parameter set.
Request:
{
"jsonrpc":"2.0","id":4,"method":"tools/call",
"params":{"name":"customer_lookup","arguments":{"id":42,"_dryRun":true}}
}Response payload (inside result.content[0].text, JSON-encoded):
{
"dry_run": true,
"rendered_sql": "SELECT 42 AS customer_id, 'fake' AS name",
"params": {"id": "42"}
}The dry-run path does NOT skip validators, role checks, or rate limits — it skips only the SQL execution step. A caller that lacks the role to invoke the tool gets the same Permission denied from a dry-run as from a real call.
Implementation:
src/mcp_route_handlers.cpp,src/mcp_authorization_policy.cpp,src/mcp_dry_run.cpp,src/mcp_response_shaper.cpp,src/mcp_tool_rate_limiter.cpp| Tests:test/integration/test_mcp_methods.py,test_mcp_rbac.py,test_mcp_dry_run.py,test_mcp_response_shaping.py,test_mcp_per_tool_rate_limit.py
Lists all available MCP resources.
Request:
{
"jsonrpc": "2.0",
"id": 5,
"method": "resources/list",
"params": {}
}Response:
{
"jsonrpc": "2.0",
"id": 5,
"result": {
"resources": [
{
"name": "customer_schema",
"description": "Customer database schema definition",
"mimeType": "application/json",
"uri": "flapi://customer_schema"
}
]
}
}| Field | Type | Description |
|---|---|---|
resources[].name |
string | Resource identifier |
resources[].description |
string | Human-readable description |
resources[].mimeType |
string | Content MIME type |
resources[].uri |
string | Resource URI |
Implementation:
src/mcp_route_handlers.cpp| Tests:test/integration/test_mcp_integration.py
Reads the content of an MCP resource.
Request:
{
"jsonrpc": "2.0",
"id": 6,
"method": "resources/read",
"params": {
"uri": "flapi://customer_schema"
}
}| Parameter | Type | Required | Description |
|---|---|---|---|
uri |
string | Yes | Resource URI to read |
Response:
{
"jsonrpc": "2.0",
"id": 6,
"result": {
"contents": [
{
"uri": "flapi://customer_schema",
"mimeType": "application/json",
"text": "{\"fields\":[{\"name\":\"id\",\"type\":\"INTEGER\"}]}"
}
]
}
}Implementation:
src/mcp_route_handlers.cpp,src/mcp_content_types.cpp| Tests:test/integration/test_mcp_integration.py
Lists all available MCP prompts.
Request:
{
"jsonrpc": "2.0",
"id": 7,
"method": "prompts/list",
"params": {}
}Response:
{
"jsonrpc": "2.0",
"id": 7,
"result": {
"prompts": [
{
"name": "analyze_customer",
"description": "Generate customer analysis prompt",
"arguments": [
{
"name": "customer_id",
"type": "string",
"description": "Parameter customer_id"
}
]
}
]
}
}Implementation:
src/mcp_route_handlers.cpp| Tests: None - see TEST_TODO.md
Retrieves a prompt with template arguments substituted.
Request:
{
"jsonrpc": "2.0",
"id": 8,
"method": "prompts/get",
"params": {
"name": "analyze_customer",
"arguments": {
"customer_id": "12345"
}
}
}| Parameter | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Prompt name |
arguments |
object | No | Template arguments |
Response:
{
"jsonrpc": "2.0",
"id": 8,
"result": {
"description": "Generate customer analysis prompt",
"messages": [
{
"role": "user",
"content": {
"type": "text",
"text": "Analyze customer 12345 and provide insights."
}
}
]
}
}Implementation:
src/mcp_route_handlers.cpp| Tests: None - see TEST_TODO.md
Sets the server log level for the current session.
Request:
{
"jsonrpc": "2.0",
"id": 9,
"method": "logging/setLevel",
"params": {
"level": "debug"
}
}| Parameter | Type | Required | Description |
|---|---|---|---|
level |
string | Yes | Log level to set |
Valid Log Levels:
| MCP Level | Maps To | Description |
|---|---|---|
debug |
DEBUG | Detailed debugging information |
info |
INFO | General operational information |
notice |
INFO | Normal but significant events |
warning |
WARNING | Warning conditions |
error |
ERROR | Error conditions |
critical |
ERROR | Critical conditions |
alert |
ERROR | Action must be taken immediately |
emergency |
ERROR | System is unusable |
Response:
{
"jsonrpc": "2.0",
"id": 9,
"result": {}
}Implementation:
src/mcp_route_handlers.cpp| Tests:test/integration/test_mcp_methods.py
Provides argument completion suggestions for tools and prompts.
Request:
{
"jsonrpc": "2.0",
"id": 10,
"method": "completion/complete",
"params": {
"ref": "customer_lookup",
"argument": "status",
"value": "act"
}
}| Parameter | Type | Required | Description |
|---|---|---|---|
ref |
string | Yes | Tool or prompt name |
argument |
string | Yes | Argument name to complete |
value |
string | No | Partial value prefix for filtering |
Response:
{
"jsonrpc": "2.0",
"id": 10,
"result": {
"values": ["active", "inactive"],
"total": 2,
"hasMore": false
}
}Completions are generated from enum validators defined on the argument.
Implementation:
src/mcp_route_handlers.cpp| Tests:test/integration/test_mcp_methods.py
MCP tools are defined in endpoint YAML files using the mcp-tool section:
# sqls/customer-lookup.yaml
mcp-tool:
name: customer_lookup
description: Retrieve customer information by ID, segment, or other criteria
result-mime-type: application/json
request:
- field-name: id
field-in: query
description: Customer ID
required: false
validators:
- type: int
min: 1
preventSqlInjection: true
- field-name: status
field-in: query
description: Customer status filter
required: false
validators:
- type: enum
values: ["active", "inactive", "pending"]
template-source: customer-lookup.sql
connection:
- customer-databaseMCP Tool Properties:
| Property | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Unique tool identifier |
description |
string | Yes | Human-readable description for LLM |
result-mime-type |
string | No | Expected result MIME type (default: application/json) |
The inputSchema for tools is automatically generated from request fields:
| Request Field | JSON Schema Property |
|---|---|
field-name |
Property name |
description |
Property description |
required: true |
Added to required array |
validators[].type |
Informs type (string by default) |
Example Conversion:
# YAML Request Definition
request:
- field-name: customer_id
description: Customer identifier
required: true
validators:
- type: int
min: 1// Generated Input Schema
{
"type": "object",
"properties": {
"customer_id": {
"type": "string",
"description": "Customer identifier"
}
},
"required": ["customer_id"]
}When a tool is called:
tools/call Request
│
▼
┌─────────────────┐
│ Extract name & │
│ arguments │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Find endpoint │
│ configuration │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Validate inputs │
│ against schema │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Render SQL │
│ template │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Execute on │
│ DuckDB │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Format as │
│ ContentResponse │
└────────┴────────┘
MCP tools support write operations (INSERT, UPDATE, DELETE) using the same configuration as REST endpoints:
mcp-tool:
name: create_customer
description: Create a new customer record
request:
- field-name: name
field-in: body
required: true
validators:
- type: string
min-length: 1
max-length: 100
- field-name: email
field-in: body
required: true
validators:
- type: email
template-source: create-customer.sql
connection:
- customer-database-- create-customer.sql
INSERT INTO customers (name, email)
VALUES ('{{{ params.name }}}', '{{{ params.email }}}')
RETURNING id, name, emailImplementation:
src/mcp_route_handlers.cpp,src/endpoint_config_parser.cpp| Tests:test/cpp/mcp_tool_handler_test.cpp,test/integration/test_mcp_methods.py
MCP resources provide static or semi-static data to AI clients:
# sqls/customer-schema.yaml
mcp-resource:
name: customer_schema
description: Customer database schema definition and field descriptions
mime-type: application/json
template-source: customer-schema.sql
connection:
- customer-database
# Optional rate limiting
rate-limit:
enabled: true
max: 10
interval: 60MCP Resource Properties:
| Property | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Unique resource identifier |
description |
string | Yes | Human-readable description |
mime-type |
string | Yes | Content MIME type |
Resources are identified by URIs following this scheme:
flapi://<resource_name>
Examples:
| Resource Name | URI |
|---|---|
customer_schema |
flapi://customer_schema |
product_catalog |
flapi://product_catalog |
system_config |
flapi://system_config |
Resource content is returned in the contents array:
{
"contents": [
{
"uri": "flapi://customer_schema",
"mimeType": "application/json",
"text": "{\"fields\":[...]}"
}
]
}| Field | Type | Description |
|---|---|---|
uri |
string | Resource URI |
mimeType |
string | Content MIME type |
text |
string | Resource content (text-based) |
blob |
string | Base64-encoded binary content |
Implementation:
src/mcp_route_handlers.cpp| Tests:test/integration/test_mcp_integration.py
MCP prompts provide pre-defined prompt templates for AI interactions:
# sqls/analyze-customer.yaml
mcp-prompt:
name: analyze_customer
description: Generate customer analysis prompt
template: |
Analyze customer {{customer_id}} and provide insights on:
- Purchase history
- Engagement patterns
- Churn risk assessment
Format the response as a structured report.
arguments:
- customer_idMCP Prompt Properties:
| Property | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Unique prompt identifier |
description |
string | Yes | Human-readable description |
template |
string | Yes | Prompt template with placeholders |
arguments |
array | No | List of argument names |
Prompts use Mustache-style placeholders:
{{argument_name}}
Example Template:
template: |
Generate a sales report for {{region}} covering {{time_period}}.
Include:
- Total revenue
- Top 5 products
- Customer acquisition trends
{{#include_projections}}
Also include Q4 projections based on current trends.
{{/include_projections}}Arguments are passed in the prompts/get request and substituted into the template:
{
"method": "prompts/get",
"params": {
"name": "sales_report",
"arguments": {
"region": "North America",
"time_period": "Q3 2024",
"include_projections": true
}
}
}Implementation:
src/mcp_route_handlers.cpp| Tests: None - see TEST_TODO.md
Configure Basic authentication for MCP:
# flapi.yaml
mcp:
enabled: true
auth:
enabled: true
type: basic
users:
- username: admin
password: "$apr1$xyz..." # MD5 hashed
roles: [admin, read, write]
- username: reader
password: plaintext123 # Plain text (not recommended)
roles: [read]Request Header:
Authorization: Basic YWRtaW46cGFzc3dvcmQ=
Configure JWT authentication:
# flapi.yaml
mcp:
enabled: true
auth:
enabled: true
type: bearer
jwt-secret: "${JWT_SECRET}"
jwt-issuer: "my-auth-server"Request Header:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Expected JWT Claims:
| Claim | Description |
|---|---|
sub |
Username/subject |
roles |
Array of role strings |
iss |
Issuer (must match jwt-issuer) |
exp |
Expiration timestamp |
Configure OpenID Connect authentication:
# flapi.yaml
mcp:
enabled: true
auth:
enabled: true
type: oidc
oidc:
provider-type: auth0 # or: okta, google, azure, generic
issuer-url: "https://your-tenant.auth0.com/"
client-id: "your-client-id"
client-secret: "${OIDC_CLIENT_SECRET}"
allowed-audiences:
- "your-api-audience"
username-claim: email
roles-claim: "https://your-app/roles"Provider Presets:
| Provider | provider-type |
Auto-configured |
|---|---|---|
| Auth0 | auth0 |
JWKS URL, claims mapping |
| Okta | okta |
JWKS URL, claims mapping |
google |
JWKS URL, claims mapping | |
| Azure AD | azure |
JWKS URL, claims mapping |
| Generic | generic |
Manual configuration |
Override authentication requirements per method:
# flapi.yaml
mcp:
enabled: true
auth:
enabled: true
type: bearer
jwt-secret: "${JWT_SECRET}"
methods:
initialize:
required: false # Allow unauthenticated initialize
tools/list:
required: false # Allow listing tools without auth
tools/call:
required: true # Require auth for tool execution
resources/read:
required: true # Require auth for resource accessImplementation:
src/mcp_auth_handler.cpp,src/oidc_auth_handler.cpp| Tests:test/integration/test_oidc_authentication.py
Default content type for tool results:
{
"type": "text",
"text": "Result data here",
"mimeType": "application/json"
}| Field | Type | Required | Description |
|---|---|---|---|
type |
string | Yes | Always "text" |
text |
string | Yes | Text content |
mimeType |
string | No | MIME type hint |
For binary image data (base64 encoded):
{
"type": "image",
"data": "iVBORw0KGgoAAAANSUhEUgAA...",
"mimeType": "image/png"
}| Field | Type | Required | Description |
|---|---|---|---|
type |
string | Yes | Always "image" |
data |
string | Yes | Base64-encoded image data |
mimeType |
string | Yes | Image MIME type |
For binary audio data:
{
"type": "audio",
"data": "UklGRiQAAABXQVZFZm10...",
"mimeType": "audio/wav"
}References to MCP resources:
{
"type": "resource",
"resource": {
"uri": "flapi://customer_schema",
"mimeType": "application/json",
"text": "{...}"
}
}flAPI automatically detects MIME types from file extensions:
| Extension | MIME Type |
|---|---|
.png |
image/png |
.jpg, .jpeg |
image/jpeg |
.gif |
image/gif |
.svg |
image/svg+xml |
.wav |
audio/wav |
.mp3 |
audio/mpeg |
.json |
application/json |
.csv |
text/csv |
.txt |
text/plain |
.pdf |
application/pdf |
.xml |
application/xml |
| (unknown) | application/octet-stream |
Implementation:
src/mcp_content_types.cpp| Tests: Image/audio/binary not tested - see TEST_TODO.md
Initialize Session:
# Initialize and capture session ID
SESSION_ID=$(curl -s -D - -X POST http://localhost:8080/mcp/jsonrpc \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {"protocolVersion": "2025-11-25"}
}' | grep -i "Mcp-Session-Id" | cut -d: -f2 | tr -d ' \r')
echo "Session: $SESSION_ID"List Tools:
curl -X POST http://localhost:8080/mcp/jsonrpc \
-H "Content-Type: application/json" \
-H "Mcp-Session-Id: $SESSION_ID" \
-d '{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/list",
"params": {}
}'Call Tool:
curl -X POST http://localhost:8080/mcp/jsonrpc \
-H "Content-Type: application/json" \
-H "Mcp-Session-Id: $SESSION_ID" \
-d '{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "customer_lookup",
"arguments": {"id": "12345"}
}
}'With Authentication:
# Basic Auth
curl -X POST http://localhost:8080/mcp/jsonrpc \
-H "Content-Type: application/json" \
-H "Authorization: Basic $(echo -n 'admin:password' | base64)" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {"protocolVersion": "2025-11-25"}
}'
# Bearer Token
curl -X POST http://localhost:8080/mcp/jsonrpc \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $JWT_TOKEN" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {"name": "customer_lookup", "arguments": {"id": "123"}}
}'Simple Client:
import requests
import json
class FlapiMCPClient:
def __init__(self, base_url: str = "http://localhost:8080"):
self.base_url = base_url
self.session_id = None
self.request_id = 0
def _call(self, method: str, params: dict = None) -> dict:
self.request_id += 1
headers = {"Content-Type": "application/json"}
if self.session_id:
headers["Mcp-Session-Id"] = self.session_id
response = requests.post(
f"{self.base_url}/mcp/jsonrpc",
headers=headers,
json={
"jsonrpc": "2.0",
"id": self.request_id,
"method": method,
"params": params or {}
}
)
# Capture session ID from response
if "Mcp-Session-Id" in response.headers:
self.session_id = response.headers["Mcp-Session-Id"]
result = response.json()
if "error" in result:
raise Exception(f"MCP Error: {result['error']}")
return result.get("result", {})
def initialize(self, protocol_version: str = "2025-11-25") -> dict:
return self._call("initialize", {"protocolVersion": protocol_version})
def list_tools(self) -> list:
result = self._call("tools/list")
return result.get("tools", [])
def call_tool(self, name: str, arguments: dict = None) -> dict:
return self._call("tools/call", {"name": name, "arguments": arguments or {}})
def list_resources(self) -> list:
result = self._call("resources/list")
return result.get("resources", [])
def read_resource(self, uri: str) -> dict:
return self._call("resources/read", {"uri": uri})
def ping(self) -> dict:
return self._call("ping")
# Usage
client = FlapiMCPClient()
client.initialize()
# List available tools
tools = client.list_tools()
print(f"Available tools: {[t['name'] for t in tools]}")
# Call a tool
result = client.call_tool("customer_lookup", {"id": "12345"})
print(f"Result: {result}")With Authentication:
class AuthenticatedMCPClient(FlapiMCPClient):
def __init__(self, base_url: str, username: str = None,
password: str = None, token: str = None):
super().__init__(base_url)
self.auth_header = None
if username and password:
import base64
credentials = base64.b64encode(f"{username}:{password}".encode()).decode()
self.auth_header = f"Basic {credentials}"
elif token:
self.auth_header = f"Bearer {token}"
def _call(self, method: str, params: dict = None) -> dict:
self.request_id += 1
headers = {"Content-Type": "application/json"}
if self.session_id:
headers["Mcp-Session-Id"] = self.session_id
if self.auth_header:
headers["Authorization"] = self.auth_header
# ... rest of implementation# flapi.yaml - Complete MCP Configuration
project-name: customer-api
project-description: Customer data API with MCP support
# Template configuration
template:
path: ./sqls
environment-whitelist:
- '^DB_.*'
- '^JWT_SECRET$'
# Database connections
connections:
customer-db:
properties:
path: ./data/customers.parquet
# DuckDB configuration
duckdb:
access_mode: READ_WRITE
threads: 4
max_memory: 2GB
# MCP configuration
mcp:
enabled: true
port: 8080
host: 0.0.0.0
allow-list-changed-notifications: true
# Instructions for LLM clients
instructions: |
# Customer API MCP Server
This server provides access to customer data.
## Available Tools
- customer_lookup: Search for customers by ID or criteria
- create_customer: Create new customer records
## Usage Guidelines
- Always validate customer IDs before lookup
- Use pagination for large result sets
# Authentication
auth:
enabled: true
type: bearer
jwt-secret: "${JWT_SECRET}"
jwt-issuer: "customer-api"
# Per-method overrides
methods:
initialize:
required: false
tools/list:
required: false
tools/call:
required: true
resources/read:
required: true# sqls/customer-lookup.yaml - MCP Tool Definition
mcp-tool:
name: customer_lookup
description: |
Retrieve customer information by ID or search criteria.
Returns customer details including name, email, and status.
result-mime-type: application/json
request:
- field-name: id
field-in: query
description: Customer ID (exact match)
required: false
validators:
- type: int
min: 1
preventSqlInjection: true
- field-name: name
field-in: query
description: Customer name (partial match)
required: false
validators:
- type: string
max-length: 100
- field-name: status
field-in: query
description: Customer status filter
required: false
validators:
- type: enum
values: ["active", "inactive", "pending"]
- field-name: limit
field-in: query
description: Maximum results to return
required: false
validators:
- type: int
min: 1
max: 100
template-source: customer-lookup.sql
connection:
- customer-db
auth:
enabled: true
type: basic
users:
- username: api
password: secret
roles: [read]-- sqls/customer-lookup.sql
SELECT
id,
name,
email,
status,
created_at
FROM read_parquet('{{{ conn.path }}}')
WHERE 1=1
{{#params.id}}
AND id = {{ params.id }}
{{/params.id}}
{{#params.name}}
AND name ILIKE '%' || '{{{ params.name }}}' || '%'
{{/params.name}}
{{#params.status}}
AND status = '{{{ params.status }}}'
{{/params.status}}
ORDER BY created_at DESC
LIMIT {{#params.limit}}{{ params.limit }}{{/params.limit}}{{^params.limit}}25{{/params.limit}}| Error Code | Message | Cause | Resolution |
|---|---|---|---|
-32700 |
Parse error | Invalid JSON in request body | Check JSON syntax |
-32600 |
Invalid Request | Missing required JSON-RPC fields | Include jsonrpc, id, method |
-32601 |
Method not found | Unknown MCP method | Check method name spelling |
-32602 |
Invalid params | Missing or invalid parameters | Check required params for method |
-32603 |
Internal error | Server-side error | Check server logs |
-32001 |
Authentication required | Method requires auth | Provide Authorization header |
-32000 |
Session error | Session-related issue | Re-initialize session |
- Reference Documentation Map - Navigation guide for all reference docs
- Configuration Reference - Configuration file options (including MCP § 2.6)
- CLI Reference - Server executable command-line options
- Config Service API Reference - Runtime configuration REST API
- MCP Configuration Tools API - 20 MCP tools for runtime management
- MCP Configuration Integration Guide - Integration architecture and flows