Skip to content

Commit d007b3b

Browse files
hyperpolymathclaude
andcommitted
feat: add Tier 5 cartridges (zotero, todoist, google-docs, google-sheets, airtable)
5 cartridges, 50 files, 52 tools total: - zotero-mcp: 12 tools (library search, collections, citations, bibliography) - todoist-mcp: 10 tools (tasks, projects, labels, comments, sections) - google-docs-mcp: 10 tools (documents, headings, search, comments, revisions) - google-sheets-mcp: 10 tools (ranges, sheets, batch reads, conditional formats) - airtable-mcp: 10 tools (bases, records, schema, views, webhooks) Each cartridge: cartridge.json, mod.js, Idris2 ABI (%default total), thread-safe Zig FFI, V-lang adapter, PanLL panels, minter.toml, README.adoc, integration tests, benchmarks. PMPL-1.0-or-later. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 1e6fa71 commit d007b3b

50 files changed

Lines changed: 6692 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// SPDX-License-Identifier: PMPL-1.0-or-later
2+
// Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>
3+
= airtable-mcp
4+
Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk>
5+
:spdx: PMPL-1.0-or-later
6+
:tier: Ayo
7+
:domain: Productivity
8+
:protocols: MCP, REST
9+
10+
== Overview
11+
12+
Airtable cartridge for the BoJ server. Provides type-safe access to the
13+
Airtable REST API for base listing, table schema retrieval, record search
14+
with formula filtering, record creation and update, field listing, view
15+
browsing, webhook management, and record comment access.
16+
17+
Connects to the Airtable API at `api.airtable.com`. Personal access token
18+
auth is always required.
19+
20+
=== State Machine
21+
22+
`Disconnected -> Connected` (authenticated via personal access token)
23+
24+
`Connected -> RateLimited -> Connected` (30 req/sec limit)
25+
26+
`Connected -> Error -> Disconnected` (error recovery)
27+
28+
=== Actions (10)
29+
30+
[cols="1,1"]
31+
|===
32+
| Category | Actions
33+
34+
| Record Reads
35+
| ListRecords, GetRecord, GetComments
36+
37+
| Record Writes
38+
| CreateRecord, UpdateRecord
39+
40+
| Schema
41+
| GetBaseSchema, ListFields, ListViews
42+
43+
| Meta
44+
| ListBases, ListWebhooks
45+
|===
46+
47+
== Architecture
48+
49+
[cols="1,1,2"]
50+
|===
51+
| Layer | Language | Purpose
52+
53+
| ABI
54+
| Idris2
55+
| Formally verified state machine with dependent-type proofs (AirtableMcp.SafeRegistry)
56+
57+
| FFI
58+
| Zig
59+
| C-compatible implementation with thread-safe session pool, action recording, category counting
60+
61+
| Adapter
62+
| V-lang
63+
| REST bridge to BoJ unified adapter protocol
64+
|===
65+
66+
== Building
67+
68+
[source,bash]
69+
----
70+
# Build FFI shared library
71+
cd ffi && zig build
72+
73+
# Run FFI tests
74+
cd ffi && zig build test
75+
76+
# Type-check ABI
77+
cd abi && idris2 --check AirtableMcp.SafeRegistry
78+
----
79+
80+
== Prerequisites
81+
82+
1. Create an Airtable personal access token at https://airtable.com/create/tokens
83+
2. Set `AIRTABLE_API_KEY` to the token value.
84+
85+
== Status
86+
87+
Development -- customised with Airtable-specific formula filtering, schema introspection, view browsing, webhook management, and record comments.
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
-- SPDX-License-Identifier: PMPL-1.0-or-later
2+
-- Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>
3+
--
4+
-- AirtableMcp.SafeRegistry — Type-safe ABI for airtable-mcp cartridge.
5+
--
6+
-- Dependent-type state machine governing Airtable REST API access.
7+
-- Encodes mandatory Bearer token auth, base listing, schema retrieval,
8+
-- record search, record creation, record update, field listing, view
9+
-- browsing, webhook management, and comment access as compile-time
10+
-- invariants.
11+
-- REST API: https://api.airtable.com/v0
12+
-- No unsafe escape hatches.
13+
14+
module AirtableMcp.SafeRegistry
15+
16+
%default total
17+
18+
-- ---------------------------------------------------------------------------
19+
-- Authentication state machine
20+
-- ---------------------------------------------------------------------------
21+
22+
||| Session state for Airtable MCP operations.
23+
||| Disconnected: no API key configured.
24+
||| Connected: authenticated and ready for API calls.
25+
||| RateLimited: rate limit hit (30 req/sec); must wait.
26+
||| Error: unrecoverable error (invalid key, permission denied).
27+
public export
28+
data SessionState
29+
= Disconnected
30+
| Connected
31+
| RateLimited
32+
| Error
33+
34+
||| Proof that a state transition is valid.
35+
||| Airtable requires personal access token — no anonymous access.
36+
public export
37+
data ValidTransition : SessionState -> SessionState -> Type where
38+
Connect : ValidTransition Disconnected Connected
39+
Disconnect : ValidTransition Connected Disconnected
40+
Throttle : ValidTransition Connected RateLimited
41+
Unthrottle : ValidTransition RateLimited Connected
42+
ConnectError : ValidTransition Connected Error
43+
DisconnError : ValidTransition Disconnected Error
44+
RecoverConnect : ValidTransition Error Connected
45+
RecoverDisconn : ValidTransition Error Disconnected
46+
47+
-- ---------------------------------------------------------------------------
48+
-- C-ABI integer encoding
49+
-- ---------------------------------------------------------------------------
50+
51+
export
52+
sessionStateToInt : SessionState -> Int
53+
sessionStateToInt Disconnected = 0
54+
sessionStateToInt Connected = 1
55+
sessionStateToInt RateLimited = 2
56+
sessionStateToInt Error = 3
57+
58+
export
59+
intToSessionState : Int -> Maybe SessionState
60+
intToSessionState 0 = Just Disconnected
61+
intToSessionState 1 = Just Connected
62+
intToSessionState 2 = Just RateLimited
63+
intToSessionState 3 = Just Error
64+
intToSessionState _ = Nothing
65+
66+
export
67+
airtable_mcp_can_transition : Int -> Int -> Int
68+
airtable_mcp_can_transition from to =
69+
case (intToSessionState from, intToSessionState to) of
70+
(Just Disconnected, Just Connected) => 1
71+
(Just Connected, Just Disconnected) => 1
72+
(Just Connected, Just RateLimited) => 1
73+
(Just RateLimited, Just Connected) => 1
74+
(Just Connected, Just Error) => 1
75+
(Just Disconnected, Just Error) => 1
76+
(Just Error, Just Connected) => 1
77+
(Just Error, Just Disconnected) => 1
78+
_ => 0
79+
80+
-- ---------------------------------------------------------------------------
81+
-- Airtable actions
82+
-- ---------------------------------------------------------------------------
83+
84+
||| Actions available through the Airtable MCP cartridge.
85+
public export
86+
data AirtableAction
87+
= ListBases
88+
| GetBaseSchema
89+
| ListRecords
90+
| GetRecord
91+
| CreateRecord
92+
| UpdateRecord
93+
| ListFields
94+
| ListViews
95+
| ListWebhooks
96+
| GetComments
97+
98+
||| Whether an action requires Connected state.
99+
export
100+
actionRequiresAuth : AirtableAction -> Bool
101+
actionRequiresAuth _ = True
102+
103+
||| Whether an action is a write/mutating operation.
104+
export
105+
actionIsMutating : AirtableAction -> Bool
106+
actionIsMutating CreateRecord = True
107+
actionIsMutating UpdateRecord = True
108+
actionIsMutating _ = False
109+
110+
||| Encode action as C-compatible integer for FFI.
111+
export
112+
actionToInt : AirtableAction -> Int
113+
actionToInt ListBases = 0
114+
actionToInt GetBaseSchema = 1
115+
actionToInt ListRecords = 2
116+
actionToInt GetRecord = 3
117+
actionToInt CreateRecord = 4
118+
actionToInt UpdateRecord = 5
119+
actionToInt ListFields = 6
120+
actionToInt ListViews = 7
121+
actionToInt ListWebhooks = 8
122+
actionToInt GetComments = 9
123+
124+
||| Decode integer to Airtable action.
125+
export
126+
intToAction : Int -> Maybe AirtableAction
127+
intToAction 0 = Just ListBases
128+
intToAction 1 = Just GetBaseSchema
129+
intToAction 2 = Just ListRecords
130+
intToAction 3 = Just GetRecord
131+
intToAction 4 = Just CreateRecord
132+
intToAction 5 = Just UpdateRecord
133+
intToAction 6 = Just ListFields
134+
intToAction 7 = Just ListViews
135+
intToAction 8 = Just ListWebhooks
136+
intToAction 9 = Just GetComments
137+
intToAction _ = Nothing
138+
139+
-- ---------------------------------------------------------------------------
140+
-- MCP tool declarations
141+
-- ---------------------------------------------------------------------------
142+
143+
public export
144+
data McpTool
145+
= ToolListBases
146+
| ToolGetBaseSchema
147+
| ToolListRecords
148+
| ToolGetRecord
149+
| ToolCreateRecord
150+
| ToolUpdateRecord
151+
| ToolListFields
152+
| ToolListViews
153+
| ToolListWebhooks
154+
| ToolGetComments
155+
156+
export
157+
toolRequiresSession : McpTool -> Bool
158+
toolRequiresSession _ = True
159+
160+
export
161+
toolCount : Nat
162+
toolCount = 10
163+
164+
export
165+
actionCount : Nat
166+
actionCount = 10

0 commit comments

Comments
 (0)