# FlowMCP Documentation v3.0.0 > FlowMCP is a schema-driven normalization layer that transforms REST APIs, local databases, and workflows into MCP-compatible tools for AI agents. > > This file concatenates 10 documentation pages into a single file for LLM consumption. > Source: https://docs.flowmcp.org ## Table of Contents 1. What is FlowMCP? 2. For LLMs 3. Schemas — Overview 4. Schemas — Tools 5. Schemas — Resources 6. Schemas — Prompts 7. Schemas — Skills 8. Agents 9. CLI 10. MCP Server --- # 1. What is FlowMCP? ## The Problem AI agents need tools — "get crypto prices", "check wallet balances", "query open data". But APIs are chaotic: different authentication methods, URL structures, response formats, and rate limits. Every integration requires custom server code, parameter validation, error handling, and response formatting. At 5 APIs this is tedious. At 50 it is unmaintainable. At 500 it is impossible without a systematic approach. ## The Solution FlowMCP is a **schema-driven normalization layer** that transforms any data source into MCP-compatible tools. You write a declarative `.mjs` schema. FlowMCP handles validation, URL construction, authentication, and response formatting. No custom server code. No boilerplate. One schema per provider. ```mermaid flowchart LR E[REST API] --> A F[SQLite DB] --> A G[Workflow] --> A A[Schema .mjs] --> B[FlowMCP Runtime] B --> C[MCP Server] C --> D[AI Agent] ``` ## Four Primitives FlowMCP v3.0.0 supports four primitives in a single schema file: - **Tools:** REST API endpoints (GET/POST/PUT/DELETE). Map parameters to URLs, inject authentication, validate inputs. The core primitive. - **Resources:** Local SQLite databases for bulk data and open data. Fast read-only queries via prepared statements — no network calls. - **Prompts:** Namespace descriptions that explain how to use tools effectively. Guide AI agents with domain context and usage patterns. - **Skills:** Multi-step workflow instructions. Reusable pipelines that compose tools and resources into higher-level operations. ## Minimal Example A complete, runnable schema — everything an AI agent needs to call the CoinGecko price API: ```javascript export const main = { namespace: 'coingecko', name: 'CoinGecko Prices', description: 'Cryptocurrency price data from CoinGecko', version: '3.0.0', root: 'https://api.coingecko.com/api/v3', tools: { simplePrice: { method: 'GET', path: '/simple/price', description: 'Get current price of cryptocurrencies', parameters: { ids: { type: 'string', required: true, description: 'Coin IDs (comma-separated)' }, vs_currencies: { type: 'string', required: true, description: 'Target currencies' } } } } } ``` > **Tip:** Most schemas only need the `main` export. An optional `handlers` export is available when API responses need transformation before reaching the AI agent. ## Quickstart ### Install FlowMCP ```bash npm install -g flowmcp ``` ### Search available schemas FlowMCP ships with 450+ pre-built schemas across crypto, DeFi, open data, and more. ```bash flowmcp search coingecko ``` ### Add a tool to your project Activates the tool and shows its expected input parameters. ```bash flowmcp add simple_price_coingecko ``` ### Call the tool ```bash flowmcp call simple_price_coingecko '{"ids": "bitcoin", "vs_currencies": "usd"}' ``` > **Note:** Some schemas require API keys configured in `~/.flowmcp/.env`. If a call fails due to missing keys, FlowMCP will tell you which variable to set. ## How It Works FlowMCP separates each schema into two exports: | Export | Purpose | Description | |--------|---------|-------------| | `main` | Declarative config | JSON-serializable, hashable — describes tools, resources, prompts, and skills | | `handlers` | Executable logic | Optional factory function that transforms API responses | This separation enables integrity hashing (detect schema tampering), security scanning (analyze handlers before execution), and shared list injection (reusable value lists loaded at runtime). ## What's Next - **[Installation](/getting-started/installation):** System requirements and setup instructions. - **[CLI Reference](/guides/cli-reference):** Complete command reference for search, add, call, validate, and test. - **[Schema Creation](/guides/schema-creation):** Write your own schemas from scratch. - **[Specification](/specification/overview):** Full v3.0.0 specification with all primitives and validation rules. --- # 2. For LLMs FlowMCP provides its complete documentation as single-file downloads optimized for AI agent context windows. ## Documentation Files | File | Content | Use Case | |------|---------|----------| | **Docs llms.txt** | Practical documentation — schemas, agents, CLI, MCP server | Building with FlowMCP | | **Spec llms.txt** | Full technical specification — validation rules, format definitions, constraints | Implementing FlowMCP-compatible tools | ## Usage Feed the appropriate file to your AI agent for full FlowMCP context: ```text # For building with FlowMCP (practical) https://docs.flowmcp.org/llms.txt # For implementing FlowMCP internals (technical) https://github.com/FlowMCP/flowmcp-spec/blob/main/spec/v3.0.0/llms.txt ``` > **Tip:** The docs `llms.txt` is sufficient for most use cases. Use the spec `llms.txt` only when you need detailed validation rules or format constraints. --- # 3. Schemas — Overview A schema is a single `.mjs` file that wraps a data source for AI agents. Each schema declares its tools, resources, prompts, and skills in a static `main` export. An optional `handlers` export adds response transformation. FlowMCP v3.0.0 supports four primitives: - **[Tools](/schemas/tools):** REST API endpoints. Map parameters to URLs, inject authentication, validate inputs. The core primitive — every schema has at least one tool. - **[Resources](/schemas/resources):** Local SQLite databases. Fast, deterministic queries for bulk data like company registers, transit schedules, or sanctions lists. - **[Prompts](/schemas/prompts):** Explanatory texts that teach AI agents how a provider's tools work together — pagination patterns, error codes, data interpretation. - **[Skills](/schemas/skills):** Multi-step workflow instructions. Reusable pipelines that compose tools and resources into higher-level operations. ## Schema Structure Every schema exports two things: | Export | Required | Purpose | |--------|----------|---------| | `main` | Yes | Declarative configuration — tools, resources, prompts, skills. JSON-serializable and hashable. | | `handlers` | No | Response transformation — pre/post processing for API responses. | > **Tip:** Most schemas only need `main`. Add `handlers` when API responses need transformation before reaching the AI agent. --- # 4. Schemas — Tools Tools wrap REST API endpoints. Each tool maps to one HTTP request. Schemas are `.mjs` files with two named exports: a static `main` block and an optional `handlers` factory function. > **Note:** This page focuses on practical tool creation. See [Schema Format](/specification/schema-format) for the full specification and [Parameters](/specification/parameters) for parameter details. ## Schema Structure A schema file has two parts: the declarative `main` export that describes what tools do, and the optional `handlers` export that transforms requests and responses. ```mermaid flowchart TD A[export const main] --> B[namespace + name + root] A --> C[tools] C --> D[method + path] C --> E[parameters] C --> F[description] A --> G[export const handlers] G --> H[preRequest] G --> I[postRequest] ``` ## The `main` Export The `main` export is a static, JSON-serializable object. No functions, no dynamic values, no imports. ### Required Fields | Field | Type | Description | |-------|------|-------------| | `namespace` | `string` | Provider identifier, lowercase letters only (`/^[a-z]+$/`). | | `name` | `string` | Schema name in PascalCase (e.g. `SmartContractExplorer`). | | `description` | `string` | What this schema does, 1-2 sentences. | | `version` | `string` | Must match `3.\d+.\d+` (semver, major must be `3`). | | `root` | `string` | Base URL for all tools. Must start with `https://` (no trailing slash). | | `tools` | `object` | Tool definitions. Keys are camelCase tool names. Maximum 8 tools. | ### Optional Fields | Field | Type | Description | |-------|------|-------------| | `docs` | `string[]` | Documentation URLs for the API provider. | | `tags` | `string[]` | Categorization tags for tool discovery. | | `requiredServerParams` | `string[]` | Environment variable names needed at runtime (e.g. API keys). | | `requiredLibraries` | `string[]` | npm packages needed by handlers. | | `headers` | `object` | Default HTTP headers applied to all tools. | | `sharedLists` | `object[]` | Shared list references for dynamic enum values. See [Shared Lists](/specification/shared-lists). | ```javascript export const main = { namespace: 'etherscan', name: 'SmartContractExplorer', description: 'Explore verified smart contracts on EVM chains via Etherscan APIs', version: '3.0.0', root: 'https://api.etherscan.io', docs: [ 'https://docs.etherscan.io/' ], tags: [ 'ethereum', 'blockchain' ], requiredServerParams: [ 'ETHERSCAN_API_KEY' ], tools: { // tool definitions here } } ``` ## Tool Definition Each key in `tools` is the tool name in camelCase. The tool name becomes part of the fully qualified MCP tool name. ### Tool Fields | Field | Type | Required | Description | |-------|------|----------|-------------| | `method` | `string` | Yes | HTTP method: `GET`, `POST`, `PUT`, `DELETE`. | | `path` | `string` | Yes | URL path appended to `root`. May contain `{{key}}` placeholders. | | `description` | `string` | Yes | What this tool does. Appears in the MCP tool description. | | `parameters` | `array` | Yes | Input parameter definitions. Can be empty `[]`. | ### Path Templates The path supports `{{key}}` placeholders that are replaced by `insert` parameters at call-time: ```javascript // Static path path: '/api' // Single placeholder path: '/api/v1/{{address}}/transactions' // Multiple placeholders path: '/api/v1/{{chainId}}/address/{{address}}/balances' ``` Every `{{key}}` placeholder must have a corresponding parameter with `location: 'insert'`. ## Parameters Each parameter has two blocks: `position` (where the value goes) and `z` (how it is validated). ### Parameter Types | Type | Description | Example | |------|-------------|---------| | `string()` | Any string value | `'string()'` | | `number()` | Numeric value | `'number()'` | | `boolean()` | True or false | `'boolean()'` | | `enum(A,B,C)` | One of the listed values | `'enum(mainnet,testnet)'` | | `array()` | Array of values | `'array()'` | ### Value Sources | Pattern | Description | Visible to User | |---------|-------------|-----------------| | `{{USER_PARAM}}` | User provides the value at call-time | Yes | | `{{SERVER_PARAM:KEY}}` | Injected from environment variable | No | | Fixed string | Sent automatically with every request | No | ### Validation Options | Option | Description | Example | |--------|-------------|---------| | `min(n)` | Minimum value or length | `'min(1)'` | | `max(n)` | Maximum value or length | `'max(100)'` | | `optional()` | Parameter is not required | `'optional()'` | | `default(value)` | Default when omitted | `'default(100)'` | ```javascript // User-provided address with length validation { position: { key: 'address', value: '{{USER_PARAM}}', location: 'query' }, z: { primitive: 'string()', options: [ 'min(42)', 'max(42)' ] } } // Fixed parameter (invisible to user) { position: { key: 'module', value: 'contract', location: 'query' }, z: { primitive: 'string()', options: [] } } // API key injected from environment { position: { key: 'apikey', value: '{{SERVER_PARAM:ETHERSCAN_API_KEY}}', location: 'query' }, z: { primitive: 'string()', options: [] } } ``` > **Tip:** Fixed parameters are common for APIs like Etherscan that use query parameters for routing (`module=contract`, `action=getabi`). They let multiple tools share the same `root` + `path`. ## Handlers The optional `handlers` export is a factory function that receives injected dependencies and returns handler objects per tool. ```javascript export const handlers = ( { sharedLists, libraries } ) => ({ toolName: { preRequest: async ( { struct, payload } ) => { // modify the request before it is sent return { struct, payload } }, postRequest: async ( { response, struct, payload } ) => { // transform the response after receiving it return { response } } } }) ``` ### Injected Dependencies | Parameter | Type | Description | |-----------|------|-------------| | `sharedLists` | `object` | Resolved shared list data, keyed by list name. Read-only (deep-frozen). | | `libraries` | `object` | Loaded npm packages from `requiredLibraries`, keyed by package name. | ### Handler Types | Handler | When | Input | Must Return | |---------|------|-------|-------------| | `preRequest` | Before the API call | `{ struct, payload }` | `{ struct, payload }` | | `postRequest` | After the API call | `{ response, struct, payload }` | `{ response }` | ### Handler Rules 1. **Handlers are optional.** Tools without handlers make direct API calls. 2. **Zero import statements.** All dependencies come through the factory function. 3. **No restricted globals.** `fetch`, `fs`, `process`, `eval` are forbidden. 4. **Return shape must match.** `preRequest` returns `{ struct, payload }`. `postRequest` returns `{ response }`. Schema files must have zero `import` statements. All external dependencies are declared in `requiredLibraries` and injected at runtime. ## Complete Example A full Etherscan schema with two tools, API key injection, and a `postRequest` handler: ```javascript export const main = { namespace: 'etherscan', name: 'SmartContractExplorer', description: 'Ethereum blockchain explorer API', version: '3.0.0', docs: [ 'https://docs.etherscan.io/' ], tags: [ 'ethereum', 'blockchain' ], root: 'https://api.etherscan.io', requiredServerParams: [ 'ETHERSCAN_API_KEY' ], headers: { 'Accept': 'application/json' }, tools: { getContractAbi: { method: 'GET', path: '/api', description: 'Get the ABI of a verified smart contract', parameters: [ { position: { key: 'module', value: 'contract', location: 'query' }, z: { primitive: 'string()', options: [] } }, { position: { key: 'action', value: 'getabi', location: 'query' }, z: { primitive: 'string()', options: [] } }, { position: { key: 'address', value: '{{USER_PARAM}}', location: 'query' }, z: { primitive: 'string()', options: [ 'min(42)', 'max(42)' ] } }, { position: { key: 'apikey', value: '{{SERVER_PARAM:ETHERSCAN_API_KEY}}', location: 'query' }, z: { primitive: 'string()', options: [] } } ] }, getSourceCode: { method: 'GET', path: '/api', description: 'Get the Solidity source code of a verified smart contract', parameters: [ { position: { key: 'module', value: 'contract', location: 'query' }, z: { primitive: 'string()', options: [] } }, { position: { key: 'action', value: 'getsourcecode', location: 'query' }, z: { primitive: 'string()', options: [] } }, { position: { key: 'address', value: '{{USER_PARAM}}', location: 'query' }, z: { primitive: 'string()', options: [ 'min(42)', 'max(42)' ] } }, { position: { key: 'apikey', value: '{{SERVER_PARAM:ETHERSCAN_API_KEY}}', location: 'query' }, z: { primitive: 'string()', options: [] } } ] } } } export const handlers = ( { sharedLists } ) => ({ getContractAbi: { postRequest: async ( { response } ) => { return { response: JSON.parse( response['result'] ) } } }, getSourceCode: { postRequest: async ( { response } ) => { const { result } = response const [ first ] = result const { SourceCode, ABI, ContractName, CompilerVersion, OptimizationUsed } = first return { response: { contractName: ContractName, compilerVersion: CompilerVersion, optimizationUsed: OptimizationUsed === '1', sourceCode: SourceCode, abi: ABI } } } } }) ``` > **Tip:** This example demonstrates: fixed parameters (`module`, `action`), user parameters (`address`), server parameter injection (`apikey`), and `postRequest` handlers that flatten nested API responses into clean output. ## Constraints | Constraint | Value | Rationale | |------------|-------|-----------| | Max tools per schema | 8 | Keeps schemas focused. Split large APIs into multiple schema files. | | Version major | `3` | Must match `3.\d+.\d+`. | | Namespace pattern | `^[a-z]+$` | Letters only. No numbers, hyphens, or underscores. | | Root URL protocol | `https://` | HTTP is not allowed. | | Root URL trailing slash | Forbidden | `root` must not end with `/`. | | Schema file imports | Zero | All dependencies are injected via the `handlers` factory. | --- # 5. Schemas — Resources Resources provide local, deterministic data via SQLite. Unlike tools (which call remote REST APIs), resources query local databases. They are perfect for bulk-downloaded open data such as company registers, transit schedules, and sanctions lists. ## What are Resources? A resource is a SQLite database bundled with a schema. The FlowMCP runtime loads the `.db` file via `sql.js` (a pure JavaScript/WASM SQLite implementation) and exposes each defined query as an MCP resource. No network calls, no API keys, no rate limits. Resources are ideal when: - Data is large and rarely changes (company registers, geographic data) - Offline access is required - Latency must be near-zero - The dataset is publicly available as a bulk download ## When to Use Resources vs Tools | Aspect | Tools | Resources | |--------|-------|-----------| | Data source | Remote REST API | Local SQLite database | | Latency | Network-dependent | Instant | | Availability | Requires internet | Always available | | Data freshness | Real-time | Snapshot (periodic refresh) | | API key required | Usually yes | No | | Use case | Live prices, on-chain data | Company registers, transit data | > **Tip:** Many schemas benefit from combining both. Use tools for live data and resources for reference lookups. The AI agent chooses the right approach based on the query. ## Resource Definition Resources are declared inside `main.resources`. Each resource points to a SQLite database and defines named queries with SQL and parameters: ```javascript export const main = { namespace: 'offeneregister', name: 'OffeneRegister', version: '3.0.0', root: '', tools: {}, resources: { companiesDb: { source: 'sqlite', database: 'companies.db', origin: 'global', description: 'German company register (OffeneRegister)', queries: { searchCompanies: { sql: "SELECT * FROM companies WHERE name LIKE ? LIMIT ?", description: 'Search companies by name', parameters: { searchTerm: { type: 'string', required: true }, limit: { type: 'number', required: false, default: 10 } }, output: { columns: ['company_number', 'name', 'registered_address', 'status'] } } } } } } ``` ## Database Paths -- Three Levels The `origin` field determines where the runtime looks for the `.db` file: ```mermaid flowchart TD A["origin: 'global'"] --> B["~/.flowmcp/data/companies.db"] C["origin: 'project'"] --> D[".flowmcp/data/companies.db"] E["origin: 'inline'"] --> F["./data/companies.db (relative to schema)"] ``` | Origin | Path Resolution | Best For | |--------|----------------|----------| | `global` | `~/.flowmcp/data/{database}` | Shared datasets used across projects | | `project` | `.flowmcp/data/{database}` | Project-specific data | | `inline` | Relative to the schema file | Self-contained schemas with small databases | > **Note:** The `origin` field is required. The runtime does not guess where the database lives. If the file is not found at the resolved path, the resource fails to load with a clear error message. ## CTE Support Complex queries can use Common Table Expressions (CTEs) for multi-step filtering: ```sql WITH recent AS ( SELECT * FROM companies WHERE registered_date > ? ) SELECT * FROM recent WHERE status = 'active' LIMIT ? ``` CTEs must still start with a read-only statement. The same SQL security rules apply: no `INSERT`, `UPDATE`, `DELETE`, or other write operations anywhere in the CTE chain. ## Constraints > **Note:** These limits keep resources focused and predictable. If you need more queries, split into multiple schemas. | Constraint | Value | Rationale | |------------|-------|-----------| | Max resources per schema | 2 | Resources are supplementary, not primary output | | Max queries per resource | 8 | 7 defined + 1 auto-injected `freeQuery` | | `getSchema` query | Required | Must return the database table structure | | SQL operations | `SELECT` only | Read-only enforcement -- no INSERT/UPDATE/DELETE | | Parameter placeholders | `?` only | Prevents SQL injection | | Source type | `sqlite` only | Future versions may add other sources | | Database file extension | `.db` | Standard SQLite extension | ### Auto-Injected Queries Two queries are handled automatically by the runtime: - **`getSchema`** -- You must define this query. It returns the database structure so AI agents can understand available tables and columns. - **`freeQuery`** -- Auto-injected by the runtime. Allows AI agents to run arbitrary `SELECT` queries within the read-only sandbox. This counts toward the 8-query limit. ## Complete Example An OffeneRegister schema with a SQLite resource for querying the German company register: ```javascript export const main = { namespace: 'offeneregister', name: 'OffeneRegister', description: 'German company register — local SQLite database', version: '3.0.0', tags: ['open-data', 'germany', 'companies'], root: '', tools: {}, resources: { companiesDb: { source: 'sqlite', database: 'openregister.db', origin: 'global', description: 'OffeneRegister company database (2.5 GB)', queries: { getSchema: { sql: "SELECT sql FROM sqlite_master WHERE type='table'", description: 'Get database schema', parameters: {}, output: { columns: ['sql'] } }, searchCompanies: { sql: "SELECT company_number, name, registered_address, status FROM companies WHERE name LIKE ? LIMIT ?", description: 'Full-text search for companies by name', parameters: { searchTerm: { type: 'string', required: true, description: 'Company name (use % for wildcards)' }, limit: { type: 'number', required: false, default: 10, description: 'Max results' } }, output: { columns: ['company_number', 'name', 'registered_address', 'status'] } }, getByNumber: { sql: "SELECT * FROM companies WHERE company_number = ?", description: 'Look up a company by its registration number', parameters: { companyNumber: { type: 'string', required: true, description: 'Company registration number' } }, output: { columns: ['company_number', 'name', 'registered_address', 'status', 'registered_date'] } }, recentRegistrations: { sql: "SELECT company_number, name, registered_date FROM companies ORDER BY registered_date DESC LIMIT ?", description: 'List the most recently registered companies', parameters: { limit: { type: 'number', required: false, default: 20, description: 'Max results' } }, output: { columns: ['company_number', 'name', 'registered_date'] } } } } } } ``` This schema has no tools and no `root` URL -- it operates entirely on local data. The AI agent can search companies, look up by number, or browse recent registrations without any network access. > **Tip:** Resource-only schemas set `root: ''` and `tools: {}`. They are valid FlowMCP schemas that expose only MCP resources, no MCP tools. ## Validation Rules Resources are validated by rules RES001-RES023. Key rules include: | Code | Rule | |------|------| | RES003 | Maximum 2 resources per schema | | RES005 | Source must be `'sqlite'` | | RES006 | Database path must end in `.db` | | RES008 | Maximum 8 queries per resource (7 + freeQuery) | | RES012 | SQL must start with `SELECT` (or `WITH` for CTEs) | | RES013 | SQL must not contain blocked patterns | | RES014 | SQL must use `?` placeholders | | RES015 | Placeholder count must match parameter count | See [Validation Rules](/specification/validation-rules) for the complete list. --- # 6. Schemas — Prompts Prompts are explanatory texts scoped to a namespace. They teach AI agents how a provider's tools work together -- pagination patterns, error codes, rate limits, combining endpoints. Prompts **explain**, they don't **instruct** (that's what [Skills](/specification/skills) do). ## Prompts vs Skills | Aspect | Prompts | Skills | |--------|---------|--------| | Purpose | Explain how tools work | Instruct step-by-step workflows | | Tone | "Here's how pagination works..." | "Step 1: Call X. Step 2: Pass result to Y." | | Model dependency | Model-neutral | Model-specific (`testedWith` required) | | Scope | Single namespace | Can reference tools from own schema | See [Prompt Architecture](/specification/prompt-architecture) for the full two-tier system (Provider-Prompts vs Agent-Prompts). ## Defining Prompts Prompts are declared in `main.prompts` and loaded from external `.mjs` files via `contentFile`: ```javascript export const main = { namespace: 'coingecko', // ... other fields ... prompts: { 'about': { contentFile: './prompts/about.mjs' }, 'pagination-guide': { contentFile: './prompts/pagination-guide.mjs' } } } ``` ## Prompt File Format Each prompt is a `.mjs` file exporting a `prompt` object: ```javascript // prompts/about.mjs export const prompt = { name: 'about', version: 'flowmcp-prompt/1.0.0', provider: 'coingecko', description: 'Overview of CoinGecko API capabilities and best practices', dependsOn: ['coingecko.simplePrice', 'coingecko.coinMarkets', 'coingecko.coinMarketChart'], references: [], content: `CoinGecko provides cryptocurrency market data through three main tools: Use {{tool:simplePrice}} for current prices of one or more tokens. Use {{tool:coinMarkets}} for market cap rankings with sorting and pagination. Use {{tool:coinMarketChart}} for historical price data over {{input:days}} days. All price endpoints return values in the currency specified by {{input:vsCurrency}}. Rate limit: 30 requests per minute on the free tier.` } ``` ## Placeholder Syntax Use `{{type:name}}` placeholders in the `content` field to reference schema elements: | Placeholder | Resolves To | Example | |-------------|-------------|---------| | `{{tool:name}}` | A tool in the same namespace | `{{tool:simplePrice}}` | | `{{input:key}}` | A user input parameter | `{{input:tokenId}}` | | `{{resource:name}}` | A resource in the same namespace | `{{resource:companiesDb}}` | > **Note:** **The `about` convention** -- Every provider should have an `about` prompt that describes the overall API capabilities, common patterns, and gotchas. This is the first thing an AI agent reads when encountering a new namespace. ## Complete Example A CoinGecko schema with an `about` prompt: ```javascript // coingecko-coins.mjs export const main = { namespace: 'coingecko', name: 'CoinData', version: '3.0.0', root: 'https://api.coingecko.com/api/v3', tools: { simplePrice: { /* ... */ }, coinMarkets: { /* ... */ }, coinMarketChart: { /* ... */ } }, prompts: { 'about': { contentFile: './prompts/about.mjs' } } } ``` ```javascript // prompts/about.mjs export const prompt = { name: 'about', version: 'flowmcp-prompt/1.0.0', provider: 'coingecko', description: 'How to use CoinGecko tools effectively', dependsOn: ['coingecko.simplePrice', 'coingecko.coinMarkets', 'coingecko.coinMarketChart'], references: [], content: `CoinGecko provides real-time and historical cryptocurrency data. {{tool:simplePrice}} returns current prices. Pass comma-separated token IDs. {{tool:coinMarkets}} returns paginated market data sorted by market cap. - Use page and per_page parameters for pagination (max 250 per page). - Default sort is market_cap_desc. {{tool:coinMarketChart}} returns OHLC + volume over {{input:days}} days. - Granularity is automatic: 1-2 days = 5min, 3-30 days = hourly, 31+ = daily. All endpoints accept {{input:vsCurrency}} (e.g. "usd", "eur", "btc").` } ``` --- # 7. Schemas — Skills Skills are instructional multi-step workflows embedded in a schema. Unlike Prompts (which explain context), Skills **instruct** -- they tell an LLM exactly what to do, step by step. Each skill declares its tool dependencies, defines typed input parameters, and records the model it was tested with. > **Tip:** **Skills vs Prompts:** Use a Prompt when you want to provide context or explain a domain. Use a Skill when you want to orchestrate a repeatable multi-step workflow that calls specific tools in sequence. ## Skill Execution Flow How a skill is resolved and executed at runtime: ```mermaid flowchart LR A[User Input] --> B[Skill Content] B --> C[Replace Placeholders] C --> D[LLM Execution] D --> E["Step 1: Call {{tool:X}}"] E --> F["Step 2: Call {{tool:Y}}"] F --> G[Structured Output] ``` The skill's `content` is a template. Placeholders like `{{input:tokenSymbol}}` are replaced with user-provided values, and `{{tool:computeRSI}}` references tell the LLM which tool to call at each step. ## Defining Skills Skills are declared in the `main` export's `skills` key. Each entry points to a separate `.mjs` file: ```javascript export const main = { namespace: 'tradingsignals', name: 'TradingSignals', version: '3.0.0', root: 'https://api.example.com', tools: { computeRSI: { /* ... */ }, computeMACD: { /* ... */ } }, skills: { 'token-technical-analysis': { file: './skills/token-technical-analysis.mjs' } } } ``` ### Skill Reference Fields Each key in `main.skills` is the skill name (must match `^[a-z][a-z0-9-]*$`). The value is an object: | Field | Type | Required | Description | |-------|------|----------|-------------| | `file` | `string` | Yes | Path to the `.mjs` skill file, relative to the schema. Must end in `.mjs`. | ## Skill File Format Each skill file exports a `skill` object with the full workflow definition: ```javascript const content = `Perform technical analysis of {{input:tokenSymbol}} on {{input:chain}}. ## Step 1: Token Discovery Use {{tool:searchBySymbol}} to find {{input:tokenSymbol}} on {{input:chain}}. ## Step 2: OHLCV Data Use {{tool:getRecursiveOhlcvEVM}} for {{input:timeframeDays}}-day candles. ## Step 3: Indicators Use {{tool:computeRSI}} with period 14. Use {{tool:computeMACD}} with fast 12, slow 26, signal 9. ## Step 4: Synthesis Compile findings into BULLISH / BEARISH / NEUTRAL signal.` export const skill = { name: 'token-technical-analysis', version: 'flowmcp-skill/1.0.0', description: 'Full technical analysis: discovery, OHLCV, indicators, chart, signal summary', testedWith: 'anthropic/claude-sonnet-4-5-20250929', requires: { tools: [ 'indicators/tool/searchBySymbol', 'ohlcv/tool/getRecursiveOhlcvEVM', 'tradingsignals/tool/computeRSI', 'tradingsignals/tool/computeMACD' ], resources: [], external: [ 'playwright' ] }, input: [ { key: 'tokenSymbol', type: 'string', description: 'Token symbol (e.g. WETH)', required: true }, { key: 'chain', type: 'string', description: 'Blockchain (e.g. ethereum)', required: true }, { key: 'timeframeDays', type: 'number', description: 'Days of history', required: false } ], output: 'Structured report with trend, momentum, volatility, chart, and signal summary', content } ``` ## Skill Object Fields | Field | Type | Required | Description | |-------|------|----------|-------------| | `name` | `string` | Yes | Must match the `name` in the schema's `skills` array entry. | | `version` | `string` | Yes | Must be `'flowmcp-skill/1.0.0'`. | | `description` | `string` | Yes | What this skill does. | | `testedWith` | `string` | Yes | Model ID the skill was tested with (e.g. `anthropic/claude-sonnet-4-5-20250929`). | | `requires` | `object` | Yes | Dependencies: `tools`, `resources`, and `external` arrays. | | `input` | `array` | No | User-provided input parameters. | | `output` | `string` | No | Description of what the skill produces. | | `content` | `string` | Yes | The instruction text with placeholders. | > **Note:** **`testedWith` is required for Skills.** Every skill must declare which model it was tested with. This is a key difference from Prompts, which do not require `testedWith`. The field records accountability -- if a skill produces unreliable results, the tested model is the first variable to check. ### `requires` Object | Field | Type | Description | |-------|------|-------------| | `tools` | `string[]` | Tool references this skill uses. Uses the full ID format (`namespace/tool/name`) for cross-schema references, or plain names for same-schema tools. | | `resources` | `string[]` | Resource names this skill reads. Must match names in `main.resources`. | | `external` | `string[]` | External capabilities not provided by the schema (e.g. `playwright`, `puppeteer`). For documentation purposes. | > **Note:** **`requires.external` is Skills-only.** Prompts do not have an `external` field. Use it to document dependencies that exist outside the FlowMCP ecosystem, so consumers know what additional setup is needed. ### `input` Array Each input parameter: | Field | Type | Description | |-------|------|-------------| | `key` | `string` | Parameter name (camelCase). Referenced in content as `{{input:key}}`. | | `type` | `string` | One of `string`, `number`, `boolean`, or `enum`. | | `description` | `string` | What this input parameter is for. | | `required` | `boolean` | Whether the user must provide this value. | ## Placeholder Syntax The `content` field supports four placeholder types, identical to the Prompts placeholder system: | Placeholder | Syntax | Resolves To | Example | |-------------|--------|-------------|---------| | Tool reference | `{{tool:name}}` | Tool name from `requires.tools` | `{{tool:computeRSI}}` | | Resource reference | `{{resource:name}}` | Resource name from `requires.resources` | `{{resource:verifiedContracts}}` | | Skill reference | `{{skill:name}}` | Another skill in the same schema | `{{skill:quick-check}}` | | Input reference | `{{input:key}}` | User-provided input value | `{{input:tokenSymbol}}` | ### Placeholder Rules 1. `{{tool:x}}` -- `x` should be listed in `requires.tools` 2. `{{resource:x}}` -- `x` should be listed in `requires.resources` 3. `{{skill:x}}` -- must reference another skill in the same schema (no circular references) 4. `{{input:x}}` -- should match an `input[].key` Unresolved placeholders produce validation warnings (not errors), except for `{{skill:x}}` which must resolve. ## Constraints | Constraint | Value | Rationale | |------------|-------|-----------| | Max skills per schema | 4 | Keep schemas focused | | `testedWith` | Required | Accountability for non-deterministic workflows | | `requires.external` | Skills-only | Prompts do not support this field | | Skill name pattern | `^[a-z][a-z0-9-]*$` | Lowercase with hyphens | | Skill file extension | `.mjs` | ES module format | | Version | `flowmcp-skill/1.0.0` | Fixed for v3.0.0 | | Content | Non-empty string | Must contain instructions | | No circular references | Via `{{skill:x}}` | Prevents infinite loops | ## Skills vs Prompts Summary | Aspect | Prompt | Skill | |--------|--------|-------| | Purpose | Explain context | Instruct step-by-step | | `testedWith` | Optional | **Required** | | `requires.external` | Not available | Available | | Placeholder system | Same | Same | | Max per schema | 4 | 4 | | File format | `.mjs` | `.mjs` | | MCP primitive | Prompts | Prompts | --- # 8. Agents Agents are purpose-driven compositions that bundle tools from multiple providers into a single, testable unit. Where individual schemas wrap a single API, agents combine the right tools for a specific task -- for example, a crypto research agent might pull from CoinGecko, Etherscan, and DeFi Llama simultaneously. > **Note:** This page covers the practical guide for building agents. For the full specification and validation rules, see [Agents Specification](/specification/agents). ## Overview An agent manifest (`agent.mjs`) declares everything the agent needs: which tools to use, which model to target, how the agent should behave, and how to verify it works. ```mermaid flowchart LR A[agent.mjs] --> B[Tool Selection] A --> C[Model Binding] A --> D[System Prompt] A --> E[Prompts] A --> F[Skills] A --> G[Resources] A --> H[Tests] B --> I["coingecko-com/tool/simplePrice"] B --> J["etherscan-io/tool/getContractAbi"] B --> K["defillama-com/tool/getProtocolTvl"] ``` ## Agent Manifest Each agent is defined by an `agent.mjs` file with `export const agent`: ```javascript export const agent = { name: 'crypto-research', version: 'flowmcp/3.0.0', description: 'Cross-provider crypto analysis agent', model: 'anthropic/claude-sonnet-4-5-20250929', systemPrompt: 'You are a crypto research agent...', tools: { 'coingecko-com/tool/simplePrice': null, 'coingecko-com/tool/coinMarkets': null, 'etherscan-io/tool/getContractAbi': null, 'defillama-com/tool/getProtocolTvl': null }, prompts: { 'research-guide': { file: './prompts/research-guide.mjs' } }, skills: { 'token-analysis': { file: './skills/token-analysis.mjs' } }, resources: {}, tests: [ { _description: 'Token price lookup', input: 'What is the current price of Bitcoin?', expectedTools: ['coingecko-com/tool/simplePrice'], expectedContent: ['bitcoin', 'price', 'USD'] }, { _description: 'Contract analysis', input: 'Analyze the USDC contract on Ethereum', expectedTools: ['etherscan-io/tool/getContractAbi'], expectedContent: ['USDC', 'contract'] }, { _description: 'DeFi protocol TVL', input: 'What is the TVL of Aave?', expectedTools: ['defillama-com/tool/getProtocolTvl'], expectedContent: ['Aave', 'TVL'] } ], sharedLists: ['evmChains'] } ``` ## Slash Rule Tools, prompts, and resources use a uniform convention: keys containing `/` are external references (value `null`), keys without `/` are inline definitions. | Key Pattern | Value | Meaning | |-------------|-------|---------| | Contains `/` | `null` | External reference from a provider schema | | No `/` | object | Inline definition owned by the agent | ```javascript tools: { 'coingecko-com/tool/simplePrice': null, // external 'customEndpoint': { method: 'GET', ... } // inline } ``` Skills are the exception -- they cannot have slash keys because they are model-specific and cannot be shared across different LLMs. ## Three Content Layers Agents separate concerns into three distinct layers that shape how the agent thinks, understands, and acts. - **Persona:** **Field:** `systemPrompt` Who the agent IS. Defines personality, expertise, and behavioral boundaries. *"You are a crypto research analyst who provides data-driven insights..."* - **Explanations:** **Field:** `prompts` How tools work. Provides context about data formats, API quirks, and interpretation guidance. *"CoinGecko returns prices in the base currency. Always convert to USD for comparison..."* - **Instructions:** **Field:** `skills` Step-by-step workflows. Guides the agent through multi-tool sequences for complex tasks. *"Step 1: Search token by name. Step 2: Fetch OHLCV data. Step 3: Calculate metrics..."* | Layer | Field | Purpose | Example | |-------|-------|---------|---------| | Persona | `systemPrompt` | Who the agent IS | "You are a crypto research analyst..." | | Explanations | `prompts` | How tools work | "CoinGecko returns prices in..." | | Instructions | `skills` | Step-by-step workflows | "Step 1: Search token. Step 2: Fetch OHLCV..." | ## Tool Cherry-Picking Tools are declared as object keys with the full ID format: `namespace/type/name`. External tools have `null` as value. This lets you pick exactly the tools an agent needs from any provider. ``` coingecko-com/tool/simplePrice # Key in tools object, value: null coingecko-com/tool/coinMarkets # Another tool from the same provider etherscan-io/tool/getContractAbi # Tool from a different provider defillama-com/tool/getProtocolTvl # Yet another provider ``` Select only the tools that serve the agent's purpose. A crypto research agent does not need every CoinGecko endpoint -- just `simplePrice` and `coinMarkets` might be enough. ## Agent Tests > **Note:** Every agent must have a minimum of 3 tests. This ensures the agent's tool selection and output quality are verified across different usage scenarios. Tests validate agent behavior at three levels: | Level | Field | What it checks | Deterministic? | |-------|-------|-----------------|----------------| | **Tool Usage** | `expectedTools` | Did the agent call the right tools? | Yes | | **Content** | `expectedContent` | Does the output contain expected keywords? | Partial | | **Quality** | Manual review | Is the output coherent and useful? | No | Each test case defines an input prompt, the tools the agent should reach for, and keywords the response should contain: ```javascript { _description: 'Token price lookup', input: 'What is the current price of Bitcoin?', expectedTools: ['coingecko-com/tool/simplePrice'], expectedContent: ['bitcoin', 'price', 'USD'] } ``` - **`expectedTools`** is deterministic -- the agent must call exactly these tools for the given input. - **`expectedContent`** is a partial check -- the response should contain these strings, but additional content is fine. - **Quality review** is manual -- read the output and verify it makes sense as a coherent answer. ## Directory Structure Each agent lives in its own directory within the catalog's `agents/` folder: ``` agents/crypto-research/ ├── agent.mjs # Manifest (export const agent) ├── prompts/ │ └── research-guide.mjs ├── skills/ │ └── token-analysis.mjs └── resources/ # Optional own databases ``` The `agent.mjs` file is the entry point. Prompts and skills are referenced by relative path from the manifest and follow the same format as [schema-level skills](/specification/skills) and [prompt architecture](/specification/prompt-architecture). --- # 9. CLI ## Installation ```bash npm install -g flowmcp ``` ## CLI Workflow The CLI follows a three-step pattern: discover tools, activate them, then call them. ```mermaid flowchart LR A[flowmcp search] --> B[Find tools] B --> C[flowmcp add] C --> D[Activate tool] D --> E[flowmcp call] E --> F[Execute tool] ``` ## Core Commands | Command | Description | |---------|-------------| | `flowmcp search ` | Find tools (max 10 results) | | `flowmcp add ` | Activate a tool + show parameters | | `flowmcp call '{json}'` | Call a tool with JSON parameters | | `flowmcp remove ` | Deactivate a tool | | `flowmcp list` | Show active tools | | `flowmcp status` | Health check | ## Search, Add, Call ### Search for tools Find tools by keyword. Results include name, description, and the command to add each tool. ```bash flowmcp search ethereum # Shows up to 10 matching tools with name + description flowmcp search "token price" # Refine query if too many results ``` ### Add a tool Activate a tool for your project. The response shows the tool's parameters with types and requirements. ```bash flowmcp add get_contract_abi_etherscan # Response shows: name, description, parameters with types ``` The parameter schema is also saved locally in `.flowmcp/tools/` for reference. ### Call a tool Execute the tool with JSON parameters. Use the parameter information from the `add` response. ```bash flowmcp call get_contract_abi_etherscan '{"address": "0xdAC17F958D2ee523a2206206994597C13D831ec7"}' ``` ## Agent Mode vs Dev Mode The CLI has two operating modes that control which commands are available: | Mode | Commands | Use Case | |------|----------|----------| | **Agent** | search, add, call, remove, list, status | Daily AI agent usage | | **Dev** | + validate, test, migrate | Schema development | ```bash flowmcp mode dev # Switch to dev mode flowmcp mode agent # Switch back to agent mode ``` > **Note:** Agent mode is the default. It exposes only the commands an AI agent needs to discover, activate, and call tools. Switch to Dev mode for schema development and validation workflows. ## Dev Mode Commands Dev mode unlocks additional commands for schema authors: ```bash flowmcp validate # Validate schema structure flowmcp test single # Live API test flowmcp validate-agent # Validate agent manifest ``` ## Local Project Config When you `add` tools, a `.flowmcp/` directory is created in your project: ``` .flowmcp/ ├── config.json # Active tools + mode └── tools/ # Parameter schemas (auto-generated) └── get_contract_abi_etherscan.json ``` Each file in `tools/` contains the tool name, description, and expected input parameters: ```json { "name": "get_contract_abi_etherscan", "description": "Returns the Contract ABI of a verified smart contract", "parameters": { "address": { "type": "string", "required": true } } } ``` ## API Keys > **Tip:** Some tools require API keys stored in `~/.flowmcp/.env`. If a `call` fails because of missing keys, add the required key to your global config: ```bash echo "ETHERSCAN_API_KEY=your_key_here" >> ~/.flowmcp/.env ``` Never commit API keys to version control. The `.env` file in `~/.flowmcp/` is your global key store and should stay on your machine only. --- # 10. MCP Server ## What is MCP? The **Model Context Protocol (MCP)** is an open standard for connecting AI models to external tools and data sources. FlowMCP can run as an MCP server, exposing all active schemas as tools to any MCP-compatible AI client. Instead of writing custom server code for each API, you declare schemas and FlowMCP handles the MCP protocol, parameter validation, and API execution. ## Architecture How FlowMCP bridges AI clients and APIs: ```mermaid flowchart LR A[AI Client] -->|MCP Protocol| B[FlowMCP MCP Server] B --> C[Schema 1: CoinGecko] B --> D[Schema 2: Etherscan] B --> E[Schema 3: DeFi Llama] C --> F[CoinGecko API] D --> G[Etherscan API] E --> H[DeFi Llama API] ``` The AI client sends tool calls over the MCP protocol. FlowMCP resolves the correct schema, validates parameters, calls the upstream API, and returns the result. ## Starting the Server The fastest way to serve schemas is through the CLI: ```bash # Serve all active tools as MCP server (stdio) flowmcp server # Serve with specific schema directory flowmcp server --schemas ./schemas/ # Serve a specific group flowmcp server --group crypto ``` For programmatic control, see the [Server Integration guide](/guides/server-integration). ## Client Integration Add FlowMCP to your `claude_desktop_config.json`: ```json { "mcpServers": { "flowmcp": { "command": "npx", "args": ["-y", "flowmcp", "server"], "env": { "ETHERSCAN_API_KEY": "your_key_here", "MORALIS_API_KEY": "your_key_here" } } } } ``` Config file location: - **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json` - **Windows**: `%APPDATA%\Claude\claude_desktop_config.json` > **Tip:** After editing the config, restart Claude Desktop to pick up the new MCP server configuration. Add FlowMCP to your Cursor MCP settings: ```json { "mcpServers": { "flowmcp": { "command": "npx", "args": ["-y", "flowmcp", "server"] } } } ``` Open Cursor Settings and navigate to the MCP section to add this configuration. Add FlowMCP as a local MCP server: ```bash claude mcp add flowmcp --scope local -- npx -y flowmcp server ``` Claude Code will automatically start the server when needed. ## Environment Variables API keys required by your schemas can be provided in three ways: | Method | Example | Best For | |--------|---------|----------| | `~/.flowmcp/.env` file | `ETHERSCAN_API_KEY=abc123` | Persistent local setup | | `env` block in client config | See Claude Desktop example above | Per-client configuration | | System environment variables | `export ETHERSCAN_API_KEY=abc123` | CI/CD and containers | > **Note:** API keys are injected as server parameters at runtime and are never exposed to the AI client. They are only used when FlowMCP calls the upstream API on behalf of the AI. ## What Gets Exposed All active tools from your `.flowmcp/config.json` become MCP primitives: | Schema Primitive | MCP Primitive | Description | |-----------------|---------------|-------------| | Tools | MCP Tools | API endpoints the AI can call | | Resources | MCP Resources | Static data the AI can read | | Prompts | MCP Prompts | Pre-built prompt templates | Each tool is registered with its name, description, and a Zod-validated parameter schema -- giving the AI client everything it needs to discover and call the tool correctly. ## What's Next - **[Server Integration](/guides/server-integration):** Programmatic server setup with stdio and HTTP/SSE transports - **[Schema Library](/ecosystem/schema-library):** Browse 187+ pre-built schemas ready to serve