Skip to main content
Glama

API-post-database-query

Query Notion databases efficiently using filters, sorting, and pagination to retrieve specific page properties and structured data from a given database identifier.

Instructions

Notion | Query a database

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
archivedNo
database_idYesIdentifier for a Notion database.
filterNoWhen supplied, limits which pages are returned based on the [filter conditions](ref:post-database-query-filter).
filter_propertiesNoA list of page property value IDs associated with the database. Use this param to limit the response to a specific page property value or values for pages that meet the `filter` criteria.
in_trashNo
page_sizeNoThe number of items from the full list desired in the response. Maximum: 100
sortsNoWhen supplied, orders the results based on the provided [sort criteria](ref:post-database-query-sort).
start_cursorNoWhen supplied, returns a page of results starting after the cursor provided. If not supplied, this endpoint will return the first page of results.

Implementation Reference

  • Handler for calling any MCP tool, including 'API-post-database-query'. Parses tool name to find matching OpenAPI operation, executes via HTTP, formats response.
    // Handle tool calling this.server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: params } = request.params // Find the operation in OpenAPI spec const operation = this.findOperation(name) if (!operation) { throw new Error(`Method ${name} not found`) } try { // Execute the operation const response = await this.httpClient.executeOperation(operation, params) // Convert response to MCP format return { content: [ { type: 'text', // currently this is the only type that seems to be used by mcp server text: JSON.stringify(response.data), // TODO: pass through the http status code text? }, ], } } catch (error) { console.error('Error in tool call', error) if (error instanceof HttpClientError) { console.error('HttpClientError encountered, returning structured error', error) const data = error.data?.response?.data ?? error.data ?? {} return { content: [ { type: 'text', text: JSON.stringify({ status: 'error', // TODO: get this from http status code? ...(typeof data === 'object' ? data : { data: data }), }), }, ], } } throw error } })
  • Registers the listTools handler which dynamically generates the list of tools, constructing names like 'API-post-database-query' from 'API' + operationId.
    this.server.setRequestHandler(ListToolsRequestSchema, async () => { const tools: Tool[] = [] // Add methods as separate tools to match the MCP format Object.entries(this.tools).forEach(([toolName, def]) => { def.methods.forEach(method => { const toolNameWithMethod = `${toolName}-${method.name}`; const truncatedToolName = this.truncateToolName(toolNameWithMethod); tools.push({ name: truncatedToolName, description: method.description, inputSchema: method.inputSchema as Tool['inputSchema'], }) }) }) return { tools } })
  • Generates inputSchema and returnSchema for each OpenAPI operation (e.g., operationId 'post-database-query'), used for the 'API-post-database-query' tool schema.
    private convertOperationToMCPMethod(operation: OpenAPIV3.OperationObject, method: string, path: string): NewToolMethod | null { if (!operation.operationId) { console.warn(`Operation without operationId at ${method} ${path}`) return null } const methodName = operation.operationId const inputSchema: IJsonSchema & { type: 'object' } = { $defs: this.convertComponentsToJsonSchema(), type: 'object', properties: {}, required: [], } // Handle parameters (path, query, header, cookie) if (operation.parameters) { for (const param of operation.parameters) { const paramObj = this.resolveParameter(param) if (paramObj && paramObj.schema) { const schema = this.convertOpenApiSchemaToJsonSchema(paramObj.schema, new Set(), false) // Merge parameter-level description if available if (paramObj.description) { schema.description = paramObj.description } inputSchema.properties![paramObj.name] = schema if (paramObj.required) { inputSchema.required!.push(paramObj.name) } } } } // Handle requestBody if (operation.requestBody) { const bodyObj = this.resolveRequestBody(operation.requestBody) if (bodyObj?.content) { // Handle multipart/form-data for file uploads // We convert the multipart/form-data schema to a JSON schema and we require // that the user passes in a string for each file that points to the local file if (bodyObj.content['multipart/form-data']?.schema) { const formSchema = this.convertOpenApiSchemaToJsonSchema(bodyObj.content['multipart/form-data'].schema, new Set(), false) if (formSchema.type === 'object' && formSchema.properties) { for (const [name, propSchema] of Object.entries(formSchema.properties)) { inputSchema.properties![name] = propSchema } if (formSchema.required) { inputSchema.required!.push(...formSchema.required!) } } } // Handle application/json else if (bodyObj.content['application/json']?.schema) { const bodySchema = this.convertOpenApiSchemaToJsonSchema(bodyObj.content['application/json'].schema, new Set(), false) // Merge body schema into the inputSchema's properties if (bodySchema.type === 'object' && bodySchema.properties) { for (const [name, propSchema] of Object.entries(bodySchema.properties)) { inputSchema.properties![name] = propSchema } if (bodySchema.required) { inputSchema.required!.push(...bodySchema.required!) } } else { // If the request body is not an object, just put it under "body" inputSchema.properties!['body'] = bodySchema inputSchema.required!.push('body') } } } } // Build description including error responses let description = operation.summary || operation.description || '' if (operation.responses) { const errorResponses = Object.entries(operation.responses) .filter(([code]) => code.startsWith('4') || code.startsWith('5')) .map(([code, response]) => { const responseObj = this.resolveResponse(response) let errorDesc = responseObj?.description || '' return `${code}: ${errorDesc}` }) if (errorResponses.length > 0) { description += '\nError Responses:\n' + errorResponses.join('\n') } } // Extract return type (response schema) const returnSchema = this.extractResponseType(operation.responses) // Generate Zod schema from input schema try { // const zodSchemaStr = jsonSchemaToZod(inputSchema, { module: "cjs" }) // console.log(zodSchemaStr) // // Execute the function with the zod instance // const zodSchema = eval(zodSchemaStr) as z.ZodType return { name: methodName, description, inputSchema, ...(returnSchema ? { returnSchema } : {}), } } catch (error) { console.warn(`Failed to generate Zod schema for ${methodName}:`, error) // Fallback to a basic object schema return { name: methodName, description, inputSchema, ...(returnSchema ? { returnSchema } : {}), } } }
  • Adds the MCP method for each OpenAPI operation to the 'API' tool group, sets lookup key to 'API-{operationId}' for 'API-post-database-query'.
    const mcpMethod = this.convertOperationToMCPMethod(operation, method, path) if (mcpMethod) { const uniqueName = this.ensureUniqueName(mcpMethod.name) mcpMethod.name = uniqueName mcpMethod.description = this.getDescription(operation.summary || operation.description || '') tools[apiName]!.methods.push(mcpMethod) openApiLookup[apiName + '-' + uniqueName] = { ...operation, method, path } zip[apiName + '-' + uniqueName] = { openApi: { ...operation, method, path }, mcp: mcpMethod } }
  • Executes the OpenAPI operation via openapi-client-axios, handling parameters, file uploads, and returns structured response or error.
    async executeOperation<T = any>( operation: OpenAPIV3.OperationObject & { method: string; path: string }, params: Record<string, any> = {}, ): Promise<HttpClientResponse<T>> { const api = await this.api const operationId = operation.operationId if (!operationId) { throw new Error('Operation ID is required') } // Handle file uploads if present const formData = await this.prepareFileUpload(operation, params) // Separate parameters based on their location const urlParameters: Record<string, any> = {} const bodyParams: Record<string, any> = formData || { ...params } // Extract path and query parameters based on operation definition if (operation.parameters) { for (const param of operation.parameters) { if ('name' in param && param.name && param.in) { if (param.in === 'path' || param.in === 'query') { if (params[param.name] !== undefined) { urlParameters[param.name] = params[param.name] if (!formData) { delete bodyParams[param.name] } } } } } } // Add all parameters as url parameters if there is no requestBody defined if (!operation.requestBody && !formData) { for (const key in bodyParams) { if (bodyParams[key] !== undefined) { urlParameters[key] = bodyParams[key] delete bodyParams[key] } } } const operationFn = (api as any)[operationId] if (!operationFn) { throw new Error(`Operation ${operationId} not found`) } try { // If we have form data, we need to set the correct headers const hasBody = Object.keys(bodyParams).length > 0 const headers = formData ? formData.getHeaders() : { ...(hasBody ? { 'Content-Type': 'application/json' } : { 'Content-Type': null }) } const requestConfig = { headers: { ...headers, }, } // first argument is url parameters, second is body parameters const response = await operationFn(urlParameters, hasBody ? bodyParams : undefined, requestConfig) // Convert axios headers to Headers object const responseHeaders = new Headers() Object.entries(response.headers).forEach(([key, value]) => { if (value) responseHeaders.append(key, value.toString()) }) return { data: response.data, status: response.status, headers: responseHeaders, } } catch (error: any) { if (error.response) { console.error('Error in http client', error) const headers = new Headers() Object.entries(error.response.headers).forEach(([key, value]) => { if (value) headers.append(key, value.toString()) }) throw new HttpClientError(error.response.statusText || 'Request failed', error.response.status, error.response.data, headers) } throw error } }

Latest Blog Posts

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/punkpeye/notion-mcp-server-3'

If you have feedback or need assistance with the MCP directory API, please join our Discord server