Skip to content

Commit 980df9b

Browse files
committed
feat: add JSON extension support with comprehensive tests, new APIs and caching behavior for list tool network requests
1 parent b71eee0 commit 980df9b

File tree

5 files changed

+1478
-103
lines changed

5 files changed

+1478
-103
lines changed

API.md

Lines changed: 216 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,23 +27,33 @@ sqlite> SELECT mcp_version();
2727

2828
---
2929

30-
### `mcp_connect(server_url, [legacy_sse], [headers_json])`
30+
### `mcp_connect(server_url, [legacy_sse], [headers_json], [use_json_ext])`
3131

32-
Connects to an MCP server using either Streamable HTTP (default) or SSE transport, with optional custom HTTP headers.
32+
Connects to an MCP server using either Streamable HTTP (default) or SSE transport, with optional custom HTTP headers and JSON extension mode.
3333

3434
**Syntax:**
3535
```sql
3636
SELECT mcp_connect(server_url);
3737
SELECT mcp_connect(server_url, legacy_sse);
3838
SELECT mcp_connect(server_url, legacy_sse, headers_json);
39+
SELECT mcp_connect(server_url, legacy_sse, headers_json, use_json_ext);
3940
```
4041

4142
**Parameters:**
4243
- `server_url` (TEXT) - URL of the MCP server (e.g., "http://localhost:8000/mcp")
4344
- `legacy_sse` (INTEGER, optional) - 1 to use SSE transport (legacy), 0 for Streamable HTTP (default)
4445
- `headers_json` (TEXT, optional) - JSON string with custom HTTP headers (e.g., `{"Authorization": "Bearer token"}`)
46+
- `use_json_ext` (INTEGER, optional) - 1 to enable JSON extension mode (returns results as JSON type), 0 for regular text mode (default)
4547

46-
**Returns:** `TEXT` - JSON object with connection status
48+
**Returns:**
49+
50+
SQLite return codes from `sqlite3_step()`:
51+
- **On success**: `SQLITE_ROW`
52+
- Regular mode (`use_json_ext=0`): Row contains JSON object with connection status
53+
- JSON mode (`use_json_ext=1`): Row contains NULL (silent success)
54+
- **On failure**: `SQLITE_ERROR` - Error message set via `sqlite3_result_error()`
55+
56+
**Note:** SQLite scalar functions always return exactly one row on success. They cannot return `SQLITE_DONE` (zero rows).
4757

4858
**Examples:**
4959
```sql
@@ -59,6 +69,17 @@ SELECT mcp_connect(
5969
0,
6070
'{"Authorization": "Bearer ghp_your_token", "X-MCP-Readonly": "true"}'
6171
);
72+
73+
-- Connect with JSON extension mode enabled
74+
SELECT mcp_connect('http://localhost:8000/mcp', 0, NULL, 1);
75+
76+
-- Connect with both custom headers and JSON extension mode
77+
SELECT mcp_connect(
78+
'http://localhost:8000/mcp',
79+
0,
80+
'{"Authorization": "Bearer token"}',
81+
1
82+
);
6283
```
6384

6485
**Response:**
@@ -169,6 +190,198 @@ SELECT mcp_call_tool('test', '{}');
169190

170191
---
171192

