cloudflare / cloudflare/agents

Feature Request: Adding allowlist/blocklist to openApiMcpServer in codemode MCP

Open
#1,268 1 comment 0 reactions 1 assignee Claimed by @mattzcarey View on GitHub
enhancement mcp
Dominant language
TypeScript
Stars
5.6k
Forks
711
Avg merge
1d 20h
Merged PRs (30d)
53

Description

I'm experimenting with building a codemode MCP server and have a few tools I was handrolling OpenAPI -> MCP for. I was going to try the `openApiMcpServer` as a plug-and-play solution for quickly experimenting with code mode, but for a variety of reasons we want to expose only a subset of routes to the agent. We can obviously just prune the json itself before running, which is fine for stable interfaces, but becomes troublesome for interfaces that somewhat regularly change.

I discussed this with Claude, who believed the change wouldn't be so complex. I've shared the relevant snippets below (I'm not well versed enough in TypeScript to fully understand what is being suggested).

Claude:

---

Very small change. The filtering needs to happen in two places:

1. **Spec pruning** (line 380) — strip paths/operations from the spec before `resolveRefs` so the `search` tool never sees them
2. **Request guard** (line 478) — reject paths at runtime in the `execute` tool so the agent can't call a blocked route even if it guesses the path

The interface I'd propose is a predicate function — more flexible than allowlist/blocklist arrays and idiomatic for this codebase:

```ts
export interface OpenApiMcpServerOptions {
spec: Record;
executor: Executor;
request: (options: RequestOptions) => Promise;
/**
* Filter which operations are exposed. Return false to exclude.
* Applied before $ref resolution — excluded operations never enter agent context.
* Also enforced at request time as a safety net.
*/
filterOperation?: (method: string, path: string, operation: { operationId?: string; tags?: string[] }) => boolean;
// ... existing fields
}
```

The implementation is ~15 lines — prune `spec.paths` before resolving, and wrap `requestFn` to check the path/method at runtime. Something like:

```ts
// Before resolveRefs:
if (options.filterOperation) {
const pruned = structuredClone(options.spec);
for (const [path, pathItem] of Object.entries(pruned.paths ?? {})) {
for (const method of ["get","post","put","patch","delete"]) {
const op = pathItem[method];
if (op && !options.filterOperation(method, path, op)) delete pathItem[method];
}
if (!Object.keys(pathItem).some(k => ["get","post","put","patch","delete"].includes(k))) {
delete pruned.paths[path];
}
}
// use pruned instead of options.spec
}

// In execute tool, wrap requestFn:
const guardedRequest = options.filterOperation
? (opts: RequestOptions) => {
// find matching path in spec, check filter — reject if blocked
}
: requestFn;
```

---

Would this be something worth adding? Thanks in advance.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.