Skip to main content

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)

Source distribution for tungsten-mcp 0.1.1
File Size Uploaded
tungsten_mcp-0.1.1.tar.gz 30.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for tungsten-mcp 0.1.1
File Interpreter ABI Platform
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

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page