Skip to main content
Glama

SignNow MCP Server

Official
signnow.py33.1 kB
from typing import Annotated, Any, Literal from fastmcp import Context from fastmcp.server.dependencies import get_http_headers from pydantic import Field from signnow_client import SignNowAPIClient from ..token_provider import TokenProvider from .create_from_template import _create_from_template from .document import _get_document, _update_document_fields from .document_download_link import _get_document_download_link from .embedded_editor import ( _create_embedded_editor, _create_embedded_editor_from_template, ) from .embedded_invite import ( _create_embedded_invite, _create_embedded_invite_from_template, ) from .embedded_sending import ( _create_embedded_sending, _create_embedded_sending_from_template, ) from .invite_status import _get_invite_status from .list_documents import _list_document_groups from .list_templates import _list_all_templates from .models import ( CreateEmbeddedEditorFromTemplateResponse, CreateEmbeddedEditorResponse, CreateEmbeddedInviteFromTemplateResponse, CreateEmbeddedInviteResponse, CreateEmbeddedSendingFromTemplateResponse, CreateEmbeddedSendingResponse, CreateFromTemplateResponse, DocumentDownloadLinkResponse, DocumentGroup, EmbeddedInviteOrder, InviteOrder, InviteStatus, SendInviteFromTemplateResponse, SendInviteResponse, SimplifiedDocumentGroupsResponse, TemplateSummaryList, UpdateDocumentFields, UpdateDocumentFieldsResponse, ) from .send_invite import _send_invite, _send_invite_from_template def bind(mcp: Any, cfg: Any) -> None: # Initialize token provider token_provider = TokenProvider() @mcp.tool(name="list_all_templates", description="Get simplified list of all templates and template groups with basic information", tags=["template", "template_group", "list"]) async def list_all_templates(ctx: Context) -> TemplateSummaryList: """Get all templates and template groups from all folders. This tool combines both individual templates and template groups into a single response. Individual templates are marked with entity_type='template' and template groups with entity_type='template_group'. Note: Individual templates are deprecated. For new implementations, prefer using template groups which are more feature-rich and actively maintained. """ headers = get_http_headers() token = token_provider.get_access_token(headers) if not token: raise ValueError("No access token available") # Initialize client and use the imported function from list_templates module client = SignNowAPIClient(token_provider.signnow_config) return await _list_all_templates(ctx, token, client) @mcp.tool(name="list_document_groups", description="Get simplified list of document groups with basic information", tags=["document_group", "list"]) def list_document_groups( ctx: Context, limit: Annotated[int, Field(ge=1, le=50, description="Maximum number of document groups to return (default: 50, max: 50)")] = 50, offset: Annotated[int, Field(ge=0, description="Number of document groups to skip for pagination (default: 0)")] = 0, ) -> SimplifiedDocumentGroupsResponse: """Provide simplified list of document groups with basic fields. Args: limit: Maximum number of document groups to return (default: 50, max: 50) offset: Number of document groups to skip for pagination (default: 0) """ headers = get_http_headers() token = token_provider.get_access_token(headers) if not token: raise ValueError("No access token available") # Use the imported function from list_documents module return _list_document_groups(token, token_provider.signnow_config, limit, offset) @mcp.tool(name="send_invite", description="Send invite to sign a document or document group", tags=["send_invite", "document", "document_group", "sign", "workflow"]) def send_invite( ctx: Context, entity_id: Annotated[str, Field(description="ID of the document or document group")], entity_type: Annotated[ Literal["document", "document_group"] | None, Field(description="Type of entity: 'document' or 'document_group' (optional). If you're passing it, make sure you know what type you have. If it's not found, try using a different type."), ] = None, orders: Annotated[list[InviteOrder] | None, Field(description="List of orders with recipients")] = None, ) -> SendInviteResponse: """Send invite to sign a document or document group. Args: entity_id: ID of the document or document group entity_type: Type of entity: 'document' or 'document_group' (optional). If you're passing it, make sure you know what type you have. If it's not found, try using a different type. orders: List of orders with recipients Returns: SendInviteResponse with invite ID and entity type """ headers = get_http_headers() token = token_provider.get_access_token(headers) if not token: raise ValueError("No access token available") # Initialize client and use the imported function from send_invite module client = SignNowAPIClient(token_provider.signnow_config) return _send_invite(entity_id, entity_type, orders or [], token, client) @mcp.tool( name="create_embedded_invite", description="Create embedded invite for signing a document or document group", tags=["send_invite", "document", "document_group", "sign", "embedded", "workflow"], ) def create_embedded_invite( ctx: Context, entity_id: Annotated[str, Field(description="ID of the document or document group")], entity_type: Annotated[ Literal["document", "document_group"] | None, Field(description="Type of entity: 'document' or 'document_group' (optional). If you're passing it, make sure you know what type you have. If it's not found, try using a different type."), ] = None, orders: Annotated[list[EmbeddedInviteOrder] | None, Field(description="List of orders with recipients")] = None, ) -> CreateEmbeddedInviteResponse: """Create embedded invite for signing a document or document group. This tool is ONLY for documents and document groups. If you have template or template group, you have to convert it to document or document group first, using create_from_template tool Args: entity_id: ID of the document or document group entity_type: Type of entity: 'document' or 'document_group' (optional). If you're passing it, make sure you know what type you have. If it's not found, try using a different type. orders: List of orders with recipients Returns: CreateEmbeddedInviteResponse with invite ID and entity type """ headers = get_http_headers() token = token_provider.get_access_token(headers) if not token: raise ValueError("No access token available") # Initialize client and use the imported function from embedded_invite module client = SignNowAPIClient(token_provider.signnow_config) return _create_embedded_invite(entity_id, entity_type, orders or [], token, client) @mcp.tool( name="create_embedded_sending", description="Create embedded sending for managing, editing, or sending invites for a document or document group", tags=["edit", "document", "document_group", "send_invite", "embedded", "workflow"], ) def create_embedded_sending( ctx: Context, entity_id: Annotated[str, Field(description="ID of the document or document group")], entity_type: Annotated[ Literal["document", "document_group"] | None, Field(description="Type of entity: 'document' or 'document_group' (optional). If you're passing it, make sure you know what type you have. If it's not found, try using a different type."), ] = None, redirect_uri: Annotated[str | None, Field(description="Optional redirect URI after completion")] = None, redirect_target: Annotated[str | None, Field(description="Optional redirect target: 'self' (default), 'blank'")] = None, link_expiration: Annotated[int | None, Field(ge=14, le=45, description="Optional link expiration in days (14-45)")] = None, type: Annotated[Literal["manage", "edit", "send-invite"] | None, Field(description="Type of sending step: 'manage', 'edit', or 'send-invite'")] = "manage", ) -> CreateEmbeddedSendingResponse: """Create embedded sending for managing, editing, or sending invites for a document or document group. This tool is ONLY for documents and document groups. If you have template or template group, you have to convert it to document or document group first, using create_from_template tool Args: entity_id: ID of the document or document group entity_type: Type of entity: 'document' or 'document_group' (optional). If you're passing it, make sure you know what type you have. If it's not found, try using a different type. redirect_uri: Optional redirect URI for the sending link redirect_target: Optional redirect target for the sending link link_expiration: Optional number of days for the sending link to expire (14-45) type: Specifies the sending step: 'manage' (default), 'edit', 'send-invite' Returns: CreateEmbeddedSendingResponse with entity type, and URL """ headers = get_http_headers() token = token_provider.get_access_token(headers) if not token: raise ValueError("No access token available") # Initialize client and use the imported function from embedded_sending module client = SignNowAPIClient(token_provider.signnow_config) return _create_embedded_sending(entity_id, entity_type, redirect_uri, redirect_target, link_expiration, type, token, client) @mcp.tool(name="create_embedded_editor", description="Create embedded editor for editing a document or document group", tags=["edit", "document", "document_group", "embedded"]) def create_embedded_editor( ctx: Context, entity_id: Annotated[str, Field(description="ID of the document or document group")], entity_type: Annotated[ Literal["document", "document_group"] | None, Field(description="Type of entity: 'document' or 'document_group' (optional). If you're passing it, make sure you know what type you have. If it's not found, try using a different type."), ] = None, redirect_uri: Annotated[str | None, Field(description="Optional redirect URI after completion")] = None, redirect_target: Annotated[str | None, Field(description="Optional redirect target: 'self' (default), 'blank'")] = None, link_expiration: Annotated[int | None, Field(ge=15, le=43200, description="Optional link expiration in minutes (15-43200)")] = None, ) -> CreateEmbeddedEditorResponse: """Create embedded editor for editing a document or document group. This tool is ONLY for documents and document groups. If you have template or template group, you have to convert it to document or document group first, using create_from_template tool Args: entity_id: ID of the document or document group entity_type: Type of entity: 'document' or 'document_group' (optional). If you're passing it, make sure you know what type you have. If it's not found, try using a different type. redirect_uri: Optional redirect URI for the editor link redirect_target: Optional redirect target for the editor link link_expiration: Optional number of minutes for the editor link to expire (15-43200) Returns: CreateEmbeddedEditorResponse with editor ID and entity type """ headers = get_http_headers() token = token_provider.get_access_token(headers) if not token: raise ValueError("No access token available") # Initialize client and use the imported function from embedded_editor module client = SignNowAPIClient(token_provider.signnow_config) return _create_embedded_editor(entity_id, entity_type, redirect_uri, redirect_target, link_expiration, token, client) @mcp.tool( name="create_from_template", description="Create a new document or document group from an existing template or template group", tags=["template", "template_group", "document", "document_group", "create", "workflow"], ) def create_from_template( ctx: Context, entity_id: Annotated[str, Field(description="ID of the template or template group")], entity_type: Annotated[ Literal["template", "template_group"] | None, Field(description="Type of entity: 'template' or 'template_group' (optional). If you're passing it, make sure you know what type you have. If it's not found, try using a different type."), ] = None, name: Annotated[str | None, Field(description="Optional name for the new document group or document (required for template groups)")] = None, ) -> CreateFromTemplateResponse: """Create a new document or document group from an existing template or template group. Args: entity_id: ID of the template or template group entity_type: Type of entity: 'template' or 'template_group' (optional). If you're passing it, make sure you know what type you have. If it's not found, try using a different type. name: Optional name for the new document group or document (required for template groups) Returns: CreateFromTemplateResponse with created entity ID, type and name """ headers = get_http_headers() token = token_provider.get_access_token(headers) if not token: raise ValueError("No access token available") # Initialize client and use the imported function from create_from_template module client = SignNowAPIClient(token_provider.signnow_config) return _create_from_template(entity_id, entity_type, name, token, client) @mcp.tool( name="send_invite_from_template", description="Create document/group from template and send invite immediately", tags=["template", "template_group", "document", "document_group", "send_invite", "workflow"], ) async def send_invite_from_template( ctx: Context, entity_id: Annotated[str, Field(description="ID of the template or template group")], entity_type: Annotated[ Literal["template", "template_group"] | None, Field(description="Type of entity: 'template' or 'template_group' (optional). If you're passing it, make sure you know what type you have. If it's not found, try using a different type."), ] = None, name: Annotated[str | None, Field(description="Optional name for the new document or document group")] = None, orders: Annotated[list[InviteOrder] | None, Field(description="List of orders with recipients for the invite")] = None, ) -> SendInviteFromTemplateResponse: """Create document or document group from template and send invite immediately. This tool combines two operations: 1. Creates a document/group from template using create_from_template 2. Sends an invite to the created entity using send_invite Args: entity_id: ID of the template or template group entity_type: Type of entity: 'template' or 'template_group' (optional). If you're passing it, make sure you know what type you have. If it's not found, try using a different type. name: Optional name for the new document or document group orders: List of orders with recipients for the invite Returns: SendInviteFromTemplateResponse with created entity info and invite details """ headers = get_http_headers() token = token_provider.get_access_token(headers) if not token: raise ValueError("No access token available") # Initialize client and use the imported function from send_invite module client = SignNowAPIClient(token_provider.signnow_config) return await _send_invite_from_template(entity_id, entity_type, name, orders or [], token, client, ctx) @mcp.tool( name="create_embedded_sending_from_template", description="Create document/group from template and create embedded sending immediately", tags=["template", "template_group", "document", "document_group", "send_invite", "embedded", "workflow"], ) async def create_embedded_sending_from_template( ctx: Context, entity_id: Annotated[str, Field(description="ID of the template or template group")], entity_type: Annotated[ Literal["template", "template_group"] | None, Field(description="Type of entity: 'template' or 'template_group' (optional). If you're passing it, make sure you know what type you have. If it's not found, try using a different type."), ] = None, name: Annotated[str | None, Field(description="Optional name for the new document or document group")] = None, redirect_uri: Annotated[str | None, Field(description="Optional redirect URI after completion")] = None, redirect_target: Annotated[str | None, Field(description="Optional redirect target: 'self' (default), 'blank'")] = None, link_expiration: Annotated[int | None, Field(ge=14, le=45, description="Optional link expiration in days (14-45)")] = None, type: Annotated[Literal["manage", "edit", "send-invite"] | None, Field(description="Type of sending step: 'manage', 'edit', or 'send-invite'")] = None, ) -> CreateEmbeddedSendingFromTemplateResponse: """Create document or document group from template and create embedded sending immediately. This tool combines two operations: 1. Creates a document/group from template using create_from_template 2. Creates an embedded sending for the created entity using create_embedded_sending Args: entity_id: ID of the template or template group entity_type: Type of entity: 'template' or 'template_group' (optional). If you're passing it, make sure you know what type you have. If it's not found, try using a different type. name: Optional name for the new document or document group redirect_uri: Optional redirect URI after completion redirect_target: Optional redirect target: 'self', 'blank', or 'self' (default) link_expiration: Optional link expiration in days (14-45) type: Type of sending step: 'manage', 'edit', or 'send-invite' Returns: CreateEmbeddedSendingFromTemplateResponse with created entity info and embedded sending details """ headers = get_http_headers() token = token_provider.get_access_token(headers) if not token: raise ValueError("No access token available") # Initialize client and use the imported function from embedded_sending module client = SignNowAPIClient(token_provider.signnow_config) return await _create_embedded_sending_from_template(entity_id, entity_type, name, redirect_uri, redirect_target, link_expiration, type, token, client, ctx) @mcp.tool( name="create_embedded_editor_from_template", description="Create document/group from template and create embedded editor immediately", tags=["template", "template_group", "document", "document_group", "embedded_editor", "embedded", "workflow"], ) async def create_embedded_editor_from_template( ctx: Context, entity_id: Annotated[str, Field(description="ID of the template or template group")], entity_type: Annotated[ Literal["template", "template_group"] | None, Field(description="Type of entity: 'template' or 'template_group' (optional). If you're passing it, make sure you know what type you have. If it's not found, try using a different type."), ] = None, name: Annotated[str | None, Field(description="Name for the new document or document group")] = None, redirect_uri: Annotated[str | None, Field(description="Optional redirect URI after completion")] = None, redirect_target: Annotated[str | None, Field(description="Optional redirect target: 'self' (default), 'blank'")] = None, link_expiration: Annotated[int | None, Field(ge=15, le=43200, description="Optional link expiration in minutes (15-43200)")] = None, ) -> CreateEmbeddedEditorFromTemplateResponse: """Create document or document group from template and create embedded editor immediately. This tool combines two operations: 1. Creates a document/group from template using create_from_template 2. Creates an embedded editor for the created entity using create_embedded_editor Args: entity_id: ID of the template or template group entity_type: Type of entity: 'template' or 'template_group' (optional). If you're passing it, make sure you know what type you have. If it's not found, try using a different type. name: Optional name for the new document or document group redirect_uri: Optional redirect URI after completion redirect_target: Optional redirect target: 'self', 'blank', or 'self' (default) link_expiration: Optional link expiration in minutes (15-43200) Returns: CreateEmbeddedEditorFromTemplateResponse with created entity info and embedded editor details """ headers = get_http_headers() token = token_provider.get_access_token(headers) if not token: raise ValueError("No access token available") # Initialize client and use the imported function from embedded_editor module client = SignNowAPIClient(token_provider.signnow_config) return await _create_embedded_editor_from_template(entity_id, entity_type, name, redirect_uri, redirect_target, link_expiration, token, client, ctx) @mcp.tool( name="create_embedded_invite_from_template", description="Create document/group from template and create embedded invite immediately", tags=["template", "template_group", "document", "document_group", "send_invite", "embedded", "workflow"], ) async def create_embedded_invite_from_template( ctx: Context, entity_id: Annotated[str, Field(description="ID of the template or template group")], entity_type: Annotated[ Literal["template", "template_group"] | None, Field(description="Type of entity: 'template' or 'template_group' (optional). If you're passing it, make sure you know what type you have. If it's not found, try using a different type."), ] = None, name: Annotated[str | None, Field(description="Optional name for the new document or document group")] = None, orders: Annotated[list[EmbeddedInviteOrder] | None, Field(description="List of orders with recipients for the embedded invite")] = None, ) -> CreateEmbeddedInviteFromTemplateResponse: """Create document or document group from template and create embedded invite immediately. This tool combines two operations: 1. Creates a document/group from template using create_from_template 2. Creates an embedded invite for the created entity using create_embedded_invite Args: entity_id: ID of the template or template group entity_type: Type of entity: 'template' or 'template_group' (optional). If you're passing it, make sure you know what type you have. If it's not found, try using a different type. name: Optional name for the new document or document group orders: List of orders with recipients for the embedded invite Returns: CreateEmbeddedInviteFromTemplateResponse with created entity info and embedded invite details """ headers = get_http_headers() token = token_provider.get_access_token(headers) if not token: raise ValueError("No access token available") # Initialize client and use the imported function from embedded_invite module client = SignNowAPIClient(token_provider.signnow_config) return await _create_embedded_invite_from_template(entity_id, entity_type, name, orders or [], token, client, ctx) @mcp.tool(name="get_invite_status", description="Get invite status for a document or document group", tags=["invite", "status", "document", "document_group", "workflow"]) def get_invite_status( ctx: Context, entity_id: Annotated[str, Field(description="ID of the document or document group")], entity_type: Annotated[ Literal["document", "document_group"] | None, Field(description="Type of entity: 'document' or 'document_group' (optional). If you're passing it, make sure you know what type you have. If it's not found, try using a different type."), ] = None, ) -> InviteStatus: """Get invite status for a document or document group. Args: entity_id: ID of the document or document group entity_type: Type of entity: 'document' or 'document_group' (optional). If you're passing it, make sure you know what type you have. If it's not found, try using a different type. Returns: InviteStatus with invite ID, status, and steps information """ headers = get_http_headers() token = token_provider.get_access_token(headers) if not token: raise ValueError("No access token available") # Initialize client and use the imported function from invite_status module client = SignNowAPIClient(token_provider.signnow_config) return _get_invite_status(entity_id, entity_type, token, client) @mcp.tool(name="get_document_download_link", description="Get download link for a document or document group", tags=["document", "document_group", "download", "link"]) def get_document_download_link( ctx: Context, entity_id: Annotated[str, Field(description="ID of the document or document group")], entity_type: Annotated[ Literal["document", "document_group"] | None, Field(description="Type of entity: 'document' or 'document_group' (optional). If you're passing it, make sure you know what type you have. If it's not found, try using a different type."), ] = None, ) -> DocumentDownloadLinkResponse: """Get download link for a document or document group. For documents: Returns direct download link. For document groups: Merges all documents in the group and returns download link for the merged document. Args: entity_id: ID of the document or document group entity_type: Type of entity: 'document' or 'document_group' (optional). If you're passing it, make sure you know what type you have. If it's not found, try using a different type. Returns: DocumentDownloadLinkResponse with download link """ headers = get_http_headers() token = token_provider.get_access_token(headers) if not token: raise ValueError("No access token available") # Initialize client and use the imported function from document_download_link module client = SignNowAPIClient(token_provider.signnow_config) return _get_document_download_link(entity_id, entity_type, token, client) @mcp.tool(name="get_document", description="Get full document or document group information with field values", tags=["document", "document_group", "get", "fields"]) def get_document( ctx: Context, entity_id: Annotated[str, Field(description="ID of the document or document group to retrieve")], entity_type: Annotated[ Literal["document", "document_group"] | None, Field(description="Type of entity: 'document' or 'document_group' (optional). If not provided, will be determined automatically"), ] = None, ) -> DocumentGroup: """Get full document or document group information with field values. Always returns a unified DocumentGroup wrapper even for a single document. This tool retrieves complete information about a document or document group, including all field values, roles, and metadata. If entity_type is not provided, the tool will automatically determine whether the entity is a document or document group. For documents, returns a DocumentGroup with a single document. For document groups, returns a DocumentGroup with all documents in the group. Args: entity_id: ID of the document or document group to retrieve entity_type: Type of entity: 'document' or 'document_group' (optional) Returns: DocumentGroup with complete information including field values for all documents """ headers = get_http_headers() token = token_provider.get_access_token(headers) if not token: raise ValueError("No access token available") # Initialize client and use the imported function from document module client = SignNowAPIClient(token_provider.signnow_config) return _get_document(client, token, entity_id, entity_type) @mcp.tool( name="update_document_fields", description="Update text fields in multiple documents (only individual documents, not document groups)", tags=["document", "fields", "update", "prefill"], ) def update_document_fields(ctx: Context, update_requests: Annotated[list[UpdateDocumentFields], Field(description="Array of document field update requests")]) -> UpdateDocumentFieldsResponse: """Update text fields in multiple documents. This tool updates text fields in multiple documents using the SignNow API. Only text fields can be updated using the prefill_text_fields endpoint. IMPORTANT: This tool works only with individual documents, not document groups. To find out what fields are available in a document or document group, use the get_document tool first. Args: update_requests: Array of UpdateDocumentFields with document IDs and fields to update Returns: UpdateDocumentFieldsResponse with results for each document update """ headers = get_http_headers() token = token_provider.get_access_token(headers) if not token: raise ValueError("No access token available") # Initialize client and use the imported function from document module client = SignNowAPIClient(token_provider.signnow_config) return _update_document_fields(client, token, update_requests) # @mcp.tool( # name="upload_document", # description="Upload a document to SignNow", # tags=["document", "upload", "file"] # ) # def upload_document( # ctx: Context, # file_content: Annotated[bytes, Field(description="Document file content as bytes")], # filename: Annotated[str, Field(description="Name of the file to upload")], # check_fields: Annotated[bool, Field(description="Whether to check for fields in the document (default: True)")] = True # ) -> UploadDocumentResponse: # """Upload a document to SignNow. # This tool uploads a document file to SignNow and returns the document ID. # The uploaded document can then be used for signing workflows. # Args: # file_content: Document file content as bytes # filename: Name of the file to upload # check_fields: Whether to check for fields in the document (default: True) # Returns: # UploadDocumentResponse with uploaded document ID, filename, and check_fields status # """ # headers = get_http_headers() # token = token_provider.get_access_token(headers) # if not token: # raise ValueError("No access token available") # # Initialize client and use the imported function from upload_document module # client = SignNowAPIClient(token_provider.signnow_config) # return _upload_document(file_content, filename, check_fields, token, client) return

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/mihasicehcek/sn-mcp-server'

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