193+
## Virtual Tables
194+
195+
The extension provides virtual tables that automatically parse MCP responses into structured rows. These are ideal for SQL queries that need to process multiple tools or results.
196+
197+
### `mcp_tools_table`
198+
199+
A virtual table that returns each tool as a row with structured columns.
200+
201+
**Syntax:**
202+
```sql
203+
SELECT * FROM mcp_tools_table;
204+
SELECT name, description FROM mcp_tools_table;
205+
SELECT * FROM mcp_tools_table WHERE name LIKE 'airbnb%';
206+
```
207+
208+
**Columns:**
209+
- `name` (TEXT) - Unique identifier for the tool
210+
- `title` (TEXT) - Optional human-readable name of the tool
211+
- `description` (TEXT) - Human-readable description of functionality
212+
- `inputSchema` (TEXT) - JSON Schema defining expected parameters
213+
- `outputSchema` (TEXT) - Optional JSON Schema defining expected output structure
214+
- `annotations` (TEXT) - Optional properties describing tool behavior
215+
216+
**Example:**
217+
```sql
218+
-- Connect to server
219+
SELECT mcp_connect('http://localhost:8000/mcp');
220+
221+
-- Query tools as rows
222+
SELECT name, description
223+
FROM mcp_tools_table
224+
WHERE name LIKE 'airbnb%';
225+
```
226+
227+
**Result:**
228+
```
229+
name description
230+
---------------- ------------------------------------------
231+
airbnb_search Search for Airbnb listings with filters
232+
airbnb_details Get details for a specific listing
233+
```
234+
235+
---
236+
237+
### `mcp_call_tool_table`
238+
239+
A virtual table that extracts text results from tool calls. Returns one row for each `type="text"` content item in the result.
240+
241+
**Syntax:**
242+
```sql
243+
SELECT text FROM mcp_call_tool_table
244+
WHERE tool_name = '<tool>' AND arguments = '<json>';
245+
```
246+
247+
**Columns:**
248+
- `tool_name` (TEXT, hidden) - Name of tool to call (required in WHERE clause)
249+
- `arguments` (TEXT, hidden) - JSON arguments for the tool (required in WHERE clause)
250+
- `text` (TEXT) - Text content from each result item
251+
252+
**Example:**
253+
```sql
254+
-- Call tool and get text results as rows
255+
SELECT text FROM mcp_call_tool_table
256+
WHERE tool_name = 'airbnb_search'
257+
AND arguments = '{"location": "Rome", "maxPrice": 100}';
258+
```
259+
260+
**Result:**
261+
```
262+
text
263+
----------------------------------------------------
264+
Found 5 listings in Rome under $100
265+
Listing 1: Cozy Apartment - $85/night
266+
Listing 2: Historic Studio - $95/night
267+
```
268+
269+
**Important Notes:**
270+
- The `tool_name` and `arguments` columns are "hidden" parameters that must be provided via the WHERE clause
271+
- This table automatically extracts only `type="text"` results from the MCP response
272+
- Each text item in the response becomes a separate row
273+
274+
---
275+
276+
## Function Variants
277+
278+
The extension provides multiple ways to access MCP functionality:
279+
280+
### Scalar Functions (Return JSON strings)
281+
282+
- `mcp_list_tools()` - Returns JSON string of all tools
283+
- `mcp_call_tool(tool_name, arguments)` - Returns JSON string of tool result
284+
- `mcp_tools_json()` - Alias for `mcp_list_tools()`
285+
- `mcp_call_tool_json(tool_name, arguments)` - Alias for `mcp_call_tool()`
286+
287+
**Behavior:**
288+
- Returns the complete JSON response from MCP
289+
- When JSON extension mode is enabled (`use_json_ext=1`), results are marked with JSON subtype for seamless use with SQLite JSON functions
290+
- When JSON extension mode is disabled, results are returned as plain text
291+
292+
Use these when you need the raw JSON response or want to process with `json_extract()`.
293+
294+
### Virtual Tables (Return structured rows)
295+
296+
- `mcp_tools_table` - Returns tools as rows with named columns
297+
- `mcp_call_tool_table` - Returns text results as rows
298+
299+
**Behavior:**
300+
- Always extract and parse the JSON response using SQLite's `json_each()` function
301+
- Return structured rows regardless of JSON extension mode setting
302+
- `mcp_tools_table` extracts the `$.tools` array and returns each tool as a row
303+
- `mcp_call_tool_table` extracts the `$.result.content` array and returns each `type="text"` item as a row
304+
305+
Use these when you need to process multiple items, filter with WHERE clauses, or join with other tables.
306+
307+
**Example comparing approaches:**
308+
309+
```sql
310+
-- Scalar function approach
311+
SELECT json_extract(value, '$.name')
312+
FROM json_each((SELECT mcp_list_tools()), '$.tools')
313+
WHERE json_extract(value, '$.name') LIKE 'airbnb%';
314+
315+
-- Virtual table approach (simpler)
316+
SELECT name
317+
FROM mcp_tools_table
318+
WHERE name LIKE 'airbnb%';
319+
```
320+
321+
---
322+
323+
## JSON Extension Mode
324+
325+
### Benefits
326+
327+
- **Direct JSON Operations**: Use `json_extract()`, `json_each()`, `json_array_length()` and other SQLite JSON functions directly on results
328+
- **Type Safety**: SQLite recognizes results as JSON type, not plain text
329+
- **Cleaner Queries**: No need to wrap results in `json()` function calls
330+
- **Better Performance**: SQLite can optimize JSON operations when the type is known
331+
332+
### Usage Examples
333+
334+
**Without JSON Extension Mode (default):**
335+
```sql
336+
-- Connect in regular text mode
337+
SELECT mcp_connect('http://localhost:8000/mcp', 0, NULL, 0);
338+
339+
-- Need to explicitly parse as JSON
340+
SELECT json_extract(json(mcp_list_tools()), '$.tools[0].name');
341+
```
342+
343+
**With JSON Extension Mode:**
344+
```sql
345+
-- Connect with JSON extension mode enabled
346+
SELECT mcp_connect('http://localhost:8000/mcp', 0, NULL, 1);
347+
348+
-- Results are automatically recognized as JSON
349+
SELECT json_extract(mcp_list_tools(), '$.tools[0].name');
350+
351+
-- Extract connection status
352+
SELECT json_extract(
353+
mcp_connect('http://localhost:8000/mcp', 0, NULL, 1),
354+
'$.status'
355+
) as status;
356+
357+
-- List all available tools using json_each
358+
SELECT
359+
json_extract(value, '$.name') as tool_name,
360+
json_extract(value, '$.description') as description
361+
FROM json_each((SELECT mcp_list_tools()), '$.tools');
362+
363+
-- Extract tool result content
364+
SELECT json_extract(
365+
mcp_call_tool('airbnb_search', '{"location": "Rome"}'),
366+
'$.result.content[0].text'
367+
) as result_text;
368+
```
369+
370+
### When to Use JSON Extension Mode
371+
372+
**Use JSON extension mode when:**
373+
- You need to extract specific fields from results using `json_extract()`
374+
- You want to iterate over arrays in results using `json_each()`
375+
- You're building queries that process JSON results
376+
- You want type safety for JSON operations
377+
378+
**Use regular text mode when:**
379+
- You just need the raw JSON string
380+
- You're displaying results to users without processing
381+
- You're integrating with systems that expect text output
382+
383+
---
384+
172385
## Transport Protocols
173386

