notion-custom-mcp
NotionCustomMCP - Agent Instructions
This document provides comprehensive guidance for AI agents on how to use the NotionCustomMCP (Model Context Protocol) server effectively.
Overview
The mssql-readonly MCP server provides read-only access to:
-
MSSQL Databases:
- StonePro: Business/ERP database with customer, job, and order data
- NotionArchive: Archived Notion data including jobs, pieces, and archives
-
Notion API (read-only operations):
- Query Notion databases, pages, and blocks
- Search across the workspace
- List users and databases
All operations are READ-ONLY. No modifications to data are allowed.
Available Databases
| Database | Description | Key Data |
|---|---|---|
stonepro |
StonePro Business/ERP database | Customers, Jobs, Orders, Inventory, Production data |
notionarchive |
NotionArchive database | Archived Notion data: Jobs, Pieces, Archives, Slabs, Cutouts |
Tool Reference
1. Database Discovery Tools
list_databases
Lists available databases that can be queried.
Parameters: None
Use when: You need to see which databases are available for querying.
Example output:
{
"databases": [
{
"name": "stonepro",
"description": "StonePro Business/ERP database",
"contains": "Customers, Jobs, Orders, Inventory, Production data"
},
{
"name": "notionarchive",
"description": "NotionArchive database",
"contains": "Archived Notion data: Jobs, Pieces, Archives, Slabs, Cutouts"
}
]
}
list_tables
List all tables in the specified database.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
database |
string | ✅ | stonepro or notionarchive |
Use when: You need to explore what tables exist in a database before querying.
Example output:
{
"database": "notionarchive",
"table_count": 15,
"view_count": 3,
"tables": ["dbo.Jobs", "dbo.Pieces", "dbo.Archives"],
"views": ["dbo.vw_ActiveJobs"]
}
describe_table
Get detailed information about a table's structure.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
database |
string | ✅ | stonepro or notionarchive |
table_name |
string | ✅ | Table name (e.g., dbo.Jobs or just Jobs) |
Use when: You need to understand column types, primary keys, and row counts before writing queries.
Example output:
{
"database": "notionarchive",
"table": "dbo.Jobs",
"row_count": 1523,
"column_count": 12,
"columns": [
{"name": "JobId", "type": "int", "nullable": false},
{"name": "JobName", "type": "nvarchar(255)", "nullable": true}
],
"primary_keys": ["JobId"]
}
search_tables
Search for tables matching a name pattern.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
database |
string | ✅ | stonepro or notionarchive |
pattern |
string | ✅ | Search pattern (e.g., Job finds Jobs, JobDetails) |
Use when: You don't know the exact table name but know part of it.
2. Query Execution Tools
execute_query
Execute a read-only SELECT query against the database.
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
database |
string | ✅ | - | stonepro or notionarchive |
query |
string | ✅ | - | SQL SELECT query to execute |
max_rows |
integer | ❌ | 100 | Maximum rows to return (max 1000) |
Use when: You need to retrieve specific data from the database.
Security notes:
- ⚠️ Only SELECT queries are allowed
- INSERT, UPDATE, DELETE, DROP, CREATE, ALTER are blocked
- EXEC, stored procedures, and system commands are blocked
- Multiple statements (using
;) are blocked
Example:
SELECT TOP 10 JobId, JobName, Status
FROM dbo.Jobs
WHERE Status = 'Active'
ORDER BY CreatedDate DESC
get_sample_data
Get sample rows from a table.
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
database |
string | ✅ | - | stonepro or notionarchive |
table_name |
string | ✅ | - | Table name |
limit |
integer | ❌ | 10 | Number of rows (max 100) |
Use when: You want to quickly see what data looks like in a table without writing a query.
test_connections
Test connections to both databases.
Parameters: None
Use when: You need to verify database connectivity before running queries.
3. Notion API Tools
notion_search
Search across all Notion pages and databases in the workspace.
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
query |
string | ❌ | "" |
Search query (empty returns recent items) |
filter_type |
string | ❌ | - | Filter by page or database |
page_size |
integer | ❌ | 20 | Results to return (max 100) |
Use when: You need to find pages or databases by name or content.
notion_list_databases
List all Notion databases accessible to the integration.
Parameters: None
Use when: You need to see what Notion databases are available for querying.
Example output:
{
"database_count": 5,
"databases": [
{
"id": "abc123...",
"title": "Jobs Database",
"url": "https://notion.so/...",
"property_count": 15,
"property_names": ["Name", "Status", "Customer", "Due Date"]
}
]
}
notion_get_database_schema
Get the schema (properties) of a Notion database.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
database_id |
string | ✅ | The Notion database ID |
Use when: You need to understand what properties a database has before querying it.
Returns: Property names, types, select/multi-select options, relation targets, formula expressions, etc.
notion_query_database
Query a Notion database with optional filtering and sorting.
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
database_id |
string | ✅ | - | The Notion database ID |
filter_json |
string | ❌ | - | JSON string of Notion filter object |
sorts_json |
string | ❌ | - | JSON string of Notion sorts array |
page_size |
integer | ❌ | 50 | Results to return (max 100) |
Use when: You need to retrieve filtered data from a Notion database.
Example filter_json:
{"property": "Status", "select": {"equals": "Done"}}
Example sorts_json:
[{"property": "Created", "direction": "descending"}]
notion_get_page
Get a Notion page by ID.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
page_id |
string | ✅ | The Notion page ID |
Use when: You need to retrieve all properties of a specific page.
notion_get_page_content
Get the content blocks of a Notion page.
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
page_id |
string | ✅ | - | The Notion page ID |
max_blocks |
integer | ❌ | 100 | Maximum blocks to return |
Use when: You need to read the actual content (paragraphs, headings, lists, etc.) of a page.
notion_list_users
List all users in the Notion workspace.
Parameters: None
Use when: You need to see who has access to the workspace or resolve user IDs to names.
Common Workflows
Exploring a Database
-
See available databases:
list_databases -
List tables in a database:
list_tables(database: "notionarchive") -
Find tables by name:
search_tables(database: "notionarchive", pattern: "Job") -
Understand table structure:
describe_table(database: "notionarchive", table_name: "dbo.Jobs") -
Preview data:
get_sample_data(database: "notionarchive", table_name: "dbo.Jobs", limit: 5)
Querying Specific Data
-
Write a SELECT query:
execute_query( database: "notionarchive", query: "SELECT JobId, JobName FROM dbo.Jobs WHERE Status = 'Active'", max_rows: 50 ) -
Join multiple tables:
execute_query( database: "notionarchive", query: "SELECT j.JobName, p.PieceName FROM dbo.Jobs j INNER JOIN dbo.Pieces p ON j.JobId = p.JobId", max_rows: 100 )
Working with Notion Data
-
Find a Notion database:
notion_list_databases -
Check database schema:
notion_get_database_schema(database_id: "abc123...") -
Query with filters:
notion_query_database( database_id: "abc123...", filter_json: '{"property": "Status", "select": {"equals": "Active"}}', sorts_json: '[{"property": "Name", "direction": "ascending"}]' ) -
Get page details:
notion_get_page(page_id: "xyz789...")
Comparing MSSQL and Notion Data
-
Get archived data from MSSQL:
execute_query( database: "notionarchive", query: "SELECT NotionPageId, JobName FROM dbo.Jobs WHERE IsArchived = 1" ) -
Get live data from Notion:
notion_query_database(database_id: "...") -
Compare the results to find discrepancies
Error Handling
Query Validation Errors
If you see "Only SELECT queries are allowed" or similar:
- ✅ Make sure your query starts with
SELECTorWITH - ✅ Remove any semicolons or multiple statements
- ✅ Don't use INSERT, UPDATE, DELETE, EXEC, or stored procedures
Database Connection Errors
If queries fail with connection errors:
-
Test connectivity:
test_connections -
Check which database is failing and report to the user
Notion API Errors
Common Notion API errors:
- "object not found": The page/database ID is invalid or not shared with the integration
- "unauthorized": The integration doesn't have access to that resource
- "rate_limited": Too many requests; wait and retry
Configuration
The MCP server uses environment variables from .env:
# MSSQL - StonePro
STONEPRO_SERVER=DS-DB01\\SQLSERVER202201
STONEPRO_DATABASE=StonePro
STONEPRO_USERNAME=SA
STONEPRO_PASSWORD=your_password
# MSSQL - NotionArchive
NOTIONARCHIVE_SERVER=DS-DB01\\SQLSERVER202201
NOTIONARCHIVE_DATABASE=NotionArchive
NOTIONARCHIVE_USERNAME=SA
NOTIONARCHIVE_PASSWORD=your_password
# Notion API
NOTION_API_KEY=ntn_your_api_key
NOTION_VERIFY_SSL=true
Security Best Practices
-
All queries are validated - The server blocks dangerous SQL patterns before execution
-
Read-only by design - No way to modify data through this MCP server
-
Sanitized identifiers - Table and column names are sanitized to prevent injection
-
Notion is read-only - Only GET operations are available; no page creation/modification
-
Credentials are masked - Passwords are never exposed in error messages or logs
Quick Reference Card
| Task | Tool | Key Parameters |
|---|---|---|
| List databases | list_databases |
- |
| List tables | list_tables |
database |
| Search tables | search_tables |
database, pattern |
| Describe table | describe_table |
database, table_name |
| Run SQL query | execute_query |
database, query, max_rows |
| Get sample data | get_sample_data |
database, table_name, limit |
| Test connections | test_connections |
- |
| Search Notion | notion_search |
query, filter_type |
| List Notion DBs | notion_list_databases |
- |
| DB schema | notion_get_database_schema |
database_id |
| Query Notion DB | notion_query_database |
database_id, filter_json, sorts_json |
| Get page | notion_get_page |
page_id |
| Get page content | notion_get_page_content |
page_id, max_blocks |
| List users | notion_list_users |
- |
VS Code Integration
Add to your .vscode/mcp.json or user mcp.json:
{
"servers": {
"mssql-readonly": {
"type": "stdio",
"command": "uv",
"args": [
"--directory",
"C:\\Users\\<username>\\Custom_MCP\\NotionCustomMCP",
"--native-tls",
"run",
"python",
"-m",
"src.server"
]
}
}
}
Project Structure
NotionCustomMCP/
├── src/
│ ├── __init__.py
│ ├── server.py # Main MCP server with all tools
│ ├── config.py # Configuration management (pydantic-settings)
│ ├── database/
│ │ ├── connection.py # MSSQL connection manager
│ │ └── queries.py # Query validation and execution
│ └── notion/
│ └── client.py # Notion API client wrapper
├── .env # Environment variables (DO NOT COMMIT)
├── .env.example # Template for environment setup
└── pyproject.toml # Project dependencies
More from ds-codi/project-memory-mcp
pyside6-mvc
Use this skill when building Python desktop applications using PySide6 with strict MVC architecture where all UI is defined by .ui files. Covers architecture patterns, controller/model/view separation, signal handling, and .ui file workflows.
95pyside6-qml-views
Use this skill when creating QML view files, designing QML component hierarchies, building layouts, styling QML controls, creating reusable QML components, implementing QML navigation / page switching, or working with QML resources. Covers QML file structure, component patterns, Material/Controls styling, resource management, and common QML idioms for desktop applications.
49pyside6-qml-architecture
Use this skill when creating a new PySide6 + QML desktop application with MVC architecture, setting up project structure, implementing the application bootstrap / DI container, or understanding how the MVC layers connect. Covers project scaffolding, entry points, singleton application class, service locator, signal registry, and lifecycle management.
47mvc-architecture
Use this skill when implementing Model-View-Controller architecture. Covers core MVC principles, layer separation, dependency injection, event-driven communication, and patterns for controllers, models, and views.
40pyside6-qml-models-services
Use this skill when creating domain models with Qt signal support, implementing the repository pattern for data persistence, building service classes for external interactions, designing the central signal registry, or working with application state management. Covers BaseModel, model serialization, database repositories, service patterns, signal definitions, and the ApplicationState singleton.
34pyside6-qml-bridge
Use this skill when exposing Python objects to QML, creating bridge classes, defining Qt properties with NOTIFY signals, implementing invokable methods / slots, or connecting QML user actions to Python controllers. Covers the QObject bridge pattern, property decorators, type conversions, context properties, and QML type registration.
32