merofoundry-mcp
A remote MCP server (Streamable HTTP transport) that exposes 39 task tools over the MeroFoundry
platform API via the shared merofoundry-client library. MeroFoundry is the platform for building
entire websites.
Tools
Data plane — writes (5 tools)
| Tool | Description |
|---|---|
describe_schema |
List models and their fields for an application |
query_records |
Query records with optional filters and pagination |
upsert_record |
Create or update a record (idempotency via record_id) |
delete_record |
Delete a record by ID |
run_rule_event |
Trigger a rule event for an application |
Authoring — Plan 2 (17 tools)
Authoring tools require an API key with the appropriate authoring permissions (applications, models, fields, forms, or rules create/update/delete, and models:publish).
Authoring keys carry a larger blast radius than data-plane keys (full CRUD including delete). Treat them accordingly.
Primitives (15)
| Tool | Description |
|---|---|
create_application |
Create a new application |
update_application |
Update an application's metadata |
delete_application |
Archive/delete an application (destructive) |
define_model |
Create a data model (table). Records require a PUBLISHED model — call publish_model after adding fields, or use scaffold_model |
update_model |
Update a model's metadata |
delete_model |
Delete a model and all its records (destructive) |
publish_model |
Publish a model's schema so records can be created/queried. Required after creating or changing fields |
add_field |
Add a field to a model. Adding a field reverts the model to draft — re-publish before records work |
update_field |
Update a field's metadata |
delete_field |
Delete a field from a model (destructive) |
define_form |
Create a form, optionally bound to a model |
update_form |
Update a form's metadata or layout |
delete_form |
Delete a form (destructive) |
define_rule |
Create a business rule |
test_rule |
Dry-run a rule without persisting |
Reads (8 tools)
Single-item and search reads, plus the file surface.
| Tool | Description |
|---|---|
get_application |
Fetch one application's metadata |
get_model |
Fetch one model and its fields |
get_record |
Fetch one record by ID |
search_records |
Full-text search across a model's records |
upload_file |
Upload a file to an application |
get_file |
Fetch a file's metadata and a short-lived download URL |
download_file |
Download a file's contents |
delete_file |
Delete a file (destructive) |
Pages (6 tools)
| Tool | Description |
|---|---|
create_page |
Create a page |
list_pages |
List an application's pages |
get_page |
Fetch one page, including its layout |
update_page |
Update a page's metadata or layout |
delete_page |
Delete a page (destructive) |
render_page |
Render a page's layout with composites expanded and style resolved |
Queries, services and governance (3 tools)
| Tool | Description |
|---|---|
run_saved_query |
Execute a saved query and return its rows |
invoke_service |
Invoke a configured outbound service |
set_outbound_governance |
Set an application's outbound-call governance policy |
Composites (2)
These tools bundle multiple primitive steps into a single call for the common-case paths.
| Tool | Description |
|---|---|
scaffold_model |
Fast path: create a model, add all its fields, and publish it in one call. fields is a list of {name, label?, type, required?, unique?, default_value?, settings?}. Returns {model_id, field_ids, published} |
create_form_simple |
Simple mode: from a field spec, scaffold a model (create + fields + publish) and create a model-bound form in simple mode — one call. Returns {model_id, form_id, field_ids} |
Publish requirement. Records require a published model. Creating a model leaves it in draft; publish_model promotes it. Adding a field after publish reverts the model to draft, requiring another publish_model. The composites handle this automatically — primitives require an explicit publish_model call.
Simple mode is an MCP-layer composite. create_form_simple is implemented entirely in the MCP server; it calls the backend primitives in sequence. The backend does not auto-generate models from forms — mode is metadata on the form. There is no magic on the server side.
Composite partial-failure. scaffold_model and create_form_simple are not transactional. If a later step fails (e.g. a field creation error), an earlier-created model may already exist in the backend, possibly in an unpublished state. The caller may need to clean up manually (e.g. delete_model) before retrying.
create_application and provisioning. create_application creates an application record, but a newly created application will not have its own API key. Key minting still requires the JWT route; it is out of scope for an app-scoped API key. provision_tenant (full control-plane onboarding) is also out of scope.
Authentication
The caller (MCP client) passes auth on every request as either:
Authorization: Bearer <api_key>X-API-Key: <api_key>
There is no tenant header. Auth is API-key only.
Run the server
MEROFOUNDRY_SERVER_ROOT=http://localhost:8000 \
uvicorn --factory merofoundry_mcp.server:build_app --port 9000
MEROFOUNDRY_SERVER_ROOT defaults to http://localhost:8000 if unset.
Install / dev
python -m venv .venv
source .venv/bin/activate
uv pip install -e ../merofoundry-client
uv pip install -e ".[dev]"
Run tests:
.venv/bin/python -m pytest
Eval setup — cross-model matrix
The evals/ directory contains a harness, Anthropic and OpenAI-compatible adapters, eval tasks, and a matrix runner (run_evals.py) that tests tool-use competence across models.
Prerequisites
Step 1 — Run meroweb-omo locally.
The /api/v1/public routes must be the hardened version (idempotency, agent-readable errors,
camelCase operationIds). This is already on its main branch.
Step 2 — Seed a sandbox application and model.
Create an application and a model with at least these text fields: name, email, company.
Step 3 — Mint an API key scoped to that app with permissions:
For data-plane tasks only:
app:read,models:read,records:read,records:create,records:update,records:delete,rules:execute
For the build_app_end_to_end authoring task (Plan 2), additionally include authoring permissions:
applications:create,applications:update,models:create,models:update,models:delete,models:publish,fields:create,fields:update,fields:delete,forms:create,forms:update,forms:delete,rules:create
Step 4 — (For local models) install Ollama and pull models, or start a llama.cpp server:
ollama pull llama3.1:8b qwen2.5:7b
For llama.cpp, start llama-server with tool-call support (the --jinja flag enables the model's own chat template to handle tools; required for some models):
llama-server --jinja -m <model-file> --port 11435
Step 5 — (For the codex adapter) start the MCP server and ensure a seeded app + API key.
The codex adapter drives the live MCP server directly (see Codex adapter below). The server must be running and the API key must be scoped to the seeded app.
Step 6 — Run the matrix.
Frontier model (Anthropic):
python -m evals.run_evals \
--app <APP_ID> --model <MODEL_ID> --api-key <SK> \
--adapter anthropic --model-name claude-opus-4-8
Local model (Ollama):
python -m evals.run_evals \
--app <APP_ID> --model <MODEL_ID> --api-key <SK> \
--adapter ollama --model-name llama3.1:8b \
--base-url http://localhost:11434/v1
Remote llama.cpp server (OpenAI-compatible endpoint):
python -m evals.run_evals \
--app <APP_ID> --model <MODEL_ID> --api-key <SK> \
--adapter llamacpp --model-name qwen3.5-122b-a10b
# default --base-url http://192.168.125.220:11435/v1; override with --base-url as needed
Codex external agent (drives the live MCP server):
python -m evals.run_evals \
--adapter codex \
--mcp-url http://localhost:9000/mcp \
--app <APP_ID> --model <MODEL_ID> --api-key <SK>
Step 7 — Read the scorecard.
The runner prints a per-task, per-model success rate: success=N/3 (default 3 runs per task).
Honest scope note
The full cross-model scorecard (tasks creating and querying real records) requires a running meroweb-omo instance with a seeded app and a scoped API key. What is verified today: llama.cpp tool-calling (qwen3.5-122b-a10b on the default server emits tool calls correctly) and codex connectivity (v0.140.0 connected and discovered all 5 tools at the time of Plan 1). The full scorecard — including the Plan 2 build_app_end_to_end authoring task — requires a live seeded sandbox and an authoring-scoped API key, and has not yet been run.
llama.cpp adapter
--adapter llamacpp treats the llama.cpp server as an OpenAI-compatible endpoint. The default base URL is http://192.168.125.220:11435/v1; override with --base-url. The model name (--model-name) is passed as-is to the API.
If a model/server does not emit tool calls, ensure llama-server was started with --jinja so the model's own chat template handles tool formatting.
Codex adapter — external agent (deepest dogfood)
--adapter codex is the highest-fidelity eval path: codex acts as the MCP client and drives the live MCP server end-to-end, exercising the full HTTP transport and auth flow. The eval runner injects the MCP server URL into each codex invocation per-run (no mutation of global codex config).
The runner sets -c sandbox_workspace_write.network_access=true so codex's sandbox can reach the local MCP server. (Note: the codex config key is sandbox_workspace_write.network_access, not sandbox_permissions; the latter is rejected by codex.)
Interactive use (not just evals). You can also register the server with codex for ad-hoc use:
codex mcp add merofoundry \
--url http://localhost:9000/mcp \
--bearer-token-env-var MEROFOUNDRY_API_KEY
export MEROFOUNDRY_API_KEY=<your MeroFoundry platform API key>
codex sends Authorization: Bearer <key> on every MCP request. Verified with codex 0.140.0: all 5 data-plane tools (describe_schema, query_records, upsert_record, delete_record, run_rule_event) are discovered. The 17 authoring tools (Plan 2) follow the same transport and auth flow.
Release gate — small-model legibility check
The small-model success rate is the design-legibility gate.
If a small local model (e.g.
llama3.1:8borqwen2.5:7b) cannot completecreate_then_query_contacts, treat it as a signal to improve the tool descriptions or error messages before shipping — not just as model weakness.
The create_then_query_contacts task is the primary gate for data-plane tools: it requires the model to call describe_schema, create three records via upsert_record, and then query them.
The build_app_end_to_end task (added in Plan 2) is the authoring acceptance gate: the model must create a data model with fields, publish it, insert records, and query them — using scaffold_model where available. It requires an authoring-scoped API key and a live backend. If small models fail this task consistently, the authoring tool descriptions need work.
DNS-rebinding host allowlist
FastMCP enables host-header validation by default for localhost-bound servers
(127.0.0.1, localhost, ::1). It accepts only Host values matching
127.0.0.1:*, localhost:*, or [::1]:* (port required).
When running behind a reverse proxy or with a real hostname, connections will
receive 421 Misdirected Request unless you either:
- Configure a
transport_securityallowlist that includes your proxy'sHostheader value, or - Disable the check with
TransportSecuritySettings(enable_dns_rebinding_protection=False).
For test clients (e.g. Starlette TestClient, httpx), send
Host: localhost:80 to satisfy the wildcard check.
For the codex eval adapter and interactive codex use, always connect via
http://localhost:9000/mcp or http://127.0.0.1:9000/mcp. Using a real
hostname or proxy address will produce 421 Invalid Host until that host is
added to the allowlist.
Optional live contract check
Verifies the hardened /api/v1/public OpenAPI has the expected camelCase operationIds. Skipped
when MERO_OPENAPI_URL is not set.
MERO_OPENAPI_URL=http://localhost:8000/api/openapi.json \
.venv/bin/python -m pytest tests/test_baas_contract.py
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file merofoundry_mcp-0.1.0.tar.gz.
File metadata
- Download URL: merofoundry_mcp-0.1.0.tar.gz
- Upload date:
- Size: 98.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
00727cab6fef2e4158126ec7ba39684a932a93eca997857c3b7b5338147becd6
|
|
| MD5 |
f4c64dc5f74d21b9208f789fc290be07
|
|
| BLAKE2b-256 |
e15743d4258b2d1112586e6463ca503ed472e808e2b9b85080c7b1fb10d6b981
|
File details
Details for the file merofoundry_mcp-0.1.0-py3-none-any.whl.
File metadata
- Download URL: merofoundry_mcp-0.1.0-py3-none-any.whl
- Upload date:
- Size: 24.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dd1c44e35af8aad5f120228a5d1a170ec703094f29db7f17a5c6486a74e27164
|
|
| MD5 |
afebc5badc5912540098e00aa02acbc5
|
|
| BLAKE2b-256 |
d077e31cae155b24ca1929e912125f92d3bdc4599d048f34aa9d47d11e1c972d
|