174387
The extension supports two MCP transport protocols:

README.md

Lines changed: 9 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,7 @@ A SQLite extension that integrates the [Model Context Protocol (MCP)](https://mo
88

99
#### Pre-built Binaries
1010

11-
Download for your platform: **macOS**, **Linux**, **Windows**, **Android**, and **iOS**
12-
13-
Or build from source (see [Building from Source](#building-from-source)).
11+
Download for your platform: **macOS**, **Linux**, **Windows**, **Android**, and **iOS**.
1412

1513
### Basic Usage
1614

@@ -88,57 +86,7 @@ Server-Sent Events for compatibility with older servers.
8886
SELECT mcp_connect('http://localhost:8931/sse', 1);
8987
```
9088

91-
## 🚦 Usage with Different Languages
92-
93-
### Python
94-
95-
```python
96-
import sqlite3
97-
98-
conn = sqlite3.connect('data.db')
99-
conn.enable_load_extension(True)
100-
conn.load_extension('./dist/mcp')
101-
102-
cursor = conn.cursor()
103-
104-
# Connect to MCP server
105-
cursor.execute("SELECT mcp_connect('http://localhost:8000/mcp')")
106-
107-
# List tools
108-
result = cursor.execute("SELECT mcp_list_tools()").fetchone()[0]
109-
tools = json.loads(result)
110-
print(f"Available tools: {len(tools['tools'])}")
111-
112-
# Call a tool
113-
cursor.execute("""
114-
SELECT mcp_call_tool('airbnb_search',
115-
'{"location": "Paris", "maxPrice": 150}')
116-
""")
117-
result = cursor.fetchone()[0]
118-
print(result)
119-
```
120-
121-
### Node.js
122-
123-
```javascript
124-
const Database = require('better-sqlite3');
125-
const db = new Database(':memory:');
126-
127-
db.loadExtension('./dist/mcp');
128-
129-
// Connect to MCP server
130-
const result = db.prepare("SELECT mcp_connect('http://localhost:8000/mcp')").get();
131-
console.log(result);
132-
133-
// Call tool
134-
const listings = db.prepare(`
135-
SELECT mcp_call_tool('airbnb_search',
136-
'{"location": "Tokyo", "adults": 2}')
137-
`).get();
138-
console.log(listings);
139-
```
140-
141-
### C
89+
## 🚦 Quick Usage Example
14290

14391
```c
14492
#include <sqlite3.h>
@@ -174,6 +122,8 @@ int main() {
174122
}
175123
```
176124

125+
See [USAGE.md](USAGE.md) for complete usage examples.
126+
177127
## 🤝 Contributing
178128

179129
Contributions are welcome! Please feel free to submit a Pull Request.
@@ -184,8 +134,8 @@ MIT License - See [LICENSE](LICENSE) for details
184134

185135
## 🔗 Related Projects
186136

187-
- [sqlite-agent](https://github.com/sqlitecloud/sqlite-agent) - A powerful AI agent for SQLite
188-
- [sqlite-ai](https://github.com/sqlitecloud/sqlite-ai) - LLM integration for SQLite
189-
- [sqlite-vector](https://github.com/sqlitecloud/sqlite-vector) - Vector search extension
190-
- [sqlite-sync](https://github.com/sqlitecloud/sqlite-sync) - Cloud synchronization
191-
- [sqlite-js](https://github.com/sqlitecloud/sqlite-js) - JavaScript engine integration
137+
- [sqlite-agent](https://github.com/sqliteai/sqlite-agent) - A powerful AI agent for SQLite
138+
- [sqlite-ai](https://github.com/sqliteai/sqlite-ai) - LLM integration for SQLite
139+
- [sqlite-vector](https://github.com/sqliteai/sqlite-vector) - Vector search extension
140+
- [sqlite-sync](https://github.com/sqliteai/sqlite-sync) - Cloud synchronization
141+
- [sqlite-js](https://github.com/sqliteai/sqlite-js) - JavaScript engine integration

0 commit comments

Comments
 (0)