tungsten-mcp
Let AI assistants like Claude work with your Tungsten panel, through the Model Context Protocol (MCP).
Ask things like "Show the 10 newest orders", "How many products are out of stock?" or "Mark order 1042 as shipped", and the AI does it with your panel's data.
What you get
- An MCP server inside your panel, at
/admin/mcp. - Tools for every resource:
list_resources,describe_resource,list_records(search, filters, sort, pages),get_record, and with a token that allows changes,create_record,update_record,delete_record. - Login with OAuth: in Claude, add the server URL as a custom connector, press Connect, log in to your panel and press Allow. No token to copy.
- An AI access (MCP) screen to see and revoke connected apps and tokens, with a How to connect guide for Claude, Claude Code, Claude Desktop and other apps.
It is safe by default:
- Each token acts as the user who made it. Their roles, policies and tenancy apply, as in the panel.
- Writes go through the resource's form: the same validation, defaults and hooks, and they show in the activity log.
- Tokens are read-only unless you switch on Allow changes. Only a hash of each token is stored.
- Password hashes, tokens, secrets and API keys are never sent.
Install
pip install tungsten-mcp
from tungsten_mcp import McpPlugin
panel = Panel(..., app_url="https://admin.example.com")
panel.plugin(McpPlugin())
panel.create_tables(engine)
Then open AI access (MCP) in the panel and press How to connect. Needs tungsten-admin 0.1.4 or newer.
Connect
Claude (web, desktop, phone): Settings, Connectors, Add custom connector, paste https://admin.example.com/admin/mcp, then Connect. Log in to the panel and press Allow.
Claude Code with login: claude mcp add --transport http tungsten https://admin.example.com/admin/mcp, then /mcp in Claude Code.
Apps without MCP login use a token: press New token on the AI access (MCP) screen.
Claude Code with a token
claude mcp add --transport http tungsten https://admin.example.com/admin/mcp --header "Authorization: Bearer YOUR_TOKEN"
Claude Desktop (Settings, Developer, Edit Config; needs Node.js)
{
"mcpServers": {
"tungsten": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://admin.example.com/admin/mcp", "--header", "Authorization:${AUTH_HEADER}"],
"env": {"AUTH_HEADER": "Bearer YOUR_TOKEN"}
}
}
}
Cursor, VS Code and others: a Streamable HTTP server with the URL and an Authorization: Bearer YOUR_TOKEN header.
Options
McpPlugin(
path="/mcp", # where the server answers, under the panel
read_only=False, # True: no create, update or delete for any token
resources=None, # only these resources (slugs or classes)
exclude=["users"], # leave these out
hidden_fields=["customers.phone", "notes"], # never send these columns
max_limit=100, # most records per list_records call
name="Shop admin", # the name the AI app shows
oauth=True, # apps can connect by logging in (needs a panel with login)
token_minutes=60, # how long an OAuth access token works
)
Your own tools
Beside the record tools, a panel can add tools of its own: subclass Tools, name them in READ or
WRITE, add them to definitions(), and pass the class as tools=.
from tungsten_mcp import McpPlugin, Tools
class ShopTools(Tools):
READ = Tools.READ + ("shop_hours",)
def definitions(self, ctx, can_write):
return super().definitions(ctx, can_write) + [
{"name": "shop_hours", "description": "When the shop is open.",
"inputSchema": {"type": "object", "properties": {}}, "annotations": {"readOnlyHint": True}},
]
def shop_hours(self, ctx):
return {"open": "9 to 5"}
panel.plugin(McpPlugin(tools=ShopTools))
A tool named in WRITE needs a token with Allow changes. Raise ToolError("...") for a problem
the AI can fix; the message goes back as the tool's answer.
A panel under a sub-path
Apps also look for the metadata at the site root (/.well-known/oauth-protected-resource/...). When the web
server gives your app only the panel's path — a cPanel Python app with base URI /admin, say — those root
addresses answer from the site next to it, and an app that builds them itself cannot log in ("couldn't
register"). Send them on in the site's .htaccess:
RewriteEngine On
RewriteRule ^\.well-known/oauth-protected-resource/admin/mcp$ /admin/.well-known/oauth-protected-resource/mcp [R=302,L]
RewriteRule ^\.well-known/oauth-authorization-server/admin$ /admin/.well-known/oauth-authorization-server [R=302,L]
RewriteRule ^\.well-known/openid-configuration/admin$ /admin/.well-known/openid-configuration [R=302,L]
RewriteRule ^\.well-known/oauth-protected-resource$ /admin/.well-known/oauth-protected-resource [L]
RewriteRule ^\.well-known/oauth-authorization-server$ /admin/.well-known/oauth-authorization-server [L]
RewriteRule ^\.well-known/openid-configuration$ /admin/.well-known/openid-configuration [L]
(On LiteSpeed an internal rewrite of the addresses that carry the panel path came back 404 from the app, so those three are sent on with a redirect, which metadata readers follow.)
With multi-tenancy, the token's user works in their first tenant. Send an X-Tenant: <id> header to pick another.
Metadata
Release files for tungsten-mcp 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| tungsten_mcp-0.1.1.tar.gz | 30.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| tungsten_mcp-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 59.2 kB
Release files / tungsten_mcp-0.1.1.tar.gz
| Download URL | tungsten_mcp-0.1.1.tar.gz |
|---|---|
| Size | 30.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a99189360ff06a94a898878fe31b1dfd332c303033bf0386d82f37a5c5741cea
|
|
BLAKE2b-256 checksum How to use checksums |
6725bb3c131d570953ef943d4cae58e356d5e0ed3dc157530462a402ae9c9e75
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Release files / tungsten_mcp-0.1.1-py3-none-any.whl
| Download URL | tungsten_mcp-0.1.1-py3-none-any.whl |
|---|---|
| Size | 28.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
bc8a393ce2ab3a4dee5a379e63dfddd287ab780d0e0588d7d9369c3eaa0c3598
|
|
BLAKE2b-256 checksum How to use checksums |
4f7bc60e0207be35b6fa1e4b8f1dd1d4c8c98c307c3b31a343e6202162c48906
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|