Logflare MCP Code Mode
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Logflare MCP Code Modelist my Logflare sources"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Logflare MCP Code Mode
A Model Context Protocol server that gives an agent three tools instead of dozens for driving the Logflare Management API. The agent writes a short JavaScript function that runs inside a Vercel Sandbox and calls the API through a thin api.request() client — looping, filtering, and chaining calls in one round-trip.
This applies Cloudflare's Code Mode pattern to Logflare:
LLMs write API-calling code more reliably than long chains of individual tool calls.
Intermediate data stays in the sandbox, out of the model's context.
The agent discovers endpoints with
search(the OpenAPI spec), then calls them withexecute_read/execute_write.
This is a local stdio server — one process per MCP client, communicating over stdin/stdout, the same way you'd run any locally-installed MCP server (npx, or a command/args entry in your client config). Logflare has no OAuth 2.1 authorization server, so there's no per-request bearer token to broker the way a remote streamable-HTTP server would; the API key is just an environment variable for the whole process.
Quickstart
Prerequisites: Node.js ≥ 20.12, pnpm (corepack enable provides it), a Vercel account with Sandbox access, and a Logflare API key (Logflare account → API Keys).
pnpm install
pnpm buildCopy .env.example to .env and fill in VERCEL_TOKEN/VERCEL_TEAM_ID/VERCEL_PROJECT_ID and LOGFLARE_API_KEY — the local .env is only for pnpm dev/pnpm test; a real MCP client sets these as env entries in its own config instead (see below).
Connect an MCP client — this repo ships a .mcp.json:
{
"mcpServers": {
"logflare-code-mode": {
"command": "node",
"args": ["dist/index.js"],
"env": {
"LOGFLARE_API_KEY": "${LOGFLARE_API_KEY}",
"VERCEL_TOKEN": "${VERCEL_TOKEN}",
"VERCEL_TEAM_ID": "${VERCEL_TEAM_ID}",
"VERCEL_PROJECT_ID": "${VERCEL_PROJECT_ID}"
}
}
}
}Once published, the same thing works via npx:
{
"mcpServers": {
"logflare-code-mode": {
"command": "npx",
"args": ["-y", "logflare-mcp-code-mode", "--read-only"],
"env": { "LOGFLARE_API_KEY": "...", "VERCEL_TOKEN": "...", "VERCEL_TEAM_ID": "...", "VERCEL_PROJECT_ID": "..." }
}
}
}Run node dist/index.js --help for the full option/env-var reference.
Try it — call execute_read with an async arrow function:
async () => {
const res = await api.request({ method: 'GET', path: '/api/sources' })
return { status: res.status, count: res.data.length }
}You get back e.g. { "status": 200, "count": 3 } — produced by code the agent wrote, run in a sandbox that can reach only the Logflare API.
Related MCP server: MCP Code Execution Server
The three tools
Each takes a single code string — an async arrow function that returns a value. console.log output comes back separately as stdout.
Tool | What it does | In scope | Annotation |
| Query the Logflare OpenAPI |
| read-only |
| Call the Logflare API via |
| read-only |
| Call the Logflare API via |
| destructive |
The workflow is: search to find an endpoint's path and request shape, then execute_read/execute_write to call it. The client is api.request({ method, path, query?, body?, contentType?, rawBody? }), which returns { status, ok, data }.
Run with --read-only to lock the whole server instance into read-only mode: search's spec only contains GET operations (so the agent can't even discover write endpoints), and execute_write isn't registered at all — it's absent from tools/list, and calling it anyway fails as an unknown tool. This is a startup flag (a property of the process), not a per-call one.
How it works
MCP client ──stdio (newline-delimited JSON-RPC)──▶ McpServer (2 or 3 tools)
│
┌───────────────────────────────┼───────────────────────────────┐
search execute_read execute_write
│ └───────────────┬───────────────┘
▼ ▼
fresh Vercel Sandbox fresh Vercel Sandbox
(networkPolicy: deny-all) (networkPolicy: allow logflare.app;
embeds `spec` LOGFLARE_API_KEY injected;
`api.request()` client)Transport —
StdioServerTransportfrom the MCP SDK: reads newline-delimited JSON-RPC from stdin, writes responses to stdout. stdout is exclusively the protocol channel — all logging goes to stderr (seesrc/log.ts).Per call — a fresh Vercel Sandbox (
@vercel/sandbox), stopped infinally. No SDK is installed inside it, so there's nothing to amortize with a warm pool.searchsandbox —networkPolicy: "deny-all"; the slimmed OpenAPI spec (fetched fromLOGFLARE_OPENAPI_URL, defaulthttps://api.logflare.app/api/openapi) is embedded asspecfor the agent's read-only code to query. In--read-onlymode the spec is filtered to GET-only operations first.execute_*sandbox —networkPolicy: { allow: ["logflare.app"] }(the Management API's actual host);LOGFLARE_API_KEYis injected as an env var and sent asAuthorization: Bearer <key>byapi.request(). The read/write split and the credential/backend/team block are enforced by the providedapi.request()client:execute_readthrows on any non-GET before the fetch, and both tools refuse the paths inBLOCKED_PATH. This is a guard against accidental or confused agent behavior, not a hard sandbox capability restriction — agent code is plain Node with the globalfetchin scope, so it could in principle calllogflare.appdirectly and bypass both checks. Safety for a genuinely adversarial caller rests on the fact that they're using their own API key against an API they already have full access to, not on this guard.Runner — agent code is written to a file and run with
node(nevereval); output returns via a result file. The code sits on its own lines in the invoke scaffold, so a trailing// commentcan't swallow the closing tokens.Vercel credentials — explicit
VERCEL_TOKEN/VERCEL_TEAM_ID/VERCEL_PROJECT_IDare required (this process never runs on Vercel itself, so there's no ambient OIDC fallback in practice).
The source is small and layered by responsibility:
File | Responsibility |
| Entry point: parses |
| The MCP surface: the two or three tools (depending on read-only mode), response formatting, the untrusted-data boundary. |
| Sandbox plumbing: runner construction, the two sandbox shapes, the injected |
| Fetches, |
| pino logger (stderr only) + credential redaction. |
Security notes
Agent code is untrusted but runs inside a Vercel Sandbox microVM and authenticates with the caller's own Logflare key — so by design it can use that key against the Logflare API. Beyond the sandbox isolation, per-tool egress, and read/write split above:
Untrusted-data boundary — all execute output (
result/stdout/stderr) may embed API content (log events, source metadata), so it's wrapped in a<untrusted-data-{uuid}>…</>envelope (error path too), with the model told not to follow instructions inside. Truncation happens before wrapping, so a size cap can't sever the closing tag.Credential/backend/team block — paths containing
access-tokens(mints/lists/reveals full API tokens),backends(backendconfigcan embed DB passwords, service-account keys, and other connection secrets), orteams(the Team response embeds the fullUserobject, whoseapi_keyis the account's master Logflare API key) are refused, matched anywhere in the path (e.g./api/sources/{id}/backends/{id}). The path is first normalized to a fixpoint (percent-decode, re-resolve dot-segments, collapse slashes, lowercase), so encoded spellings (/%61ccess-tokens,//backends,/x%2F..%2Fbackends,/TEAMS) still match; it only over-blocks. This guard covers the intendedapi.request()path; see the caveat above about rawfetchin the sandbox.Known gap — some
Sourcefields (slack_hook_url,webhook_notification_url) embed secrets the caller configured (their own Slack webhook, etc.) rather than Logflare-minted credentials. These are not blocked, the same way reading your own resource's other fields isn't blocked — but a prompt-injected agent could still surface them into its context viaexecute_read/execute_write, same as any other resource field.Output caps — bounded inside the sandbox before reaching the server: runner result cap (400k chars),
head -creads (500k file / 20k per stream), final server truncate (100k result / 10k logs).Token location — like Vercel Sandbox generally, there's no outbound-fetch proxy hook to keep the token out of the isolate, so
LOGFLARE_API_KEYlives in the sandbox env (agent code can read it). Safety rests on isolation + egress — the key only reacheslogflare.app— not token secrecy.Single-tenant by design — there's no bearer-token auth gate because there's nothing to gate: this process is spawned per-caller by an MCP client, already scoped to whoever's shell/config started it, unlike the remote-HTTP shape this was originally built as (see
git log— the streamable-HTTP version is preserved in history if a remote deployment is ever needed again).
Configuration
Env var / flag | Default | Meaning |
| — | Required. The Logflare API key used for every |
| — | Required. Vercel API token for sandbox creation. |
| — | Required. Vercel team ID for sandbox creation. |
| — | Required. Vercel project ID for sandbox creation. |
| off | Hide |
|
| Vercel Sandbox runtime the sandboxes boot from |
|
| Per-call budget for the agent's code |
|
| Override the OpenAPI spec URL the |
|
|
|
|
|
|
Observability
Structured logs via pino to stderr only — stdout is reserved for JSON-RPC. One line per tool invocation/completion (tool name, code length, duration, calledEndpoints count for execute calls) plus a startup line noting read-only mode. Use LOG_FORMAT=pretty locally. Credentials are never logged (see redactToken in src/log.ts).
Testing
pnpm testtest/server.test.ts— the MCP surface via an in-memory client/server pair (tool list, annotations, error shapes,readOnly: truehidingexecute_write). No key.test/stdio.test.ts— end-to-end over the real stdio transport: spawns the built binary as a child process and speaks newline-delimited JSON-RPC over its stdin/stdout, exactly like a real MCP client. Covers--help,--read-onlyover the wire, and that stdout only ever carries JSON-RPC (logs land on stderr). No key. Requirespnpm buildfirst.test/sandbox.test.ts— offline unit tests for the credential/backend/team guard (path normalization + block regex). No key, no sandbox.test/spec.test.ts— offline unit tests for the read-only spec filter (GET-only operations, paths with no GET dropped entirely). No key, no network.test/live.test.ts— end-to-end against real Logflare + Vercel Sandbox: spec search,execute_readGET plus non-GET rejection, trailing-comment tolerance, error/SyntaxErrorsurfacing inside the boundary, the credential/backend/team guard (including encoded bypasses), anexecute_writecreate+delete round-trip, egress denial, and the stdout size cap. Runs only whenLOGFLARE_API_KEYand theVERCEL_*credentials are set.
Available Tools
3 toolsexecute_readRead from the Logflare APIARead-only
Read data from the Logflare Management API by writing JavaScript. Only GET requests are allowed — use execute_write for anything that changes state.
Example: async () => (await api.request({ method: 'GET', path: '/api/sources' })).data
Your code is an async arrow function that returns a value. In scope:
declare const api: { request<T = unknown>(options: { method?: "GET" | "POST" | "PUT" | "PATCH" | "DELETE"; // default GET path: string; // e.g. "/api/sources" — see the search tool query?: Record<string, string | number | boolean | undefined>; body?: unknown; // JSON by default contentType?: string; // overrides the default application/json rawBody?: boolean; // send body as-is (no JSON.stringify) }): Promise<{ status: number; ok: boolean; data: T }>; };
Returns a JSON object — result (or error), calledEndpoints, and stdout/stderr — wrapped in an untrusted-data envelope. Use the search tool first to find paths. Access-token, backend, and team endpoints (/api/access-tokens, /api/backends, /api/teams) are blocked — they mint/reveal access tokens, backend connection config, or the account's master API key.
| Name | Required | Description | Default |
|---|---|---|---|
| code | Yes | Async arrow function using `api`; must return a value. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false. The description adds that only GET requests are allowed, that certain endpoints (access-tokens, backends, teams) are blocked, and describes the return structure (untrusted-data envelope). No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is fairly long but well-structured: a concise purpose sentence, then example, then details. Every sentence adds value, though it could be slightly more trimmed. Still, it avoids redundancy and is organized.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite no output schema, the description explains the return format (result, calledEndpoints, stdout/stderr in untrusted-data envelope), mentions blocked endpoints, and provides sufficient context for a read tool. No major gaps.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Input schema has one parameter 'code' with minimal description. The description adds significant meaning: an example async function, the full type signature of the `api` object, and details on return values. This greatly enriches the agent's understanding of how to write the code.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states 'Read data from the Logflare Management API by writing JavaScript' and specifies 'Only GET requests are allowed', providing a specific verb, resource, and method restriction. It distinguishes from sibling execute_write by noting that execute_write should be used for state changes.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly says 'use execute_write for anything that changes state' and advises 'Use the search tool first to find paths'. This gives clear when-to-use and when-not-to-use guidance, along with alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
execute_writeWrite to the Logflare APIADestructive
Call the Logflare Management API by writing JavaScript, including state-changing requests (POST/PUT/PATCH/DELETE). Use execute_read for plain reads.
Example: async () => (await api.request({ method: 'POST', path: '/api/sources', body: { name: 'my-source' } })).data
Your code is an async arrow function that returns a value. In scope:
declare const api: { request<T = unknown>(options: { method?: "GET" | "POST" | "PUT" | "PATCH" | "DELETE"; // default GET path: string; // e.g. "/api/sources" — see the search tool query?: Record<string, string | number | boolean | undefined>; body?: unknown; // JSON by default contentType?: string; // overrides the default application/json rawBody?: boolean; // send body as-is (no JSON.stringify) }): Promise<{ status: number; ok: boolean; data: T }>; };
Returns a JSON object — result (or error), calledEndpoints, and stdout/stderr — wrapped in an untrusted-data envelope. Use the search tool first to find paths. Access-token, backend, and team endpoints (/api/access-tokens, /api/backends, /api/teams) are blocked — they mint/reveal access tokens, backend connection config, or the account's master API key.
| Name | Required | Description | Default |
|---|---|---|---|
| code | Yes | Async arrow function using `api`; must return a value. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already set destructiveHint=true and readOnlyHint=false. Description adds valuable context: the tool performs mutation (POST/PUT/PATCH/DELETE), explains the return envelope, and lists blocked endpoints. No contradictions.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Well-structured with purpose statement, usage guideline, example, and detailed param explanation. Slightly verbose but each section adds value. Could be tightened by removing redundant details like the full api definition in scope.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter tool with no output schema, the description covers input (code format), API usage, return format, and security restrictions. Addresses all key aspects an agent needs to know.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema describes the 'code' parameter minimally. Description provides a full example, the api object definition, and details on how to structure requests, adding significant meaning beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Clearly states it calls the Logflare Management API with state-changing requests (POST/PUT/PATCH/DELETE). Distinguishes from sibling execute_read by specifying write vs read.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly tells when to use this tool ('for state-changing requests') and when to use the alternative ('Use execute_read for plain reads'). Warns about blocked endpoints (access-tokens, backends, teams) to prevent misuse.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
searchSearch the Logflare API specARead-onlyIdempotent
Search the Logflare Management API's OpenAPI spec by writing JavaScript. Runs in a network-isolated sandbox.
Your code is an async arrow function that returns a value; it receives spec (all $refs resolved inline):
interface OperationInfo { summary?: string; description?: string; deprecated?: boolean; tags?: string[]; parameters?: Array<{ name: string; in: string; required?: boolean; schema?: unknown; description?: string }>; requestBody?: { required?: boolean; content?: Record<string, { schema?: unknown }> }; responses?: Record<string, { description?: string; content?: Record<string, { schema?: unknown }> }>; } declare const spec: { paths: Record<string, Record<string, OperationInfo>> };
Use this to find endpoints and their parameters/request bodies before calling execute_read/execute_write. Output over 100k chars is truncated — return small slices.
Example — find endpoints for sources (grouped by path): async () => Object.entries(spec.paths) .filter(([path]) => path.includes('/sources')) .map(([path, ops]) => ({ path, methods: Object.keys(ops) }))
Example — inspect one operation's request body and parameters: async () => spec.paths['/api/sources']?.post
| Name | Required | Description | Default |
|---|---|---|---|
| code | Yes | Async arrow function receiving `spec`; must return a value. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false. The description adds valuable behavioral context: code runs in a network-isolated sandbox, output over 100k chars is truncated, and the function is async returning a value. No contradictions.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured: concise first line, then detailed interface, usage note, and examples. Every sentence adds value. It is appropriately sized for the complexity of the tool.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers all necessary aspects: sandbox, input specification, output truncation, and usage context. No output schema exists, but the description implicitly informs about return values. Complete for a tool of this complexity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema describes one parameter 'code' with a basic description. The description significantly enhances meaning by providing the full TypeScript interface for `spec`, examples, and execution constraints. This far exceeds the schema coverage (100% baseline).
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: 'Search the Logflare Management API's OpenAPI spec by writing JavaScript.' It specifies the verb (search) and the resource (API spec), effectively distinguishing it from sibling tools like execute_read and execute_write.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly tells when to use the tool: 'Use this to find endpoints and their parameters/request bodies before calling execute_read/execute_write.' It provides a clear context and examples, guiding the agent on appropriate usage.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
3 tool updates
v0.1.0- First observed
execute_read - First observed
execute_write - First observed
search
TDQS
The three tools have clearly distinct purposes: execute_read for read-only GET requests, execute_write for state-changing requests, and search for exploring the API spec. There is no overlap.
The naming pattern is inconsistent: two tools use the 'execute_' prefix (execute_read, execute_write), while the third is simply 'search', breaking the verb_noun pattern.
Three tools is borderline for a server that aims to cover a full API. While the number is not excessive, it feels minimal, and a typical server might include more dedicated tools instead of relying on generic code execution.
The tool set covers all possible operations on the Logflare Management API: read, write, and spec exploration. Users can perform any CRUD action via execute_read and execute_write, making the surface complete.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Discover, inspect and run 63,000+ agent tools from one balance. Pay per call, no subscriptions.
1Sandbox workspace tools: search, file read, DB queries, integrations. Returns synthetic data.
- SuperlogOAuthsh.superlog
Open-source agent that observes and fixes your application. Query logs, traces, metrics, incidents.
Gateway between LLM agents and world data through eight tools and a bundled endpoint catalog.
Related MCP Servers
- AlicenseAqualityFmaintenanceEnables AI models to dynamically create and execute their own custom tools through a meta-function architecture, supporting JavaScript, Python, and Shell runtimes with sandboxed security and human approval flows.510MIT
- FlicenseNot gradedqualityNot gradedmaintenanceEnables efficient code execution in a secure sandbox with 98.7% token reduction by allowing agents to write JavaScript/TypeScript code to interact with tools, process data, and maintain state instead of loading all tool definitions into context.-
- AlicenseNot gradedqualityFmaintenanceEnables interaction with the complete Cloudflare API using a codemode pattern that allows agents to search the OpenAPI spec and execute API calls via JavaScript. This approach minimizes token usage by keeping the massive specification on the server and only returning relevant results.11128Apache 2.0
- FlicenseCqualityDmaintenanceEnables on-demand generation of TypeScript tools using an LLM with human-in-the-loop approval and safe sandboxed execution. It allows users to create and persist custom functionality through natural language requests.81-
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/Rodriguespn/logflare-mcp-code-mode'
If you have feedback or need assistance with the MCP directory API, please join our Discord server